File indexing completed on 2024-04-14 04:36:48

0001 /*
0002     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include <KPublicTransport/Journey>
0008 #include <KPublicTransport/JourneyReply>
0009 #include <KPublicTransport/JourneyRequest>
0010 #include <KPublicTransport/Location>
0011 #include <KPublicTransport/LocationReply>
0012 #include <KPublicTransport/LocationRequest>
0013 #include <KPublicTransport/Manager>
0014 #include <KPublicTransport/Stopover>
0015 #include <KPublicTransport/StopoverReply>
0016 #include <KPublicTransport/StopoverRequest>
0017 
0018 #include <QDir>
0019 #include <QSignalSpy>
0020 #include <QStandardPaths>
0021 #include <QtTest>
0022 
0023 using namespace KPublicTransport;
0024 
0025 class QueryTest : public QObject
0026 {
0027     Q_OBJECT
0028 private:
0029     Location loc(const char *name, float lat, float lon) const
0030     {
0031         Location l;
0032         l.setName(QString::fromUtf8(name));
0033         l.setCoordinate(lat, lon);
0034         return l;
0035     }
0036 
0037     static bool hasRealtimeJourneyData(const std::vector<Journey> &journeys) {
0038         return std::any_of(journeys.begin(), journeys.end(), [](const auto &jny) {
0039             return std::any_of(jny.sections().begin(), jny.sections().end(), [](const auto &sec) {
0040                 return sec.hasExpectedDepartureTime() || sec.hasExpectedArrivalTime() || sec.hasExpectedDeparturePlatform() || sec.hasExpectedArrivalPlatform();
0041             });
0042         });
0043     }
0044 
0045     static constexpr const auto TIMEOUT = 60000;
0046 
0047     KPublicTransport::Manager m_ptMgr;
0048 
0049 private Q_SLOTS:
0050     void initTestCase()
0051     {
0052         QStandardPaths::setTestModeEnabled(true);
0053         QDir(QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation)).removeRecursively();
0054 
0055         m_ptMgr.setAllowInsecureBackends(true);
0056     }
0057 
0058     void testBackend_data()
0059     {
0060         QTest::addColumn<QString>("backend");
0061         QTest::addColumn<Location>("loc1");
0062         QTest::addColumn<Location>("loc2");
0063 
0064         // international
0065         // TODO un_gbfs - this needs special-casing given it cannot do journey and departure searches
0066         QTest::newRow("un_navitia") << "un_navitia" << loc("Paris Gare de Lyon", 48.84444, 2.37412) << loc("Paris Aéroport Charles de Gaulle 2 TGV", 49.00423, 2.57215);
0067         QTest::newRow("au_navitia") << "au_navitia" << loc("King George Square Station",  -27.468903869, 153.0242799) << loc("Brisbane International Airport", -27.404467, 153.108597);
0068 
0069         // national
0070         QTest::newRow("at_oebb") << "at_oebb" << loc("Wien Hauptbahnhof", 48.18282, 16.37859) << loc("Linz/Donau Hbf", 48.29058, 14.29018);
0071         QTest::newRow("be_sncb") << "be_sncb" << loc("Bruxelles Midi", 50.83604, 4.33679) << loc("Mechelen", 51.01745, 4.48336);
0072         QTest::newRow("ch_opentransportdata") << "ch_opentransportdata" << loc("Zürich Flughafen", 47.45, 8.561) << loc("Randa", 46.09982, 7.78149);
0073         // endpoint defunct
0074         // QTest::newRow("ch_sbb") << "ch_sbb" << loc("Zürich Flughafen", 47.45015, 8.56199 ) << loc("Randa", 46.09982, 7.78149);
0075         QTest::newRow("de_db") << "de_db" << loc("Berlin Hauptbahnhof", 52.52509, 13.36946) << loc("Frankfurt Hbf", 50.10675, 8.66281);
0076         QTest::newRow("dk_dsb") << "dk_dsb" << loc("København H", 55.67228, 12.56442) << loc("Københavns Lufthavn Kastrup", 55.62940, 12.64872);
0077         QTest::newRow("ee_peatus") << "ee_peatus" << loc("Tallinn Hobujaama", 59.43727, 24.75824) << loc("Pärnu", 58.37254, 24.55502);
0078         QTest::newRow("eu_railteam") << "eu_railteam" << loc("Bruxelles Midi", 50.8353, 4.33679) << loc("Amsterdam Centraal", 52.37923, 4.90055);
0079         QTest::newRow("fi_digitransit") << "fi_digitransit" << loc("Helsinki", 60.17174, 24.94148) << loc("Espoo", 60.20530, 24.65748);
0080         QTest::newRow("fi_waltti") << "fi_waltti" << loc("Helsinki", 60.17174, 24.94148) << loc("Tampere", 61.49859, 23.77392);
0081         QTest::newRow("fr_sncf") << "fr_sncf" << loc("Paris Gare de Lyon", 48.84444, 2.37412) << loc("Paris Aéroport Charles de Gaulle 2 TGV", 49.00423, 2.57215);
0082         QTest::newRow("gb_traveline") << "gb_traveline" << loc( "London Euston", 51.52814, -0.13365) << loc("Glasgow Queen Street", 55.86252, -4.25074);
0083         QTest::newRow("ie_tfi") << "ie_tfi" << loc("Dublin Connolly", 53.35258, -6.24706) << loc("Cork Kent", 51.90159, -8.45823);
0084         QTest::newRow("lu_cfl") << "lu_cfl" << loc("Luxembourg Gare Centrale", 49.59962, 6.13473) << loc("Ettelbruck", 49.84745, 6.10645);
0085         QTest::newRow("nl_ns") << "nl_ns" << loc("Amsterdam Centraal", 52.37923, 4.90055) << loc("Den Haag Centraal", 52.08108, 4.32406);
0086         QTest::newRow("no_entur") << "no_entur" << loc("Oslo", 59.91157, 10.75413) << loc("Bergen", 60.39033, 5.33396);
0087         QTest::newRow("pl_pkp") << "pl_pkp" << loc("Warszawa Centralna", 52.228862, 21.00323295) << loc("Gdańsk Główny", 54.35625, 18.64417);
0088         QTest::newRow("se_resrobot") << "se_resrobot" << loc("Stockholm Central", 59.32976, 18.05715) << loc("Göteborgs centralstation", 57.70913, 11.97321);
0089         // TODO tn_sncft
0090 
0091         // local
0092         QTest::newRow("at_3_vor") << "at_3_vor" << loc("Wien Hauptbahnhof", 48.185184, 16.37641) << loc("Wien Flughafen", 48.12012, 16.56441);
0093         QTest::newRow("at_4_linz") << "at_4_linz" << loc("Linz/Donau Hbf", 48.29007, 14.29207) << loc("Hörsching", 48.24549, 14.18587);
0094         QTest::newRow("at_4_ooevv") << "at_4_ooevv" << loc("Linz/Donau Hbf", 48.29058, 14.29018) << loc("Hörsching", 48.24549, 14.18587);
0095         QTest::newRow("at_5_svv") << "at_5_svv" << loc("Salzburg Hbf", 47.81285, 13.04592) << loc("Freilassing", 47.83690, 12.97673);
0096         QTest::newRow("at_6_vvst") << "at_6_vvst" << loc("Graz Hauptbahnhof", 47.07236, 15.41665) << loc("Bruck an der Mur", 47.41413, 15.28000);
0097         QTest::newRow("at_7_vvt") << "at_7_vvt" << loc("Innsbruck Hbf", 47.26289, 11.40163) << loc("Kufstein", 47.58308, 12.16626);
0098         QTest::newRow("at_8_vvv") << "at_8_vvv" << loc("Bregenz", 47.50307, 9.74019) << loc("Dornbirn", 47.413280, 9.743741);
0099         QTest::newRow("at_9_wien") << "at_9_wien" << loc("Wien Hauptbahnhof", 48.18282, 16.37859) << loc("Wien Praterstern", 48.21870, 16.39247);
0100 
0101         QTest::newRow("au_nsw") << "au_nsw" << loc("Sydney Central", -33.88315, 151.20587) << loc("Sydney Internation Airport", -33.93503, 151.16603);
0102 
0103         QTest::newRow("ch_zh_zvv") << "ch_zh_zvv" << loc("Zürich Flughafen", 47.45015, 8.56199 ) << loc("Zürich HB", 47.37833, 8.53912);
0104 
0105         QTest::newRow("de_bb_bbnavi_angermuende") << "de_bb_bbnavi_angermuende" << loc("Angermünde", 53.01579, 13.99634) << loc("Schwedt", 53.06298, 14.29054);
0106         QTest::newRow("de_bb_vbb") << "de_bb_vbb" << loc("Berlin Hauptbahnhof", 52.52509, 13.36946) << loc("Berlin Alexanderplatz", 52.52147, 13.41134);
0107         QTest::newRow("de_be_bvg") << "de_be_bvg" << loc("Berlin Hauptbahnhof", 52.52509, 13.36946) << loc("Berlin Alexanderplatz", 52.52147, 13.41134);
0108         QTest::newRow("de_bw_bwegt") << "de_bw_bwegt" << loc("Stuttgart Hbf", 48.78539, 9.18345) << loc("Herrenberg", 48.59392, 8.86275);
0109         QTest::newRow("de_bw_kvv") << "de_bw_kvv" << loc("Karlsruhe Hbf", 48.99342, 8.40173 ) << loc("Ettlingen Stadt", 48.93867, 8.40953);
0110         QTest::newRow("de_bw_stadtnavi") << "de_bw_stadtnavi" << loc("Stuttgart Hbf", 48.78539, 9.18345) << loc("Herrenberg", 48.59392, 8.86275);
0111         QTest::newRow("de_bw_ulm") << "de_bw_ulm" << loc("Ulm Hbf", 48.39946, 9.98302) << loc("Neu Ulm", 48.39330, 10.00520);
0112         QTest::newRow("de_bw_vvs") << "de_bw_vvs" << loc("Stuttgart Hbf", 48.78539, 9.18345) << loc("Herrenberg", 48.59392, 8.86275);
0113         QTest::newRow("de_by_bayern") << "de_by_bayern" << loc("München Hbf", 48.14046, 11.55819) << loc("Nürnberg Hbf", 49.44559, 11.08219);
0114         QTest::newRow("de_by_invg") << "de_by_invg" << loc("Ingolstadt Hbf", 48.74436, 11.43746) << loc("Ingolstadt Nord", 48.77350, 11.43251);
0115         QTest::newRow("de_by_mvv") << "de_by_mvv" << loc("München Hbf", 48.14046, 11.55819) << loc("Isartor", 48.13375, 11.58303);
0116         QTest::newRow("de_by_vgn") << "de_by_vgn" << loc("Erlangen", 49.59591, 11.00220) << loc("Nürnberg Hbf", 49.44559, 11.08219);
0117         QTest::newRow("de_he_nvv") << "de_he_nvv" << loc("Kassel Hbf", 51.31836, 9.48946) << loc("Kassel Wilhelmshöhe", 51.31137, 9.44827);
0118         QTest::newRow("de_he_rmv") << "de_he_rmv" << loc("Frankfurt Hbf", 50.10675, 8.66281) << loc("Frankfurt Flughafen Regionalbf", 50.05129, 8.57170);
0119         QTest::newRow("de_hh_hvv") << "de_hh_hvv" << loc("Hamburg Hauptbahnhof", 53.55299, 10.00702) << loc("Hamburg Altona", 53.55284, 9.93569);
0120         QTest::newRow("de_mv_rsag") << "de_mv_rsag" << loc("Rostock Hauptbahnhof", 54.07814, 12.13206) << loc("Warnemünde Bahnhof", 54.17695, 12.09069);
0121         QTest::newRow("de_mv_vmv") << "de_mv_vmv" << loc("Rostock Hauptbahnhof", 54.07814, 12.13206) << loc("Stralsund Hbf", 54.30766, 13.07931);
0122         QTest::newRow("de_ni_efa") << "de_ni_efa" << loc("Hannover Hbf", 52.37715, 9.74171) << loc("Bremen Hbf", 53.08322, 8.81388);
0123         QTest::newRow("de_ni_gvh") << "de_ni_gvh" << loc("Hannover Hbf", 52.37715, 9.74171) << loc("Bremen Hbf", 53.08322, 8.81388);
0124         QTest::newRow("de_ni_vbn") << "de_ni_vbn" << loc("Hannover Hbf", 52.37715, 9.74171) << loc("Bremen Hbf", 53.08322, 8.81388);
0125         QTest::newRow("de_ni_vsn") << "de_ni_vsn" << loc("Osnabrück Hbf",52.27280, 8.06136) << loc("Göttingen", 51.53676, 9.92626);
0126         QTest::newRow("de_nw_avv") << "de_nw_avv" << loc("Aachen Hbf", 50.76784, 6.09130) << loc("Aachen West", 50.78025, 6.07124);
0127         // TODO de_nw_muenster
0128         QTest::newRow("de_nw_vrr") << "de_nw_vrr" << loc("Düsseldorf Hbf", 51.21991, 6.79419) << loc("Essen Hbf", 51.45127, 7.01388);
0129         QTest::newRow("de_nw_vrs") << "de_nw_vrs" << loc("Köln Hbf", 50.94305, 6.95908) << loc("Bonn Hbf", 50.73203, 7.09719);
0130         QTest::newRow("de_nw_zks") << "de_nw_zks" << loc("Düsseldorf Hbf", 51.21991, 6.79419) << loc("Essen Hbf", 51.45127, 7.01388);
0131         QTest::newRow("de_rp_rolph") << "de_rp_rolph" << loc("Mainz Hbf", 50.00113, 8.25865) << loc("Kaiserslautern Hauptbahnhof", 49.43607, 7.76849);
0132         QTest::newRow("de_rp_vrn") << "de_rp_vrn" << loc("Kaiserslautern Hauptbahnhof", 49.43607, 7.76849) << loc("Mannheim Hauptbahnhof", 49.47930, 8.46947);
0133         QTest::newRow("de_rp_vrt") << "de_rp_vrt" << loc("Trier Hauptbahnhof", 49.75687, 6.65245) << loc("Wittlich Hauptbahnhof", 49.97306, 6.94357);
0134         QTest::newRow("de_sh_sh") << "de_sh_sh" << loc("Hamburg Hauptbahnhof", 53.55299, 10.00702) << loc("Hamburg-Altona", 53.55284, 9.93569);
0135         QTest::newRow("de_sl_saarvv") << "de_sl_saarvv" << loc("Saarbrücken Hauptbahnhof", 49.24116, 6.99110) << loc("Saarlouis Hbf", 49.32766, 6.75103);
0136         QTest::newRow("de_sn_vvo") << "de_sn_vvo" << loc("Dresden Hbf", 51.04025, 13.73160) << loc("Chemnitz Hauptbahnhof", 50.83981, 12.93069);
0137         QTest::newRow("de_st_insa") << "de_st_insa" << loc("Leipzig Hbf", 51.34508, 12.38196) << loc("Leipzig S Bahnhof Messe", 51.39603, 12.38987);
0138         QTest::newRow("de_th_vmt") << "de_th_vmt" << loc("Erfurt Hbf", 50.97227, 11.03790) << loc("Jena Paradies", 50.92491, 11.58725);
0139 
0140         QTest::newRow("fi_17_helsinki") << "fi_17_helsinki" << loc("Helsinki", 60.17174, 24.94148) << loc("Espoo", 60.20530, 24.65748);
0141 
0142         QTest::newRow("fr_ara_metromobilite") << "fr_ara_metromobilite" << loc("Grenoble", 45.19140, 5.71449) << loc("Échorolles", 45.15272, 5.71976);
0143 
0144         // TODO it_21_piemonte
0145         QTest::newRow("it_21_torino") << "it_21_torino" << loc("Torino Porta Nuova", 45.06098, 7.67777) << loc("Torino Dora GTT", 45.09068, 7.67700);
0146 
0147         QTest::newRow("us_ca_bart") << "us_ca_bart" << loc("San Francisco International Airport (SFO)", 37.61622, -122.39180) << loc("San Francisco Powell Street",  37.78441, -122.40767);
0148         QTest::newRow("us_ca_la_metro") << "us_ca_la_metro" << loc("Los Angeles Union Station", 34.05563, -118.23407) << loc("South Pasadena", 34.11518, -118.15811);
0149         QTest::newRow("us_ga_marta") << "us_ga_marta" << loc("Five Points", 33.75390, -84.39140) << loc("Airport", 33.64084, -84.44637);
0150         // TODO us_il_chicago
0151         QTest::newRow("us_ma_mbta") << "us_ma_mbta" << loc("Boston South Station", 42.35057, -71.05535) << loc("Boston North Station", 42.36696, -71.06263);
0152         // TODO us_or_trimet
0153         QTest::newRow("us_tx_cmta") << "us_tx_cmta" << loc("Downtown", 30.26487, -97.73928) << loc("crestview", 30.33921, -97.71968);
0154     }
0155 
0156     void testBackend()
0157     {
0158         QFETCH(QString, backend);
0159         QFETCH(Location, loc1);
0160         QFETCH(Location, loc2);
0161 
0162         // location search by name
0163         {
0164             LocationRequest req;
0165             req.setBackendIds({backend});
0166             req.setName(loc1.name());
0167             auto reply = m_ptMgr.queryLocation(req);
0168             QSignalSpy spy(reply, &LocationReply::finished);
0169             QVERIFY(spy.wait(TIMEOUT));
0170             QCOMPARE(spy.size(), 1);
0171             QEXPECT_FAIL("us_ga_marta", "needs investigation", Continue);
0172             QCOMPARE(reply->error(), Reply::NoError);
0173             QEXPECT_FAIL("us_ga_marta", "needs investigation", Continue);
0174             QCOMPARE(reply->errorString(), QString());
0175             QEXPECT_FAIL("fr_ara_metromobilite", "needs investigation", Continue);
0176             QEXPECT_FAIL("it_21_torino", "needs investigation", Continue);
0177             QEXPECT_FAIL("us_ga_marta", "needs investigation", Continue);
0178             QVERIFY(reply->result().size() > 0);
0179             const auto results = reply->takeResult();
0180             if (!results.empty()) {
0181                 // sanity check the result, should be close enough to where we expect it
0182                 // there can be valid deviations of a few km due to lack of precision in our test data and
0183                 // the use of fairly large objects like airports
0184                 const auto d = Location::distance(loc1.latitude(), loc1.longitude(), results[0].latitude(), results[0].longitude());
0185                 QVERIFY(std::isnan(d) || d < 10'000);
0186             }
0187         }
0188 
0189         // location search by coordinate
0190         {
0191             LocationRequest req;
0192             req.setBackendIds({backend});
0193             req.setCoordinate(loc2.latitude(), loc2.longitude());
0194             req.setMaximumResults(1);
0195             auto reply = m_ptMgr.queryLocation(req);
0196             QSignalSpy spy(reply, &LocationReply::finished);
0197             QVERIFY(spy.wait(TIMEOUT));
0198             QCOMPARE(reply->error(), Reply::NoError);
0199             QCOMPARE(reply->errorString(), QString());
0200             QCOMPARE(spy.size(), 1);
0201             QEXPECT_FAIL("at_6_vvst", "needs investigation", Continue);
0202             QEXPECT_FAIL("fr_ara_metromobilite", "needs investigation", Continue);
0203             QVERIFY(reply->result().size() > 0);
0204         }
0205 
0206         // departure by name
0207         {
0208             StopoverRequest req;
0209             req.setBackendIds({backend});
0210             Location loc;
0211             loc.setName(loc2.name());
0212             req.setStop(loc);
0213             auto reply = m_ptMgr.queryStopover(req);
0214             QSignalSpy spy(reply, &StopoverReply::finished);
0215             QVERIFY(spy.wait(TIMEOUT));
0216             QEXPECT_FAIL("no_entur", "name-based location search returns null results?!", Continue);
0217             QEXPECT_FAIL("it_21_torino", "needs investigation", Continue);
0218             QEXPECT_FAIL("us_ca_la_metro", "needs investigation", Continue);
0219             QEXPECT_FAIL("us_ga_marta", "needs investigation", Continue);
0220             QEXPECT_FAIL("us_ma_mbta", "needs investigation", Continue);
0221             QCOMPARE(reply->error(), Reply::NoError);
0222             QEXPECT_FAIL("no_entur", "name-based location search returns null results?!", Continue);
0223             QEXPECT_FAIL("it_21_torino", "needs investigation", Continue);
0224             QEXPECT_FAIL("us_ca_la_metro", "needs investigation", Continue);
0225             QEXPECT_FAIL("us_ga_marta", "needs investigation", Continue);
0226             QEXPECT_FAIL("us_ma_mbta", "needs investigation", Continue);
0227             QCOMPARE(reply->errorString(), QString());
0228             QCOMPARE(spy.size(), 1);
0229             QEXPECT_FAIL("no_entur", "name-based location search returns null results?!", Continue);
0230             QEXPECT_FAIL("fr_ara_metromobilite", "needs investigation", Continue);
0231             QEXPECT_FAIL("it_21_torino", "needs investigation", Continue);
0232             QEXPECT_FAIL("us_ca_la_metro", "needs investigation", Continue);
0233             QEXPECT_FAIL("us_ga_marta", "needs investigation", Continue);
0234             QEXPECT_FAIL("us_ma_mbta", "needs investigation", Continue);
0235             QVERIFY(reply->result().size() > 0);
0236         }
0237 
0238         // departure by coordinate
0239         {
0240             StopoverRequest req;
0241             req.setBackendIds({backend});
0242             Location loc;
0243             loc.setCoordinate(loc1.latitude(), loc1.longitude());
0244             req.setStop(loc);
0245             auto reply = m_ptMgr.queryStopover(req);
0246             QSignalSpy spy(reply, &StopoverReply::finished);
0247             QVERIFY(spy.wait(TIMEOUT));
0248             QCOMPARE(reply->error(), Reply::NoError);
0249             QCOMPARE(reply->errorString(), QString());
0250             QCOMPARE(spy.size(), 1);
0251             QEXPECT_FAIL("at_3_vor", "needs investigation", Continue);
0252             QEXPECT_FAIL("at_4_ooevv", "needs investigation", Continue);
0253             QEXPECT_FAIL("at_8_vvv", "needs investigation", Continue);
0254             QEXPECT_FAIL("fr_ara_metromobilite", "needs investigation", Continue);
0255             QEXPECT_FAIL("pl_pkp", "needs investigation", Continue);
0256             QEXPECT_FAIL("us_ca_la_metro", "needs investigation", Continue);
0257             QEXPECT_FAIL("us_ma_mbta", "needs investigation", Continue);
0258             QVERIFY(reply->result().size() > 0);
0259         }
0260 
0261         // journey
0262         {
0263             JourneyRequest req;
0264             req.setBackendIds({backend});
0265             req.setFrom(loc1);
0266             req.setTo(loc2);
0267             req.setMaximumResults(1);
0268             auto reply = m_ptMgr.queryJourney(req);
0269             QSignalSpy spy(reply, &JourneyReply::finished);
0270             QVERIFY(spy.wait(TIMEOUT));
0271             QCOMPARE(reply->error(), Reply::NoError);
0272             QCOMPARE(reply->errorString(), QString());
0273             QCOMPARE(spy.size(), 1);
0274             QVERIFY(reply->result().size() > 0);
0275             qDebug() << "Journey realtime data:" << hasRealtimeJourneyData(reply->result());
0276         }
0277     }
0278 };
0279 
0280 QTEST_GUILESS_MAIN(QueryTest)
0281 
0282 #include "querytest.moc"