File indexing completed on 2024-05-12 05:17:29

0001 /*
0002     SPDX-FileCopyrightText: 2018 Volker Krause <vkrause@kde.org>
0003     SPDX-FileCopyrightText: 2018 Luca Beltrame <lbeltrame@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include <KItinerary/BusTrip>
0009 #include <KItinerary/Flight>
0010 #include <KItinerary/Organization>
0011 #include <KItinerary/Place>
0012 #include <KItinerary/Reservation>
0013 #include <KItinerary/TrainTrip>
0014 #include <KItinerary/Ticket>
0015 
0016 #include <KItinerary/JsonLdDocument>
0017 
0018 #include <QDebug>
0019 #include <QQmlComponent>
0020 #include <QQmlContext>
0021 #include <QQmlEngine>
0022 #include <QObject>
0023 #include <QTest>
0024 
0025 using namespace KItinerary;
0026 
0027 class DatatypesTest : public QObject
0028 {
0029     Q_OBJECT
0030 private Q_SLOTS:
0031     void testValueTypeSemantics()
0032     {
0033         Airport airport;
0034         airport.setName(QStringLiteral("Berlin Tegel"));
0035         {
0036             auto ap2 = airport;
0037             QCOMPARE(ap2.name(), QLatin1StringView("Berlin Tegel"));
0038             ap2.setIataCode(QStringLiteral("TXL"));
0039             QVERIFY(airport.iataCode().isEmpty());
0040         }
0041         Place place = airport; // assignment to base class works, but cannot be reversed
0042         QCOMPARE(place.name(), QLatin1StringView("Berlin Tegel"));
0043         place.setName(QStringLiteral("London Heathrow")); // changing a value degenerated to its base class will detach but not slice
0044         QCOMPARE(place.name(), QLatin1StringView("London Heathrow"));
0045         QCOMPARE(JsonLdDocument::readProperty(place, "className").toString(),
0046                  QLatin1StringView("Place")); // className is not polymorphic
0047 
0048         QVERIFY(!airport.geo().isValid());
0049         QCOMPARE(JsonLdDocument::readProperty(airport, "className").toString(),
0050                  QLatin1StringView("Airport"));
0051         QCOMPARE(JsonLdDocument::readProperty(airport, "name").toString(),
0052                  QLatin1StringView("Berlin Tegel"));
0053 
0054         // detach on base properties must not slice
0055         FlightReservation res;
0056         QCOMPARE(JsonLdDocument::readProperty(res, "className").toString(),
0057                  QLatin1StringView("FlightReservation"));
0058         res.setAirplaneSeat(QStringLiteral("10E"));
0059         QCOMPARE(res.airplaneSeat(), QLatin1StringView("10E"));
0060         auto res2 = res;
0061         QCOMPARE(res2.airplaneSeat(), QLatin1StringView("10E"));
0062         res2.setReservationNumber(QStringLiteral("XXX007"));
0063         QCOMPARE(res2.airplaneSeat(), QLatin1StringView("10E"));
0064 
0065         // changing default-created properties should not leak
0066         Flight flight;
0067         QCOMPARE(JsonLdDocument::readProperty(flight, "className").toString(),
0068                  QLatin1StringView("Flight"));
0069         QVariant v = flight;
0070         QVERIFY(v.canConvert<Flight>());
0071         JsonLdDocument::writeProperty(v, "departureAirport", airport);
0072         QCOMPARE(v.value<Flight>().departureAirport().name(),
0073                  QLatin1StringView("Berlin Tegel"));
0074 
0075         // make sure all meta types are generated
0076         TrainTrip tt;
0077         QCOMPARE(JsonLdDocument::readProperty(tt, "className").toString(),
0078                  QLatin1StringView("TrainTrip"));
0079         BusTrip bus;
0080         QCOMPARE(JsonLdDocument::readProperty(bus, "className").toString(),
0081                  QLatin1StringView("BusTrip"));
0082 
0083         Ticket ticket;
0084         QCOMPARE(
0085             JsonLdDocument::readProperty(ticket.ticketedSeat(), "className")
0086                 .toString(),
0087             QLatin1StringView("Seat"));
0088 
0089         Organization org;
0090         org.setName(QStringLiteral("JR East"));
0091         org.setEmail(QStringLiteral("nowhere@nowhere.com"));
0092         org.setTelephone(QStringLiteral("+55-1234-345"));
0093         org.setUrl(QUrl(QStringLiteral("http://www.jreast.co.jp/e/")));
0094         QCOMPARE(JsonLdDocument::readProperty(org, "className").toString(),
0095                  QLatin1StringView("Organization"));
0096         QCOMPARE(org.name(), QLatin1StringView("JR East"));
0097         QCOMPARE(org.email(), QLatin1StringView("nowhere@nowhere.com"));
0098         QCOMPARE(org.telephone(), QLatin1StringView("+55-1234-345"));
0099         QCOMPARE(org.url(),
0100                  QUrl(QLatin1StringView("http://www.jreast.co.jp/e/")));
0101 
0102         tt.setProvider(org);
0103         res.setProvider(org);
0104         bus.setProvider(org);
0105         QCOMPARE(tt.provider().name(), QLatin1StringView("JR East"));
0106         QCOMPARE(tt.provider().email(),
0107                  QLatin1StringView("nowhere@nowhere.com"));
0108         QCOMPARE(res.provider().name(), QLatin1StringView("JR East"));
0109         QCOMPARE(res.provider().email(),
0110                  QLatin1StringView("nowhere@nowhere.com"));
0111         QCOMPARE(bus.provider().name(), QLatin1StringView("JR East"));
0112         QCOMPARE(bus.provider().email(),
0113                  QLatin1StringView("nowhere@nowhere.com"));
0114 
0115         Airline airline;
0116         airline.setIataCode(QStringLiteral("LH"));
0117         flight.setAirline(airline);
0118         QCOMPARE(flight.airline().iataCode(), QLatin1StringView("LH"));
0119         {
0120             const auto flight2 = flight;
0121             QCOMPARE(flight2.airline().iataCode(), QLatin1StringView("LH"));
0122             QCOMPARE(JsonLdDocument::readProperty(flight.airline(), "className")
0123                          .toString(),
0124                      QLatin1StringView("Airline"));
0125             QCOMPARE(JsonLdDocument::readProperty(flight.airline(), "iataCode")
0126                          .toString(),
0127                      QLatin1StringView("LH"));
0128         }
0129     }
0130 
0131     void testQmlCompatibility()
0132     {
0133         // one variant and one typed property
0134         FlightReservation res;
0135         Flight flight;
0136         Airport airport;
0137         airport.setName(QStringLiteral("Berlin Tegel"));
0138         flight.setDepartureAirport(airport);
0139         res.setReservationFor(flight);
0140 
0141         QQmlEngine engine;
0142         engine.rootContext()->setContextProperty(QStringLiteral("_res"), res);
0143         QQmlComponent component(&engine);
0144         component.setData("import QtQml 2.2\nQtObject { Component.onCompleted: console.log(_res.reservationFor.departureAirport.name); }", QUrl());
0145         if (component.status() == QQmlComponent::Error) {
0146             qWarning() << component.errorString();
0147         }
0148         QCOMPARE(component.status(), QQmlComponent::Ready);
0149         auto obj = component.create();
0150         QVERIFY(obj);
0151     }
0152 
0153     void testUpCastHelper()
0154     {
0155         Place p;
0156         FoodEstablishment r;
0157         Airport a;
0158         a.setName(QStringLiteral("Berlin Tegel"));
0159         a.setIataCode(QStringLiteral("TXL"));
0160 
0161         QVERIFY(JsonLd::canConvert<Place>(a));
0162         QVERIFY(JsonLd::canConvert<Airport>(a));
0163         QVERIFY(!JsonLd::canConvert<FoodEstablishment>(a));
0164         QVERIFY(!JsonLd::canConvert<Airport>(p));
0165 
0166         p = JsonLd::convert<Place>(a);
0167         QCOMPARE(p.name(), QLatin1StringView("Berlin Tegel"));
0168     }
0169 
0170     void testCompare()
0171     {
0172         Place p1;
0173         Place p2; // base type
0174         QCOMPARE(p1, p2);
0175         QCOMPARE(p1, p1);
0176         p1.setName(QStringLiteral("Berlin"));
0177         QVERIFY(!(p1 == p2));
0178         QVERIFY(p1 != p2);
0179         QCOMPARE(p1, p1);
0180         p2.setName(QStringLiteral("Berlin"));
0181         QCOMPARE(p1, p2);
0182 
0183         GeoCoordinates coord1;
0184         GeoCoordinates coord2; // primitive types
0185         QCOMPARE(coord1, coord2);
0186         QCOMPARE(coord1, coord1);
0187         coord1 = { 52.5, 13.8 };
0188         QVERIFY(!(coord1 == coord2));
0189 
0190         p1.setGeo(coord1);
0191         p2.setGeo({52.5, 13.8});
0192         QCOMPARE(p1, p2);
0193 
0194         Airport a1;
0195         Airport a2; // polymorphic types
0196         a1.setIataCode(QStringLiteral("TXL"));
0197         a2.setIataCode(QStringLiteral("TXL"));
0198         QCOMPARE(a1, a2);
0199         a1.setName(QStringLiteral("Berlin Tegel"));
0200         QVERIFY(a1 != a2);
0201         a2.setName(QStringLiteral("Berlin Tegel"));
0202         QCOMPARE(a1, a2);
0203         QCOMPARE(a1, a1);
0204 
0205         Flight f1;
0206         f1.setDepartureAirport(a1);
0207         Flight f2;
0208         f2.setDepartureAirport(a2);
0209         QCOMPARE(f1, f2);
0210 
0211         FlightReservation r1;
0212         r1.setReservationFor(f1);
0213         FlightReservation r2;
0214         r2.setReservationFor(f2);
0215         QCOMPARE(r1, r2);
0216     }
0217 
0218     void testStrictDateTimeHandling()
0219     {
0220         LodgingReservation r;
0221         r.setCheckinTime(QDateTime({2023, 12, 23}, {15, 1}, QTimeZone::UTC));
0222         QCOMPARE(r.checkinTime(), QDateTime({2023, 12, 23}, {15, 1}, QTimeZone::UTC));
0223         QCOMPARE(r.checkinTime().timeSpec(), Qt::UTC);
0224         r.setCheckinTime(QDateTime({2023, 12, 23}, {16, 1}, QTimeZone::fromSecondsAheadOfUtc(3600)));
0225         QCOMPARE(r.checkinTime(), QDateTime({2023, 12, 23}, {15, 1}, QTimeZone::UTC));
0226         QCOMPARE(r.checkinTime().timeSpec(), Qt::OffsetFromUTC);
0227         r.setCheckinTime(QDateTime({2023, 12, 23}, {16, 1}, QTimeZone("Europe/Brussels")));
0228         QCOMPARE(r.checkinTime(), QDateTime({2023, 12, 23}, {15, 1}, QTimeZone::UTC));
0229         QCOMPARE(r.checkinTime().timeSpec(), Qt::TimeZone);
0230     }
0231 };
0232 
0233 QTEST_GUILESS_MAIN(DatatypesTest)
0234 
0235 #include "datatypestest.moc"