From 501bd2b4b8cf678f18236ca4129ba913d74eaf00 Mon Sep 17 00:00:00 2001 From: berrux_dev Date: Fri, 18 Sep 2026 17:49:15 +0200 Subject: [PATCH] Extends migration tests for flm and flt services --- .../qt6-migrated-legatus/tests/CMakeLists.txt | 51 +++++++++++++- .../tests/test_CppTopicGeneratorGrantlee.cpp | 31 ++++++-- .../tests/test_build_rti_guards.cpp | 25 +++---- .../tests/test_export_headers.cpp | 70 ++++++++++++------- .../tests/test_flm_dtc.cpp | 52 ++++++++++++-- .../tests/test_flm_enums.cpp | 50 +++++++++++-- .../tests/test_qt6_api_migrations.cpp | 7 +- 7 files changed, 232 insertions(+), 54 deletions(-) diff --git a/qt6-after/qt6-migrated-legatus/tests/CMakeLists.txt b/qt6-after/qt6-migrated-legatus/tests/CMakeLists.txt index d466e8d23..67a908753 100644 --- a/qt6-after/qt6-migrated-legatus/tests/CMakeLists.txt +++ b/qt6-after/qt6-migrated-legatus/tests/CMakeLists.txt @@ -106,12 +106,29 @@ if(BUILD_TESTING) endif() add_executable(migration_tests ${EXISTING_SOURCES}) - + + # FLM/FLT tests include build-tree generated headers (flm_[dtc|ftc|enums], + # flt_[dtc|ftc|enums]) - make sure codegen of these services ran first. + if(TARGET svcFlmCommon) + add_dependencies(migration_tests svcFlmCommon) + endif() + if(TARGET svcFltCommon) + add_dependencies(migration_tests svcFltCommon) + endif() + # Enable Qt Meta-Object Compiler for tests with Q_OBJECT set_target_properties(migration_tests PROPERTIES AUTOMOC ON) target_compile_features(migration_tests PRIVATE cxx_std_17) + # BEFORE: the root CMakeLists' include_directories() puts include/ early + # on the path, so the BUILD_RTI=OFF stub variant of DDS/Generic would + # shadow the real DDS framework headers that the generated flm/flt + # service headers pull in — same fix the service CMakeLists enforce + # with include_directories(BEFORE ${CMAKE_SOURCE_DIR}/Lts). + target_include_directories(migration_tests BEFORE PRIVATE + ${CMAKE_SOURCE_DIR}/Lts + ) target_include_directories(migration_tests PRIVATE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/include @@ -121,8 +138,29 @@ if(BUILD_TESTING) ${CMAKE_BINARY_DIR}/Lts/Common/LtsTimeline ${CMAKE_SOURCE_DIR}/Lts/Common/LtsTimelineClassic ${CMAKE_BINARY_DIR}/Lts/Services + ${CMAKE_SOURCE_DIR}/Lts/Services ${CMAKE_SOURCE_DIR}/Z/src/NGLLogger ) + + # test_flm_dtc_impl_custom.cpp includes flm_dtc_impl_custom.h, which + # pulls in the generated flm_dtc_impl.h. Its include guard requires + # MAKE_SVCFLMCLIENT_LIB (defined by NGL_ADD_LIBRARY on svcFlmClient, + # which compiles flm_dtc_impl_custom.cpp). + target_compile_definitions(migration_tests PRIVATE MAKE_SVCFLMCLIENT_LIB) + + # test_CppTopicGeneratorGrantlee.cpp bootstraps the NGL root logger + # before constructing the generator. The headers + # resolve via Z/src, the generated ngllogger_export.h via the + # library's binary dir. + target_include_directories(migration_tests PRIVATE + ${CMAKE_SOURCE_DIR}/Z/src + ${CMAKE_BINARY_DIR}/Z/src/NGLLogger + ) + + # Export-header tests locate generated headers in the build tree. + # The directory name is not stable across pipeline stages (build4), + # so the path is passed in instead of being hardcoded. + target_compile_definitions(migration_tests PRIVATE MIGRATION_TEST_BUILD_DIR="${CMAKE_BINARY_DIR}") # Link against Qt6 components (Qt6::Test not needed - using gtest) if(QT6_GUI_AVAILABLE) @@ -174,6 +212,17 @@ endif() if(TARGET nglwidgets AND QT6_GUI_AVAILABLE) target_link_libraries(migration_tests PRIVATE nglwidgets) endif() + + # FLM/FLT service tests include the Q_OBJECT custom headers of the + # migrated services (flm_db_impl_custom.h, flm_dtc_impl_custom.h). + # Their moc output references the generated bases' staticMetaObject + # (DatabaseInterface, DtcImpl) defined in the service libraries. + if(TARGET svcFlmCommon) + target_link_libraries(migration_tests PRIVATE svcFlmCommon) + endif() + if(TARGET svcFlmClient) + target_link_libraries(migration_tests PRIVATE svcFlmClient) + endif() # Link against LtsTimelineClassic only if it exists (may not exist with MIGRATE_MODULE) if(TARGET LtsTimelineClassic) diff --git a/qt6-after/qt6-migrated-legatus/tests/test_CppTopicGeneratorGrantlee.cpp b/qt6-after/qt6-migrated-legatus/tests/test_CppTopicGeneratorGrantlee.cpp index 3ec284959..45b79524d 100644 --- a/qt6-after/qt6-migrated-legatus/tests/test_CppTopicGeneratorGrantlee.cpp +++ b/qt6-after/qt6-migrated-legatus/tests/test_CppTopicGeneratorGrantlee.cpp @@ -1,22 +1,39 @@ #include "CppTopicGeneratorGrantlee.h" +#include + #include +namespace +{ +// GeneratorGrantleeBase acquires its logger from the NGL root logger in its +// constructor. getNGLRootLogger() throws NotCreatedError as long as no root +// logger was created, so the test has to bootstrap one first. An empty +// configuration falls back to WARN logging on stdout ('quiet' suppresses +// the notice on stderr); 'ignorealreadycreated' keeps repeat calls +// idempotent across tests of this binary. +NGL::INGLLogger& ensureRootLogger() +{ + return NGL::NGLLoggerBootstrap::createNGLRootLogger(QString(), true, QString(), true); +} +} // namespace + // Test that CppTopicGeneratorGrantlee can be instantiated TEST(CppTopicGeneratorGrantleeTest, CanInstantiate) { - CodeGen::CppTopicGeneratorGrantlee generator; - // Basic instantiation test - constructor should not throw - EXPECT_NO_THROW({ CodeGen::CppTopicGeneratorGrantlee gen2; }); + ensureRootLogger(); + // Constructor acquires the logger from the root logger and must not throw + EXPECT_NO_THROW({ CodeGen::CppTopicGeneratorGrantlee generator; }); } // Test that the generator has expected base class functionality TEST(CppTopicGeneratorGrantleeTest, HasLoggerName) { + ensureRootLogger(); CodeGen::CppTopicGeneratorGrantlee generator; - // The generator should have a logger name set in constructor - // This verifies the base class initialization worked correctly - EXPECT_TRUE(true); // Placeholder - actual test depends on base class API + // The base class created its "CodeGen.CppTopicGeneratorGrantlee" logger + // from the root logger — retrieving that logger must not throw. + EXPECT_NO_THROW(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CodeGen.CppTopicGeneratorGrantlee")); } // Test compilation of header dependencies @@ -26,4 +43,4 @@ TEST(CppTopicGeneratorGrantleeTest, HeaderCompiles) // compile correctly with Qt6/C++23 // Includes: CppTopicGeneratorGrantlee.h, StructBuilder.h, NGLLogger, QCryptographicHash, grantlee/context.h EXPECT_TRUE(true); // Compilation itself is the test -} \ No newline at end of file +} diff --git a/qt6-after/qt6-migrated-legatus/tests/test_build_rti_guards.cpp b/qt6-after/qt6-migrated-legatus/tests/test_build_rti_guards.cpp index 062160ff1..48cb8b454 100644 --- a/qt6-after/qt6-migrated-legatus/tests/test_build_rti_guards.cpp +++ b/qt6-after/qt6-migrated-legatus/tests/test_build_rti_guards.cpp @@ -3,9 +3,12 @@ * @brief Tests für BUILD_RTI conditional compilation guards * * Tests verify that: - * 1. Code compiles with BUILD_RTI=OFF (fallback mode) - * 2. RTI-dependent code is properly guarded - * 3. Non-RTI code paths work correctly + * 1. BUILD_RTI is defined as 1 in the validated configuration + * 2. RTI-dependent code paths are active (BUILD_RTI=ON) + * 3. #if BUILD_RTI guards compile and evaluate correctly + * + * BUILD_RTI=ON is the only valid migration configuration — the OFF + * variant is neither built nor tested. */ #include @@ -23,27 +26,25 @@ TEST(BuildRTIGuards, MacroDefined) #endif } -// Test 2: Verify DDS connector compiles without RTI -TEST(BuildRTIGuards, DDSConnectorFallback) +// Test 2: Verify RTI code paths are active in the validated configuration +TEST(BuildRTIGuards, RtiAvailableInValidatedConfig) { - // This test verifies that DDS-related headers can be included - // and basic functionality works without RTI libraries - // The actual DDS connector should have fallback implementations + // The validated migration configuration is BUILD_RTI=ON: the RTI + // code paths must be compiled in and available. bool rti_available = false; #ifdef BUILD_RTI rti_available = true; #endif - EXPECT_FALSE(rti_available); // In fallback mode, RTI is not available + EXPECT_TRUE(rti_available); } // Test 3: Verify conditional compilation doesn't break build TEST(BuildRTIGuards, ConditionalCompilationSafe) { - // Verify that #if BUILD_RTI guards don't cause syntax errors + // Verify that #if BUILD_RTI guards evaluate to the active branch int value = 0; #if BUILD_RTI value = 1; #endif - // In fallback mode, value should remain 0 - EXPECT_EQ(value, 0); + EXPECT_EQ(value, 1); } \ No newline at end of file diff --git a/qt6-after/qt6-migrated-legatus/tests/test_export_headers.cpp b/qt6-after/qt6-migrated-legatus/tests/test_export_headers.cpp index ed814cd96..4ad42ba78 100644 --- a/qt6-after/qt6-migrated-legatus/tests/test_export_headers.cpp +++ b/qt6-after/qt6-migrated-legatus/tests/test_export_headers.cpp @@ -5,6 +5,11 @@ * Tests verify that export headers exist and can be included without errors. * Note: Export macros are defined via CMake target_compile_definitions, * so we test header existence and structure rather than macro expansion. + * + * All export headers are generated into the build tree. The build directory + * is passed in via the MIGRATION_TEST_BUILD_DIR compile definition (its + * name is not stable across pipeline stages), and only headers of targets + * that are part of the validated build are checked. */ #include @@ -12,6 +17,14 @@ #include #include +#ifndef MIGRATION_TEST_BUILD_DIR +#error "MIGRATION_TEST_BUILD_DIR must be defined by tests/CMakeLists.txt" +#endif + +namespace +{ +const std::string kBuildDir = MIGRATION_TEST_BUILD_DIR; + // Helper to check if file exists and is readable bool fileExists(const std::string& path) { @@ -29,32 +42,38 @@ std::string readFile(const std::string& path) } return std::string((std::istreambuf_iterator(file)), std::istreambuf_iterator()); } +} // namespace // Test 1: nglwidgets_export.h exists TEST(ExportHeaders, NglWidgetsExportExists) { - std::string path = "build/Z/src/nglwidgets/nglwidgets_export.h"; + std::string path = kBuildDir + "/Z/src/nglwidgets/nglwidgets_export.h"; EXPECT_TRUE(fileExists(path)) << "Export header not found: " << path; } // Test 2: qtsingleapplication_export.h exists TEST(ExportHeaders, QtSingleApplicationExportExists) { - std::string path = "build/Z/src/QtSingleApplication/qtsingleapplication_export.h"; + std::string path = kBuildDir + "/Z/src/QtSingleApplication/qtsingleapplication_export.h"; EXPECT_TRUE(fileExists(path)) << "Export header not found: " << path; } // Test 3: ltssessiondata_export.h exists TEST(ExportHeaders, LtsSessionDataExportExists) { - std::string path = "build/Lts/Common/LtsSession/ltssessiondata_export.h"; + std::string path = kBuildDir + "/Lts/Common/LtsSession/ltssessiondata_export.h"; EXPECT_TRUE(fileExists(path)) << "Export header not found: " << path; } -// Test 4: svcgmpserver_export.h exists -TEST(ExportHeaders, SvcGmpServerExportExists) +// Test 4: ddsconnector_export.h exists +TEST(ExportHeaders, DdsConnectorExportExists) { - std::string path = "build/Lts/Services/GuezMinelayerProcessing/svcgmpserver_export.h"; + // This originally asserted svcgmpserver_export.h (GuezMinelayerProcessing). + // That sibling service is not part of this migration and is not built by + // the validation pipeline, so its export header is never generated. + // ddsconnector is a core dependency of the migrated FileManagement and + // FilterManagement services and part of the validated build. + std::string path = kBuildDir + "/Lts/DDS/DDSConnector/ddsconnector_export.h"; EXPECT_TRUE(fileExists(path)) << "Export header not found: " << path; } @@ -62,12 +81,15 @@ TEST(ExportHeaders, SvcGmpServerExportExists) TEST(ExportHeaders, HaveIncludeGuards) { std::vector headers = { - "build/Z/src/nglwidgets/nglwidgets_export.h", "build/Z/src/QtSingleApplication/qtsingleapplication_export.h", - "build/Lts/Common/LtsSession/ltssessiondata_export.h", "build/Lts/Proxies/ProjectDataManagement/pdm_export.h"}; + kBuildDir + "/Z/src/nglwidgets/nglwidgets_export.h", + kBuildDir + "/Z/src/QtSingleApplication/qtsingleapplication_export.h", + kBuildDir + "/Lts/Common/LtsSession/ltssessiondata_export.h", + kBuildDir + "/Lts/DDS/DDSConnector/ddsconnector_export.h"}; for (const auto& header : headers) { std::string content = readFile(header); + EXPECT_FALSE(content.empty()) << "Export header not found: " << header; if (!content.empty()) { // Check for #ifndef guard @@ -83,16 +105,17 @@ TEST(ExportHeaders, HaveIncludeGuards) // Test 6: Export macros follow naming convention TEST(ExportHeaders, MacroNamingConvention) { - // Check that export headers follow CMake naming convention - std::string adlerPath = - "qt-migration-legatus/qt6-after/qt6-migrated-legatus/build/Lts/Plugins/AdlerJson/adler_export.h"; - std::string content = readFile(adlerPath); + // Check that export headers follow CMake naming convention: + // _EXPORT_H guard for target + std::string connectorPath = kBuildDir + "/Lts/DDS/DDSConnector/ddsconnector_export.h"; + std::string content = readFile(connectorPath); + EXPECT_FALSE(content.empty()) << "Export header not found: " << connectorPath; if (!content.empty()) { - // Should have ADLER_EXPORT_H guard - bool hasCorrectGuard = content.find("#ifndef ADLER_EXPORT_H") != std::string::npos; - EXPECT_TRUE(hasCorrectGuard) << "adler_export.h should use ADLER_EXPORT_H guard"; + // Should have DDSCONNECTOR_EXPORT_H guard + bool hasCorrectGuard = content.find("#ifndef DDSCONNECTOR_EXPORT_H") != std::string::npos; + EXPECT_TRUE(hasCorrectGuard) << "ddsconnector_export.h should use DDSCONNECTOR_EXPORT_H guard"; } } @@ -100,18 +123,17 @@ TEST(ExportHeaders, MacroNamingConvention) TEST(ExportHeaders, ExportAndNoExportMacros) { std::vector> expectedMacros = { - {"qt-migration-legatus/qt6-after/qt6-migrated-legatus/build/Lts/Plugins/AdlerJson/adler_export.h", "ADLER"}, - {"qt-migration-legatus/qt6-after/qt6-migrated-legatus/build/Lts/Services/PresentationManagement/" - "svcprecommon_export.h", - "SVCPRECOMMON"}, - {"qt-migration-legatus/qt6-after/qt6-migrated-legatus/build/Lts/Common/LtsSession/ltssessiondata_export.h", - "LTSESSIONDATA"}, - {"qt-migration-legatus/qt6-after/qt6-migrated-legatus/build/Lts/Proxies/ProjectDataManagement/pdm_export.h", - "PDM"}}; + {kBuildDir + "/Lts/DDS/DDSConnector/ddsconnector_export.h", "DDSCONNECTOR"}, + {kBuildDir + "/Lts/DDS/FTS/ddsfts_export.h", "DDSFTS"}, + {kBuildDir + "/Lts/DDS/Core/ddscore_export.h", "DDSCORE"}, + // Target LtsSessionData uppercases to LTSSESSIONDATA (LTS + SESSIONDATA), + // matching the macros generated in ltssessiondata_export.h. + {kBuildDir + "/Lts/Common/LtsSession/ltssessiondata_export.h", "LTSSESSIONDATA"}}; for (const auto& [header, prefix] : expectedMacros) { std::string content = readFile(header); + EXPECT_FALSE(content.empty()) << "Export header not found: " << header; if (!content.empty()) { bool hasExport = content.find(prefix + "_EXPORT") != std::string::npos; @@ -121,4 +143,4 @@ TEST(ExportHeaders, ExportAndNoExportMacros) EXPECT_TRUE(hasNoExport) << header << " should define " << prefix << "_NO_EXPORT"; } } -} \ No newline at end of file +} diff --git a/qt6-after/qt6-migrated-legatus/tests/test_flm_dtc.cpp b/qt6-after/qt6-migrated-legatus/tests/test_flm_dtc.cpp index 1c3309d0e..91eb20e85 100644 --- a/qt6-after/qt6-migrated-legatus/tests/test_flm_dtc.cpp +++ b/qt6-after/qt6-migrated-legatus/tests/test_flm_dtc.cpp @@ -1,16 +1,60 @@ /** * @file test_flm_dtc.cpp - * @brief Compilation test for FileManagement/flm_dtc.h + * @brief Verhaltenstests für die generierte FileManagement Dtc/Ftc-Schnittstelle * - * This test verifies that the migrated header compiles correctly with Qt6/C++23. + * Diese Tests prüfen den von CODEGEN_CLIENT_TOPICS_IFC aus flm_service.xml + * generierten Header (Lts/Services/FileManagement/flm_dtc.h bzw. flm_ftc.h) + * aus dem Build-Tree. Es darf keinen Stub-Header im Quellbaum geben. */ #include "FileManagement/flm_dtc.h" +#include "FileManagement/flm_ftc.h" #include +#include +#include -TEST(flm_dtc_Compilation, HeaderCompiles) +/** + * @test Der generierte Dtc muss von QObject abgeleitet sein (Signale für Topic-Updates). + */ +TEST(flm_dtc_Generated, DtcIsQObjectDerived) { - // This test verifies that the header compiles without errors + static_assert(std::is_base_of::value, + "generierter Dtc muss von QObject abgeleitet sein"); + EXPECT_TRUE(true); +} + +/** + * @test Die generierten Identifier müssen dem Service-Namensschema folgen. + */ +TEST(flm_dtc_Generated, IdentifiersMatchService) +{ + EXPECT_STREQ(FileManagement::Interface::Dtc::identifier(), "FileManagement.Interface.Dtc"); + EXPECT_STREQ(FileManagement::Interface::Ftc::identifier(), "FileManagement.Interface.Ftc"); +} + +/** + * @test Die Schnittstellen sind abstrakt und stellen die Topic-Zugriffe aus + * flm_service.xml bereit (Folder, FileContent, ...). + */ +TEST(flm_dtc_Generated, TopicInterfacesAreAbstract) +{ + using DtcType = FileManagement::Interface::Dtc; + using FtcType = FileManagement::Interface::Ftc; + + static_assert(std::is_abstract::value, "Dtc muss abstrakt sein"); + static_assert(std::is_abstract::value, "Ftc muss abstrakt sein"); + + EXPECT_TRUE(true); +} + +/** + * @test Include-Guard: mehrfaches Einbinden der generierten Header ist erlaubt. + */ +TEST(flm_dtc_Generated, MultipleIncludeGuard) +{ +// Including the header multiple times should not cause errors +#include "FileManagement/flm_dtc.h" +#include "FileManagement/flm_ftc.h" EXPECT_TRUE(true); } diff --git a/qt6-after/qt6-migrated-legatus/tests/test_flm_enums.cpp b/qt6-after/qt6-migrated-legatus/tests/test_flm_enums.cpp index 71e23ec9a..0ed76dbac 100644 --- a/qt6-after/qt6-migrated-legatus/tests/test_flm_enums.cpp +++ b/qt6-after/qt6-migrated-legatus/tests/test_flm_enums.cpp @@ -1,16 +1,58 @@ /** * @file test_flm_enums.cpp - * @brief Compilation test for FileManagement/flm_enums.hpp + * @brief Verhaltenstests für die aus flm_service.xml generierten Enums * - * This test verifies that the migrated header compiles correctly with Qt6/C++23. + * Diese Tests prüfen die Enum-Werte im generierten Header + * (Lts/Services/FileManagement/flm_enums.hpp aus flm_enums.idl via rtiddsgen) + * gegen die Definitionen in flm_service.xml. rtiddsgen 7.7 generiert + * enum class; Stub-Werte (z. B. FileStatus mit fünf Einträgen) fallen damit auf. */ #include "Lts/Services/FileManagement/flm_enums.hpp" #include -TEST(flm_enums_Compilation, HeaderCompiles) +/** + * @test FileStatus: laut flm_service.xml gilt Valid = 0 und Deleted = 1. + */ +TEST(flm_enums_Generated, FileStatusValues) { - // This test verifies that the header compiles without errors + EXPECT_EQ(static_cast(FileManagement::FileStatus::Valid), 0); + EXPECT_EQ(static_cast(FileManagement::FileStatus::Deleted), 1); +} + +/** + * @test FileType: Stichproben aus der Definition in flm_service.xml + * (Unknown = 0, Pdf = 3, AdlerJson = 19). + */ +TEST(flm_enums_Generated, FileTypeValues) +{ + EXPECT_EQ(static_cast(FileManagement::FileType::Unknown), 0); + EXPECT_EQ(static_cast(FileManagement::FileType::Pdf), 3); + EXPECT_EQ(static_cast(FileManagement::FileType::AdlerJson), 19); +} + +/** + * @test FileCategory und MainFolder: Werte aus flm_service.xml + * (Global = 1, Exercise = 2, User = 3 bzw. GlobalDocuments = 1, ...). + */ +TEST(flm_enums_Generated, FileCategoryAndMainFolderValues) +{ + EXPECT_EQ(static_cast(FileManagement::FileCategory::Global), 1); + EXPECT_EQ(static_cast(FileManagement::FileCategory::Exercise), 2); + EXPECT_EQ(static_cast(FileManagement::FileCategory::User), 3); + + EXPECT_EQ(static_cast(FileManagement::MainFolder::GlobalDocuments), 1); + EXPECT_EQ(static_cast(FileManagement::MainFolder::ExerciseDocuments), 2); + EXPECT_EQ(static_cast(FileManagement::MainFolder::UserDocuments), 3); +} + +/** + * @test Include-Guard: mehrfaches Einbinden des generierten Headers ist erlaubt. + */ +TEST(flm_enums_Generated, MultipleIncludeGuard) +{ +// Including the header multiple times should not cause errors +#include "Lts/Services/FileManagement/flm_enums.hpp" EXPECT_TRUE(true); } diff --git a/qt6-after/qt6-migrated-legatus/tests/test_qt6_api_migrations.cpp b/qt6-after/qt6-migrated-legatus/tests/test_qt6_api_migrations.cpp index 1808b9054..794758d27 100644 --- a/qt6-after/qt6-migrated-legatus/tests/test_qt6_api_migrations.cpp +++ b/qt6-after/qt6-migrated-legatus/tests/test_qt6_api_migrations.cpp @@ -50,8 +50,11 @@ TEST(Qt6ApiMigrations, QStringViewBasic) QStringView subView = view.mid(6, 4); // "Qt6 " EXPECT_EQ(subView.toString(), QStringLiteral("Qt6 ")); - // Test that view doesn't allocate memory - EXPECT_EQ(view.data(), original.data()); + // Test that view doesn't allocate memory: QStringView is a non-owning + // view onto the original's buffer. Note: the non-const QString::data() + // detaches the shared QString (copy-on-write) and would move the buffer, + // so the comparison has to use the const overload (constData()). + EXPECT_EQ(view.data(), original.constData()); } // Test 2: QStringView with function parameters