knowledgedbtest.cpp 14.7 KB
Newer Older
Volker Krause's avatar
Volker Krause committed
1
/*
2
  SPDX-FileCopyrightText: 2018 Volker Krause <vkrause@kde.org>
Volker Krause's avatar
Volker Krause committed
3

4
   SPDX-License-Identifier: LGPL-2.0-or-later
Volker Krause's avatar
Volker Krause committed
5
6
*/

7
#include <KItinerary/CountryDb>
8

9
#include <config-kitinerary.h>
10
#include <knowledgedb/alphaid.h>
11
#include <knowledgedb/timezonedb.cpp>
12
#include <knowledgedb/trainstationdb.h>
Volker Krause's avatar
Volker Krause committed
13
14
15
16
17
18
19
20
21

#include <QDebug>
#include <QObject>
#include <QTest>
#include <QTimeZone>

using namespace KItinerary;
using namespace KItinerary::KnowledgeDb;

22
23
24
25
26
27
28
29
namespace KItinerary { namespace KnowledgeDb {
char *toString(CountryId c)
{
    using QTest::toString;
    return toString(c.toString());
}
}}

30
31
32
33
34
35
char *toString(const QTimeZone &tz)
{
    using QTest::toString;
    return toString(tz.id());
}

Volker Krause's avatar
Volker Krause committed
36
37
38
39
class KnowledgeDbTest : public QObject
{
    Q_OBJECT
private Q_SLOTS:
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
    void testUnalignedNumber()
    {
        constexpr UnalignedNumber<3> uic1(8001337);
        constexpr UnalignedNumber<3> uic2(8001330);
        static_assert(sizeof(uic1) == 3, "");
        static_assert(alignof(UnalignedNumber<3>) == 1, "");
        QVERIFY(!(uic1 < uic2));
        QVERIFY(uic2 < uic1);
        QVERIFY(uic1 != uic2);
        QVERIFY(!(uic1 == uic2));

        constexpr UnalignedNumber<3> uic3(9899776);
        constexpr UnalignedNumber<3> uic4(1000191);
        QVERIFY(!(uic3 < uic4));
        QVERIFY(uic4 < uic3);
        QVERIFY(uic3 != uic4);
        QVERIFY(!(uic3 == uic4));
        QCOMPARE(uic3.value(), 9899776);
        QCOMPARE(uic4.value(), 1000191);

        constexpr UnalignedNumber<3> uic[2] = { UnalignedNumber<3>(8301700), UnalignedNumber<3>(8301701) };
        static_assert(sizeof(uic) == 6, "");
        QVERIFY(uic[0] < uic[1]);
        QVERIFY(uic[0] == uic[0]);
        QVERIFY(uic[0] != uic[1]);
    }

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
   void testAlphaId()
   {
       using ID3 = AlphaId<uint16_t, 3>;
       constexpr ID3 id1{"ABC"};
       const ID3 id2(QStringLiteral("CBA"));
       static_assert(sizeof(id1) == 2, "");
       QVERIFY(id1.isValid());
       QVERIFY(id2.isValid());
       QVERIFY(id1 < id2);
       QVERIFY(!(id2 < id1));
       QVERIFY(id1 == id1);
       QVERIFY(id1 != id2);
       QVERIFY(!(id1 == id2));
       QVERIFY(!(id1 != id1));

       QCOMPARE(id1.toString(), QLatin1String("ABC"));
       QCOMPARE(id2.toString(), QLatin1String("CBA"));

       constexpr ID3 id3;
       QVERIFY(!id3.isValid());
       QVERIFY(id3.toString().isEmpty());

       qDebug() << id1;
    }

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
    void testStationIdentifiers()
    {
        auto sncf = KnowledgeDb::SncfStationId(QStringLiteral("FRPNO"));
        QVERIFY(sncf.isValid());
        QCOMPARE(sncf.toString(), QLatin1String("FRPNO"));
        sncf = KnowledgeDb::SncfStationId(QStringLiteral("Abc"));
        QVERIFY(!sncf.isValid());
        sncf =  KnowledgeDb::SncfStationId(QStringLiteral("CHZID"));
        QVERIFY(sncf.isValid());
        QCOMPARE(sncf.toString(), QLatin1String("CHZID"));

        auto vrCode = KnowledgeDb::VRStationCode(QStringLiteral("HSL"));
        QVERIFY(vrCode.isValid());
        QCOMPARE(vrCode.toString(), QLatin1String("HSL"));
    }

Volker Krause's avatar
Volker Krause committed
108
109
    void testIBNRLookup()
    {
110
        auto station = KnowledgeDb::stationForIbnr(IBNR{1234567});
Volker Krause's avatar
Volker Krause committed
111
112
        QVERIFY(!station.coordinate.isValid());

113
        station = KnowledgeDb::stationForIbnr({});
Volker Krause's avatar
Volker Krause committed
114
115
        QVERIFY(!station.coordinate.isValid());

116
        station = KnowledgeDb::stationForIbnr(IBNR{8011160});
Volker Krause's avatar
Volker Krause committed
117
        QVERIFY(station.coordinate.isValid());
118
        QCOMPARE(station.country, CountryId{"DE"});
Volker Krause's avatar
Volker Krause committed
119

120
        station = KnowledgeDb::stationForIbnr(IBNR{8501687});
Volker Krause's avatar
Volker Krause committed
121
        QVERIFY(station.coordinate.isValid());
122
        QCOMPARE(station.country, CountryId{"CH"});
123
124
125
126
127

        // Aachen West, very close to the NL border, should be in DE timezone
        station = KnowledgeDb::stationForIbnr(IBNR{8000404});
        QVERIFY(station.coordinate.isValid());
        QCOMPARE(station.country, CountryId{"DE"});
Volker Krause's avatar
Volker Krause committed
128
129
    }

130
131
132
133
134
135
136
137
138
139
140
141
142
    void testUICLookup()
    {
        auto station = KnowledgeDb::stationForUic(UICStation{1234567});
        QVERIFY(!station.coordinate.isValid());

        station = KnowledgeDb::stationForUic({});
        QVERIFY(!station.coordinate.isValid());

        station = KnowledgeDb::stationForUic(UICStation{1001332});
        QVERIFY(station.coordinate.isValid());
        QCOMPARE(station.country, CountryId{"FI"});
    }

143
    void testSncfStationIdLookup()
Volker Krause's avatar
Volker Krause committed
144
    {
145
        auto station = KnowledgeDb::stationForSncfStationId({});
Volker Krause's avatar
Volker Krause committed
146
147
        QVERIFY(!station.coordinate.isValid());

148
        station = KnowledgeDb::stationForSncfStationId(SncfStationId{"XXXXX"});
Volker Krause's avatar
Volker Krause committed
149
150
        QVERIFY(!station.coordinate.isValid());

151
        station = KnowledgeDb::stationForSncfStationId(SncfStationId{"FRAES"});
Volker Krause's avatar
Volker Krause committed
152
        QVERIFY(station.coordinate.isValid());
153
        QCOMPARE(station.country, CountryId{"FR"});
Volker Krause's avatar
Volker Krause committed
154

155
        station = KnowledgeDb::stationForSncfStationId(SncfStationId{QStringLiteral("FRXYT")});
Volker Krause's avatar
Volker Krause committed
156
        QVERIFY(station.coordinate.isValid());
157
        QCOMPARE(station.country, CountryId{"FR"});
Volker Krause's avatar
Volker Krause committed
158

159
        station = KnowledgeDb::stationForSncfStationId(SncfStationId{"CHGVA"});
Volker Krause's avatar
Volker Krause committed
160
        QVERIFY(station.coordinate.isValid());
161
        QCOMPARE(station.country, CountryId{"CH"});
Volker Krause's avatar
Volker Krause committed
162
163
164
        station = KnowledgeDb::stationForSncfStationId(SncfStationId{"FRHWO"}); // alias for CHGVA...
        QVERIFY(station.coordinate.isValid());
        QCOMPARE(station.country, CountryId{"CH"});
165
166
167
168

        station = KnowledgeDb::stationForSncfStationId(SncfStationId{"NLAMA"}); // vs. SNCB ID of NLASC
        QVERIFY(station.coordinate.isValid());
        QCOMPARE(station.country, CountryId{"NL"});
Volker Krause's avatar
Volker Krause committed
169
    }
170

171
172
173
174
175
176
177
178
179
180
181
182
183
    void testBenerailStationIdLookup()
    {
        auto station = KnowledgeDb::stationForBenerailId({});
        QVERIFY(!station.coordinate.isValid());

        station = KnowledgeDb::stationForBenerailId(BenerailStationId{"XXXXX"});
        QVERIFY(!station.coordinate.isValid());

        station = KnowledgeDb::stationForBenerailId(BenerailStationId{"NLASC"});
        QVERIFY(station.coordinate.isValid());
        QCOMPARE(station.country, CountryId{"NL"});
    }

184
185
186
187
    void testCountryDb()
    {
        auto country = KnowledgeDb::countryForId(CountryId{});
        QCOMPARE(country.drivingSide, KnowledgeDb::DrivingSide::Unknown);
188
        QCOMPARE(country.powerPlugTypes, {Unknown});
189
190
191

        country = KnowledgeDb::countryForId(CountryId{"DE"});
        QCOMPARE(country.drivingSide, KnowledgeDb::DrivingSide::Right);
192
        QCOMPARE(country.powerPlugTypes, KnowledgeDb::PowerPlugTypes{TypeC|TypeF});
193
194
        country = KnowledgeDb::countryForId(CountryId{"GB"});
        QCOMPARE(country.drivingSide, KnowledgeDb::DrivingSide::Left);
195
        QCOMPARE(country.powerPlugTypes, {TypeG});
196
        country = KnowledgeDb::countryForId(CountryId{"GL"});
197
        QCOMPARE(country.drivingSide, KnowledgeDb::DrivingSide::Right);
198
    }
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239

