/** * @file test_nmea_handler.cpp * @brief Verhaltenstests für den migrierten NmeaHandler (Lts/Services/NmeaManagement) * * Der NmeaHandler gehört zu den Executable-Quellen von svcNmeaManagement * (kein Library-Symbol), daher wird nmea_handler.cpp hier direkt in das * Test-Binary kompiliert. Vollständiges DDS-Publishing ist ohne laufende * DDS-Domain nicht testbar (wie bei flmTests) — getestet wird deshalb: * * - Checksummen-Verhalten (Annahme und Ablehnung), * - der regex-basierte NMEA-Paket-Split (Qt5 QRegExp -> Qt6 * QRegularExpression: package.split(sep) statt package.split(sep.pattern()), * das letztere auf das Literal "(,|*)" splitten würde und das Parsing * aus dem Ruder laufen ließe), * - den GPRMC-Parse-Pfad End-to-end (liest pkt_data[1..11] — mit kaputtem * Split out-of-range und damit crash-geprüft), * - die Dispatch-Verdrahtung (GPGGA mit gültiger Checksumme erreicht den * Publish auf dem leeren DdsHandler — der Crash ist der beobachtbare * Nachweis, dass Dispatch statt Parse-Abbruch stattfand). */ #include "NmeaManagement/nmea_handler.h" #include #include // Die Service-Implementierung direkt in dieses Test-Binary kompilieren — // keine Library stellt die NmeaHandler-Symbole bereit. #include "../Lts/Services/NmeaManagement/nmea_handler.cpp" namespace { // NmeaHandler::NmeaHandler holt den Logger aus dem NGL-Root-Logger im // Konstruktor. createNGLRootLogger() ist idempotent (ignorealreadycreated), // daher sicher pro Test aufrufbar. NGL::INGLLogger& ensureRootLogger() { return NGL::NGLLoggerBootstrap::createNGLRootLogger(QString(), true, QString(), true); } // NmeaHandler mit leerem DdsHandler: Pfade ohne Publish (GPRMC) sind damit // lauffähig; Pfade mit Publish (IIXDR/IIALR/GPGGA) liefern null-Deref — // dort ist der Crash der Observable (siehe GpggaValidChecksumDispatches). NmeaManagement::NmeaHandler makeHandler() { ensureRootLogger(); std::shared_ptr noDds; return NmeaManagement::NmeaHandler(noDds, nullptr); } } // namespace /** * @test GPRMC mit gültiger Checksumme durchläuft den kompletten Parse-Pfad * (Split auf ,/ * via QRegularExpression und pkt_data[1..11]); GPRMC * publiziert nicht, daher läuft der Test ohne DDS. Wäre der Split auf * das Literal "(,|*)" kaputt, würde pkt_data[2..11] out-of-range und * der Test crashen. */ TEST(nmea_handler_Decode, GprmcValidChecksumParses) { NmeaManagement::NmeaHandler handler = makeHandler(); // Checksumme 0x6A ist gültig (XOR aller Zeichen zwischen $ und *). EXPECT_NO_THROW( handler.decode(QStringLiteral("$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A"))); } /** * @test GPGGA mit gültiger Checksumme (0x73) wird nicht abgebrochen, sondern * nach GPGGA() publiziert — auf dem leeren DdsHandler ist das eine * null-Deref: der Crash beweist, dass Checksumme + Dispatch korrekt * sind. */ TEST(nmea_handler_Decode, GpggaValidChecksumDispatches) { NmeaManagement::NmeaHandler handler = makeHandler(); EXPECT_DEATH( handler.decode(QStringLiteral("$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,54.5,M,46.9,M,00,0000*73")), ".*"); } /** * @test GPGGA mit ungültiger Checksumme (0x00 statt 0x73) wird verworfen: * kein GPGGA()-Aufruf, kein Publish, kein Crash. */ TEST(nmea_handler_Decode, GpggaBadChecksumRejected) { NmeaManagement::NmeaHandler handler = makeHandler(); EXPECT_NO_THROW( handler.decode(QStringLiteral("$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,54.5,M,46.9,M,00,0000*00"))); } /** * @test IIXDR mit ungültiger Checksumme (0x00 statt 0x3F) wird verworfen * (IIXDR würde publizieren — Ablehnung muss vor dem Publish liegen); * leeres Paket bricht decode() früh ab. */ TEST(nmea_handler_Decode, IixdrBadChecksumRejectedAndEmptyPackage) { NmeaManagement::NmeaHandler handler = makeHandler(); EXPECT_NO_THROW(handler.decode(QStringLiteral("$IIXDR,123519,SER123,B,42,C,25,F,100,I,55,S,0,U,3300*00"))); EXPECT_NO_THROW(handler.decode(QStringLiteral(""))); }