diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index 6abc047..bc57078 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -1,18 +1,19 @@ add_definitions(-DSOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}") ecm_add_test(mergeutiltest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(locationtest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(linetest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(departuretest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(journeytest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(platformtest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(notestest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(backendtest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(navitiaparsertest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(hafasmgateparsertest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(hafasqueryparsertest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(efaparsertest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(deutschebahntest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) +ecm_add_test(otpparsertest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(publictransportmanagertest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) ecm_add_test(cachetest.cpp LINK_LIBRARIES Qt5::Test KPublicTransport) diff --git a/autotests/data/otp/fi-digitransit-departure.in.json b/autotests/data/otp/fi-digitransit-departure.in.json new file mode 100644 index 0000000..b136e50 --- /dev/null +++ b/autotests/data/otp/fi-digitransit-departure.in.json @@ -0,0 +1,117 @@ +{ + "nearest": { + "edges": [ + { + "node": { + "place": { + "stop": { + "gtfsId": "MATKA:4_TPE", + "name": "TAMPERE", + "lat": 61.498776, + "lon": 23.773019, + "timezone": null, + "parentStation": null + }, + "stoptimes": [ + { + "stop": { + "platformCode": null + }, + "serviceDay": 1578520800, + "scheduledArrival": 93300, + "realtimeArrival": 93300, + "scheduledDeparture": 95400, + "realtimeDeparture": 95400, + "realtime": false, + "trip": { + "tripHeadsign": "ROVANIEMI", + "route": { + "type": 102, + "shortName": "273", + "color": null, + "textColor": null, + "alerts": [] + } + } + } + ] + } + } + }, + { + "node": { + "place": { + "stop": { + "gtfsId": "MATKA:4_TPE", + "name": "TAMPERE", + "lat": 61.498776, + "lon": 23.773019, + "timezone": null, + "parentStation": null + }, + "stoptimes": [ + { + "stop": { + "platformCode": null + }, + "serviceDay": 1578520800, + "scheduledArrival": 97500, + "realtimeArrival": 97500, + "scheduledDeparture": 99900, + "realtimeDeparture": 99900, + "realtime": true, + "trip": { + "tripHeadsign": "HELSINKI", + "route": { + "type": 102, + "shortName": "266", + "color": null, + "textColor": null, + "alerts": [] + } + } + } + ] + } + } + }, + { + "node": { + "place": { + "stop": { + "gtfsId": "MATKA:4_TPE", + "name": "TAMPERE", + "lat": 61.498776, + "lon": 23.773019, + "timezone": null, + "parentStation": null + }, + "stoptimes": [ + { + "stop": { + "platformCode": null + }, + "serviceDay": 1578607200, + "scheduledArrival": 18240, + "realtimeArrival": 18240, + "scheduledDeparture": 18240, + "realtimeDeparture": 18240, + "realtime": false, + "trip": { + "tripHeadsign": "HELSINKI", + "route": { + "type": 2, + "shortName": "160", + "color": null, + "textColor": null, + "alerts": [] + } + } + } + ] + } + } + } + ] + } +} diff --git a/autotests/data/otp/fi-digitransit-departure.out.json b/autotests/data/otp/fi-digitransit-departure.out.json new file mode 100644 index 0000000..340bc17 --- /dev/null +++ b/autotests/data/otp/fi-digitransit-departure.out.json @@ -0,0 +1,53 @@ +[ + { + "disruptionEffect": "NormalService", + "route": { + "direction": "ROVANIEMI", + "line": { + "mode": "LongDistanceTrain", + "name": "273" + } + }, + "scheduledArrivalTime": "2020-01-09T23:55:00", + "scheduledDepartureTime": "2020-01-10T00:30:00", + "stopPoint": { + "latitude": 61.498775482177734, + "longitude": 23.773019790649414, + "name": "TAMPERE" + } + }, + { + "disruptionEffect": "NormalService", + "route": { + "direction": "HELSINKI", + "line": { + "mode": "LongDistanceTrain", + "name": "266" + } + }, + "scheduledArrivalTime": "2020-01-10T01:05:00", + "scheduledDepartureTime": "2020-01-10T01:45:00", + "stopPoint": { + "latitude": 61.498775482177734, + "longitude": 23.773019790649414, + "name": "TAMPERE" + } + }, + { + "disruptionEffect": "NormalService", + "route": { + "direction": "HELSINKI", + "line": { + "mode": "Train", + "name": "160" + } + }, + "scheduledArrivalTime": "2020-01-10T03:04:00", + "scheduledDepartureTime": "2020-01-10T03:04:00", + "stopPoint": { + "latitude": 61.498775482177734, + "longitude": 23.773019790649414, + "name": "TAMPERE" + } + } +] diff --git a/autotests/data/otp/fi-digitransit-journey.in.json b/autotests/data/otp/fi-digitransit-journey.in.json new file mode 100644 index 0000000..7e21efc --- /dev/null +++ b/autotests/data/otp/fi-digitransit-journey.in.json @@ -0,0 +1,364 @@ +{ + "plan": { + "itineraries": [ + { + "legs": [ + { + "startTime": 1578589999000, + "endTime": 1578590054000, + "departureDelay": 0, + "arrivalDelay": 0, + "realTime": false, + "distance": 69.688, + "mode": "WALK", + "transitLeg": false, + "from": { + "name": "Origin", + "lat": 60.219459533691406, + "lon": 24.81308937072754, + "stop": null + }, + "to": { + "name": "LEPPÄVAARA", + "lat": 60.219265, + "lon": 24.814299, + "stop": { + "gtfsId": "MATKA:4_LPV", + "platformCode": null, + "timezone": null + } + }, + "trip": null + }, + { + "startTime": 1578590054000, + "endTime": 1578590363000, + "departureDelay": 14, + "arrivalDelay": -37, + "realTime": true, + "distance": 6973.995075871777, + "mode": "RAIL", + "transitLeg": true, + "from": { + "name": "LEPPÄVAARA", + "lat": 60.219265, + "lon": 24.814299, + "stop": { + "gtfsId": "MATKA:4_LPV", + "platformCode": null, + "timezone": null + } + }, + "to": { + "name": "PASILA", + "lat": 60.19855, + "lon": 24.93345, + "stop": { + "gtfsId": "MATKA:4_PSL", + "platformCode": null, + "timezone": null + } + }, + "trip": { + "route": { + "type": 102, + "desc": null, + "shortName": "986", + "color": null, + "textColor": null, + "alerts": [] + }, + "tripHeadsign": "HELSINKI", + "tripShortName": null + } + }, + { + "startTime": 1578591059000, + "endTime": 1578591601000, + "departureDelay": 359, + "arrivalDelay": 361, + "realTime": true, + "distance": 12058.311247846734, + "mode": "RAIL", + "transitLeg": true, + "from": { + "name": "PASILA", + "lat": 60.19855, + "lon": 24.93345, + "stop": { + "gtfsId": "MATKA:4_PSL", + "platformCode": null, + "timezone": null + } + }, + "to": { + "name": "TIKKURILA", + "lat": 60.292201, + "lon": 25.043618, + "stop": { + "gtfsId": "MATKA:4_TKL", + "platformCode": null, + "timezone": null + } + }, + "trip": { + "route": { + "type": 102, + "desc": null, + "shortName": "73", + "color": null, + "textColor": null, + "alerts": [] + }, + "tripHeadsign": "KAJAANI", + "tripShortName": null + } + }, + { + "startTime": 1578591881000, + "endTime": 1578598680000, + "departureDelay": 101, + "arrivalDelay": 0, + "realTime": true, + "distance": 152092.50815154385, + "mode": "RAIL", + "transitLeg": true, + "from": { + "name": "TIKKURILA", + "lat": 60.292201, + "lon": 25.043618, + "stop": { + "gtfsId": "MATKA:4_TKL", + "platformCode": null, + "timezone": null + } + }, + "to": { + "name": "TAMPERE", + "lat": 61.498776, + "lon": 23.773019, + "stop": { + "gtfsId": "MATKA:4_TPE", + "platformCode": null, + "timezone": null + } + }, + "trip": { + "route": { + "type": 102, + "desc": null, + "shortName": "265", + "color": null, + "textColor": null, + "alerts": [] + }, + "tripHeadsign": "KEMIJÄRVI", + "tripShortName": null + } + }, + { + "startTime": 1578598680000, + "endTime": 1578599156000, + "departureDelay": 0, + "arrivalDelay": 0, + "realTime": false, + "distance": 570.328, + "mode": "WALK", + "transitLeg": false, + "from": { + "name": "TAMPERE", + "lat": 61.498776, + "lon": 23.773019, + "stop": { + "gtfsId": "MATKA:4_TPE", + "platformCode": null, + "timezone": null + } + }, + "to": { + "name": "Destination", + "lat": 61.49858856201172, + "lon": 23.7739200592041, + "stop": null + }, + "trip": null + } + ] + }, + { + "legs": [ + { + "startTime": 1578593035000, + "endTime": 1578593160000, + "departureDelay": 0, + "arrivalDelay": 0, + "realTime": false, + "distance": 127.501, + "mode": "WALK", + "transitLeg": false, + "from": { + "name": "Origin", + "lat": 60.219459533691406, + "lon": 24.81308937072754, + "stop": null + }, + "to": { + "name": "Leppävaara", + "lat": 60.219477, + "lon": 24.813224, + "stop": { + "gtfsId": "HSL:2111552", + "platformCode": "2", + "timezone": null + } + }, + "trip": null + }, + { + "startTime": 1578593160000, + "endTime": 1578593614000, + "departureDelay": 0, + "arrivalDelay": 34, + "realTime": true, + "distance": 7839.484392977336, + "mode": "RAIL", + "transitLeg": true, + "from": { + "name": "Leppävaara", + "lat": 60.219477, + "lon": 24.813224, + "stop": { + "gtfsId": "HSL:2111552", + "platformCode": "2", + "timezone": null + } + }, + "to": { + "name": "Pasila", + "lat": 60.199474, + "lon": 24.932652, + "stop": { + "gtfsId": "HSL:1174554", + "platformCode": "8", + "timezone": null + } + }, + "trip": { + "route": { + "type": 109, + "desc": null, + "shortName": "U", + "color": null, + "textColor": null, + "alerts": [] + }, + "tripHeadsign": "Helsinki", + "tripShortName": null + } + }, + { + "startTime": 1578593614000, + "endTime": 1578593770000, + "departureDelay": 0, + "arrivalDelay": 0, + "realTime": false, + "distance": 201.82799999999997, + "mode": "WALK", + "transitLeg": false, + "from": { + "name": "Pasila", + "lat": 60.199474, + "lon": 24.932652, + "stop": { + "gtfsId": "HSL:1174554", + "platformCode": "8", + "timezone": null + } + }, + "to": { + "name": "PASILA", + "lat": 60.19855, + "lon": 24.93345, + "stop": { + "gtfsId": "MATKA:4_PSL", + "platformCode": null, + "timezone": null + } + }, + "trip": null + }, + { + "startTime": 1578594600000, + "endTime": 1578599880000, + "departureDelay": 0, + "arrivalDelay": 0, + "realTime": false, + "distance": 162792.89955847053, + "mode": "RAIL", + "transitLeg": true, + "from": { + "name": "PASILA", + "lat": 60.19855, + "lon": 24.93345, + "stop": { + "gtfsId": "MATKA:4_PSL", + "platformCode": null, + "timezone": null + } + }, + "to": { + "name": "TAMPERE", + "lat": 61.498776, + "lon": 23.773019, + "stop": { + "gtfsId": "MATKA:4_TPE", + "platformCode": null, + "timezone": null + } + }, + "trip": { + "route": { + "type": 2, + "desc": null, + "shortName": "53", + "color": null, + "textColor": null, + "alerts": [] + }, + "tripHeadsign": "VAASA", + "tripShortName": null + } + }, + { + "startTime": 1578599880000, + "endTime": 1578600356000, + "departureDelay": 0, + "arrivalDelay": 0, + "realTime": false, + "distance": 570.328, + "mode": "WALK", + "transitLeg": false, + "from": { + "name": "TAMPERE", + "lat": 61.498776, + "lon": 23.773019, + "stop": { + "gtfsId": "MATKA:4_TPE", + "platformCode": null, + "timezone": null + } + }, + "to": { + "name": "Destination", + "lat": 61.49858856201172, + "lon": 23.7739200592041, + "stop": null + }, + "trip": null + } + ] + } + ] + } +} + diff --git a/autotests/data/otp/fi-digitransit-journey.out.json b/autotests/data/otp/fi-digitransit-journey.out.json new file mode 100644 index 0000000..5d758cb --- /dev/null +++ b/autotests/data/otp/fi-digitransit-journey.out.json @@ -0,0 +1,215 @@ +[ + { + "sections": [ + { + "disruptionEffect": "NormalService", + "distance": 70, + "from": { + "latitude": 60.219459533691406, + "longitude": 24.81308937072754, + "name": "Origin" + }, + "mode": "Walking", + "scheduledArrivalTime": "2020-01-09T17:14:14", + "scheduledDepartureTime": "2020-01-09T17:13:19", + "to": { + "latitude": 60.21926498413086, + "longitude": 24.814298629760742, + "name": "LEPPÄVAARA" + } + }, + { + "disruptionEffect": "NormalService", + "distance": 6973, + "from": { + "latitude": 60.21926498413086, + "longitude": 24.814298629760742, + "name": "LEPPÄVAARA" + }, + "mode": "PublicTransport", + "route": { + "direction": "HELSINKI", + "line": { + "mode": "LongDistanceTrain", + "name": "986" + } + }, + "scheduledArrivalTime": "2020-01-09T17:19:23", + "scheduledDepartureTime": "2020-01-09T17:14:14", + "to": { + "latitude": 60.198551177978516, + "longitude": 24.93345069885254, + "name": "PASILA" + } + }, + { + "disruptionEffect": "NormalService", + "distance": 12058, + "from": { + "latitude": 60.198551177978516, + "longitude": 24.93345069885254, + "name": "PASILA" + }, + "mode": "PublicTransport", + "route": { + "direction": "KAJAANI", + "line": { + "mode": "LongDistanceTrain", + "name": "73" + } + }, + "scheduledArrivalTime": "2020-01-09T17:40:01", + "scheduledDepartureTime": "2020-01-09T17:30:59", + "to": { + "latitude": 60.29220199584961, + "longitude": 25.043617248535156, + "name": "TIKKURILA" + } + }, + { + "disruptionEffect": "NormalService", + "distance": 152092, + "from": { + "latitude": 60.29220199584961, + "longitude": 25.043617248535156, + "name": "TIKKURILA" + }, + "mode": "PublicTransport", + "route": { + "direction": "KEMIJÄRVI", + "line": { + "mode": "LongDistanceTrain", + "name": "265" + } + }, + "scheduledArrivalTime": "2020-01-09T19:38:00", + "scheduledDepartureTime": "2020-01-09T17:44:41", + "to": { + "latitude": 61.498775482177734, + "longitude": 23.773019790649414, + "name": "TAMPERE" + } + }, + { + "disruptionEffect": "NormalService", + "distance": 570, + "from": { + "latitude": 61.498775482177734, + "longitude": 23.773019790649414, + "name": "TAMPERE" + }, + "mode": "Walking", + "scheduledArrivalTime": "2020-01-09T19:45:56", + "scheduledDepartureTime": "2020-01-09T19:38:00", + "to": { + "latitude": 61.49858856201172, + "longitude": 23.7739200592041, + "name": "Destination" + } + } + ] + }, + { + "sections": [ + { + "disruptionEffect": "NormalService", + "distance": 127, + "from": { + "latitude": 60.219459533691406, + "longitude": 24.81308937072754, + "name": "Origin" + }, + "mode": "Walking", + "scheduledArrivalTime": "2020-01-09T18:06:00", + "scheduledDepartureTime": "2020-01-09T18:03:55", + "to": { + "latitude": 60.219478607177734, + "longitude": 24.81322479248047, + "name": "Leppävaara" + } + }, + { + "disruptionEffect": "NormalService", + "distance": 7839, + "from": { + "latitude": 60.219478607177734, + "longitude": 24.81322479248047, + "name": "Leppävaara" + }, + "mode": "PublicTransport", + "route": { + "direction": "Helsinki", + "line": { + "mode": "RapidTransit", + "name": "U" + } + }, + "scheduledArrivalTime": "2020-01-09T18:13:34", + "scheduledDepartureTime": "2020-01-09T18:06:00", + "to": { + "latitude": 60.1994743347168, + "longitude": 24.93265151977539, + "name": "Pasila" + } + }, + { + "disruptionEffect": "NormalService", + "distance": 201, + "from": { + "latitude": 60.1994743347168, + "longitude": 24.93265151977539, + "name": "Pasila" + }, + "mode": "Walking", + "scheduledArrivalTime": "2020-01-09T18:16:10", + "scheduledDepartureTime": "2020-01-09T18:13:34", + "to": { + "latitude": 60.198551177978516, + "longitude": 24.93345069885254, + "name": "PASILA" + } + }, + { + "disruptionEffect": "NormalService", + "distance": 162792, + "from": { + "latitude": 60.198551177978516, + "longitude": 24.93345069885254, + "name": "PASILA" + }, + "mode": "PublicTransport", + "route": { + "direction": "VAASA", + "line": { + "mode": "Train", + "name": "53" + } + }, + "scheduledArrivalTime": "2020-01-09T19:58:00", + "scheduledDepartureTime": "2020-01-09T18:30:00", + "to": { + "latitude": 61.498775482177734, + "longitude": 23.773019790649414, + "name": "TAMPERE" + } + }, + { + "disruptionEffect": "NormalService", + "distance": 570, + "from": { + "latitude": 61.498775482177734, + "longitude": 23.773019790649414, + "name": "TAMPERE" + }, + "mode": "Walking", + "scheduledArrivalTime": "2020-01-09T20:05:56", + "scheduledDepartureTime": "2020-01-09T19:58:00", + "to": { + "latitude": 61.49858856201172, + "longitude": 23.7739200592041, + "name": "Destination" + } + } + ] + } +] diff --git a/autotests/otpparsertest.cpp b/autotests/otpparsertest.cpp new file mode 100644 index 0000000..647002d --- /dev/null +++ b/autotests/otpparsertest.cpp @@ -0,0 +1,111 @@ +/* + Copyright (C) 2020 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 "backends/opentripplannerparser.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define s(x) QStringLiteral(x) + +using namespace KPublicTransport; + +class OtpParserTest : public QObject +{ + Q_OBJECT +private: + QByteArray readFile(const QString &fn) + { + QFile f(fn); + f.open(QFile::ReadOnly); + return f.readAll(); + } + +private Q_SLOTS: + void initTestCase() + { + qputenv("TZ", "UTC"); + qRegisterMetaType(); + } + + void testParseDepartures_data() + { + QTest::addColumn("inFileName"); + QTest::addColumn("refFileName"); + + QTest::newRow("fi-digitransit-departures") + << s(SOURCE_DIR "/data/otp/fi-digitransit-departure.in.json") + << s(SOURCE_DIR "/data/otp/fi-digitransit-departure.out.json"); + } + + void testParseDepartures() + { + QFETCH(QString, inFileName); + QFETCH(QString, refFileName); + + const auto res = OpenTripPlannerParser::parseDepartures(QJsonDocument::fromJson(readFile(inFileName)).object()); + const auto jsonRes = Departure::toJson(res); + + const auto ref = QJsonDocument::fromJson(readFile(refFileName)).array(); + + if (jsonRes != ref) { + qDebug().noquote() << QJsonDocument(jsonRes).toJson(); + } + QVERIFY(!jsonRes.empty()); + QCOMPARE(jsonRes, ref); + } + + void testParseJourney_data() + { + QTest::addColumn("inFileName"); + QTest::addColumn("refFileName"); + + QTest::newRow("fi-digitransit-departures") + << s(SOURCE_DIR "/data/otp/fi-digitransit-journey.in.json") + << s(SOURCE_DIR "/data/otp/fi-digitransit-journey.out.json"); + } + + void testParseJourney() + { + QFETCH(QString, inFileName); + QFETCH(QString, refFileName); + + const auto res = OpenTripPlannerParser::parseJourneys(QJsonDocument::fromJson(readFile(inFileName)).object()); + const auto jsonRes = Journey::toJson(res); + + const auto ref = QJsonDocument::fromJson(readFile(refFileName)).array(); + + if (jsonRes != ref) { + qDebug().noquote() << QJsonDocument(jsonRes).toJson(); + } + QVERIFY(!jsonRes.empty()); + QCOMPARE(jsonRes, ref); + } +}; + +QTEST_GUILESS_MAIN(OtpParserTest) + +#include "otpparsertest.moc" diff --git a/src/lib/backends/opentripplannerparser.h b/src/lib/backends/opentripplannerparser.h index a1d8e86..7a33dc3 100644 --- a/src/lib/backends/opentripplannerparser.h +++ b/src/lib/backends/opentripplannerparser.h @@ -1,37 +1,41 @@ /* Copyright (C) 2020 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 . */ #ifndef KPUBLICTRANSPORT_OPENTRIPPLANNERPARSER_H #define KPUBLICTRANSPORT_OPENTRIPPLANNERPARSER_H +#include "kpublictransport_export.h" + #include #include class QJsonObject; namespace KPublicTransport { -/** Parser for OTP responses as defined by the GraphQL files in the otp/ subdir. */ +/** Parser for OTP responses as defined by the GraphQL files in the otp/ subdir. + * @internal only exported for unit tests + */ namespace OpenTripPlannerParser { - std::vector parseDepartures(const QJsonObject &obj); - std::vector parseJourneys(const QJsonObject &obj); + KPUBLICTRANSPORT_EXPORT std::vector parseDepartures(const QJsonObject &obj); + KPUBLICTRANSPORT_EXPORT std::vector parseJourneys(const QJsonObject &obj); } } #endif // KPUBLICTRANSPORT_OPENTRIPPLANNERPARSER_H