    void testPowerPlugCompat_data()
    {
        using namespace KnowledgeDb;

        QTest::addColumn<PowerPlugTypes>("plugs");
        QTest::addColumn<PowerPlugTypes>("sockets");
        QTest::addColumn<PowerPlugTypes>("failPlugs");
        QTest::addColumn<PowerPlugTypes>("failSockets");

        QTest::newRow("empty") << PowerPlugTypes{} << PowerPlugTypes{} << PowerPlugTypes{} << PowerPlugTypes{};
        QTest::newRow("DE-DE") << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{} << PowerPlugTypes{};
        QTest::newRow("DE-CH") << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeC|TypeJ} << PowerPlugTypes{TypeF} << PowerPlugTypes{TypeJ};
        QTest::newRow("CH-DE") << PowerPlugTypes{TypeC|TypeJ} << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeJ} << PowerPlugTypes{TypeF};
        QTest::newRow("DE-FR") << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeC|TypeE} << PowerPlugTypes{} << PowerPlugTypes{};
        QTest::newRow("DE-GB") << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeG} << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeG};
        QTest::newRow("DE-IT") << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeC|TypeF|TypeL} << PowerPlugTypes{} << PowerPlugTypes{TypeL};
        QTest::newRow("IT-DE") << PowerPlugTypes{TypeC|TypeF|TypeL} << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeL} << PowerPlugTypes{};
        QTest::newRow("DE-IL") << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeC|TypeH|TypeM} << PowerPlugTypes{TypeF} << PowerPlugTypes{TypeH|TypeM};
        QTest::newRow("DE-AO") << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeC} << PowerPlugTypes{TypeF} << PowerPlugTypes{};
        QTest::newRow("AO-DE") << PowerPlugTypes{TypeC} << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{} << PowerPlugTypes{};
        QTest::newRow("DE-DK") << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeC|TypeE|TypeF|TypeK} << PowerPlugTypes{} << PowerPlugTypes{};
        QTest::newRow("DK-DE") << PowerPlugTypes{TypeC|TypeF|TypeE|TypeK} << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeK} << PowerPlugTypes{};
        QTest::newRow("DE-ZA") << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeC|TypeD|TypeM|TypeN} << PowerPlugTypes{TypeF} << PowerPlugTypes{TypeD|TypeM|TypeN};
        QTest::newRow("ZA-CH") << PowerPlugTypes{TypeC|TypeD|TypeM|TypeN} << PowerPlugTypes{TypeC|TypeJ} << PowerPlugTypes{TypeD|TypeM|TypeN} << PowerPlugTypes{TypeJ};
        QTest::newRow("ZA-DE") << PowerPlugTypes{TypeC|TypeD|TypeM|TypeN} << PowerPlugTypes{TypeC|TypeF} << PowerPlugTypes{TypeD|TypeM|TypeN} << PowerPlugTypes{TypeF};
        QTest::newRow("ZA-IT") << PowerPlugTypes{TypeC|TypeD|TypeM|TypeN} << PowerPlugTypes{TypeC|TypeF|TypeL} << PowerPlugTypes{TypeD|TypeM|TypeN} << PowerPlugTypes{TypeF|TypeL};
    }

    void testPowerPlugCompat()
    {
        using namespace KnowledgeDb;

        QFETCH(PowerPlugTypes, plugs);
        QFETCH(PowerPlugTypes, sockets);
        QFETCH(PowerPlugTypes, failPlugs);
        QFETCH(PowerPlugTypes, failSockets);

        QCOMPARE(KnowledgeDb::incompatiblePowerPlugs(plugs, sockets), failPlugs);
        QCOMPARE(KnowledgeDb::incompatiblePowerSockets(plugs, sockets), failSockets);
    }
