chore: use lizardbyte-common in c++ (#5356)

Co-authored-by: Kishi <41839133+Kishi85@users.noreply.github.com>
This commit is contained in:
Dave Lane
2026-06-30 19:12:10 -04:00
committed by GitHub
parent bba6c6cac0
commit 09dc9e4c35
34 changed files with 103 additions and 226 deletions

View File

@@ -15,10 +15,12 @@ include_directories("${CMAKE_SOURCE_DIR}")
enable_testing()
# Add GoogleTest directory to the project
set(GTEST_SOURCE_DIR "${CMAKE_SOURCE_DIR}/third-party/googletest")
set(GTEST_SOURCE_DIR "${CMAKE_SOURCE_DIR}/third-party/lizardbyte-common/third-party/googletest")
set(INSTALL_GTEST OFF)
set(INSTALL_GMOCK OFF)
add_subdirectory("${GTEST_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/googletest")
if(NOT TARGET gtest)
add_subdirectory("${GTEST_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/googletest")
endif()
include_directories("${GTEST_SOURCE_DIR}/googletest/include" "${GTEST_SOURCE_DIR}")
# coverage
@@ -167,7 +169,7 @@ add_dependencies(${PROJECT_NAME} sync_locale_files)
# Build the list of libraries to link
set(TEST_LINK_LIBRARIES
${SUNSHINE_EXTERNAL_LIBRARIES}
gtest
lizardbyte::test_support
${PLATFORM_LIBRARIES}
)

View File

@@ -20,9 +20,10 @@
// local includes
#include "src/file_handler.h"
class ConfigConsistencyTest: public ::testing::Test {
class ConfigConsistencyTest: public BaseTest {
protected:
void SetUp() override {
BaseTest::SetUp();
// Define the expected mapping between documentation sections and UI tabs
expectedDocToTabMapping = {
{"General", "general"},

View File

@@ -37,9 +37,10 @@ struct ExternalCommandTestData {
xfail_reason(std::move(xfail_rsn)) {}
};
class ExternalCommandTest: public ::testing::TestWithParam<ExternalCommandTestData> {
class ExternalCommandTest: public BaseTest, public ::testing::WithParamInterface<ExternalCommandTestData> {
protected:
void SetUp() override {
BaseTest::SetUp();
if constexpr (IS_WINDOWS) {
current_platform = "windows";
} else if constexpr (IS_MACOS) {

View File

@@ -23,7 +23,7 @@
namespace fs = std::filesystem;
class LocaleConsistencyTest: public ::testing::Test {
class LocaleConsistencyTest: public BaseTest {
protected:
// Extract locale options from config.cpp
static std::set<std::string, std::less<>> extractConfigCppLocales() {

View File

@@ -12,7 +12,7 @@
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
#include <gtest/gtest.h>
#include <lizardbyte/common/testing.h>
#include <src/globals.h>
#include <src/logging.h>
#include <src/platform/common.h>
@@ -146,7 +146,7 @@ namespace test_utils {
#define IS_FREEBSD false
#endif
struct PlatformTestSuite: testing::Test {
struct PlatformTestSuite: BaseTest {
static void SetUpTestSuite() {
ASSERT_FALSE(platf_deinit);
BOOST_LOG(tests) << "Setting up platform test suite";

View File

@@ -5,7 +5,7 @@
#pragma once
#include "tests_common.h"
struct SunshineEventListener: testing::EmptyTestEventListener {
struct SunshineEventListener: BufferedTestEventListener {
SunshineEventListener() {
sink = boost::make_shared<sink_t>();
sink_buffer = boost::make_shared<std::stringstream>();
@@ -14,51 +14,30 @@ struct SunshineEventListener: testing::EmptyTestEventListener {
}
void OnTestProgramStart(const testing::UnitTest &unit_test) override {
static_cast<void>(unit_test);
boost::log::core::get()->add_sink(sink);
}
void OnTestProgramEnd(const testing::UnitTest &unit_test) override {
static_cast<void>(unit_test);
boost::log::core::get()->remove_sink(sink);
}
void OnTestStart(const testing::TestInfo &test_info) override {
BOOST_LOG(tests) << "From " << test_info.file() << ":" << test_info.line();
BOOST_LOG(tests) << " " << test_info.test_suite_name() << "/" << test_info.name() << " started";
protected:
void logTestEvent(const std::string &message) override {
BOOST_LOG(tests) << message;
}
void OnTestPartResult(const testing::TestPartResult &test_part_result) override {
std::string file = test_part_result.file_name();
BOOST_LOG(tests) << "At " << file << ":" << test_part_result.line_number();
auto result_text = test_part_result.passed() ? "Success" :
test_part_result.nonfatally_failed() ? "Non-fatal failure" :
test_part_result.fatally_failed() ? "Failure" :
"Skip";
std::string summary = test_part_result.summary();
std::string message = test_part_result.message();
BOOST_LOG(tests) << " " << result_text << ": " << summary;
if (message != summary) {
BOOST_LOG(tests) << " " << message;
}
[[nodiscard]] std::string bufferedTestOutput() const override {
return sink_buffer->str();
}
void OnTestEnd(const testing::TestInfo &test_info) override {
auto &result = *test_info.result();
auto result_text = result.Passed() ? "passed" :
result.Skipped() ? "skipped" :
"failed";
BOOST_LOG(tests) << test_info.test_suite_name() << "/" << test_info.name() << " " << result_text;
if (result.Failed()) {
std::cout << sink_buffer->str();
}
void clearBufferedTestOutput() override {
sink_buffer->str("");
sink_buffer->clear();
}
private:
using sink_t = boost::log::sinks::synchronous_sink<boost::log::sinks::text_ostream_backend>;
boost::shared_ptr<sink_t> sink;
boost::shared_ptr<std::stringstream> sink_buffer;

View File

@@ -7,48 +7,6 @@
#include <boost/asio/ip/host_name.hpp>
#include <src/platform/common.h>
struct SetEnvTest: ::testing::TestWithParam<std::tuple<std::string, std::string, int>> {
protected:
void TearDown() override {
// Clean up environment variable after each test
const auto &[name, value, expected] = GetParam();
platf::unset_env(name);
}
};
TEST_P(SetEnvTest, SetEnvironmentVariableTests) {
const auto &[name, value, expected] = GetParam();
platf::set_env(name, value);
const char *env_value = std::getenv(name.c_str());
if (expected == 0 && !value.empty()) {
ASSERT_NE(env_value, nullptr);
ASSERT_EQ(std::string(env_value), value);
} else {
ASSERT_EQ(env_value, nullptr);
}
}
TEST_P(SetEnvTest, UnsetEnvironmentVariableTests) {
const auto &[name, value, expected] = GetParam();
platf::unset_env(name);
const char *env_value = std::getenv(name.c_str());
if (expected == 0) {
ASSERT_EQ(env_value, nullptr);
}
}
INSTANTIATE_TEST_SUITE_P(
SetEnvTests,
SetEnvTest,
::testing::Values(
std::make_tuple("SUNSHINE_UNIT_TEST_ENV_VAR", "test_value_0", 0),
std::make_tuple("SUNSHINE_UNIT_TEST_ENV_VAR", "test_value_1", 0),
std::make_tuple("", "test_value", -1)
)
);
TEST(HostnameTests, TestAsioEquality) {
// These should be equivalent on all platforms for ASCII hostnames
ASSERT_EQ(platf::get_host_name(), boost::asio::ip::host_name());

View File

@@ -16,7 +16,7 @@
/**
* @brief Test fixture for utf_utils namespace functions
*/
class UtfUtilsTest: public testing::Test {};
class UtfUtilsTest: public BaseTest {};
TEST_F(UtfUtilsTest, FromUtf8WithEmptyString) {
const std::string empty_string = "";

View File

@@ -10,6 +10,7 @@ using namespace audio;
struct AudioTest: PlatformTestSuite, testing::WithParamInterface<std::tuple<std::basic_string_view<char>, config_t>> {
void SetUp() override {
BaseTest::SetUp();
m_config = std::get<1>(GetParam());
m_mail = std::make_shared<safe::mail_raw_t>();
}

View File

@@ -89,7 +89,7 @@ X4wnh1bwdiidqpcgyuKossLOPxbS786WmsesaAWPnpoY6M8aija+ALwNNuWWmyMg
*
* This fixture creates a real server to test the actual confighttp functions.
*/
class ConfigHttpTest: public ::testing::Test { // NOSONAR(cpp:S3656) - protected members are intentional for test fixture subclassing
class ConfigHttpTest: public BaseTest { // NOSONAR(cpp:S3656) - protected members are intentional for test fixture subclassing
protected:
std::unique_ptr<SimpleWeb::Server<SimpleWeb::HTTPS>> server;
std::unique_ptr<SimpleWeb::Client<SimpleWeb::HTTPS>> client;
@@ -107,6 +107,7 @@ protected:
std::filesystem::path web_dir_test_file;
void SetUp() override {
BaseTest::SetUp();
// Save current config
saved_username = config::sunshine.username;
saved_password = config::sunshine.password;
@@ -354,6 +355,7 @@ protected:
if (std::filesystem::exists(test_web_dir)) {
std::filesystem::remove_all(test_web_dir);
}
BaseTest::TearDown();
}
static std::string create_auth_header(const std::string &username, const std::string &password) {
@@ -1251,7 +1253,6 @@ TEST_F(BrowseDirectoryTest, IsBrowsableExecutable_LinuxGroupExecBit_ReturnsTrue)
TEST_F(BrowseDirectoryTest, BuildBrowseEntries_TypeAny_ReturnsAllEntries) {
const auto entries = confighttp::build_browse_entries(browse_test_dir, "any");
ASSERT_TRUE(entries.is_array());
// subdir_a, subdir_b, file_alpha.txt, file_beta.txt, test_exec[.exe] = 5
ASSERT_EQ(entries.size(), 5u);
}

View File

@@ -43,7 +43,7 @@ namespace {
const std::string max_uint_string {std::to_string(std::numeric_limits<unsigned int>::max())};
template<class T>
struct DisplayDeviceConfigTest: testing::TestWithParam<T> {};
struct DisplayDeviceConfigTest: BaseTest, testing::WithParamInterface<T> {};
} // namespace
using ParseDeviceId = DisplayDeviceConfigTest<std::pair<std::string, std::string>>;

View File

@@ -7,7 +7,7 @@
#include <format>
#include <src/file_handler.h>
struct FileHandlerParentDirectoryTest: testing::TestWithParam<std::tuple<std::string, std::string>> {};
struct FileHandlerParentDirectoryTest: BaseTest, testing::WithParamInterface<std::tuple<std::string, std::string>> {};
TEST_P(FileHandlerParentDirectoryTest, Run) {
auto [input, expected] = GetParam();
@@ -24,7 +24,7 @@ INSTANTIATE_TEST_SUITE_P(
)
);
struct FileHandlerMakeDirectoryTest: testing::TestWithParam<std::tuple<std::string, bool, bool>> {};
struct FileHandlerMakeDirectoryTest: BaseTest, testing::WithParamInterface<std::tuple<std::string, bool, bool>> {};
TEST_P(FileHandlerMakeDirectoryTest, Run) {
auto [input, expected, remove] = GetParam();
@@ -52,7 +52,7 @@ INSTANTIATE_TEST_SUITE_P(
)
);
struct FileHandlerTests: testing::TestWithParam<std::tuple<int, std::string>> {};
struct FileHandlerTests: BaseTest, testing::WithParamInterface<std::tuple<int, std::string>> {};
INSTANTIATE_TEST_SUITE_P(
TestFiles,

View File

@@ -76,7 +76,7 @@ X4wnh1bwdiidqpcgyuKossLOPxbS786WmsesaAWPnpoY6M8aija+ALwNNuWWmyMg
9SVDV76xJzM36Uq7Kg3QJYTlY04WmPIdJHkCtXWf9g==
-----END CERTIFICATE-----)";
struct PairingTest: testing::TestWithParam<std::tuple<pairing_input, pairing_output>> {};
struct PairingTest: BaseTest, testing::WithParamInterface<std::tuple<pairing_input, pairing_output>> {};
TEST_P(PairingTest, Run) {
auto [input, expected] = GetParam();

View File

@@ -11,7 +11,7 @@
// local imports
#include <src/httpcommon.h>
struct UrlEscapeTest: testing::TestWithParam<std::tuple<std::string, std::string>> {};
struct UrlEscapeTest: BaseTest, testing::WithParamInterface<std::tuple<std::string, std::string>> {};
TEST_P(UrlEscapeTest, Run) {
const auto &[input, expected] = GetParam();
@@ -28,7 +28,7 @@ INSTANTIATE_TEST_SUITE_P(
)
);
struct UrlGetHostTest: testing::TestWithParam<std::tuple<std::string, std::string>> {};
struct UrlGetHostTest: BaseTest, testing::WithParamInterface<std::tuple<std::string, std::string>> {};
TEST_P(UrlGetHostTest, Run) {
const auto &[input, expected] = GetParam();
@@ -45,7 +45,7 @@ INSTANTIATE_TEST_SUITE_P(
)
);
struct DownloadFileTest: testing::TestWithParam<std::tuple<std::string, std::string>> {};
struct DownloadFileTest: BaseTest, testing::WithParamInterface<std::tuple<std::string, std::string>> {};
TEST_P(DownloadFileTest, Run) {
const auto &[url, filename] = GetParam();

View File

@@ -22,7 +22,7 @@ namespace {
constexpr auto log_file = "test_sunshine.log";
} // namespace
struct LogLevelsTest: testing::TestWithParam<decltype(log_levels)::value_type> {};
struct LogLevelsTest: BaseTest, testing::WithParamInterface<decltype(log_levels)::value_type> {};
INSTANTIATE_TEST_SUITE_P(
Logging,

View File

@@ -8,6 +8,7 @@
struct MouseHIDTest: PlatformTestSuite, testing::WithParamInterface<util::point_t> {
void SetUp() override {
BaseTest::SetUp();
#ifdef _WIN32
// TODO: Windows tests are failing, `get_mouse_loc` seems broken and `platf::abs_mouse` too
// the alternative `platf::abs_mouse` method seem to work better during tests,
@@ -21,6 +22,7 @@ struct MouseHIDTest: PlatformTestSuite, testing::WithParamInterface<util::point_
void TearDown() override {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
BaseTest::TearDown();
}
};

View File

@@ -6,7 +6,7 @@
#include <src/network.h>
struct MdnsInstanceNameTest: testing::TestWithParam<std::tuple<std::string, std::string>> {};
struct MdnsInstanceNameTest: BaseTest, testing::WithParamInterface<std::tuple<std::string, std::string>> {};
TEST_P(MdnsInstanceNameTest, Run) {
auto [input, expected] = GetParam();
@@ -30,11 +30,12 @@ INSTANTIATE_TEST_SUITE_P(
/**
* @brief Test fixture for bind_address tests with setup/teardown
*/
class BindAddressTest: public ::testing::Test {
class BindAddressTest: public BaseTest {
protected:
std::string original_bind_address;
void SetUp() override {
BaseTest::SetUp();
// Save the original bind_address config
original_bind_address = config::sunshine.bind_address;
}
@@ -42,6 +43,7 @@ protected:
void TearDown() override {
// Restore the original bind_address config
config::sunshine.bind_address = original_bind_address;
BaseTest::TearDown();
}
};

View File

@@ -14,9 +14,10 @@
namespace fs = std::filesystem;
class ProcessPNGTest: public ::testing::Test {
class ProcessPNGTest: public BaseTest {
protected:
void SetUp() override {
BaseTest::SetUp();
// Create test directory
test_dir = fs::temp_directory_path() / "sunshine_process_png_test"; // NOSONAR(cpp:S5443) - safe for tests
fs::create_directories(test_dir);
@@ -27,6 +28,7 @@ protected:
if (fs::exists(test_dir)) {
fs::remove_all(test_dir);
}
BaseTest::TearDown();
}
// Helper function to create a file with specific content

View File

@@ -8,6 +8,7 @@
struct EncoderTest: PlatformTestSuite, testing::WithParamInterface<video::encoder_t *> {
void SetUp() override {
BaseTest::SetUp();
auto &encoder = *GetParam();
if (!video::validate_encoder(encoder, false)) {
// Encoder failed validation,
@@ -49,7 +50,7 @@ TEST_P(EncoderTest, ValidateEncoder) {
// todo:: test something besides fixture setup
}
struct FramerateX100Test: testing::TestWithParam<std::tuple<std::int32_t, AVRational>> {};
struct FramerateX100Test: BaseTest, testing::WithParamInterface<std::tuple<std::int32_t, AVRational>> {};
TEST_P(FramerateX100Test, Run) {
const auto &[x100, expected] = GetParam();