// // Unit tests for the LtsSession module: LtsSessionData (the module's pure // data class - session state singleton, presets, operator rights, visible // parties and debug flags). Compiled into the LtsSessionData library target. // #include #include #include #include #include using LtsSessionData::PartiesByExercise; using SessionData = LtsSessionData::LtsSessionData; class ltssession_unit_test : public QObject { Q_OBJECT private slots: void singletonIdentity(); void constructorDefaults(); void operatorRightChecks(); void presetsRoundtrip(); void removePresetsKeepsDomainId(); void sessionFieldsRoundtrip(); void loggedOut(); void visibleParties(); void debugFlags(); void clearScope(); private: // LtsSessionData is a process-wide singleton and clear() only resets the // preset + operator state. Bring it back to a known baseline before each // slot so the slots do not depend on execution order. void resetSessionData(); }; void ltssession_unit_test::resetSessionData() { auto* data = SessionData::getInstance(); data->clear(); // fields that clear() intentionally does not reset: data->setDomainIdPreset(-1); data->setQosFile(QStringList()); data->setScriptId(0); data->setWorkstationId(-1); data->setRequestedAppId(LtsAppDescriptor::App::Login); data->setTcpConnectionUrl(QUrl()); data->setAsTablet(false); data->setPlaceScriptScreens(false); for (const QString& key : data->debugFlags().keys()) data->removeDebugFlag(key); } void ltssession_unit_test::singletonIdentity() { resetSessionData(); auto* data = SessionData::getInstance(); QVERIFY(data != nullptr); // singleton: same instance on every call QCOMPARE(SessionData::getInstance(), data); } void ltssession_unit_test::constructorDefaults() { resetSessionData(); auto* data = SessionData::getInstance(); // presets QCOMPARE(data->getDomainIdPreset(), -1); QCOMPARE(data->getPartitionIdPreset(), -1); QCOMPARE(data->getPartitionTypePreset(), IDL::PartitionType::Any); QVERIFY(data->getOperatorNamePreset().isEmpty()); QVERIFY(data->getPasswordPreset().isEmpty()); QVERIFY(data->getQosFile().isEmpty()); // session state QCOMPARE(data->getOperatorId(), -1); QCOMPARE(data->getScriptId(), 0); QVERIFY(data->getOperatorName().isEmpty()); QVERIFY(data->getOperatorRights().isEmpty()); QVERIFY(!data->getShowTerminalWindow()); QVERIFY(data->getProfilePicture().isNull()); QVERIFY(data->getVisibleParties().isEmpty()); QVERIFY(!data->getTcpConnectionUrl().isValid()); QCOMPARE(data->getRequestedAppId(), LtsAppDescriptor::App::Login); QCOMPARE(data->getWorkstationId(), -1); QVERIFY(!data->isTablet()); QVERIFY(!data->getPlaceScriptScreens()); QVERIFY(data->debugFlags().isEmpty()); } void ltssession_unit_test::operatorRightChecks() { resetSessionData(); auto* data = SessionData::getInstance(); // fresh state: only right 0 is granted QVERIFY(data->hasOperatorRight(0)); QVERIFY(!data->hasOperatorRight(1)); QVERIFY(!data->hasOperatorRight(-1)); // explicit rights data->setOperatorRights(QSet{1, 2}); QVERIFY(data->hasOperatorRight(1)); QVERIFY(data->hasOperatorRight(2)); QVERIFY(!data->hasOperatorRight(3)); QVERIFY(data->hasOperatorRight(0)); // 0 is always granted // -1 means "all rights" data->setOperatorRights(QSet{-1}); QVERIFY(data->hasOperatorRight(42)); QVERIFY(data->hasOperatorRight(12345)); QVERIFY(data->hasOperatorRight(0)); } void ltssession_unit_test::presetsRoundtrip() { resetSessionData(); auto* data = SessionData::getInstance(); data->setOperatorPreset(QStringLiteral("operator-name"), QStringLiteral("secret")); QCOMPARE(data->getOperatorNamePreset(), QStringLiteral("operator-name")); QCOMPARE(data->getPasswordPreset(), QStringLiteral("secret")); data->setDomainIdPreset(7); QCOMPARE(data->getDomainIdPreset(), 7); data->setPartitionPreset(3, IDL::PartitionType::Exercise); QCOMPARE(data->getPartitionIdPreset(), 3); QCOMPARE(data->getPartitionTypePreset(), IDL::PartitionType::Exercise); const QStringList expectedQos{QStringLiteral("a.qos"), QStringLiteral("b.qos")}; data->setQosFile(expectedQos); QCOMPARE(data->getQosFile(), expectedQos); } void ltssession_unit_test::removePresetsKeepsDomainId() { resetSessionData(); auto* data = SessionData::getInstance(); data->setOperatorPreset(QStringLiteral("op"), QStringLiteral("pw")); data->setDomainIdPreset(7); data->setPartitionPreset(3, IDL::PartitionType::Global); data->removePresets(); QCOMPARE(data->getPartitionIdPreset(), -1); QCOMPARE(data->getPartitionTypePreset(), IDL::PartitionType::Any); QVERIFY(data->getOperatorNamePreset().isEmpty()); QVERIFY(data->getPasswordPreset().isEmpty()); // the domain id preset is kept on purpose QCOMPARE(data->getDomainIdPreset(), 7); } void ltssession_unit_test::sessionFieldsRoundtrip() { resetSessionData(); auto* data = SessionData::getInstance(); data->setScriptId(5); QCOMPARE(data->getScriptId(), 5); data->setOperatorId(42); QCOMPARE(data->getOperatorId(), 42); data->setOperatorName(QStringLiteral("Max Mustermann")); QCOMPARE(data->getOperatorName(), QStringLiteral("Max Mustermann")); data->setShowTerminalWindow(true); QVERIFY(data->getShowTerminalWindow()); data->setTcpConnectionUrl(QUrl(QStringLiteral("tcp://127.0.0.1:51234"))); QCOMPARE(data->getTcpConnectionUrl(), QUrl(QStringLiteral("tcp://127.0.0.1:51234"))); data->setRequestedAppId(LtsAppDescriptor::App::Situation); QCOMPARE(data->getRequestedAppId(), LtsAppDescriptor::App::Situation); data->setWorkstationId(11); QCOMPARE(data->getWorkstationId(), 11); data->setPlaceScriptScreens(true); QVERIFY(data->getPlaceScriptScreens()); // a null pixmap is a valid (unfilled) profile picture in console mode data->setProfilePicture(QPixmap()); QVERIFY(data->getProfilePicture().isNull()); } void ltssession_unit_test::loggedOut() { resetSessionData(); auto* data = SessionData::getInstance(); data->setScriptId(9); // not part of the logged-out state data->setOperatorId(5); data->setOperatorName(QStringLiteral("op")); data->setOperatorRights(QSet{1}); data->setShowTerminalWindow(true); PartiesByExercise parties; parties.exerciseId = 1; parties.visibleParties = QVector{10}; data->setVisibleParties(QVector{parties}); data->loggedOut(); QCOMPARE(data->getOperatorId(), -1); QVERIFY(data->getOperatorName().isEmpty()); QVERIFY(data->getOperatorRights().isEmpty()); QVERIFY(!data->getShowTerminalWindow()); QVERIFY(data->getVisibleParties().isEmpty()); QVERIFY(data->getProfilePicture().isNull()); // unrelated fields are left untouched QCOMPARE(data->getScriptId(), 9); } void ltssession_unit_test::visibleParties() { resetSessionData(); auto* data = SessionData::getInstance(); PartiesByExercise exercise1; exercise1.exerciseId = 1; exercise1.visibleParties = QVector{10, 11}; PartiesByExercise exercise2; exercise2.exerciseId = 2; exercise2.visibleParties = QVector{20}; data->setVisibleParties(QVector{exercise1, exercise2}); QVERIFY(data->isVisibleParty(1, 10)); QVERIFY(data->isVisibleParty(1, 11)); QVERIFY(!data->isVisibleParty(1, 12)); QVERIFY(data->isVisibleParty(2, 20)); QVERIFY(!data->isVisibleParty(2, 10)); QVERIFY(!data->isVisibleParty(99, 10)); // unknown exercise const QVector expectedParties1{10, 11}; QCOMPARE(data->getVisibleParties(1), expectedParties1); QCOMPARE(data->getVisibleParties(2), QVector{20}); QVERIFY(data->getVisibleParties(99).isEmpty()); const auto& all = data->getVisibleParties(); QCOMPARE(static_cast(all.size()), 2); QCOMPARE(all[0].exerciseId, 1); QCOMPARE(all[1].exerciseId, 2); } void ltssession_unit_test::debugFlags() { resetSessionData(); auto* data = SessionData::getInstance(); QVERIFY(!data->hasDebugFlag(QStringLiteral("flag"))); QVERIFY(data->debugFlagValue(QStringLiteral("flag")).isNull()); data->setDebugFlagValue(QStringLiteral("flag"), 42); QVERIFY(data->hasDebugFlag(QStringLiteral("flag"))); QCOMPARE(data->debugFlagValue(QStringLiteral("flag")).toInt(), 42); // values are overwritten, not accumulated data->setDebugFlagValue(QStringLiteral("flag"), QStringLiteral("value")); QCOMPARE(data->debugFlagValue(QStringLiteral("flag")).toString(), QStringLiteral("value")); QCOMPARE(static_cast(data->debugFlags().size()), 1); data->setDebugFlagValue(QStringLiteral("other"), 7); QCOMPARE(static_cast(data->debugFlags().size()), 2); data->removeDebugFlag(QStringLiteral("flag")); QVERIFY(!data->hasDebugFlag(QStringLiteral("flag"))); QVERIFY(data->debugFlagValue(QStringLiteral("flag")).isNull()); QCOMPARE(static_cast(data->debugFlags().size()), 1); data->removeDebugFlag(QStringLiteral("other")); QVERIFY(data->debugFlags().isEmpty()); // removing an unknown flag is a no-op data->removeDebugFlag(QStringLiteral("unknown")); QVERIFY(data->debugFlags().isEmpty()); } void ltssession_unit_test::clearScope() { resetSessionData(); auto* data = SessionData::getInstance(); data->setScriptId(9); data->setWorkstationId(3); data->setTcpConnectionUrl(QUrl(QStringLiteral("tcp://127.0.0.1:51234"))); data->setPlaceScriptScreens(true); data->setDebugFlagValue(QStringLiteral("flag"), 1); data->setOperatorId(5); data->setOperatorName(QStringLiteral("op")); data->setOperatorRights(QSet{1}); data->setDomainIdPreset(7); data->setPartitionPreset(3, IDL::PartitionType::Exercise); data->clear(); // operator state and presets are gone QCOMPARE(data->getOperatorId(), -1); QVERIFY(data->getOperatorName().isEmpty()); QVERIFY(data->getOperatorRights().isEmpty()); QCOMPARE(data->getPartitionIdPreset(), -1); QCOMPARE(data->getPartitionTypePreset(), IDL::PartitionType::Any); QVERIFY(data->getOperatorNamePreset().isEmpty()); QVERIFY(data->getPasswordPreset().isEmpty()); // everything else is preserved by clear() QCOMPARE(data->getDomainIdPreset(), 7); QCOMPARE(data->getScriptId(), 9); QCOMPARE(data->getWorkstationId(), 3); QCOMPARE(data->getTcpConnectionUrl(), QUrl(QStringLiteral("tcp://127.0.0.1:51234"))); QVERIFY(data->getPlaceScriptScreens()); QVERIFY(data->hasDebugFlag(QStringLiteral("flag"))); } QTEST_MAIN(ltssession_unit_test) #include "ltssession_unit_test.moc"