From b333e68361e8c06fb25faa3fb05f17423699b349 Mon Sep 17 00:00:00 2001 From: xiepengfei Date: Wed, 15 Jul 2026 09:06:07 +0800 Subject: [PATCH] test(coop): add cooperation core module coverage tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests for Settings, ConfigManager, CommonUitls, filesystem, CooperationUtil, phone helpers and discover controller safe paths. Add crash signal handler in main.cpp to flush gcov on SIGSEGV. 新增cooperation核心模块测试,覆盖配置管理、通用工具、文件系统、 协作工具、手机模块和发现控制器的安全路径。main.cpp添加崩溃信号 处理器以确保段错误时刷新gcov覆盖率数据。 Log: 添加cooperation模块覆盖率测试 Influence: 仅新增测试文件和main.cpp信号处理,不影响现有功能逻辑。 --- tests/coop/CMakeLists.txt | 12 +- tests/coop/commonutils_test.cpp | 116 ++++++++ tests/coop/configmanager_test.cpp | 47 +++ tests/coop/cooperation_extra_test.cpp | 140 +++++++++ tests/coop/discover_safe_test.cpp | 154 ++++++++++ tests/coop/filesystem_test.cpp | 117 ++++++++ tests/coop/main.cpp | 15 +- tests/coop/phone_smoke_test.cpp | 227 ++++++++++++++ tests/coop/settings_test.cpp | 276 ++++++++++++++++++ .../session_core/session_integration_test.cpp | 220 ++++++++++++++ 10 files changed, 1319 insertions(+), 5 deletions(-) create mode 100644 tests/coop/commonutils_test.cpp create mode 100644 tests/coop/configmanager_test.cpp create mode 100644 tests/coop/cooperation_extra_test.cpp create mode 100644 tests/coop/discover_safe_test.cpp create mode 100644 tests/coop/filesystem_test.cpp create mode 100644 tests/coop/phone_smoke_test.cpp create mode 100644 tests/coop/settings_test.cpp create mode 100644 tests/session_core/session_integration_test.cpp diff --git a/tests/coop/CMakeLists.txt b/tests/coop/CMakeLists.txt index a672ec4e8..840a5ea60 100644 --- a/tests/coop/CMakeLists.txt +++ b/tests/coop/CMakeLists.txt @@ -69,7 +69,15 @@ add_executable(coop_tests ${COOP_SRC} ${CMAKE_SOURCE_DIR}/tests/session_core/protoendpoint_test.cpp ${CMAKE_SOURCE_DIR}/tests/session_core/protoclient_server_test.cpp ${CMAKE_SOURCE_DIR}/tests/session_core/cooperationcore_test.cpp - ${CMAKE_SOURCE_DIR}/tests/session_core/discover_extra_test.cpp) + ${CMAKE_SOURCE_DIR}/tests/session_core/discover_extra_test.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/settings_test.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/configmanager_test.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/commonutils_test.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/filesystem_test.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/cooperation_extra_test.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/phone_smoke_test.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/discover_safe_test.cpp + ${CMAKE_SOURCE_DIR}/tests/session_core/session_integration_test.cpp) target_compile_options(coop_tests PRIVATE -fno-access-control -fprofile-arcs -ftest-coverage) target_compile_definitions(coop_tests PRIVATE EXECUTABLE_PROG_DIR="${CMAKE_BINARY_DIR}" ENABLE_PHONE=1) target_include_directories(coop_tests PRIVATE @@ -91,5 +99,5 @@ endif() if(VNCCLIENT_LIBRARY) target_link_libraries(coop_tests PRIVATE ${VNCCLIENT_LIBRARY}) endif() -target_link_options(coop_tests PRIVATE -fprofile-arcs -ftest-coverage) +target_link_options(coop_tests PRIVATE -fprofile-arcs -ftest-coverage -Wl,--allow-multiple-definition) add_test(NAME coop_tests COMMAND coop_tests) diff --git a/tests/coop/commonutils_test.cpp b/tests/coop/commonutils_test.cpp new file mode 100644 index 000000000..7b5240fe5 --- /dev/null +++ b/tests/coop/commonutils_test.cpp @@ -0,0 +1,116 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include "common/commonutils.h" + +#include +#include +#include +#include + +using deepin_cross::CommonUitls; + +TEST(CommonUitlsTest, GenerateRandomPasswordIsSixDigits) +{ + QString pwd = CommonUitls::generateRandomPassword(); + EXPECT_EQ(pwd.length(), 6); + for (const QChar &c : pwd) { + EXPECT_TRUE(c.isDigit()); + } +} + +TEST(CommonUitlsTest, GenerateRandomPasswordProducesVariedOutput) +{ + QString a = CommonUitls::generateRandomPassword(); + QString b = CommonUitls::generateRandomPassword(); + EXPECT_EQ(a.length(), 6); + EXPECT_EQ(b.length(), 6); +} + +TEST(CommonUitlsTest, ElidedTextShortReturnsUnchanged) +{ + EXPECT_EQ(CommonUitls::elidedText("hi", Qt::ElideRight, 5).toStdString(), "hi"); + EXPECT_EQ(CommonUitls::elidedText("hi", Qt::ElideLeft, 5).toStdString(), "hi"); + EXPECT_EQ(CommonUitls::elidedText("hi", Qt::ElideMiddle, 5).toStdString(), "hi"); + EXPECT_EQ(CommonUitls::elidedText("hi", Qt::ElideNone, 5).toStdString(), "hi"); +} + +TEST(CommonUitlsTest, ElidedTextElideRight) +{ + QString out = CommonUitls::elidedText("abcdefghij", Qt::ElideRight, 5); + EXPECT_EQ(out.length(), 8); + EXPECT_TRUE(out.endsWith("...")); + EXPECT_EQ(out.left(5).toStdString(), "abcde"); +} + +TEST(CommonUitlsTest, ElidedTextElideLeft) +{ + QString out = CommonUitls::elidedText("abcdefghij", Qt::ElideLeft, 5); + EXPECT_EQ(out.length(), 8); + EXPECT_TRUE(out.startsWith("...")); + EXPECT_EQ(out.right(5).toStdString(), "fghij"); +} + +TEST(CommonUitlsTest, ElidedTextElideMiddle) +{ + QString out = CommonUitls::elidedText("abcdefghij", Qt::ElideMiddle, 5); + EXPECT_EQ(out.length(), 5); + EXPECT_TRUE(out.contains("...")); +} + +TEST(CommonUitlsTest, ElidedTextElideNoneReturnsOriginal) +{ + QString out = CommonUitls::elidedText("abcdefghij", Qt::ElideNone, 5); + EXPECT_EQ(out.toStdString(), "abcdefghij"); +} + +TEST(CommonUitlsTest, IsPortInUsePrivilegedPortOne) +{ + EXPECT_FALSE(CommonUitls::isPortInUse(1)); +} + +TEST(CommonUitlsTest, GetAvailablePortInRange) +{ + int port = CommonUitls::getAvailablePort(); + EXPECT_GE(port, 13628); + EXPECT_LT(port, 23628); +} + +TEST(CommonUitlsTest, IpcServerNameContainsAppName) +{ + QString name = CommonUitls::ipcServerName("myapp"); + EXPECT_FALSE(name.isEmpty()); + EXPECT_TRUE(name.contains("myapp")); + EXPECT_TRUE(name.contains(".ipc")); +} + +TEST(CommonUitlsTest, TipConfPathEndsWithFlag) +{ + QString path = CommonUitls::tipConfPath(); + EXPECT_FALSE(path.isEmpty()); + EXPECT_TRUE(path.endsWith("tip.flag")); +} + +TEST(CommonUitlsTest, IsFirstStartFlagTransitions) +{ + QString flagPath = QString("%1/%2/%3/first_run.flag") + .arg(QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation)) + .arg(qApp->organizationName()) + .arg(qApp->applicationName()); + QFile::remove(flagPath); + + EXPECT_TRUE(CommonUitls::isFirstStart()); + EXPECT_FALSE(CommonUitls::isFirstStart()); +} + +TEST(CommonUitlsTest, GetFirstIpDoesNotCrash) +{ + std::string ip = CommonUitls::getFirstIp(); + EXPECT_NO_FATAL_FAILURE(CommonUitls::getFirstIp()); + if (!ip.empty()) { + EXPECT_GT(ip.length(), static_cast(0)); + } +} diff --git a/tests/coop/configmanager_test.cpp b/tests/coop/configmanager_test.cpp new file mode 100644 index 000000000..236ab5978 --- /dev/null +++ b/tests/coop/configmanager_test.cpp @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include "configs/settings/configmanager.h" +#include "configs/settings/settings.h" + +#include + +TEST(CoopConfigManagerTest, InstanceIsSingleton) +{ + EXPECT_EQ(ConfigManager::instance(), ConfigManager::instance()); +} + +TEST(CoopConfigManagerTest, AppSettingReturnsValidSettings) +{ + Settings *s = ConfigManager::instance()->appSetting(); + ASSERT_NE(s, nullptr); + EXPECT_NE(s, nullptr); +} + +TEST(CoopConfigManagerTest, SetAndReadAppAttributeRoundTrip) +{ + ConfigManager::instance()->setAppAttribute("CoopUnitTestGroup", "someKey", 12345); + QVariant v = ConfigManager::instance()->appAttribute("CoopUnitTestGroup", "someKey"); + EXPECT_EQ(v.toInt(), 12345); +} + +TEST(CoopConfigManagerTest, AppAttributeUnknownReturnsInvalid) +{ + QVariant v = ConfigManager::instance()->appAttribute("NoSuchCoopGroup", "NoSuchKey"); + EXPECT_FALSE(v.isValid()); +} + +TEST(CoopConfigManagerTest, AppAttributeStringRoundTrip) +{ + ConfigManager::instance()->setAppAttribute("CoopStrGroup", "name", QVariant("hello")); + QVariant v = ConfigManager::instance()->appAttribute("CoopStrGroup", "name"); + EXPECT_EQ(v.toString().toStdString(), "hello"); +} + +TEST(CoopConfigManagerTest, SyncAppAttributeReturnsBool) +{ + EXPECT_NO_FATAL_FAILURE(ConfigManager::instance()->syncAppAttribute()); +} diff --git a/tests/coop/cooperation_extra_test.cpp b/tests/coop/cooperation_extra_test.cpp new file mode 100644 index 000000000..e9c56aac4 --- /dev/null +++ b/tests/coop/cooperation_extra_test.cpp @@ -0,0 +1,140 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include +#include + +#include "lib/cooperation/core/utils/cooperationutil.h" +#include "lib/cooperation/core/discover/deviceinfo.h" +#include "lib/cooperation/core/net/helper/sharehelper.h" +#include "lib/cooperation/core/net/helper/transferhelper.h" +#include "base/baseutils.h" + +using cooperation_core::CooperationUtil; +using cooperation_core::DeviceInfo; +using cooperation_core::ShareHelper; +using cooperation_core::TransferHelper; +using ::DeviceInfoPointer; +using deepin_cross::BaseUtils; + +TEST(CooperationExtraTest, MainWindowWidgetNullWithoutRegisteredWindow) +{ + EXPECT_EQ(CooperationUtil::instance()->mainWindowWidget(), nullptr); +} + +TEST(CooperationExtraTest, ActivateWindowNoCrashWithoutWindow) +{ + EXPECT_NO_FATAL_FAILURE(CooperationUtil::instance()->activateWindow()); +} + +TEST(CooperationExtraTest, RegisterDeviceOperationNoCrashWithoutWindow) +{ + QVariantMap map; + map.insert("id", QString("test-op")); + map.insert("description", QString("desc")); + EXPECT_NO_FATAL_FAILURE(CooperationUtil::instance()->registerDeviceOperation(map)); +} + +TEST(CooperationExtraTest, DeviceInfoReturnsExpectedKeys) +{ + QVariantMap info = CooperationUtil::deviceInfo(); + EXPECT_FALSE(info.isEmpty()); + EXPECT_TRUE(info.contains(AppSettings::IPAddress)); + EXPECT_TRUE(info.contains(AppSettings::OSType)); + EXPECT_TRUE(info.contains(AppSettings::DeviceNameKey)); + EXPECT_TRUE(info.contains(AppSettings::DiscoveryModeKey)); + EXPECT_TRUE(info.contains(AppSettings::TransferModeKey)); + EXPECT_TRUE(info.contains(AppSettings::StoragePathKey)); + EXPECT_TRUE(info.contains(AppSettings::LinkDirectionKey)); +} + +TEST(CooperationExtraTest, DeviceInfoDefaultOsTypeIsOther) +{ + DeviceInfoPointer info(new DeviceInfo); + EXPECT_EQ(info->osType(), BaseUtils::OS_TYPE::kOther); +} + +TEST(CooperationExtraTest, DeviceInfoOsTypeRoundTripAllValues) +{ + DeviceInfoPointer info(new DeviceInfo("1.1.1.1", "host")); + + info->setOsType(BaseUtils::OS_TYPE::kLinux); + EXPECT_EQ(info->osType(), BaseUtils::OS_TYPE::kLinux); + + info->setOsType(BaseUtils::OS_TYPE::kWindows); + EXPECT_EQ(info->osType(), BaseUtils::OS_TYPE::kWindows); + + info->setOsType(BaseUtils::OS_TYPE::kMacOS); + EXPECT_EQ(info->osType(), BaseUtils::OS_TYPE::kMacOS); + + info->setOsType(BaseUtils::OS_TYPE::kOther); + EXPECT_EQ(info->osType(), BaseUtils::OS_TYPE::kOther); +} + +TEST(CooperationExtraTest, DeviceInfoOsTypePersistsViaVariantMap) +{ + DeviceInfoPointer original(new DeviceInfo("2.2.2.2", "host2")); + original->setOsType(BaseUtils::OS_TYPE::kWindows); + + QVariantMap map = original->toVariantMap(); + EXPECT_EQ(map.value(AppSettings::OSType).toInt(), static_cast(BaseUtils::OS_TYPE::kWindows)); + + DeviceInfoPointer restored = DeviceInfo::fromVariantMap(map); + ASSERT_NE(restored, nullptr); + EXPECT_EQ(restored->osType(), BaseUtils::OS_TYPE::kWindows); +} + +TEST(CooperationExtraTest, DeviceInfoDeviceTypeDirectSetterRoundTrip) +{ + DeviceInfoPointer pc(new DeviceInfo("3.3.3.3", "pc")); + pc->setDeviceType(DeviceInfo::DeviceType::PC); + EXPECT_EQ(pc->deviceType(), DeviceInfo::DeviceType::PC); + + DeviceInfoPointer mob(new DeviceInfo("4.4.4.4", "phone")); + mob->setDeviceType(DeviceInfo::DeviceType::Mobile); + EXPECT_EQ(mob->deviceType(), DeviceInfo::DeviceType::Mobile); +} + +TEST(CooperationExtraTest, ShareHelperInstanceNonNull) +{ + EXPECT_NE(ShareHelper::instance(), nullptr); +} + +TEST(CooperationExtraTest, ShareHelperInstanceSamePointer) +{ + auto *a = ShareHelper::instance(); + auto *b = ShareHelper::instance(); + EXPECT_EQ(a, b); +} + +TEST(CooperationExtraTest, ShareHelperRegistConnectBtnNoCrash) +{ + EXPECT_NO_FATAL_FAILURE(ShareHelper::instance()->registConnectBtn()); +} + +TEST(CooperationExtraTest, TransferHelperInstanceNonNull) +{ + EXPECT_NE(TransferHelper::instance(), nullptr); +} + +TEST(CooperationExtraTest, TransferHelperInstanceSamePointer) +{ + auto *a = TransferHelper::instance(); + auto *b = TransferHelper::instance(); + EXPECT_EQ(a, b); +} + +TEST(CooperationExtraTest, TransferHelperRegistBtnNoCrash) +{ + EXPECT_NO_FATAL_FAILURE(TransferHelper::instance()->registBtn()); +} + +TEST(CooperationExtraTest, TransferHelperStatusEnumValues) +{ + EXPECT_NE(TransferHelper::Idle, TransferHelper::Confirming); + EXPECT_NE(TransferHelper::Connecting, TransferHelper::Transfering); + EXPECT_EQ(TransferHelper::instance()->transferStatus(), TransferHelper::Idle); +} diff --git a/tests/coop/discover_safe_test.cpp b/tests/coop/discover_safe_test.cpp new file mode 100644 index 000000000..1407d765b --- /dev/null +++ b/tests/coop/discover_safe_test.cpp @@ -0,0 +1,154 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include +#include +#include +#include +#include + +#include "lib/cooperation/core/discover/discovercontroller.h" +#include "lib/cooperation/core/discover/discovercontroller_p.h" +#include "lib/cooperation/core/discover/deviceinfo.h" +#include "lib/cooperation/core/global_defines.h" + +using namespace cooperation_core; + +namespace { +QString makeValidDeviceJson(const QString &ip, const QString &name) +{ + QVariantMap map; + map.insert(AppSettings::IPAddress, ip); + map.insert(AppSettings::DeviceNameKey, name); + map.insert(AppSettings::DiscoveryModeKey, 0); + map.insert(AppSettings::TransferModeKey, 0); + map.insert(AppSettings::LinkDirectionKey, 0); + map.insert(AppSettings::ClipboardShareKey, false); + map.insert(AppSettings::PeripheralShareKey, false); + map.insert(AppSettings::CooperationEnabled, true); + map.insert(AppSettings::OSType, 0); + + QJsonObject obj = QJsonObject::fromVariantMap(map); + return QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::Compact)); +} +} // namespace + +class DiscoverSafeTest : public ::testing::Test { +protected: + void SetUp() override + { + auto *c = DiscoverController::instance(); + c->_historyDevices.clear(); + c->d->onlineDeviceList.clear(); + c->d->historyDeviceMap.clear(); + c->d->searchDevice.reset(); + } +}; + +TEST_F(DiscoverSafeTest, UpdatePublishNoopBeforeZeroConfInit) +{ + EXPECT_NO_FATAL_FAILURE(DiscoverController::instance()->updatePublish()); +} + +TEST_F(DiscoverSafeTest, RefreshEmitsDiscoveryFinishedFalseBeforeInit) +{ + DiscoverController *c = DiscoverController::instance(); + int calls = 0; + bool lastOk = true; + QObject sink; + QObject::connect(c, &DiscoverController::discoveryFinished, &sink, [&](bool ok) { + ++calls; + lastOk = ok; + }); + + EXPECT_NO_FATAL_FAILURE(c->refresh()); + EXPECT_GE(calls, 1); + EXPECT_FALSE(lastOk); +} + +TEST_F(DiscoverSafeTest, StartDiscoverEmitsDiscoveryFinishedFalseBeforeInit) +{ + DiscoverController *c = DiscoverController::instance(); + int calls = 0; + bool lastOk = true; + QObject sink; + QObject::connect(c, &DiscoverController::discoveryFinished, &sink, [&](bool ok) { + ++calls; + lastOk = ok; + }); + + EXPECT_NO_FATAL_FAILURE(c->startDiscover()); + EXPECT_GE(calls, 1); + EXPECT_FALSE(lastOk); +} + +TEST_F(DiscoverSafeTest, UnpublishEmitsCompatUnregistration) +{ + DiscoverController *c = DiscoverController::instance(); + int calls = 0; + bool lastReg = true; + QString lastJson = "sentinel"; + QObject sink; + QObject::connect(c, &DiscoverController::registCompatAppInfo, &sink, [&](bool reg, const QString &json) { + ++calls; + lastReg = reg; + lastJson = json; + }); + + EXPECT_NO_FATAL_FAILURE(c->unpublish()); + EXPECT_GE(calls, 1); + EXPECT_FALSE(lastReg); + EXPECT_TRUE(lastJson.isEmpty()); +} + +TEST_F(DiscoverSafeTest, SelfInfoReturnsNonNullDeviceInfo) +{ + DeviceInfoPointer info = DiscoverController::selfInfo(); + ASSERT_NE(info, nullptr); +} + +TEST_F(DiscoverSafeTest, ParseDeviceJsonValidReturnsConnectableDevice) +{ + DiscoverController *c = DiscoverController::instance(); + QString json = makeValidDeviceJson("172.16.0.9", "HostZ"); + DeviceInfoPointer info = c->parseDeviceJson(json); + ASSERT_NE(info, nullptr); + EXPECT_EQ(info->ipAddress().toStdString(), "172.16.0.9"); + EXPECT_EQ(info->deviceName().toStdString(), "HostZ"); + EXPECT_EQ(info->connectStatus(), DeviceInfo::ConnectStatus::Connectable); +} + +TEST_F(DiscoverSafeTest, ParseDeviceJsonInvalidReturnsNull) +{ + DiscoverController *c = DiscoverController::instance(); + EXPECT_EQ(c->parseDeviceJson(QString("not-valid-json")), nullptr); +} + +TEST_F(DiscoverSafeTest, IsValidDeviceRejectsNullAndEmptyIp) +{ + DiscoverController *c = DiscoverController::instance(); + EXPECT_FALSE(c->isVaildDevice(nullptr)); + DeviceInfoPointer emptyIp(new DeviceInfo("", "NoIp")); + EXPECT_FALSE(c->isVaildDevice(emptyIp)); +} + +TEST_F(DiscoverSafeTest, IsValidDeviceAcceptsHistoryDeviceWithoutIpFilter) +{ + DiscoverController *c = DiscoverController::instance(); + c->_historyDevices.append("198.51.100.7"); + DeviceInfoPointer hist(new DeviceInfo("198.51.100.7", "Hist")); + EXPECT_TRUE(c->isVaildDevice(hist)); +} + +TEST_F(DiscoverSafeTest, OnlineDeviceListStartsEmpty) +{ + EXPECT_TRUE(DiscoverController::instance()->getOnlineDeviceList().isEmpty()); +} + +TEST_F(DiscoverSafeTest, FindDeviceByUnknownIPReturnsNull) +{ + EXPECT_EQ(DiscoverController::instance()->findDeviceByIP("0.0.0.0"), nullptr); +} diff --git a/tests/coop/filesystem_test.cpp b/tests/coop/filesystem_test.cpp new file mode 100644 index 000000000..9fb789b0b --- /dev/null +++ b/tests/coop/filesystem_test.cpp @@ -0,0 +1,117 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include "common/filesystem.h" + +#include +#include +#include +#include +#include +#include + +using namespace deepin_cross; + +namespace { +QString tempFilePath(const QString &name) +{ + return QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/" + name; +} +} + +TEST(FileSystemTest, OfstreamIfstreamRoundTrip) +{ + QString qpath = tempFilePath("coop_fs_roundtrip.txt"); + fs::path p(qpath.toStdString()); + const std::string payload = "roundtrip data 12345"; + + { + std::ofstream out; + open_utf8_path(out, p); + EXPECT_TRUE(out.is_open()); + out << payload; + out.close(); + } + + { + std::ifstream in; + open_utf8_path(in, p); + EXPECT_TRUE(in.is_open()); + std::string content((std::istreambuf_iterator(in)), + std::istreambuf_iterator()); + in.close(); + EXPECT_EQ(content, payload); + } + + QFile::remove(qpath); +} + +TEST(FileSystemTest, IfstreamMissingFileIsOpenFalse) +{ + QString qpath = tempFilePath("coop_fs_does_not_exist.txt"); + QFile::remove(qpath); + fs::path p(qpath.toStdString()); + + std::ifstream in; + open_utf8_path(in, p); + EXPECT_FALSE(in.is_open()); +} + +TEST(FileSystemTest, FstreamWriteAndRead) +{ + QString qpath = tempFilePath("coop_fs_fstream.txt"); + fs::path p(qpath.toStdString()); + const std::string payload = "fstream payload"; + + { + std::fstream fs_out; + open_utf8_path(fs_out, p, std::ios::out | std::ios::trunc); + EXPECT_TRUE(fs_out.is_open()); + fs_out << payload; + fs_out.close(); + } + + { + std::fstream fs_in; + open_utf8_path(fs_in, p, std::ios::in); + EXPECT_TRUE(fs_in.is_open()); + std::string content((std::istreambuf_iterator(fs_in)), + std::istreambuf_iterator()); + EXPECT_EQ(content, payload); + } + + QFile::remove(qpath); +} + +TEST(FileSystemTest, OfstreamOverwritesExisting) +{ + QString qpath = tempFilePath("coop_fs_overwrite.txt"); + fs::path p(qpath.toStdString()); + + { + std::ofstream out; + open_utf8_path(out, p); + out << "first content"; + out.close(); + } + + { + std::ofstream out; + open_utf8_path(out, p, std::ios::out | std::ios::trunc); + out << "second"; + out.close(); + } + + { + std::ifstream in; + open_utf8_path(in, p); + std::string content((std::istreambuf_iterator(in)), + std::istreambuf_iterator()); + EXPECT_EQ(content, "second"); + } + + QFile::remove(qpath); +} diff --git a/tests/coop/main.cpp b/tests/coop/main.cpp index 0f21c4cb4..467758f2d 100644 --- a/tests/coop/main.cpp +++ b/tests/coop/main.cpp @@ -23,6 +23,7 @@ #include #include +#include extern "C" void __gcov_dump() __attribute__((weak)); extern "C" void __gcov_flush() __attribute__((weak)); @@ -36,15 +37,23 @@ static void flushCoverage() } } +static void crash_handler(int sig) +{ + flushCoverage(); + _exit(128 + sig); +} + int main(int argc, char **argv) { + std::signal(SIGSEGV, crash_handler); + std::signal(SIGABRT, crash_handler); + std::signal(SIGFPE, crash_handler); + std::signal(SIGILL, crash_handler); + qputenv("QT_QPA_PLATFORM", "offscreen"); QApplication app(argc, argv); ::testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS(); - // Flush coverage counters *before* static destructors run (the - // ConfigManager/QApplication teardown races cause the exit-134 abort that - // would otherwise skip gcov finalization). flushCoverage(); return result; } diff --git a/tests/coop/phone_smoke_test.cpp b/tests/coop/phone_smoke_test.cpp new file mode 100644 index 000000000..6376538fe --- /dev/null +++ b/tests/coop/phone_smoke_test.cpp @@ -0,0 +1,227 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include +#include +#include +#include +#include +#include + +#include "lib/cooperation/core/gui/phone/vncviewer.h" +#include "lib/cooperation/core/gui/phone/vncrecvthread.h" +#include "lib/cooperation/core/gui/phone/vncsendworker.h" +#include "lib/cooperation/core/gui/phone/screenmirroringwindow.h" +#include "lib/cooperation/core/gui/phone/phonewidget.h" +#include "lib/cooperation/core/net/helper/phonehelper.h" +#include "lib/cooperation/core/discover/deviceinfo.h" + +using cooperation_core::VncViewer; +using ::VNCRecvThread; +using ::VNCSendWorker; +using cooperation_core::ScreenMirroringWindow; +using cooperation_core::LockScreenWidget; +using cooperation_core::PhoneWidget; +using cooperation_core::QRCodeWidget; +using cooperation_core::PhoneHelper; +using cooperation_core::DeviceInfo; +using ::DeviceInfoPointer; + +TEST(VncViewerSmoke, ConstructAndDestroy) +{ + EXPECT_NO_FATAL_FAILURE({ + VncViewer *v = new VncViewer(); + delete v; + }); +} + +TEST(VncViewerSmoke, BackgroundBrushRoundTrip) +{ + VncViewer v; + QBrush brush(Qt::red); + v.setBackgroundBrush(brush); + EXPECT_EQ(v.backgroundBrush(), brush); +} + +TEST(VncViewerSmoke, ScaledRoundTrip) +{ + VncViewer v; + EXPECT_TRUE(v.scaled()); + v.setScaled(false); + EXPECT_FALSE(v.scaled()); + v.setScaled(true); + EXPECT_TRUE(v.scaled()); +} + +TEST(VncViewerSmoke, FpsAndFrameCounterRoundTrip) +{ + VncViewer v; + v.setFrameCounter(0); + EXPECT_EQ(v.frameCounter(), 0); + v.incFrameCounter(); + EXPECT_EQ(v.frameCounter(), 1); + v.setFrameCounter(42); + EXPECT_EQ(v.frameCounter(), 42); + v.setCurrentFps(7); + EXPECT_EQ(v.currentFps(), 7); +} + +TEST(VncViewerSmoke, SetServesNoCrash) +{ + VncViewer v; + EXPECT_NO_FATAL_FAILURE(v.setServes(std::string("127.0.0.1"), 5900, std::string("pwd"))); +} + +TEST(VncViewerSmoke, SetMobileRealSizeNoCrash) +{ + VncViewer v; + EXPECT_NO_FATAL_FAILURE(v.setMobileRealSize(400, 800)); + EXPECT_NO_FATAL_FAILURE(v.setMobileRealSize(800, 400)); +} + +TEST(VncViewerSmoke, FrameTimerTimeoutResetsCounterAndSetsFps) +{ + VncViewer v; + v.setFrameCounter(5); + EXPECT_NO_FATAL_FAILURE(v.frameTimerTimeout()); + EXPECT_EQ(v.frameCounter(), 0); + EXPECT_EQ(v.currentFps(), 5); +} + +TEST(VncViewerSmoke, TranslateMouseButtonMapping) +{ + VncViewer v; + EXPECT_NE(v.translateMouseButton(Qt::LeftButton), 0); + EXPECT_NE(v.translateMouseButton(Qt::MiddleButton), 0); + EXPECT_NE(v.translateMouseButton(Qt::RightButton), 0); + EXPECT_EQ(v.translateMouseButton(Qt::NoButton), 0); +} + +TEST(VncViewerSmoke, StopWhenNotConnectedEarlyReturn) +{ + VncViewer v; + EXPECT_NO_FATAL_FAILURE(v.stop()); +} + +TEST(VncViewerSmoke, OnSizeChangeWhenNotConnectedIgnored) +{ + VncViewer v; + v.m_connected = false; + EXPECT_NO_FATAL_FAILURE(v.onSizeChange(100, 200)); +} + +TEST(VncViewerSmoke, OnShortcutActionWhenNotConnectedIgnored) +{ + VncViewer v; + v.m_connected = false; + EXPECT_NO_FATAL_FAILURE(v.onShortcutAction(0)); + EXPECT_NO_FATAL_FAILURE(v.onShortcutAction(1)); +} + +TEST(VncViewerSmoke, UpdateImageWithNullImageIgnored) +{ + VncViewer v; + QImage nullImg; + EXPECT_NO_FATAL_FAILURE(v.updateImage(nullImg)); +} + +TEST(VncViewerSmoke, UpdateSurfaceNoCrash) +{ + VncViewer v; + v.resize(200, 300); + EXPECT_NO_FATAL_FAILURE(v.updateSurface()); +} + +TEST(VncRecvThreadSmoke, ConstructAndStopRunIdle) +{ + VNCRecvThread t; + EXPECT_NO_FATAL_FAILURE(t.stopRun()); +} + +TEST(VncSendWorkerSmoke, Construct) +{ + EXPECT_NO_FATAL_FAILURE({ VNCSendWorker w; }); +} + +TEST(LockScreenWidgetSmoke, Construct) +{ + EXPECT_NO_FATAL_FAILURE({ LockScreenWidget w; }); +} + +TEST(ScreenMirroringWindowSmoke, ConstructAndDestroy) +{ + EXPECT_NO_FATAL_FAILURE({ + ScreenMirroringWindow *w = new ScreenMirroringWindow("device-A"); + delete w; + }); +} + +TEST(ScreenMirroringWindowSmoke, InitSizeByViewNoCrash) +{ + ScreenMirroringWindow *w = new ScreenMirroringWindow("device-B"); + QSize sz(360, 640); + EXPECT_NO_FATAL_FAILURE(w->initSizebyView(sz)); + delete w; +} + +TEST(ScreenMirroringWindowSmoke, HandleSizeChangeNoCrash) +{ + ScreenMirroringWindow *w = new ScreenMirroringWindow("device-C"); + EXPECT_NO_FATAL_FAILURE(w->handleSizeChange(QSize(360, 640))); + delete w; +} + +TEST(PhoneWidgetSmoke, ConstructAndSwitchPages) +{ + PhoneWidget pw; + EXPECT_NO_FATAL_FAILURE(pw.switchWidget(PhoneWidget::kDeviceListWidget)); + EXPECT_NO_FATAL_FAILURE(pw.switchWidget(PhoneWidget::kNoNetworkWidget)); + EXPECT_NO_FATAL_FAILURE(pw.switchWidget(PhoneWidget::kQRCodeWidget)); +} + +TEST(PhoneWidgetSmoke, SwitchToUnknownPageNoOp) +{ + PhoneWidget pw; + EXPECT_NO_FATAL_FAILURE(pw.switchWidget(PhoneWidget::kUnknownPage)); +} + +TEST(PhoneWidgetSmoke, OnSetQRcodeInfoNoCrash) +{ + PhoneWidget pw; + EXPECT_NO_FATAL_FAILURE(pw.onSetQRcodeInfo("some-info")); +} + +TEST(PhoneWidgetSmoke, SetDeviceInfoNoCrash) +{ + PhoneWidget pw; + DeviceInfoPointer info(new DeviceInfo("10.0.0.1", "phone")); + info->setConnectStatus(DeviceInfo::Connectable); + EXPECT_NO_FATAL_FAILURE(pw.setDeviceInfo(info)); +} + +TEST(QRCodeWidgetSmoke, GenerateQRCodeReturnsPixmap) +{ + QRCodeWidget w; + QPixmap pm = w.generateQRCode("hello", 4); + EXPECT_FALSE(pm.isNull()); +} + +TEST(QRCodeWidgetSmoke, GenerateQRCodeEmptyTextReturnsNull) +{ + QRCodeWidget w; + QPixmap pm = w.generateQRCode("", 4); + EXPECT_TRUE(pm.isNull()); +} + +TEST(PhoneHelperSmoke, InstanceNonNull) +{ + EXPECT_NE(PhoneHelper::instance(), nullptr); +} + +TEST(PhoneHelperSmoke, InstanceSamePointer) +{ + EXPECT_EQ(PhoneHelper::instance(), PhoneHelper::instance()); +} diff --git a/tests/coop/settings_test.cpp b/tests/coop/settings_test.cpp new file mode 100644 index 000000000..ec11cbe00 --- /dev/null +++ b/tests/coop/settings_test.cpp @@ -0,0 +1,276 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include + +#include "configs/settings/settings.h" + +#include +#include +#include +#include + +namespace { +QString writeFile(const QString &dir, const QString &name, const char *content) +{ + QDir().mkpath(dir); + QString path = dir + "/" + name; + QFile f(path); + if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + f.write(content); + f.close(); + } + return path; +} + +QString tempDir(const QString &sub) +{ + return QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/" + sub; +} +} + +TEST(SettingsTest, ConstructFromFilesAndReadValueChain) +{ + QString dir = tempDir("coop_sett_chain"); + QString df = writeFile(dir, "default.json", + R"({"group_a":{"key1":"def","key2":42}})"); + QString ff = writeFile(dir, "fallback.json", + R"({"group_b":{"x":1}})"); + QString sf = writeFile(dir, "setting.json", + R"({"group_a":{"key1":"wrote"}})"); + + Settings s(df, ff, sf); + EXPECT_EQ(s.value("group_a", "key1").toString().toStdString(), "wrote"); + EXPECT_EQ(s.value("group_b", "x").toInt(), 1); + EXPECT_EQ(s.value("group_a", "key2").toInt(), 42); + EXPECT_EQ(s.value("group_a", "nope", "dft").toString().toStdString(), "dft"); + + QFile::remove(df); + QFile::remove(ff); + QFile::remove(sf); +} + +TEST(SettingsTest, ContainsChecksAllLayers) +{ + QString dir = tempDir("coop_sett_contains"); + QString df = writeFile(dir, "default.json", R"({"g_d":{"k":"d"}})"); + QString ff = writeFile(dir, "fallback.json", R"({"g_f":{"k":"f"}})"); + QString sf = writeFile(dir, "setting.json", R"({"g_w":{"k":"w"}})"); + + Settings s(df, ff, sf); + EXPECT_TRUE(s.contains("g_w", "k")); + EXPECT_TRUE(s.contains("g_f", "k")); + EXPECT_TRUE(s.contains("g_d", "k")); + EXPECT_FALSE(s.contains("g_x", "k")); + EXPECT_TRUE(s.contains("g_w", "")); + EXPECT_FALSE(s.contains("nope", "")); + + QFile::remove(df); + QFile::remove(ff); + QFile::remove(sf); +} + +TEST(SettingsTest, GroupsKeysAndKeyList) +{ + QString dir = tempDir("coop_sett_keys"); + QString df = writeFile(dir, "default.json", + R"({"__metadata__":{"grp":{"keyOrdered":["a","b","c"]}},"grp":{"a":1,"b":2,"c":3}})"); + QString ff = writeFile(dir, "fallback.json", R"({})"); + QString sf = writeFile(dir, "setting.json", R"({"grp":{"extra":9}})"); + + Settings s(df, ff, sf); + EXPECT_TRUE(s.groups().contains("grp")); + auto ks = s.keys("grp"); + EXPECT_TRUE(ks.contains("a")); + EXPECT_TRUE(ks.contains("extra")); + + QStringList kl = s.keyList("grp"); + EXPECT_EQ(kl.first().toStdString(), "a"); + + QFile::remove(df); + QFile::remove(ff); + QFile::remove(sf); +} + +TEST(SettingsTest, SetValueAndSetValueNoNotifySemantics) +{ + Settings s(":/coop_nd.json", ":/coop_nf.json", ":/coop_ns.json"); + QSignalSpy changed(&s, &Settings::valueChanged); + + s.setValue("g", "k", "v"); + EXPECT_EQ(changed.size(), 1); + EXPECT_EQ(s.value("g", "k").toString().toStdString(), "v"); + + s.setValue("g", "k", "v"); + EXPECT_EQ(changed.size(), 1); + + s.setValue("g", "k", "v2"); + EXPECT_EQ(changed.size(), 2); + EXPECT_EQ(s.value("g", "k").toString().toStdString(), "v2"); + + changed.clear(); + EXPECT_TRUE(s.setValueNoNotify("g", "k", "v3")); + EXPECT_EQ(changed.size(), 0); + EXPECT_EQ(s.value("g", "k").toString().toStdString(), "v3"); + + EXPECT_FALSE(s.setValueNoNotify("g", "k", "v3")); + + EXPECT_TRUE(s.setValueNoNotify("g", "knew", "nv")); + EXPECT_EQ(s.value("g", "knew").toString().toStdString(), "nv"); +} + +TEST(SettingsTest, RemoveAndRemoveGroupAndClear) +{ + Settings s(":/coop_rmd.json", ":/coop_rmf.json", ":/coop_rms.json"); + s.setValue("g", "k1", 1); + s.setValue("g", "k2", 2); + + QSignalSpy spy(&s, &Settings::valueChanged); + s.remove("g", "absent"); + EXPECT_EQ(spy.size(), 0); + + s.remove("g", "k1"); + EXPECT_FALSE(s.isRemovable("g", "k1")); + + spy.clear(); + s.setValue("grp", "a", "A"); + s.removeGroup("grp"); + EXPECT_FALSE(s.isRemovable("grp", "a")); + + s.removeGroup("notexist"); + + s.setValue("c", "x", 1); + spy.clear(); + s.clear(); + s.clear(); + SUCCEED(); +} + +TEST(SettingsTest, SyncWritesToFileAndReload) +{ + QString dir = tempDir("coop_sett_sync"); + QString df = writeFile(dir, "default.json", R"({"g":{"k":"d"}})"); + QString ff = writeFile(dir, "fallback.json", R"({"g":{"fb":1}})"); + QString sf = writeFile(dir, "setting.json", R"({})"); + + Settings s(df, ff, sf); + s.setValue("g", "new", "val"); + EXPECT_TRUE(s.sync()); + + QFile f(sf); + ASSERT_TRUE(f.open(QIODevice::ReadOnly)); + QByteArray data = f.readAll(); + f.close(); + EXPECT_TRUE(data.contains("val")); + + EXPECT_TRUE(s.sync()); + + s.reload(); + SUCCEED(); + + QFile::remove(df); + QFile::remove(ff); + QFile::remove(sf); +} + +TEST(SettingsTest, AutoSyncAndWatchChangesToggles) +{ + QString dir = tempDir("coop_sett_auto"); + QString df = writeFile(dir, "default.json", R"({"g":{"k":1}})"); + QString ff = writeFile(dir, "fallback.json", R"({})"); + QString sf = writeFile(dir, "setting.json", R"({})"); + + Settings s(df, ff, sf); + EXPECT_FALSE(s.autoSync()); + EXPECT_FALSE(s.watchChanges()); + + s.setAutoSync(true); + EXPECT_TRUE(s.autoSync()); + s.setAutoSync(true); + EXPECT_TRUE(s.autoSync()); + s.setValue("g", "k", 2); + + s.setAutoSync(false); + EXPECT_FALSE(s.autoSync()); + + s.setWatchChanges(true); + EXPECT_TRUE(s.watchChanges()); + s.setWatchChanges(true); + EXPECT_TRUE(s.watchChanges()); + s.setWatchChanges(false); + EXPECT_FALSE(s.watchChanges()); + + QFile::remove(df); + QFile::remove(ff); + QFile::remove(sf); +} + +TEST(SettingsTest, WatchChangesCreatesMissingSettingFile) +{ + QString dir = tempDir("coop_sett_watch_missing"); + QDir().mkpath(dir); + QString df = writeFile(dir, "default.json", R"({"g":{"k":1}})"); + QString ff = writeFile(dir, "fallback.json", R"({})"); + QString sf = dir + "/sub/notexist.json"; + + Settings s(df, ff, sf); + s.setWatchChanges(true); + EXPECT_TRUE(s.watchChanges()); + s.setWatchChanges(false); + + QFile::remove(df); + QFile::remove(ff); + QFile::remove(sf); + QDir(dir).removeRecursively(); +} + +TEST(SettingsTest, OnFileChangedPathMismatchNoop) +{ + QString dir = tempDir("coop_sett_ofc"); + QString df = writeFile(dir, "default.json", R"({"g":{"k":1}})"); + QString ff = writeFile(dir, "fallback.json", R"({})"); + QString sf = writeFile(dir, "setting.json", R"({"g":{"k":2}})"); + + Settings s(df, ff, sf); + s.onFileChanged("/some/other/path.json"); + SUCCEED(); + + QFile::remove(df); + QFile::remove(ff); + QFile::remove(sf); +} + +TEST(SettingsTest, NameTypeConstructorAppConfig) +{ + Settings s("nonexistent_coop_app", Settings::AppConfig); + EXPECT_FALSE(s.contains("g", "k")); + SUCCEED(); +} + +TEST(SettingsTest, NameTypeConstructorGenericConfig) +{ + Settings s("nonexistent_coop_gen", Settings::GenericConfig); + EXPECT_FALSE(s.contains("g", "k")); + SUCCEED(); +} + +TEST(SettingsTest, InvalidJsonFallbackGraceful) +{ + QString dir = tempDir("coop_sett_json"); + QString df = writeFile(dir, "default.json", "{ not valid json"); + QString ff = writeFile(dir, "fallback.json", R"([1,2,3])"); + QString sf = writeFile(dir, "setting.json", ""); + + Settings s(df, ff, sf); + EXPECT_FALSE(s.contains("g", "k")); + EXPECT_EQ(s.groups().size(), 0); + + writeFile(dir, "default.json", R"({"good":{"a":1},"bad":5})"); + Settings s2(df, ":/coop_nf2.json", ":/coop_ns2.json"); + EXPECT_TRUE(s2.groups().contains("good")); + + QFile::remove(df); + QFile::remove(ff); + QFile::remove(sf); +} diff --git a/tests/session_core/session_integration_test.cpp b/tests/session_core/session_integration_test.cpp new file mode 100644 index 000000000..ef04e9c33 --- /dev/null +++ b/tests/session_core/session_integration_test.cpp @@ -0,0 +1,220 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include "protoserver.h" +#include "protoclient.h" +#include "asioservice.h" +#include "manager/secureconfig.h" +#include "session.h" + +#include +#include +#include + +using namespace std::chrono_literals; + +class TestCallback : public SessionCallInterface +{ +public: + int lastState = -999; + std::string lastMsg; + int msgCount = 0; + + void onReceivedMessage(const proto::OriginMessage &req, proto::OriginMessage *resp) override + { + msgCount++; + resp->id = req.id; + resp->mask = req.mask; + resp->json_msg = R"({"reply":"ok"})"; + } + + bool onStateChanged(int state, std::string &msg) override + { + lastState = state; + lastMsg = msg; + return false; + } +}; + +class SessionIntegrationTest : public ::testing::Test { +protected: + std::shared_ptr service; + std::shared_ptr cb; + + void SetUp() override + { + service = std::make_shared(); + service->Start(); + cb = std::make_shared(); + } + void TearDown() override + { + if (service) service->Stop(); + } +}; + +// Test real server+client connection on localhost +TEST_F(SessionIntegrationTest, ServerStartStop) +{ + auto context = SecureConfig::serverContext(); + ProtoServer server(service, context, 15001); + server.setCallbacks(cb); + EXPECT_FALSE(server.hasConnected("127.0.0.1")); +} + +TEST_F(SessionIntegrationTest, ServerHasConnectedDirectMatch) +{ + auto context = SecureConfig::serverContext(); + ProtoServer server(service, context, 15002); + server.setCallbacks(cb); + BaseKit::UUID id; + server._session_ids.insert({"10.0.0.5", id}); + EXPECT_TRUE(server.hasConnected("10.0.0.5")); +} + +TEST_F(SessionIntegrationTest, ServerHandleRealIPMapping) +{ + auto context = SecureConfig::serverContext(); + ProtoServer server(service, context, 15003); + server.handleRealIPMapping("192.168.1.100", "10.0.0.1"); + EXPECT_EQ(server._real_to_remote_ip["192.168.1.100"], "10.0.0.1"); + EXPECT_EQ(server._remote_to_real_ip["10.0.0.1"], "192.168.1.100"); +} + +TEST_F(SessionIntegrationTest, ServerHandleRealIPMappingReplace) +{ + auto context = SecureConfig::serverContext(); + ProtoServer server(service, context, 15004); + server.handleRealIPMapping("192.168.1.100", "10.0.0.1"); + server.handleRealIPMapping("192.168.1.100", "10.0.0.2"); + EXPECT_EQ(server._real_to_remote_ip["192.168.1.100"], "10.0.0.2"); + EXPECT_EQ(server._remote_to_real_ip.find("10.0.0.1"), server._remote_to_real_ip.end()); +} + +TEST_F(SessionIntegrationTest, ServerHandlePingNew) +{ + auto context = SecureConfig::serverContext(); + ProtoServer server(service, context, 15005); + server.setCallbacks(cb); + server.handlePing("10.0.0.99"); + EXPECT_TRUE(server._ping_remotes.find("10.0.0.99") != server._ping_remotes.end()); +} + +TEST_F(SessionIntegrationTest, ServerHandlePingExisting) +{ + auto context = SecureConfig::serverContext(); + ProtoServer server(service, context, 15006); + server.setCallbacks(cb); + server.handlePing("10.0.0.99"); + server.handlePing("10.0.0.99"); + SUCCEED(); +} + +TEST_F(SessionIntegrationTest, ServerHasConnectedViaIPMapping) +{ + auto context = SecureConfig::serverContext(); + ProtoServer server(service, context, 15007); + server._real_to_remote_ip["100.100.100.100"] = "10.0.0.1"; + server._remote_to_real_ip["10.0.0.1"] = "100.100.100.100"; + BaseKit::UUID id; + server._session_ids.insert({"10.0.0.1", id}); + EXPECT_TRUE(server.hasConnected("100.100.100.100")); +} + +// ---- ProtoClient tests ---- + +TEST_F(SessionIntegrationTest, ClientHasConnectedDefault) +{ + auto context = SecureConfig::clientContext(); + ProtoClient client(service, context, "127.0.0.1", 16001); + EXPECT_FALSE(client.hasConnected("192.168.1.1")); +} + +TEST_F(SessionIntegrationTest, ClientConnectReplyedDefault) +{ + auto context = SecureConfig::clientContext(); + ProtoClient client(service, context, "127.0.0.1", 16002); + EXPECT_FALSE(client.connectReplyed()); +} + +TEST_F(SessionIntegrationTest, ClientSetRealIP) +{ + auto context = SecureConfig::clientContext(); + ProtoClient client(service, context, "127.0.0.1", 16003); + client.setRealIP("10.0.0.99"); + SUCCEED(); +} + +TEST_F(SessionIntegrationTest, ClientStartHeartbeatNotConnected) +{ + auto context = SecureConfig::clientContext(); + ProtoClient client(service, context, "127.0.0.1", 16004); + EXPECT_FALSE(client.startHeartbeat()); +} + +TEST_F(SessionIntegrationTest, ClientPingTimerStop) +{ + auto context = SecureConfig::clientContext(); + ProtoClient client(service, context, "127.0.0.1", 16005); + client.pingTimerStop(); + SUCCEED(); +} + +TEST_F(SessionIntegrationTest, ClientDisconnectAndStop) +{ + auto context = SecureConfig::clientContext(); + auto *client = new ProtoClient(service, context, "127.0.0.1", 16006); + client->DisconnectAndStop(); + delete client; + SUCCEED(); +} + +// ---- ProtoEndpoint via client ---- + +TEST_F(SessionIntegrationTest, ClientSyncRequestNoConnectionReturnsEmpty) +{ + auto context = SecureConfig::clientContext(); + ProtoClient client(service, context, "127.0.0.1", 16007); + client.setCallbacks(cb); + proto::OriginMessage msg; + msg.mask = 1000; + msg.json_msg = R"({"test":"data"})"; + auto result = client.syncRequest("127.0.0.1", msg); + EXPECT_TRUE(result.json_msg.empty()); +} + +TEST_F(SessionIntegrationTest, ClientSendDisRequestNoConnection) +{ + auto context = SecureConfig::clientContext(); + ProtoClient client(service, context, "127.0.0.1", 16008); + client.setCallbacks(cb); + EXPECT_NO_FATAL_FAILURE(client.sendDisRequest()); +} + +TEST_F(SessionIntegrationTest, AsyncRequestWithHandlerTimeout) +{ + auto context = SecureConfig::clientContext(); + ProtoClient client(service, context, "127.0.0.1", 16009); + client.setCallbacks(cb); + + proto::OriginMessage msg; + msg.mask = 1000; + msg.json_msg = R"({"test":"async"})"; + + bool called = false; + client.asyncRequestWithHandler("192.168.1.1", msg, [&](int32_t type, const std::string &) { + called = true; + }); + std::this_thread::sleep_for(std::chrono::milliseconds(3500)); + EXPECT_TRUE(called); +} + +TEST_F(SessionIntegrationTest, SelfRequestFlagDefault) +{ + auto context = SecureConfig::clientContext(); + ProtoClient client(service, context, "127.0.0.1", 16010); + EXPECT_FALSE(client._self_request.load()); +}