mirror of
https://github.com/logos-co/logos-liblogos.git
synced 2026-08-27 12:51:10 +00:00
* remove outdated scripts and folders * simplify cmakelists * remove old static module methods
329 lines
12 KiB
C++
329 lines
12 KiB
C++
#include <gtest/gtest.h>
|
|
#include "app_lifecycle.h"
|
|
#include "plugin_manager.h"
|
|
#include "logos_core_internal.h"
|
|
#include "logos_mode.h"
|
|
#include "logos_api.h"
|
|
#include <QCoreApplication>
|
|
#include <QDebug>
|
|
|
|
// Custom main to ensure QCoreApplication exists for tests
|
|
int main(int argc, char** argv) {
|
|
// Create QCoreApplication for the test environment
|
|
QCoreApplication app(argc, argv);
|
|
|
|
// Initialize GoogleTest
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
|
|
// Run all tests
|
|
return RUN_ALL_TESTS();
|
|
}
|
|
|
|
// Test fixture for app lifecycle tests
|
|
class AppLifecycleTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
// Clear global state before each test
|
|
g_plugins_dirs.clear();
|
|
g_loaded_plugins.clear();
|
|
g_known_plugins.clear();
|
|
|
|
// Reset mode to default (Remote)
|
|
LogosModeConfig::setMode(LogosMode::Remote);
|
|
|
|
g_plugin_processes.clear();
|
|
|
|
// Clear local plugin APIs
|
|
g_local_plugin_apis.clear();
|
|
}
|
|
|
|
void TearDown() override {
|
|
// Clean up after each test
|
|
// Note: We don't call AppLifecycle::cleanup() here because it deletes
|
|
// the QCoreApplication which we need to keep for the test process
|
|
|
|
for (auto it = g_plugin_processes.begin(); it != g_plugin_processes.end(); ++it) {
|
|
QProcess* process = it.value();
|
|
process->terminate();
|
|
process->waitForFinished(1000);
|
|
delete process;
|
|
}
|
|
g_plugin_processes.clear();
|
|
|
|
// Clean up local plugin APIs
|
|
for (auto it = g_local_plugin_apis.begin(); it != g_local_plugin_apis.end(); ++it) {
|
|
delete it.value();
|
|
}
|
|
g_local_plugin_apis.clear();
|
|
|
|
// Clear global state
|
|
g_plugins_dirs.clear();
|
|
g_loaded_plugins.clear();
|
|
g_known_plugins.clear();
|
|
}
|
|
};
|
|
|
|
// =============================================================================
|
|
// Initialization Tests
|
|
// =============================================================================
|
|
|
|
// Verifies that init() properly sets g_app to the existing QCoreApplication
|
|
// and marks g_app_created_by_us as false when reusing an existing app
|
|
TEST_F(AppLifecycleTest, Init_CreatesNewApp) {
|
|
// In a fresh environment with no existing QCoreApplication,
|
|
// init() should create one
|
|
// Note: We can't test this directly since our test main creates a QCoreApplication
|
|
// This test verifies that init() works when called
|
|
|
|
char* argv[] = {(char*)"test"};
|
|
|
|
// If there's already an app, this will reuse it
|
|
QCoreApplication* beforeApp = QCoreApplication::instance();
|
|
|
|
AppLifecycle::init(1, argv);
|
|
|
|
// App should be initialized
|
|
ASSERT_TRUE(AppLifecycle::isInitialized());
|
|
|
|
// If there was an existing app, we should reuse it and not claim ownership
|
|
if (beforeApp) {
|
|
EXPECT_EQ(QCoreApplication::instance(), beforeApp);
|
|
EXPECT_FALSE(AppLifecycle::isAppOwnedByUs());
|
|
}
|
|
}
|
|
|
|
// Verifies that init() registers QObject* as a Qt metatype,
|
|
// which is required for signal/slot communication with QObject pointers
|
|
TEST_F(AppLifecycleTest, Init_RegistersMetaType) {
|
|
char* argv[] = {(char*)"test"};
|
|
AppLifecycle::init(1, argv);
|
|
|
|
// Verify QObject* is registered as a metatype
|
|
int typeId = QMetaType::fromName("QObject*").id();
|
|
EXPECT_NE(typeId, QMetaType::UnknownType);
|
|
}
|
|
|
|
// =============================================================================
|
|
// Mode Configuration Tests
|
|
// =============================================================================
|
|
|
|
// Verifies that setMode(1) correctly sets the SDK to Local mode (in-process plugins)
|
|
TEST_F(AppLifecycleTest, SetMode_LocalMode) {
|
|
AppLifecycle::setMode(1);
|
|
|
|
EXPECT_EQ(LogosModeConfig::getMode(), LogosMode::Local);
|
|
EXPECT_TRUE(LogosModeConfig::isLocal());
|
|
EXPECT_FALSE(LogosModeConfig::isRemote());
|
|
}
|
|
|
|
// Verifies that setMode(0) correctly sets the SDK to Remote mode (separate processes)
|
|
TEST_F(AppLifecycleTest, SetMode_RemoteMode) {
|
|
// First set to Local
|
|
AppLifecycle::setMode(1);
|
|
|
|
// Then set to Remote
|
|
AppLifecycle::setMode(0);
|
|
|
|
EXPECT_EQ(LogosModeConfig::getMode(), LogosMode::Remote);
|
|
EXPECT_TRUE(LogosModeConfig::isRemote());
|
|
EXPECT_FALSE(LogosModeConfig::isLocal());
|
|
}
|
|
|
|
// Verifies that the default mode is Remote (separate process communication)
|
|
TEST_F(AppLifecycleTest, SetMode_DefaultIsRemote) {
|
|
// After SetUp, mode should be Remote (we reset it in SetUp)
|
|
EXPECT_EQ(LogosModeConfig::getMode(), LogosMode::Remote);
|
|
}
|
|
|
|
// =============================================================================
|
|
// Plugin Directory Tests
|
|
// =============================================================================
|
|
|
|
// Verifies that setPluginsDir() correctly sets a single plugins directory
|
|
TEST_F(AppLifecycleTest, SetPluginsDir_SetsDirectory) {
|
|
const char* testDir = "/test/plugins";
|
|
|
|
AppLifecycle::setPluginsDir(testDir);
|
|
|
|
auto dirs = AppLifecycle::getPluginsDirs();
|
|
ASSERT_EQ(dirs.size(), 1);
|
|
EXPECT_EQ(dirs[0].toStdString(), testDir);
|
|
}
|
|
|
|
// Verifies that setPluginsDir() clears any existing directories before setting the new one
|
|
TEST_F(AppLifecycleTest, SetPluginsDir_ClearsExisting) {
|
|
// Add multiple directories
|
|
AppLifecycle::addPluginsDir("/dir1");
|
|
AppLifecycle::addPluginsDir("/dir2");
|
|
ASSERT_EQ(AppLifecycle::getPluginsDirs().size(), 2);
|
|
|
|
// SetPluginsDir should clear and replace
|
|
AppLifecycle::setPluginsDir("/new_dir");
|
|
|
|
auto dirs = AppLifecycle::getPluginsDirs();
|
|
ASSERT_EQ(dirs.size(), 1);
|
|
EXPECT_EQ(dirs[0].toStdString(), "/new_dir");
|
|
}
|
|
|
|
// Verifies that addPluginsDir() appends directories to the list without clearing existing ones
|
|
TEST_F(AppLifecycleTest, AddPluginsDir_AppendsDirectory) {
|
|
AppLifecycle::addPluginsDir("/dir1");
|
|
AppLifecycle::addPluginsDir("/dir2");
|
|
|
|
auto dirs = AppLifecycle::getPluginsDirs();
|
|
ASSERT_EQ(dirs.size(), 2);
|
|
EXPECT_EQ(dirs[0].toStdString(), "/dir1");
|
|
EXPECT_EQ(dirs[1].toStdString(), "/dir2");
|
|
}
|
|
|
|
// Verifies that addPluginsDir() prevents duplicate directory entries
|
|
TEST_F(AppLifecycleTest, AddPluginsDir_NoDuplicates) {
|
|
AppLifecycle::addPluginsDir("/test");
|
|
AppLifecycle::addPluginsDir("/test");
|
|
|
|
// Should only be added once
|
|
EXPECT_EQ(AppLifecycle::getPluginsDirs().size(), 1);
|
|
}
|
|
|
|
// =============================================================================
|
|
// Cleanup Tests
|
|
// =============================================================================
|
|
|
|
// Verifies that cleanup operations clear the global plugin state
|
|
// Note: Can't call full cleanup() as it would delete the test's QCoreApplication
|
|
TEST_F(AppLifecycleTest, Cleanup_ClearsGlobals) {
|
|
// Set up some state
|
|
g_loaded_plugins.append("test_plugin");
|
|
g_known_plugins["test"] = "/path/to/test";
|
|
g_plugins_dirs.append("/test");
|
|
|
|
// Note: We can't actually call AppLifecycle::cleanup() because it would
|
|
// delete the QCoreApplication used by the test runner
|
|
// Instead, we'll test the individual cleanup operations
|
|
|
|
// Manually clean up like cleanup() does
|
|
g_loaded_plugins.clear();
|
|
g_known_plugins.clear();
|
|
|
|
EXPECT_TRUE(g_loaded_plugins.isEmpty());
|
|
EXPECT_TRUE(g_known_plugins.isEmpty());
|
|
}
|
|
|
|
// Documents that cleanup() deletes the QCoreApplication when we created it
|
|
// Cannot be tested directly as it would kill the test runner's app
|
|
TEST_F(AppLifecycleTest, Cleanup_DeletesOwnedApp) {
|
|
// We can't actually test this in the test environment because
|
|
// there's already a QCoreApplication instance from the test runner
|
|
// This test documents the expected behavior
|
|
|
|
// Expected behavior (documented):
|
|
// - If g_app_created_by_us is true, delete g_app
|
|
// - Set g_app to nullptr
|
|
// - Set g_app_created_by_us to false
|
|
|
|
EXPECT_TRUE(true) << "This behavior is tested indirectly through integration tests";
|
|
}
|
|
|
|
// Verifies that init() sets g_app_created_by_us=false when reusing an existing app,
|
|
// ensuring cleanup() won't delete an app it doesn't own
|
|
TEST_F(AppLifecycleTest, Cleanup_PreservesExternalApp) {
|
|
// Verify that when we use an existing app, the flag is set correctly
|
|
char* argv[] = {(char*)"test"};
|
|
AppLifecycle::init(1, argv);
|
|
|
|
EXPECT_FALSE(AppLifecycle::isAppOwnedByUs()) << "Should not claim ownership of external app";
|
|
}
|
|
|
|
// =============================================================================
|
|
// ProcessEvents Test
|
|
// =============================================================================
|
|
|
|
// Verifies that processEvents() gracefully handles g_app being null without crashing
|
|
TEST_F(AppLifecycleTest, ProcessEvents_HandlesNoApp) {
|
|
// Set g_app to nullptr temporarily
|
|
QCoreApplication* savedApp = g_app;
|
|
g_app = nullptr;
|
|
|
|
// Should not crash
|
|
EXPECT_NO_THROW(AppLifecycle::processEvents());
|
|
|
|
// Restore
|
|
g_app = savedApp;
|
|
}
|
|
|
|
// Verifies that processEvents() successfully processes Qt events when g_app is valid
|
|
TEST_F(AppLifecycleTest, ProcessEvents_CallsAppProcessEvents) {
|
|
char* argv[] = {(char*)"test"};
|
|
AppLifecycle::init(1, argv);
|
|
|
|
// Should not crash and should complete
|
|
EXPECT_NO_THROW(AppLifecycle::processEvents());
|
|
}
|
|
|
|
// =============================================================================
|
|
// Start Function Tests (Limited testing without actual plugins)
|
|
// =============================================================================
|
|
|
|
// Verifies that start() clears the loaded plugins list before discovering new plugins
|
|
TEST_F(AppLifecycleTest, Start_ClearsLoadedPlugins) {
|
|
// Add some plugins to the loaded list (using internal API for setup)
|
|
g_loaded_plugins.append("old_plugin");
|
|
ASSERT_FALSE(PluginManager::getLoadedPlugins().isEmpty());
|
|
|
|
char* argv[] = {(char*)"test"};
|
|
AppLifecycle::init(1, argv);
|
|
|
|
AppLifecycle::start();
|
|
|
|
// Should clear the loaded plugins list at start
|
|
// Note: plugins might be loaded during start(), so we just verify
|
|
// that start() was called successfully
|
|
EXPECT_TRUE(true);
|
|
}
|
|
|
|
// Verifies that start() uses custom plugin directories when configured
|
|
TEST_F(AppLifecycleTest, Start_UsesCustomPluginsDirs) {
|
|
char* argv[] = {(char*)"test"};
|
|
AppLifecycle::init(1, argv);
|
|
|
|
AppLifecycle::setPluginsDir("/custom/plugins");
|
|
|
|
// After start, plugins dir should still contain our custom dir
|
|
AppLifecycle::start();
|
|
|
|
auto dirs = AppLifecycle::getPluginsDirs();
|
|
ASSERT_EQ(dirs.size(), 1);
|
|
EXPECT_EQ(dirs[0].toStdString(), "/custom/plugins");
|
|
}
|
|
|
|
// =============================================================================
|
|
// Exec Test
|
|
// =============================================================================
|
|
|
|
// Verifies that exec() returns -1 when g_app is null (error condition)
|
|
TEST_F(AppLifecycleTest, Exec_ReturnsNegativeWhenNoApp) {
|
|
// Set g_app to nullptr temporarily (need internal API for this edge case)
|
|
QCoreApplication* savedApp = g_app;
|
|
g_app = nullptr;
|
|
|
|
int result = AppLifecycle::exec();
|
|
|
|
EXPECT_EQ(result, -1);
|
|
|
|
// Restore
|
|
g_app = savedApp;
|
|
}
|
|
|
|
// Verifies that after init(), g_app is set and exec() would be callable
|
|
// Note: Can't actually call exec() as it blocks on the event loop
|
|
TEST_F(AppLifecycleTest, Exec_WithAppAvailable) {
|
|
char* argv[] = {(char*)"test"};
|
|
AppLifecycle::init(1, argv);
|
|
|
|
ASSERT_TRUE(AppLifecycle::isInitialized());
|
|
|
|
// We can't actually call exec() as it would block
|
|
// Just verify the app exists and exec would be callable
|
|
EXPECT_TRUE(AppLifecycle::isInitialized());
|
|
}
|