240
241
242
243
244

    void testTimezoneForCountry()
    {
        using namespace KnowledgeDb;

245
246
247
248
249
        QCOMPARE(timezoneForLocation(NAN, NAN, u"DE", {}), QTimeZone("Europe/Berlin"));
        QCOMPARE(timezoneForLocation(NAN, NAN, u"FR", {}), QTimeZone("Europe/Paris"));
        QCOMPARE(timezoneForLocation(NAN, NAN, u"BR", {}), QTimeZone());
        QCOMPARE(timezoneForLocation(NAN, NAN, u"US", {}), QTimeZone());
        QCOMPARE(timezoneForLocation(NAN, NAN, u"US", u"CA"), QTimeZone("America/Los_Angeles"));
250
251
    }

252
253
254
255
256
    void testTimezoneForLocation()
    {
        using namespace KnowledgeDb;

        // basic checks in all quadrants
257
258
259
260
        QCOMPARE(timezoneForLocation(52.4, 13.1, {}, {}), QTimeZone("Europe/Berlin"));
        QCOMPARE(timezoneForLocation(-8.0, -35.0, {}, {}), QTimeZone("America/Recife"));
        QCOMPARE(timezoneForLocation(-36.5, 175.0, {}, {}), QTimeZone("Pacific/Auckland"));
        QCOMPARE(timezoneForLocation(44.0, -79.5, {}, {}), QTimeZone("America/Toronto"));
261
262

        // Special case: Northern Vietnam has a Thai timezone
263
        QCOMPARE(timezoneForLocation(21.0, 106.0, {}, {}), QTimeZone("Asia/Bangkok"));
264
265

        // Maastricht (NL), very close to the BE border
266
267
        QCOMPARE(timezoneForLocation(50.8505, 5.6881, QString(), {}), QTimeZone("Europe/Amsterdam"));
        QCOMPARE(timezoneForLocation(50.8505, 5.6881, u"NL", {}), QTimeZone("Europe/Amsterdam"));
268
269

        // Aachen, at the BE/DE/NL corner
270
271
        QCOMPARE(timezoneForLocation(50.7717, 6.04235, QString(), {}), QTimeZone("Europe/Berlin"));
        QCOMPARE(timezoneForLocation(50.7717, 6.04235, u"DE", {}), QTimeZone("Europe/Berlin"));
272
        //QCOMPARE(timezoneForLocation(50.7727, 6.01565, QString()), QTimeZone("Europe/Brussels"));
273
        QCOMPARE(timezoneForLocation(50.7727, 6.01565, u"BE", {}), QTimeZone("Europe/Brussels"));
274
275

        // Geneva (CH), very close to the FR border
276
        QCOMPARE(timezoneForLocation(46.23213, 6.10636, u"CH", {}), QTimeZone("Europe/Zurich"));
277
278

        // Busingen (DE), enclosed by CH, and in theory its own timezone (which we ignore)
279
280
        QCOMPARE(timezoneForLocation(47.69947, 8.68833, u"DE", {}), QTimeZone("Europe/Berlin"));
        QCOMPARE(timezoneForLocation(47.67904, 8.68813, {}, {}), QTimeZone("Europe/Zurich"));
281
282

        // Baarle, the ultimate special case, NL/BE differs house by house
283
284
285
        QCOMPARE(timezoneForLocation(51.44344, 4.93373, u"BE", {}), QTimeZone("Europe/Brussels"));
        QCOMPARE(timezoneForLocation(51.44344, 4.93373, u"NL", {}), QTimeZone("Europe/Amsterdam"));
        const auto tz = timezoneForLocation(51.44344, 4.93373, {}, {});
286
        QVERIFY(tz == QTimeZone("Europe/Amsterdam") || tz == QTimeZone("Europe/Brussels"));
287
288

        // Eliat Airport (IL), close to JO, and with a minor timezone variation due to different weekends
289
290
        QCOMPARE(timezoneForLocation(29.72530, 35.00598, u"IL", {}), QTimeZone("Asia/Jerusalem"));
        QCOMPARE(timezoneForLocation(29.60908, 35.02038, u"JO", {}), QTimeZone("Asia/Amman"));
291
292

        // Tijuana (MX), close to US, tests equivalent tz search in the neighbouring country
293
294
        QCOMPARE(timezoneForLocation(32.54274, -116.97505, u"MX", {}), QTimeZone("America/Tijuana"));
        QCOMPARE(timezoneForLocation(32.55783, -117.04773, u"US", {}), QTimeZone("America/Los_Angeles"));
295
296

        // Cordoba (AR), AR has several sub-zones that are all equivalent
297
        QCOMPARE(timezoneForLocation(-31.4, -64.2, u"AR", {}), QTimeZone("America/Argentina/Buenos_Aires"));
298
299

        // polar regions
300
301
        QCOMPARE(timezoneForLocation(-90.0, 0.0, {}, {}), QTimeZone());
        QCOMPARE(timezoneForLocation(90.0, 0.0, {}, {}), QTimeZone());
302
303

        // Hong Kong seems problematic on FreeBSD
304
        QCOMPARE(timezoneForLocation(22.31600, 113.93688, {}, {}), QTimeZone("Asia/Hong_Kong"));
305
306

        // coordinates not provided
307
        QCOMPARE(timezoneForLocation(NAN, NAN, u"LU", {}), QTimeZone("Europe/Luxembourg"));
308
309
    }

