File indexing completed on 2024-05-12 05:13:46
0001 /* 0002 SPDX-FileCopyrightText: 2018 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "testhelper.h" 0008 0009 #include "applicationcontroller.h" 0010 #include "reservationmanager.h" 0011 #include "pkpassmanager.h" 0012 0013 #include <KItinerary/Flight> 0014 #include <KItinerary/Reservation> 0015 0016 #include <QtTest/qtest.h> 0017 #include <QSignalSpy> 0018 #include <QStandardPaths> 0019 #include <KItinerary/Place> 0020 #include <KItinerary/Visit> 0021 0022 using namespace KItinerary; 0023 0024 class ReservationManagerTest : public QObject 0025 { 0026 Q_OBJECT 0027 private Q_SLOTS: 0028 void initTestCase() 0029 { 0030 QStandardPaths::setTestModeEnabled(true); 0031 } 0032 0033 void testOperations() 0034 { 0035 ReservationManager mgr; 0036 Test::clearAll(&mgr); 0037 0038 QSignalSpy addSpy(&mgr, &ReservationManager::reservationAdded); 0039 QVERIFY(addSpy.isValid()); 0040 QSignalSpy updateSpy(&mgr, &ReservationManager::reservationChanged); 0041 QVERIFY(updateSpy.isValid()); 0042 QSignalSpy rmSpy(&mgr, &ReservationManager::reservationRemoved); 0043 QVERIFY(rmSpy.isValid()); 0044 0045 QVERIFY(mgr.batches().empty()); 0046 auto ctrl = Test::makeAppController(); 0047 ctrl->setReservationManager(&mgr); 0048 ctrl->importFromUrl(QUrl::fromLocalFile(QLatin1StringView(SOURCE_DIR "/data/4U8465-v1.json"))); 0049 0050 auto res = mgr.batches(); 0051 QCOMPARE(res.size(), 1); 0052 const auto &resId = res[0]; 0053 QVERIFY(!resId.isEmpty()); 0054 0055 QCOMPARE(addSpy.size(), 1); 0056 QCOMPARE(addSpy.at(0).at(0).toString(), resId); 0057 QVERIFY(updateSpy.isEmpty()); 0058 QVERIFY(!mgr.reservation(resId).isNull()); 0059 0060 ctrl->importFromUrl(QUrl::fromLocalFile(QLatin1StringView(SOURCE_DIR "/data/4U8465-v2.json"))); 0061 QCOMPARE(addSpy.size(), 1); 0062 QCOMPARE(updateSpy.size(), 1); 0063 QCOMPARE(mgr.batches().size(), 1); 0064 QCOMPARE(updateSpy.at(0).at(0).toString(), resId); 0065 QVERIFY(mgr.reservation(resId).isValid()); 0066 0067 mgr.removeReservation(resId); 0068 QCOMPARE(addSpy.size(), 1); 0069 QCOMPARE(updateSpy.size(), 1); 0070 QCOMPARE(rmSpy.size(), 1); 0071 QCOMPARE(rmSpy.at(0).at(0).toString(), resId); 0072 QVERIFY(mgr.batches().empty()); 0073 QVERIFY(mgr.reservation(resId).isNull()); 0074 0075 Test::clearAll(&mgr); 0076 auto attraction = KItinerary::TouristAttraction(); 0077 attraction.setName(QStringLiteral("Sky Tree")); 0078 auto visit = KItinerary::TouristAttractionVisit(); 0079 visit.setTouristAttraction(attraction); 0080 0081 const auto addedResId = mgr.addReservation(QVariant::fromValue(visit)); 0082 QCOMPARE(addedResId, mgr.batches().at(0)); 0083 0084 QCOMPARE(addSpy.size(), 2); 0085 QCOMPARE(mgr.batches().size(), 1); 0086 QCOMPARE(addSpy.at(1).at(0).toString(), addedResId); 0087 QVERIFY(mgr.reservation(addedResId).isValid()); 0088 } 0089 0090 void testPkPassChanges() 0091 { 0092 PkPassManager passMgr; 0093 Test::clearAll(&passMgr); 0094 0095 ReservationManager mgr; 0096 Test::clearAll(&mgr); 0097 0098 auto ctrl = Test::makeAppController(); 0099 ctrl->setPkPassManager(&passMgr); 0100 ctrl->setReservationManager(&mgr); 0101 0102 QSignalSpy addSpy(&mgr, &ReservationManager::reservationAdded); 0103 QVERIFY(addSpy.isValid()); 0104 QSignalSpy updateSpy(&mgr, &ReservationManager::reservationChanged); 0105 QVERIFY(updateSpy.isValid()); 0106 0107 QVERIFY(mgr.batches().empty()); 0108 const auto passId = QStringLiteral("pass.booking.kde.org/MTIzNA=="); 0109 0110 ctrl->importFromUrl(QUrl::fromLocalFile(QLatin1StringView(SOURCE_DIR "/data/boardingpass-v1.pkpass"))); 0111 QCOMPARE(addSpy.size(), 1); 0112 QVERIFY(updateSpy.isEmpty()); 0113 0114 ctrl->importFromUrl(QUrl::fromLocalFile(QLatin1StringView(SOURCE_DIR "/data/boardingpass-v2.pkpass"))); 0115 QCOMPARE(addSpy.size(), 1); 0116 QCOMPARE(updateSpy.size(), 1); 0117 } 0118 0119 void testBatchPersistence() 0120 { 0121 ReservationManager mgr; 0122 Test::clearAll(&mgr); 0123 auto ctrl = Test::makeAppController(); 0124 ctrl->setReservationManager(&mgr); 0125 0126 QCOMPARE(mgr.batches().size(), 0); 0127 ctrl->importFromUrl(QUrl::fromLocalFile(QLatin1StringView(SOURCE_DIR "/data/google-multi-passenger-flight.json"))); 0128 QCOMPARE(mgr.batches().size(), 2); 0129 0130 const auto batchId = mgr.batches()[0]; 0131 QVERIFY(!batchId.isEmpty()); 0132 QCOMPARE(mgr.batchForReservation(batchId), batchId); 0133 0134 const auto l = mgr.reservationsForBatch(batchId); 0135 QCOMPARE(l.size(), 2); 0136 QVERIFY(!l.at(0).isEmpty()); 0137 QVERIFY(!l.at(1).isEmpty()); 0138 QVERIFY(l.at(0) != l.at(1)); 0139 QVERIFY(l.at(0) == batchId || l.at(1) == batchId); 0140 const auto resId = l.at(0) == batchId ? l.at(1) : l.at(0); 0141 QCOMPARE(mgr.batchForReservation(resId), batchId); 0142 QCOMPARE(mgr.reservationsForBatch(resId), QStringList()); 0143 0144 // recreating the instance should see the same state 0145 ReservationManager mgr2; 0146 QCOMPARE(mgr2.batches().size(), 2); 0147 QCOMPARE(mgr2.batches()[0], batchId); 0148 const auto l2 = mgr2.reservationsForBatch(batchId); 0149 QCOMPARE(l2.size(), 2); 0150 QVERIFY((l2.at(0) == l.at(0) && l2.at(1) == l.at(1)) || (l2.at(0) == l.at(1) && l2.at(1) == l.at(0))); 0151 } 0152 0153 void testBatchOperations() 0154 { 0155 ReservationManager mgr; 0156 Test::clearAll(&mgr); 0157 QCOMPARE(mgr.batches().size(), 0); 0158 0159 QSignalSpy batchAddSpy(&mgr, &ReservationManager::batchAdded); 0160 QSignalSpy batchChangeSpy(&mgr, &ReservationManager::batchChanged); 0161 QSignalSpy batchContentSpy(&mgr, &ReservationManager::batchContentChanged); 0162 QSignalSpy batchRenameSpy(&mgr, &ReservationManager::batchRenamed); 0163 QSignalSpy batchRemovedSpy(&mgr, &ReservationManager::batchRemoved); 0164 0165 auto ctrl = Test::makeAppController(); 0166 ctrl->setReservationManager(&mgr); 0167 ctrl->importFromUrl(QUrl::fromLocalFile(QLatin1StringView(SOURCE_DIR "/data/google-multi-passenger-flight.json"))); 0168 QCOMPARE(batchAddSpy.size(), 2); 0169 QCOMPARE(batchChangeSpy.size(), 2); 0170 QCOMPARE(batchRenameSpy.size(), 0); 0171 QCOMPARE(batchRemovedSpy.size(), 0); 0172 0173 const auto batchId = batchAddSpy.at(0).at(0).toString(); 0174 const auto l = mgr.reservationsForBatch(batchId); 0175 QCOMPARE(l.size(), 2); 0176 0177 // changing secondary reservation triggers batch update 0178 const auto secId = l.at(0) == batchId ? l.at(1) : l.at(0); 0179 QCOMPARE(mgr.batchForReservation(secId), batchId); 0180 auto res = mgr.reservation(secId).value<FlightReservation>(); 0181 auto flight = res.reservationFor().value<Flight>(); 0182 flight.setArrivalTerminal(QStringLiteral("foo")); 0183 res.setReservationFor(flight); 0184 0185 batchAddSpy.clear(); 0186 batchChangeSpy.clear(); 0187 mgr.updateReservation(secId, res); 0188 QCOMPARE(batchAddSpy.size(), 0); 0189 QCOMPARE(batchChangeSpy.size(), 0); 0190 QCOMPARE(batchContentSpy.size(), 1); 0191 QCOMPARE(batchRenameSpy.size(), 0); 0192 QCOMPARE(batchRemovedSpy.size(), 0); 0193 QCOMPARE(batchContentSpy.at(0).at(0), batchId); 0194 0195 // de-batching by update, moving to new batch 0196 flight.setDepartureTime(flight.departureTime().addYears(1)); 0197 res.setReservationFor(flight); 0198 0199 batchAddSpy.clear(); 0200 batchContentSpy.clear(); 0201 mgr.updateReservation(secId, res); 0202 QCOMPARE(batchAddSpy.size(), 1); 0203 QCOMPARE(batchChangeSpy.size(), 1); 0204 QCOMPARE(batchContentSpy.size(), 0); 0205 QCOMPARE(batchRenameSpy.size(), 0); 0206 QCOMPARE(batchRemovedSpy.size(), 0); 0207 QCOMPARE(batchAddSpy.at(0).at(0), secId); 0208 QCOMPARE(batchChangeSpy.at(0).at(0), batchId); 0209 0210 // re-batching by update, moving to existing batch 0211 flight.setDepartureTime(flight.departureTime().addYears(-1)); 0212 res.setReservationFor(flight); 0213 0214 batchAddSpy.clear(); 0215 batchChangeSpy.clear(); 0216 mgr.updateReservation(secId, res); 0217 QCOMPARE(batchAddSpy.size(), 0); 0218 QCOMPARE(batchChangeSpy.size(), 1); 0219 QCOMPARE(batchContentSpy.size(), 0); 0220 QCOMPARE(batchRenameSpy.size(), 0); 0221 QCOMPARE(batchRemovedSpy.size(), 1); 0222 QCOMPARE(batchChangeSpy.at(0).at(0), batchId); 0223 QCOMPARE(batchRemovedSpy.at(0).at(0), secId); 0224 0225 QCOMPARE(mgr.reservationsForBatch(batchId).size(), 2); 0226 QCOMPARE(mgr.batchForReservation(batchId), batchId); 0227 QCOMPARE(mgr.batchForReservation(secId), batchId); 0228 QCOMPARE(mgr.hasBatch(batchId), true); 0229 QCOMPARE(mgr.hasBatch(secId), false); 0230 0231 // changing primary does update batch 0232 auto res2 = mgr.reservation(batchId).value<FlightReservation>(); 0233 auto flight2 = res.reservationFor().value<Flight>(); 0234 flight2.setArrivalTerminal(QStringLiteral("bar")); 0235 res2.setReservationFor(flight2); 0236 0237 batchChangeSpy.clear(); 0238 batchRemovedSpy.clear(); 0239 mgr.updateReservation(batchId, res2); 0240 QCOMPARE(batchAddSpy.size(), 0); 0241 QCOMPARE(batchChangeSpy.size(), 0); 0242 QCOMPARE(batchContentSpy.size(), 1); 0243 QCOMPARE(batchRenameSpy.size(), 0); 0244 QCOMPARE(batchRemovedSpy.size(), 0); 0245 QCOMPARE(batchContentSpy.at(0).at(0), batchId); 0246 0247 // de-batch by changing the primary one renames the batch 0248 flight2.setDepartureTime(flight2.departureTime().addYears(1)); 0249 res2.setReservationFor(flight2); 0250 0251 batchContentSpy.clear(); 0252 mgr.updateReservation(batchId, res2); 0253 QCOMPARE(batchAddSpy.size(), 1); 0254 QCOMPARE(batchChangeSpy.size(), 0); 0255 QCOMPARE(batchContentSpy.size(), 0); 0256 QCOMPARE(batchRenameSpy.size(), 1); 0257 QCOMPARE(batchRemovedSpy.size(), 0); 0258 QCOMPARE(batchAddSpy.at(0).at(0), batchId); 0259 QCOMPARE(batchRenameSpy.at(0).at(0), batchId); 0260 QCOMPARE(batchRenameSpy.at(0).at(1), secId); 0261 0262 QCOMPARE(mgr.batches().size(), 3); 0263 QCOMPARE(mgr.reservationsForBatch(batchId), QStringList(batchId)); 0264 QCOMPARE(mgr.reservationsForBatch(secId), QStringList(secId)); 0265 QCOMPARE(mgr.batchForReservation(batchId), batchId); 0266 QCOMPARE(mgr.batchForReservation(secId), secId); 0267 0268 // re-batch again, should be same as before 0269 flight2.setDepartureTime(flight2.departureTime().addYears(-1)); 0270 res2.setReservationFor(flight2); 0271 0272 batchAddSpy.clear(); 0273 batchRenameSpy.clear(); 0274 mgr.updateReservation(batchId, res2); 0275 QCOMPARE(batchAddSpy.size(), 0); 0276 QCOMPARE(batchChangeSpy.size(), 1); 0277 QCOMPARE(batchContentSpy.size(), 0); 0278 QCOMPARE(batchRenameSpy.size(), 0); 0279 QCOMPARE(batchRemovedSpy.size(), 1); 0280 QCOMPARE(batchChangeSpy.at(0).at(0), secId); 0281 QCOMPARE(batchRemovedSpy.at(0).at(0), batchId); 0282 0283 QCOMPARE(mgr.batches().size(), 2); 0284 QCOMPARE(mgr.reservationsForBatch(secId).size(), 2); 0285 QCOMPARE(mgr.batchForReservation(batchId), secId); 0286 QCOMPARE(mgr.batchForReservation(secId), secId); 0287 0288 // removing primary reservation triggers batch rename 0289 batchChangeSpy.clear(); 0290 batchRemovedSpy.clear(); 0291 mgr.removeReservation(secId); 0292 QCOMPARE(batchAddSpy.size(), 0); 0293 QCOMPARE(batchChangeSpy.size(), 0); 0294 QCOMPARE(batchRenameSpy.size(), 1); 0295 QCOMPARE(batchRemovedSpy.size(), 0); 0296 QCOMPARE(batchRenameSpy.at(0).at(0), secId); 0297 QCOMPARE(batchRenameSpy.at(0).at(1), batchId); 0298 0299 QCOMPARE(mgr.batches().size(), 2); 0300 QCOMPARE(mgr.reservationsForBatch(batchId).size(), 1); 0301 QCOMPARE(mgr.batchForReservation(batchId), batchId); 0302 QCOMPARE(mgr.batchForReservation(secId), QString()); 0303 0304 // removing the entire batch 0305 batchRenameSpy.clear(); 0306 mgr.removeBatch(batchId); 0307 QCOMPARE(batchAddSpy.size(), 0); 0308 QCOMPARE(batchChangeSpy.size(), 0); 0309 QCOMPARE(batchContentSpy.size(), 0); 0310 QCOMPARE(batchRenameSpy.size(), 0); 0311 QCOMPARE(batchRemovedSpy.size(), 1); 0312 QCOMPARE(batchRemovedSpy.at(0).at(0), batchId); 0313 0314 QCOMPARE(mgr.batches().size(), 1); 0315 QCOMPARE(mgr.reservationsForBatch(batchId).size(), 0); 0316 QCOMPARE(mgr.batchForReservation(batchId), QString()); 0317 } 0318 0319 void testCancellation() 0320 { 0321 ReservationManager mgr; 0322 Test::clearAll(&mgr); 0323 auto ctrl = Test::makeAppController(); 0324 ctrl->setReservationManager(&mgr); 0325 QCOMPARE(mgr.batches().size(), 0); 0326 ctrl->importFromUrl(QUrl::fromLocalFile(QLatin1StringView(SOURCE_DIR "/../tests/randa2017.json"))); 0327 QCOMPARE(mgr.batches().size(), 11); 0328 0329 auto res = mgr.reservation(mgr.batches().at(0)); 0330 QCOMPARE(JsonLd::convert<Reservation>(res).reservationStatus(), Reservation::ReservationConfirmed); 0331 res = mgr.reservation(mgr.batches().at(10)); 0332 QVERIFY(JsonLd::canConvert<Reservation>(res)); 0333 QCOMPARE(JsonLd::convert<Reservation>(res).reservationStatus(), Reservation::ReservationConfirmed); 0334 0335 QSignalSpy batchAddSpy(&mgr, &ReservationManager::batchAdded); 0336 QSignalSpy batchChangeSpy(&mgr, &ReservationManager::batchChanged); 0337 QSignalSpy batchContentSpy(&mgr, &ReservationManager::batchContentChanged); 0338 QSignalSpy batchRenameSpy(&mgr, &ReservationManager::batchRenamed); 0339 QSignalSpy batchRemovedSpy(&mgr, &ReservationManager::batchRemoved); 0340 0341 ctrl->importFromUrl(QUrl::fromLocalFile(QLatin1StringView(SOURCE_DIR "/../tests/randa2017-flight-cancellation.json"))); 0342 QCOMPARE(mgr.batches().size(), 11); 0343 QCOMPARE(batchAddSpy.size(), 0); 0344 QCOMPARE(batchChangeSpy.size(), 0); 0345 QCOMPARE(batchContentSpy.size(), 2); 0346 QCOMPARE(batchRenameSpy.size(), 0); 0347 QCOMPARE(batchRemovedSpy.size(), 0); 0348 0349 res = mgr.reservation(mgr.batches().at(0)); 0350 QVERIFY(JsonLd::canConvert<Reservation>(res)); 0351 QCOMPARE(JsonLd::convert<Reservation>(res).reservationStatus(), Reservation::ReservationCancelled); 0352 res = mgr.reservation(mgr.batches().at(10)); 0353 QVERIFY(JsonLd::canConvert<Reservation>(res)); 0354 QCOMPARE(JsonLd::convert<Reservation>(res).reservationStatus(), Reservation::ReservationCancelled); 0355 } 0356 }; 0357 0358 QTEST_GUILESS_MAIN(ReservationManagerTest) 0359 0360 #include "reservationmanagertest.moc"