diff --git a/autotests/applicationcontrollertest.cpp b/autotests/applicationcontrollertest.cpp index b67db84..ebbcba7 100644 --- a/autotests/applicationcontrollertest.cpp +++ b/autotests/applicationcontrollertest.cpp @@ -1,114 +1,115 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include class AppControllerTest : public QObject { Q_OBJECT private: void clearPasses(PkPassManager *mgr) { - for (const auto id : mgr->passes()) + for (const auto &id : mgr->passes()) { mgr->removePass(id); + } } void clearReservations(ReservationManager *mgr) { - for (const auto id : mgr->reservations()) { + for (const auto &id : mgr->reservations()) { mgr->removeReservation(id); } } QByteArray readFile(const QString &fn) { QFile f(fn); f.open(QFile::ReadOnly); return f.readAll(); } private slots: void initTestCase() { qputenv("TZ", "UTC"); QStandardPaths::setTestModeEnabled(true); } void testImportData() { PkPassManager passMgr; clearPasses(&passMgr); QSignalSpy passSpy(&passMgr, &PkPassManager::passAdded); QVERIFY(passSpy.isValid()); ReservationManager resMgr; clearReservations(&resMgr); QSignalSpy resSpy(&resMgr, &ReservationManager::reservationAdded); QVERIFY(resSpy.isValid()); ApplicationController appController; appController.setPkPassManager(&passMgr); appController.setReservationManager(&resMgr); appController.importData(readFile(QLatin1String(SOURCE_DIR "/data/4U8465-v1.json"))); QCOMPARE(resSpy.size(), 1); QCOMPARE(passSpy.size(), 0); appController.importData(readFile(QLatin1String(SOURCE_DIR "/data/boardingpass-v1.pkpass"))); QCOMPARE(resSpy.size(), 1); QCOMPARE(passSpy.size(), 1); appController.importData("M1DOE/JOHN EXXX007 TXLBRUSN 2592 110Y"); QCOMPARE(resSpy.size(), 2); QCOMPARE(passSpy.size(), 1); // TODO PDF } void testImportFile() { PkPassManager passMgr; clearPasses(&passMgr); QSignalSpy passSpy(&passMgr, &PkPassManager::passAdded); QVERIFY(passSpy.isValid()); ReservationManager resMgr; clearReservations(&resMgr); QSignalSpy resSpy(&resMgr, &ReservationManager::reservationAdded); QVERIFY(resSpy.isValid()); ApplicationController appController; appController.setPkPassManager(&passMgr); appController.setReservationManager(&resMgr); appController.importFromUrl(QUrl::fromLocalFile(QLatin1String(SOURCE_DIR "/data/4U8465-v1.json"))); QCOMPARE(resSpy.size(), 1); QCOMPARE(passSpy.size(), 0); appController.importFromUrl(QUrl::fromLocalFile(QLatin1String(SOURCE_DIR "/data/boardingpass-v1.pkpass"))); QCOMPARE(resSpy.size(), 1); QCOMPARE(passSpy.size(), 1); // TODO PDF } }; QTEST_GUILESS_MAIN(AppControllerTest) #include "applicationcontrollertest.moc" diff --git a/autotests/pkpassmanagertest.cpp b/autotests/pkpassmanagertest.cpp index 15ea57e..736f99c 100644 --- a/autotests/pkpassmanagertest.cpp +++ b/autotests/pkpassmanagertest.cpp @@ -1,88 +1,89 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include class PkPassManagerTest : public QObject { Q_OBJECT private: void clearPasses(PkPassManager *mgr) { - for (const auto id : mgr->passes()) + for (const auto &id : mgr->passes()) { mgr->removePass(id); + } } private slots: void initTestCase() { QStandardPaths::setTestModeEnabled(true); } void testImport() { PkPassManager mgr; clearPasses(&mgr); QSignalSpy addSpy(&mgr, &PkPassManager::passAdded); QVERIFY(addSpy.isValid()); QSignalSpy updateSpy(&mgr, &PkPassManager::passUpdated); QVERIFY(updateSpy.isValid()); QSignalSpy rmSpy(&mgr, &PkPassManager::passRemoved); QVERIFY(rmSpy.isValid()); const auto passId = QStringLiteral("pass.booking.kde.org/MTIzNA=="); QVERIFY(mgr.passes().isEmpty()); QCOMPARE(mgr.pass(passId), nullptr); mgr.importPass(QUrl::fromLocalFile(QLatin1String(SOURCE_DIR "/data/boardingpass-v1.pkpass"))); QCOMPARE(addSpy.size(), 1); QCOMPARE(addSpy.at(0).at(0).toString(), passId); QVERIFY(updateSpy.isEmpty()); QVERIFY(mgr.pass(passId)); auto passes = mgr.passes(); QCOMPARE(passes.size(), 1); QCOMPARE(passes.at(0), passId); mgr.importPass(QUrl::fromLocalFile(QLatin1String(SOURCE_DIR "/data/boardingpass-v2.pkpass"))); QCOMPARE(addSpy.size(), 1); QCOMPARE(updateSpy.size(), 1); QCOMPARE(mgr.passes().size(), 1); QCOMPARE(updateSpy.at(0).at(0).toString(), passId); QCOMPARE(updateSpy.at(0).at(1).toStringList().size(), 1); QCOMPARE(updateSpy.at(0).at(1).toStringList().at(0), QStringLiteral("Gate changed to G30.")); QVERIFY(mgr.pass(passId)); clearPasses(&mgr); QCOMPARE(addSpy.size(), 1); QCOMPARE(updateSpy.size(), 1); QCOMPARE(rmSpy.size(), 1); QCOMPARE(rmSpy.at(0).at(0).toString(), passId); QVERIFY(mgr.passes().isEmpty()); QCOMPARE(mgr.pass(passId), nullptr); } }; QTEST_GUILESS_MAIN(PkPassManagerTest) #include "pkpassmanagertest.moc" diff --git a/autotests/reservationmanagertest.cpp b/autotests/reservationmanagertest.cpp index b48127f..c934429 100644 --- a/autotests/reservationmanagertest.cpp +++ b/autotests/reservationmanagertest.cpp @@ -1,141 +1,142 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include class ReservationManagerTest : public QObject { Q_OBJECT private: void clearReservations(ReservationManager *mgr) { - for (const auto id : mgr->reservations()) { + for (const auto &id : mgr->reservations()) { mgr->removeReservation(id); } } void clearPasses(PkPassManager *mgr) { - for (const auto id : mgr->passes()) + for (const auto &id : mgr->passes()) { mgr->removePass(id); + } } QByteArray readFile(const QString &fn) { QFile f(fn); f.open(QFile::ReadOnly); return f.readAll(); } private slots: void initTestCase() { QStandardPaths::setTestModeEnabled(true); } void testOperations() { ReservationManager mgr; clearReservations(&mgr); QSignalSpy addSpy(&mgr, &ReservationManager::reservationAdded); QVERIFY(addSpy.isValid()); QSignalSpy updateSpy(&mgr, &ReservationManager::reservationUpdated); QVERIFY(updateSpy.isValid()); QSignalSpy rmSpy(&mgr, &ReservationManager::reservationRemoved); QVERIFY(rmSpy.isValid()); QVERIFY(mgr.reservations().isEmpty()); mgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/4U8465-v1.json"))); auto res = mgr.reservations(); QCOMPARE(res.size(), 1); - const auto resId = res.at(0); + const auto &resId = res.at(0); QVERIFY(!resId.isEmpty()); QCOMPARE(addSpy.size(), 1); QCOMPARE(addSpy.at(0).at(0).toString(), resId); QVERIFY(updateSpy.isEmpty()); QVERIFY(!mgr.reservation(resId).isNull()); mgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/4U8465-v2.json"))); QCOMPARE(addSpy.size(), 1); QCOMPARE(updateSpy.size(), 1); QCOMPARE(mgr.reservations().size(), 1); QCOMPARE(updateSpy.at(0).at(0).toString(), resId); QVERIFY(mgr.reservation(resId).isValid()); mgr.removeReservation(resId); QCOMPARE(addSpy.size(), 1); QCOMPARE(updateSpy.size(), 1); QCOMPARE(rmSpy.size(), 1); QCOMPARE(rmSpy.at(0).at(0).toString(), resId); QVERIFY(mgr.reservations().isEmpty()); QVERIFY(mgr.reservation(resId).isNull()); clearReservations(&mgr); auto attraction = KItinerary::TouristAttraction(); attraction.setName(QStringLiteral("Sky Tree")); auto visit = KItinerary::TouristAttractionVisit(); visit.setTouristAttraction(attraction); mgr.addReservation(QVariant::fromValue(visit)); auto addedResId = mgr.reservations().at(0); QCOMPARE(addSpy.size(), 2); QVERIFY(!mgr.reservations().isEmpty()); QCOMPARE(mgr.reservations().size(), 1); QCOMPARE(addSpy.at(1).at(0).toString(), addedResId); QVERIFY(mgr.reservation(addedResId).isValid()); } void testPkPassChanges() { PkPassManager passMgr; clearPasses(&passMgr); ReservationManager mgr; mgr.setPkPassManager(&passMgr); clearReservations(&mgr); QSignalSpy addSpy(&mgr, &ReservationManager::reservationAdded); QVERIFY(addSpy.isValid()); QSignalSpy updateSpy(&mgr, &ReservationManager::reservationUpdated); QVERIFY(updateSpy.isValid()); QVERIFY(mgr.reservations().isEmpty()); const auto passId = QStringLiteral("pass.booking.kde.org/MTIzNA=="); passMgr.importPass(QUrl::fromLocalFile(QLatin1String(SOURCE_DIR "/data/boardingpass-v1.pkpass"))); QCOMPARE(addSpy.size(), 1); QVERIFY(updateSpy.isEmpty()); passMgr.importPass(QUrl::fromLocalFile(QLatin1String(SOURCE_DIR "/data/boardingpass-v2.pkpass"))); QCOMPARE(addSpy.size(), 1); QCOMPARE(updateSpy.size(), 1); } }; QTEST_GUILESS_MAIN(ReservationManagerTest) #include "reservationmanagertest.moc" diff --git a/autotests/timelinemodeltest.cpp b/autotests/timelinemodeltest.cpp index 26f82dc..1ece68e 100644 --- a/autotests/timelinemodeltest.cpp +++ b/autotests/timelinemodeltest.cpp @@ -1,533 +1,534 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "modelverificationpoint.h" #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) #include #endif #include #include #include #include #include class TimelineModelTest : public QObject { Q_OBJECT private: void clearPasses(PkPassManager *mgr) { - for (const auto id : mgr->passes()) + for (const auto &id : mgr->passes()) { mgr->removePass(id); + } } void clearReservations(ReservationManager *mgr) { - for (const auto id : mgr->reservations()) { + for (const auto &id : mgr->reservations()) { mgr->removeReservation(id); } } QByteArray readFile(const QString &fn) { QFile f(fn); f.open(QFile::ReadOnly); return f.readAll(); } private slots: void initTestCase() { qputenv("TZ", "UTC"); QStandardPaths::setTestModeEnabled(true); } void init() { TripGroupManager::clear(); } void testModel() { PkPassManager mgr; clearPasses(&mgr); ReservationManager resMgr; clearReservations(&resMgr); resMgr.setPkPassManager(&mgr); TimelineModel model; #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) QAbstractItemModelTester tester(&model); #endif model.setReservationManager(&resMgr); QSignalSpy insertSpy(&model, &TimelineModel::rowsInserted); QVERIFY(insertSpy.isValid()); QSignalSpy updateSpy(&model, &TimelineModel::dataChanged); QVERIFY(updateSpy.isValid()); QSignalSpy rmSpy(&model, &TimelineModel::rowsRemoved); QVERIFY(rmSpy.isValid()); QCOMPARE(model.rowCount(), 1); QCOMPARE(model.index(0, 0).data(TimelineModel::ElementTypeRole), TimelineModel::TodayMarker); mgr.importPass(QUrl::fromLocalFile(QLatin1String(SOURCE_DIR "/data/boardingpass-v1.pkpass"))); QCOMPARE(insertSpy.size(), 1); QCOMPARE(insertSpy.at(0).at(1).toInt(), 0); QCOMPARE(insertSpy.at(0).at(2).toInt(), 0); QVERIFY(updateSpy.isEmpty()); QCOMPARE(model.rowCount(), 2); QCOMPARE(model.index(0, 0).data(TimelineModel::ElementTypeRole), TimelineModel::Flight); mgr.importPass(QUrl::fromLocalFile(QLatin1String(SOURCE_DIR "/data/boardingpass-v2.pkpass"))); QCOMPARE(insertSpy.size(), 1); QCOMPARE(updateSpy.size(), 1); QCOMPARE(updateSpy.at(0).at(0).toModelIndex().row(), 0); QCOMPARE(model.rowCount(), 2); clearReservations(&resMgr); QCOMPARE(insertSpy.size(), 1); QCOMPARE(updateSpy.size(), 1); QCOMPARE(rmSpy.size(), 1); QCOMPARE(model.rowCount(), 1); } void testNestedElements() { ReservationManager resMgr; clearReservations(&resMgr); TimelineModel model; #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) QAbstractItemModelTester tester(&model); #endif model.setHomeCountryIsoCode(QStringLiteral("DE")); model.setReservationManager(&resMgr); QSignalSpy insertSpy(&model, &TimelineModel::rowsInserted); QVERIFY(insertSpy.isValid()); QSignalSpy updateSpy(&model, &TimelineModel::dataChanged); QVERIFY(updateSpy.isValid()); QSignalSpy rmSpy(&model, &TimelineModel::rowsRemoved); QVERIFY(rmSpy.isValid()); QCOMPARE(model.rowCount(), 1); QCOMPARE(model.index(0, 0).data(TimelineModel::ElementTypeRole), TimelineModel::TodayMarker); resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/haus-randa-v1.json"))); QCOMPARE(insertSpy.size(), 3); QCOMPARE(insertSpy.at(0).at(1).toInt(), 0); QCOMPARE(insertSpy.at(0).at(2).toInt(), 0); QCOMPARE(insertSpy.at(1).at(1).toInt(), 1); QCOMPARE(insertSpy.at(1).at(2).toInt(), 1); QVERIFY(updateSpy.isEmpty()); QCOMPARE(model.rowCount(), 4); QCOMPARE(model.index(0, 0).data(TimelineModel::ElementTypeRole), TimelineModel::CountryInfo); QCOMPARE(model.index(1, 0).data(TimelineModel::ElementTypeRole), TimelineModel::Hotel); QCOMPARE(model.index(1, 0).data(TimelineModel::ElementRangeRole), TimelineModel::RangeBegin); QCOMPARE(model.index(2, 0).data(TimelineModel::ElementTypeRole), TimelineModel::Hotel); QCOMPARE(model.index(2, 0).data(TimelineModel::ElementRangeRole), TimelineModel::RangeEnd); // move end date of a hotel booking: dataChanged on RangeBegin, move (or del/ins) on RangeEnd resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/haus-randa-v2.json"))); QCOMPARE(insertSpy.size(), 4); QCOMPARE(updateSpy.size(), 1); QCOMPARE(rmSpy.size(), 1); QCOMPARE(updateSpy.at(0).at(0).toModelIndex().row(), 1); QCOMPARE(insertSpy.at(2).at(1).toInt(), 0); QCOMPARE(insertSpy.at(2).at(2).toInt(), 0); QCOMPARE(rmSpy.at(0).at(1), 2); QCOMPARE(model.rowCount(), 4); // delete a split element const auto resId = model.data(model.index(1, 0), TimelineModel::ReservationIdsRole).toStringList().value(0); QVERIFY(!resId.isEmpty()); resMgr.removeReservation(resId); QCOMPARE(rmSpy.size(), 4); QCOMPARE(model.rowCount(), 1); QCOMPARE(model.index(0, 0).data(TimelineModel::ElementTypeRole), TimelineModel::TodayMarker); } void testCountryInfos() { ReservationManager resMgr; clearReservations(&resMgr); TimelineModel model; #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) QAbstractItemModelTester tester(&model); #endif model.setHomeCountryIsoCode(QStringLiteral("DE")); model.setReservationManager(&resMgr); QCOMPARE(model.rowCount(), 1); QCOMPARE(model.index(0, 0).data(TimelineModel::ElementTypeRole), TimelineModel::TodayMarker); resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/flight-txl-lhr-sfo.json"))); QCOMPARE(model.rowCount(), 5); // 2x country info, 2x flights, today marker QCOMPARE(model.index(0, 0).data(TimelineModel::ElementTypeRole), TimelineModel::CountryInfo); auto countryInfo = model.index(0, 0).data(TimelineModel::CountryInformationRole).value(); QCOMPARE(countryInfo.drivingSide(), KItinerary::KnowledgeDb::DrivingSide::Left); QCOMPARE(countryInfo.drivingSideDiffers(), true); QCOMPARE(countryInfo.powerPlugCompatibility(), CountryInformation::Incompatible); QCOMPARE(model.index(1, 0).data(TimelineModel::ElementTypeRole), TimelineModel::Flight); QCOMPARE(model.index(2, 0).data(TimelineModel::ElementTypeRole), TimelineModel::CountryInfo); countryInfo = model.index(2, 0).data(TimelineModel::CountryInformationRole).value(); QCOMPARE(countryInfo.drivingSide(), KItinerary::KnowledgeDb::DrivingSide::Right); QCOMPARE(countryInfo.drivingSideDiffers(), false); QCOMPARE(countryInfo.powerPlugCompatibility(), CountryInformation::Incompatible); QCOMPARE(model.index(3, 0).data(TimelineModel::ElementTypeRole), TimelineModel::Flight); QCOMPARE(model.index(4, 0).data(TimelineModel::ElementTypeRole), TimelineModel::TodayMarker); // remove the GB flight should also remove the GB country info auto resId = model.index(1, 0).data(TimelineModel::ReservationIdsRole).toStringList().value(0); resMgr.removeReservation(resId); QCOMPARE(model.rowCount(), 3); QCOMPARE(model.index(0, 0).data(TimelineModel::ElementTypeRole), TimelineModel::CountryInfo); QCOMPARE(model.index(1, 0).data(TimelineModel::ElementTypeRole), TimelineModel::Flight); QCOMPARE(model.index(2, 0).data(TimelineModel::ElementTypeRole), TimelineModel::TodayMarker); // remove the US flight should also remove the US country info resId = model.index(1, 0).data(TimelineModel::ReservationIdsRole).toStringList().value(0); resMgr.removeReservation(resId); QCOMPARE(model.rowCount(), 1); QCOMPARE(model.index(0, 0).data(TimelineModel::ElementTypeRole), TimelineModel::TodayMarker); } void testWeatherElements() { using namespace KItinerary; ReservationManager resMgr; clearReservations(&resMgr); WeatherForecastManager weatherMgr; weatherMgr.setTestModeEnabled(true); TimelineModel model; #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) QAbstractItemModelTester tester(&model); #endif model.setReservationManager(&resMgr); model.setWeatherForecastManager(&weatherMgr); QCOMPARE(model.rowCount(), 1); // no weather data, as we don't know where we are // Add an element that will result in a defined location GeoCoordinates geo; geo.setLatitude(52.0f); geo.setLongitude(13.0f); Airport a; a.setGeo(geo); Flight f; f.setArrivalAirport(a); f.setDepartureTime(QDateTime(QDate(2018, 1, 1), QTime(0, 0))); FlightReservation res; res.setReservationFor(f); resMgr.addReservation(res); QCOMPARE(model.rowCount(), 11); // 1x flight, 1x today, 9x weather QCOMPARE(model.index(0, 0).data(TimelineModel::ElementTypeRole), TimelineModel::Flight); QCOMPARE(model.index(1, 0).data(TimelineModel::ElementTypeRole), TimelineModel::TodayMarker); QCOMPARE(model.index(2, 0).data(TimelineModel::ElementTypeRole), TimelineModel::WeatherForecast); auto fc = model.index(2, 0).data(TimelineModel::WeatherForecastRole).value(); QVERIFY(fc.isValid()); QCOMPARE(fc.dateTime().date(), QDate::currentDate()); QCOMPARE(fc.minimumTemperature(), 13.0f); QCOMPARE(fc.maximumTemperature(), 52.0f); QCOMPARE(model.index(10, 0).data(TimelineModel::ElementTypeRole), TimelineModel::WeatherForecast); fc = model.index(10, 0).data(TimelineModel::WeatherForecastRole).value(); QVERIFY(fc.isValid()); QCOMPARE(fc.dateTime().date(), QDate::currentDate().addDays(8)); // Add a flight one day from now changing location mid-day geo.setLatitude(46.0f); geo.setLongitude(8.0f); a.setGeo(geo); f.setArrivalAirport(a); f.setDepartureTime(QDateTime(QDate::currentDate().addDays(1), QTime(12, 0))); f.setArrivalTime(QDateTime(QDate::currentDate().addDays(1), QTime(14, 0))); res.setReservationFor(f); resMgr.addReservation(res); QCOMPARE(model.rowCount(), 13); // 2x flight, 1x today, 10x weather QCOMPARE(model.index(0, 0).data(TimelineModel::ElementTypeRole), TimelineModel::Flight); QCOMPARE(model.index(1, 0).data(TimelineModel::ElementTypeRole), TimelineModel::TodayMarker); QCOMPARE(model.index(2, 0).data(TimelineModel::ElementTypeRole), TimelineModel::WeatherForecast); fc = model.index(2, 0).data(TimelineModel::WeatherForecastRole).value(); QVERIFY(fc.isValid()); QCOMPARE(fc.dateTime().date(), QDate::currentDate()); QCOMPARE(model.index(3, 0).data(TimelineModel::ElementTypeRole), TimelineModel::WeatherForecast); fc = model.index(3, 0).data(TimelineModel::WeatherForecastRole).value(); QVERIFY(fc.isValid()); QCOMPARE(fc.minimumTemperature(), 13.0f); QCOMPARE(fc.maximumTemperature(), 52.0f); QCOMPARE(fc.dateTime(), QDateTime(QDate::currentDate().addDays(1), QTime(0, 0))); QCOMPARE(model.index(4, 0).data(TimelineModel::ElementTypeRole), TimelineModel::Flight); QCOMPARE(model.index(5, 0).data(TimelineModel::ElementTypeRole), TimelineModel::WeatherForecast); fc = model.index(5, 0).data(TimelineModel::WeatherForecastRole).value(); QVERIFY(fc.isValid()); QCOMPARE(fc.minimumTemperature(), 8.0f); QCOMPARE(fc.maximumTemperature(), 46.0f); QCOMPARE(fc.dateTime(), QDateTime(QDate::currentDate().addDays(1), QTime(14, 0))); QCOMPARE(model.index(6, 0).data(TimelineModel::ElementTypeRole), TimelineModel::WeatherForecast); fc = model.index(6, 0).data(TimelineModel::WeatherForecastRole).value(); QCOMPARE(fc.minimumTemperature(), 8.0f); QCOMPARE(fc.maximumTemperature(), 46.0f); QVERIFY(fc.isValid()); QCOMPARE(fc.dateTime(), QDateTime(QDate::currentDate().addDays(2), QTime(0, 0))); // check we get update signals for all weather elements QSignalSpy spy(&model, &TimelineModel::dataChanged); QVERIFY(spy.isValid()); emit weatherMgr.forecastUpdated(); QCOMPARE(spy.size(), 10); fc = model.index(3, 0).data(TimelineModel::WeatherForecastRole).value(); QVERIFY(fc.isValid()); QCOMPARE(fc.minimumTemperature(), 13.0f); QCOMPARE(fc.maximumTemperature(), 52.0f); QCOMPARE(fc.dateTime(), QDateTime(QDate::currentDate().addDays(1), QTime(0, 0))); fc = model.index(9, 0).data(TimelineModel::WeatherForecastRole).value(); QVERIFY(fc.isValid()); QCOMPARE(fc.minimumTemperature(), 8.0f); QCOMPARE(fc.maximumTemperature(), 46.0f); QCOMPARE(fc.dateTime(), QDateTime(QDate::currentDate().addDays(5), QTime(0, 0))); // add a location change far in the future, this must not change anything geo.setLatitude(60.0f); geo.setLongitude(11.0f); a.setGeo(geo); f.setArrivalAirport(a); f.setDepartureTime(QDateTime(QDate::currentDate().addYears(1), QTime(6, 0))); res.setReservationFor(f); resMgr.addReservation(res); QCOMPARE(model.rowCount(), 14); fc = model.index(3, 0).data(TimelineModel::WeatherForecastRole).value(); QVERIFY(fc.isValid()); QCOMPARE(fc.minimumTemperature(), 13.0f); QCOMPARE(fc.maximumTemperature(), 52.0f); QCOMPARE(fc.dateTime(), QDateTime(QDate::currentDate().addDays(1), QTime(0, 0))); fc = model.index(9, 0).data(TimelineModel::WeatherForecastRole).value(); QVERIFY(fc.isValid()); QCOMPARE(fc.minimumTemperature(), 8.0f); QCOMPARE(fc.maximumTemperature(), 46.0f); QCOMPARE(fc.dateTime(), QDateTime(QDate::currentDate().addDays(5), QTime(0, 0))); // result is the same when data hasn't been added incrementally model.setReservationManager(nullptr); model.setReservationManager(&resMgr); QCOMPARE(model.rowCount(), 14); fc = model.index(3, 0).data(TimelineModel::WeatherForecastRole).value(); QVERIFY(fc.isValid()); QCOMPARE(fc.minimumTemperature(), 13.0f); QCOMPARE(fc.maximumTemperature(), 52.0f); QCOMPARE(fc.dateTime(), QDateTime(QDate::currentDate().addDays(1), QTime(0, 0))); fc = model.index(9, 0).data(TimelineModel::WeatherForecastRole).value(); QVERIFY(fc.isValid()); QCOMPARE(fc.minimumTemperature(), 8.0f); QCOMPARE(fc.maximumTemperature(), 46.0f); QCOMPARE(fc.dateTime(), QDateTime(QDate::currentDate().addDays(5), QTime(0, 0))); // clean up auto resId = model.index(13, 0).data(TimelineModel::ReservationIdsRole).toStringList().value(0); resMgr.removeReservation(resId); resId = model.index(4, 0).data(TimelineModel::ReservationIdsRole).toStringList().value(0); resMgr.removeReservation(resId); QCOMPARE(model.rowCount(), 11); // test case: two conesequtive location changes, the first one to an unknown location // result: the weather element before the first location change ends with the start of that // result 2: we get a second weather element the same day after the second location change // TODO } void testMultiTraveller() { using namespace KItinerary; ReservationManager resMgr; clearReservations(&resMgr); TimelineModel model; #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) QAbstractItemModelTester tester(&model); #endif model.setReservationManager(&resMgr); QCOMPARE(model.rowCount(), 1); // 1x TodayMarker QSignalSpy insertSpy(&model, &TimelineModel::rowsInserted); QVERIFY(insertSpy.isValid()); QSignalSpy updateSpy(&model, &TimelineModel::dataChanged); QVERIFY(updateSpy.isValid()); QSignalSpy rmSpy(&model, &TimelineModel::rowsRemoved); QVERIFY(rmSpy.isValid()); // full import at runtime resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/google-multi-passenger-flight.json"))); QCOMPARE(model.rowCount(), 3); // 2x Flight, 1x TodayMarger QCOMPARE(insertSpy.count(), 2); QCOMPARE(updateSpy.count(), 2); QCOMPARE(model.index(0, 0).data(TimelineModel::ElementTypeRole), TimelineModel::Flight); QCOMPARE(model.index(1, 0).data(TimelineModel::ElementTypeRole), TimelineModel::Flight); QCOMPARE(model.index(2, 0).data(TimelineModel::ElementTypeRole), TimelineModel::TodayMarker); QCOMPARE(model.index(0, 0).data(TimelineModel::ReservationIdsRole).toStringList().size(), 2); QCOMPARE(model.index(1, 0).data(TimelineModel::ReservationIdsRole).toStringList().size(), 2); // already existing data model.setReservationManager(nullptr); model.setReservationManager(&resMgr); QCOMPARE(model.rowCount(), 3); // 2x Flight, 1x TodayMarger QCOMPARE(model.index(0, 0).data(TimelineModel::ElementTypeRole), TimelineModel::Flight); QCOMPARE(model.index(1, 0).data(TimelineModel::ElementTypeRole), TimelineModel::Flight); QCOMPARE(model.index(2, 0).data(TimelineModel::ElementTypeRole), TimelineModel::TodayMarker); QCOMPARE(model.index(0, 0).data(TimelineModel::ReservationIdsRole).toStringList().size(), 2); QCOMPARE(model.index(1, 0).data(TimelineModel::ReservationIdsRole).toStringList().size(), 2); // update splits element updateSpy.clear(); insertSpy.clear(); auto resId = model.index(1, 0).data(TimelineModel::ReservationIdsRole).toStringList().value(0); QVERIFY(!resId.isEmpty()); auto res = resMgr.reservation(resId).value(); auto flight = res.reservationFor().value(); flight.setDepartureTime(flight.departureTime().addDays(1)); res.setReservationFor(flight); resMgr.updateReservation(resId, res); QCOMPARE(model.rowCount(), 4); QCOMPARE(updateSpy.count(), 1); QCOMPARE(insertSpy.count(), 1); QCOMPARE(rmSpy.count(), 0); // update merges two elements updateSpy.clear(); insertSpy.clear(); rmSpy.clear(); flight.setDepartureTime(flight.departureTime().addDays(-1)); res.setReservationFor(flight); resMgr.updateReservation(resId, res); QCOMPARE(model.rowCount(), 3); QCOMPARE(updateSpy.count(), 1); QCOMPARE(rmSpy.count(), 1); QCOMPARE(insertSpy.count(), 0); // removal of merged items updateSpy.clear(); rmSpy.clear(); clearReservations(&resMgr); QCOMPARE(model.rowCount(), 1); QCOMPARE(rmSpy.count(), 2); QCOMPARE(updateSpy.count(), 2); } void testDayChange() { ReservationManager resMgr; clearReservations(&resMgr); WeatherForecastManager weatherMgr; weatherMgr.setTestModeEnabled(true); TimelineModel model; #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) QAbstractItemModelTester tester(&model); #endif model.setHomeCountryIsoCode(QStringLiteral("DE")); model.setCurrentDateTime(QDateTime({2196, 10, 14}, {12, 34})); model.setReservationManager(&resMgr); model.setWeatherForecastManager(&weatherMgr); ModelVerificationPoint vp0(QLatin1String(SOURCE_DIR "/data/timeline/daychange-r0.model")); vp0.setRoleFilter({TimelineModel::ReservationIdsRole}); QVERIFY(vp0.verify(&model)); // changing the day should move the today marker model.setCurrentDateTime(QDateTime({2196, 10, 15}, {0, 15})); ModelVerificationPoint vp1(QLatin1String(SOURCE_DIR "/data/timeline/daychange-r1.model")); vp1.setRoleFilter({TimelineModel::ReservationIdsRole}); QVERIFY(vp1.verify(&model)); // load something to define the current location, so we get weather resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/flight-txl-lhr-sfo.json"))); ModelVerificationPoint vp2(QLatin1String(SOURCE_DIR "/data/timeline/daychange-r2.model")); vp2.setRoleFilter({TimelineModel::ReservationIdsRole}); QVERIFY(vp2.verify(&model)); // changing the day should move the today marker and weather one day forward model.setCurrentDateTime(QDateTime({2196, 10, 16}, {19, 30})); ModelVerificationPoint vp3(QLatin1String(SOURCE_DIR "/data/timeline/daychange-r3.model")); vp3.setRoleFilter({TimelineModel::ReservationIdsRole}); QVERIFY(vp3.verify(&model)); } void testContent_data() { QTest::addColumn("baseName"); QDirIterator it(QLatin1String(SOURCE_DIR "/data/timeline/"), {QLatin1String("*.json")}); while (it.hasNext()) { it.next(); const auto baseName = it.fileInfo().baseName(); QTest::newRow(baseName.toUtf8().constData()) << baseName; } } void testContent() { QFETCH(QString, baseName); ReservationManager resMgr; clearReservations(&resMgr); resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/timeline/") + baseName + QLatin1String(".json"))); TripGroupManager groupMgr; groupMgr.setReservationManager(&resMgr); TimelineModel model; #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) QAbstractItemModelTester tester(&model); #endif model.setHomeCountryIsoCode(QStringLiteral("DE")); model.setCurrentDateTime(QDateTime({1996, 10, 14}, {12, 34})); model.setReservationManager(&resMgr); model.setTripGroupManager(&groupMgr); // check state is correct for data imported at the start ModelVerificationPoint vp(QLatin1String(SOURCE_DIR "/data/timeline/") + baseName + QLatin1String(".model")); vp.setRoleFilter({TimelineModel::ReservationIdsRole, TimelineModel::TripGroupIdRole}); QVERIFY(vp.verify(&model)); // retry with loading during runtime clearReservations(&resMgr); resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/timeline/") + baseName + QLatin1String(".json"))); QVERIFY(vp.verify(&model)); } }; QTEST_GUILESS_MAIN(TimelineModelTest) #include "timelinemodeltest.moc" diff --git a/autotests/tripgroupproxytest.cpp b/autotests/tripgroupproxytest.cpp index 284ed4a..014e75d 100644 --- a/autotests/tripgroupproxytest.cpp +++ b/autotests/tripgroupproxytest.cpp @@ -1,120 +1,120 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "modelverificationpoint.h" #include #include #include #include #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) #include #endif #include #include #include class TripGroupProxyTest : public QObject { Q_OBJECT private: void clearReservations(ReservationManager *mgr) { - for (const auto id : mgr->reservations()) { + for (const auto &id : mgr->reservations()) { mgr->removeReservation(id); } } QByteArray readFile(const QString &fn) { QFile f(fn); f.open(QFile::ReadOnly); return f.readAll(); } private slots: void initTestCase() { qputenv("LC_ALL", "en_US.utf-8"); QStandardPaths::setTestModeEnabled(true); } void init() { TripGroupManager::clear(); } void testExpandCollapse() { ReservationManager resMgr; clearReservations(&resMgr); resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/timeline/multi-traveler-merge-with-countryinfo.json"))); resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/google-multi-passenger-flight.json"))); resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/../tests/randa2017.json"))); TripGroupManager groupMgr; QSignalSpy addSpy(&groupMgr, &TripGroupManager::tripGroupAdded); groupMgr.setReservationManager(&resMgr); QCOMPARE(groupMgr.tripGroups().size(), 3); QCOMPARE(addSpy.size(), 3); TimelineModel model; model.setHomeCountryIsoCode(QStringLiteral("DE")); model.setCurrentDateTime(QDateTime({1996, 10, 14}, {12, 34})); model.setReservationManager(&resMgr); model.setTripGroupManager(&groupMgr); TripGroupProxyModel proxy; #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) QAbstractItemModelTester tester(&proxy); #endif proxy.setSourceModel(&model); proxy.expand(addSpy.at(0).at(0).toString()); proxy.expand(addSpy.at(1).at(0).toString()); proxy.expand(addSpy.at(2).at(0).toString()); ModelVerificationPoint vp0(QLatin1String(SOURCE_DIR "/data/tripgroupproxy/expand-collapse-r0.model")); vp0.setRoleFilter({TimelineModel::ReservationIdsRole, TimelineModel::TripGroupIdRole}); QVERIFY(vp0.verify(&proxy)); proxy.collapse(addSpy.at(0).at(0).toString()); ModelVerificationPoint vp1(QLatin1String(SOURCE_DIR "/data/tripgroupproxy/expand-collapse-r1.model")); vp1.setRoleFilter({TimelineModel::ReservationIdsRole, TimelineModel::TripGroupIdRole}); QVERIFY(vp1.verify(&proxy)); proxy.collapse(addSpy.at(1).at(0).toString()); ModelVerificationPoint vp2(QLatin1String(SOURCE_DIR "/data/tripgroupproxy/expand-collapse-r2.model")); vp2.setRoleFilter({TimelineModel::ReservationIdsRole, TimelineModel::TripGroupIdRole}); QVERIFY(vp2.verify(&proxy)); proxy.collapse(addSpy.at(2).at(0).toString()); ModelVerificationPoint vp3(QLatin1String(SOURCE_DIR "/data/tripgroupproxy/expand-collapse-r3.model")); vp3.setRoleFilter({TimelineModel::ReservationIdsRole, TimelineModel::TripGroupIdRole}); QVERIFY(vp3.verify(&proxy)); proxy.expand(addSpy.at(2).at(0).toString()); QVERIFY(vp2.verify(&proxy)); proxy.expand(addSpy.at(1).at(0).toString()); QVERIFY(vp1.verify(&proxy)); proxy.expand(addSpy.at(0).at(0).toString()); QVERIFY(vp0.verify(&proxy)); } }; QTEST_GUILESS_MAIN(TripGroupProxyTest) #include "tripgroupproxytest.moc" diff --git a/autotests/tripgrouptest.cpp b/autotests/tripgrouptest.cpp index 32b12bc..cf272a2 100644 --- a/autotests/tripgrouptest.cpp +++ b/autotests/tripgrouptest.cpp @@ -1,182 +1,182 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include class TripGroupTest : public QObject { Q_OBJECT private: void clearReservations(ReservationManager *mgr) { - for (const auto id : mgr->reservations()) { + for (const auto &id : mgr->reservations()) { mgr->removeReservation(id); } } QByteArray readFile(const QString &fn) { QFile f(fn); f.open(QFile::ReadOnly); return f.readAll(); } private slots: void initTestCase() { qputenv("LC_ALL", "en_US.utf-8"); QStandardPaths::setTestModeEnabled(true); } void init() { TripGroupManager::clear(); } void testGrouping() { ReservationManager resMgr; clearReservations(&resMgr); resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/google-multi-passenger-flight.json"))); { TripGroupManager mgr; QSignalSpy addSpy(&mgr, &TripGroupManager::tripGroupAdded); QVERIFY(addSpy.isValid()); mgr.setReservationManager(&resMgr); QCOMPARE(addSpy.size(), 1); auto g = mgr.tripGroup(addSpy.at(0).at(0).toString()); QCOMPARE(g.elements().size(), resMgr.reservations().size()); } TripGroupManager::clear(); clearReservations(&resMgr); resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/../tests/randa2017.json"))); { TripGroupManager mgr; QSignalSpy addSpy(&mgr, &TripGroupManager::tripGroupAdded); QVERIFY(addSpy.isValid()); mgr.setReservationManager(&resMgr); QCOMPARE(addSpy.size(), 1); auto g = mgr.tripGroup(addSpy.at(0).at(0).toString()); QCOMPARE(g.elements().size(), resMgr.reservations().size()); } TripGroupManager::clear(); clearReservations(&resMgr); resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/timeline/multi-traveler-merge-with-countryinfo.json"))); { TripGroupManager mgr; QSignalSpy addSpy(&mgr, &TripGroupManager::tripGroupAdded); QVERIFY(addSpy.isValid()); mgr.setReservationManager(&resMgr); QCOMPARE(addSpy.size(), 1); auto g = mgr.tripGroup(addSpy.at(0).at(0).toString()); QCOMPARE(g.elements().size(), resMgr.reservations().size()); } TripGroupManager::clear(); resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/google-multi-passenger-flight.json"))); resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/../tests/randa2017.json"))); { TripGroupManager mgr; QSignalSpy addSpy(&mgr, &TripGroupManager::tripGroupAdded); QVERIFY(addSpy.isValid()); mgr.setReservationManager (&resMgr); QCOMPARE(addSpy.size(), 3); QCOMPARE(mgr.tripGroup(addSpy.at(0).at(0).toString()).elements().size(), 4); QCOMPARE(mgr.tripGroup(addSpy.at(1).at(0).toString()).elements().size(), 4); QCOMPARE(mgr.tripGroup(addSpy.at(2).at(0).toString()).elements().size(), 12); } } void testChanges() { ReservationManager resMgr; clearReservations(&resMgr); TripGroupManager mgr; mgr.setReservationManager(&resMgr); QSignalSpy addSpy(&mgr, &TripGroupManager::tripGroupAdded); QSignalSpy changeSpy(&mgr, &TripGroupManager::tripGroupChanged); QSignalSpy rmSpy(&mgr, &TripGroupManager::tripGroupRemoved); resMgr.importReservation(readFile(QLatin1String(SOURCE_DIR "/data/google-multi-passenger-flight.json"))); QCOMPARE(addSpy.size(), 1); auto g = mgr.tripGroup(addSpy.at(0).at(0).toString()); QCOMPARE(g.elements().size(), resMgr.reservations().size()); QCOMPARE(changeSpy.size(), 1); changeSpy.clear(); clearReservations(&resMgr); QCOMPARE(rmSpy.size(), 1); QCOMPARE(changeSpy.size(), 2); } void testGroupName_data() { QTest::addColumn("fileName"); QTest::addColumn("expectedName"); QTest::newRow("SFO one way") << QStringLiteral(SOURCE_DIR "/data/google-multi-passenger-flight.json") << QStringLiteral("San Francisco Airport (March 2017)"); QTest::newRow("FLR one way multi traveller") << QStringLiteral(SOURCE_DIR "/data/timeline/multi-traveler-merge-with-countryinfo.json") << QStringLiteral("Peretola (January 2000)"); QTest::newRow("Randa") << QStringLiteral(SOURCE_DIR "/../tests/randa2017.json") << QStringLiteral("Randa (September 2017)"); QTest::newRow("Almeria") << QStringLiteral(SOURCE_DIR "/../tests/akademy2017.json") << QStringLiteral("Almería (July 2017)"); QTest::newRow("Symmetric") << QStringLiteral(SOURCE_DIR "/data/tripgroup/deutschebahn_two-leg-return.txt.json") << QStringLiteral("Somewhere(Specific) (November 2027)"); QTest::newRow("Symmetric, 2 elements") << QStringLiteral(SOURCE_DIR "/data/tripgroup/flight-direct-return.json") << QStringLiteral("Oslo Airport (June 2018)"); QTest::newRow("Triangular, different PNR") << QStringLiteral(SOURCE_DIR "/data/tripgroup/train-triangular-different-pnr.json") << QStringLiteral("Somewhere (February/March 2018)"); } void testGroupName() { QFETCH(QString, fileName); QFETCH(QString, expectedName); ReservationManager resMgr; clearReservations(&resMgr); resMgr.importReservation(readFile(fileName)); TripGroupManager mgr; QSignalSpy addSpy(&mgr, &TripGroupManager::tripGroupAdded); mgr.setReservationManager(&resMgr); QCOMPARE(addSpy.size(), 1); auto g = mgr.tripGroup(addSpy.at(0).at(0).toString()); QCOMPARE(g.elements().size(), resMgr.reservations().size()); QCOMPARE(g.name(), expectedName); } void testLeadingAppendixRemoval() { ReservationManager resMgr; clearReservations(&resMgr); resMgr.importReservation(readFile(QStringLiteral(SOURCE_DIR "/data/tripgroup/leading-appendix.json"))); TripGroupManager mgr; QSignalSpy addSpy(&mgr, &TripGroupManager::tripGroupAdded); mgr.setReservationManager(&resMgr); QCOMPARE(addSpy.size(), 1); auto g = mgr.tripGroup(addSpy.at(0).at(0).toString()); QCOMPARE(g.elements().size(), resMgr.reservations().size() - 1); QCOMPARE(g.name(), QStringLiteral("Oslo Airport (June 2000)")); } }; QTEST_GUILESS_MAIN(TripGroupTest) #include "tripgrouptest.moc"