310
311
312
313
314
315
316
    void testUICCountryCodeLookup()
    {
        using namespace KnowledgeDb;

        QCOMPARE(KnowledgeDb::countryIdForUicCode(80), CountryId{"DE"});
        QCOMPARE(KnowledgeDb::countryIdForUicCode(0), CountryId{});
    }
317

318
319
320
321
322
323
324
325
326
327
328
329
    void testIndianRailwaysStationCodeLookup()
    {
        auto station = KnowledgeDb::stationForIndianRailwaysStationCode(QString());
        QVERIFY(!station.coordinate.isValid());

        station = KnowledgeDb::stationForIndianRailwaysStationCode(QStringLiteral("NDLS"));
        QVERIFY(station.coordinate.isValid());
        QCOMPARE(station.country, CountryId{"IN"});

        station = KnowledgeDb::stationForIndianRailwaysStationCode(QStringLiteral("ndls"));
        QVERIFY(!station.coordinate.isValid());
    }
330
331
332
333
334
335
336
337
338

    void testFinishStationCodeLookup()
    {
        auto station = KnowledgeDb::stationForVRStationCode(VRStationCode(QStringLiteral("HKI")));
        QVERIFY(station.coordinate.isValid());

        station = KnowledgeDb::stationForVRStationCode(VRStationCode(QStringLiteral("BLÄ")));
        QVERIFY(!station.coordinate.isValid());
    }
Volker Krause's avatar
Volker Krause committed
339
340
341
342
343
};

QTEST_APPLESS_MAIN(KnowledgeDbTest)

#include "knowledgedbtest.moc"