File indexing completed on 2022-11-29 19:02:33

0001 /*
0002     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include <KOpeningHours/Interval>
0008 #include <KOpeningHours/OpeningHours>
0009 
0010 #include <QTest>
0011 
0012 using namespace KOpeningHours;
0013 
0014 void initLocale()
0015 {
0016     qputenv("LC_ALL", "en_US.utf-8");
0017     qputenv("LANG", "en_US");
0018     qputenv("TZ", "Europe/Berlin");
0019 }
0020 
0021 Q_CONSTRUCTOR_FUNCTION(initLocale)
0022 
0023 class EvaluateTest : public QObject
0024 {
0025     Q_OBJECT
0026 private Q_SLOTS:
0027     void testNext_data()
0028     {
0029         QTest::addColumn<QByteArray>("expression");
0030         QTest::addColumn<QDateTime>("begin");
0031         QTest::addColumn<QDateTime>("end");
0032 
0033         // "now" is 2020-11-07 18:00 Saturday
0034         QTest::newRow("time only, following") << QByteArray("20:00-22:00") << QDateTime({2020, 11, 7}, {20, 0}) << QDateTime({2020, 11, 7}, {22, 0});
0035         QTest::newRow("time only, next day") << QByteArray("08:00-10:00") << QDateTime({2020, 11, 8}, {8, 0}) << QDateTime({2020, 11, 8}, {10, 0});
0036         QTest::newRow("time only, overlapping") << QByteArray("08:00-22:00") << QDateTime({2020, 11, 7}, {8, 0}) << QDateTime({2020, 11, 7}, {22, 0});
0037         QTest::newRow("minutes") << QByteArray("18:45-21:15") << QDateTime({2020, 11, 7}, {18, 45}) << QDateTime({2020, 11, 7}, {21, 15});
0038         QTest::newRow("time range wrap around") << QByteArray("19:00-06:00") << QDateTime({2020, 11, 7}, {19, 0}) << QDateTime({2020, 11, 8}, {6, 0});
0039         QTest::newRow("time range wrap overlap") << QByteArray("23:00-19:00") << QDateTime({2020, 11, 6}, {23, 0}) << QDateTime({2020, 11, 7}, {19, 0});
0040         QTest::newRow("time range wrap prev") << QByteArray("23:00-17:00") << QDateTime({2020, 11, 7}, {23, 0}) << QDateTime({2020, 11, 8}, {17, 0});
0041         QTest::newRow("time range overflow") << QByteArray("20:00-30:00") << QDateTime({2020, 11, 7}, {20, 0}) << QDateTime({2020, 11, 8}, {6, 0});
0042         QTest::newRow("time range max") << QByteArray("00:00-24:00") << QDateTime({2020, 11, 7}, {0, 0}) << QDateTime({2020, 11, 8}, {0, 0});
0043 
0044         QTest::newRow("two time ranges") << QByteArray("08:00-10:00,20:00-22:00") << QDateTime({2020, 11, 7}, {20, 0}) << QDateTime({2020, 11, 7}, {22, 0});
0045         QTest::newRow("time ranges next day") << QByteArray("08:30-10:45,12:00-13:30,14:00-15:00") << QDateTime({2020, 11, 8}, {8, 30}) << QDateTime({2020, 11, 8}, {10, 45});
0046 
0047         QTest::newRow("time start match") << QByteArray("18:00-22:00") << QDateTime({2020, 11, 7}, {18, 0}) << QDateTime({2020, 11, 7}, {22, 0});
0048         QTest::newRow("time end match") << QByteArray("16:00-18:00") << QDateTime({2020, 11, 8}, {16, 0}) << QDateTime({2020, 11, 8}, {18, 0});
0049 
0050         QTest::newRow("time open end future") << QByteArray("20:00+") << QDateTime({2020, 11, 7}, {20, 0}) << QDateTime({2020, 11, 7}, {20, 0});
0051         QTest::newRow("time open end now") << QByteArray("18:00+") << QDateTime({2020, 11, 7}, {18, 0}) << QDateTime({2020, 11, 7}, {18, 0});
0052         QTest::newRow("time open end past") << QByteArray("12:00+") << QDateTime({2020, 11, 8}, {12, 0}) << QDateTime({2020, 11, 8}, {12, 0});
0053         QTest::newRow("time range open end") << QByteArray("16:00-22:00+") << QDateTime({2020, 11, 7}, {16, 0}) << QDateTime({2020, 11, 7}, {22, 0});
0054 
0055         QTest::newRow("matching day") << QByteArray("Sa") << QDateTime({2020, 11, 7}, {0, 0}) << QDateTime({2020, 11, 8}, {0, 0});
0056         QTest::newRow("next day") << QByteArray("Su") << QDateTime({2020, 11, 8}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0057         QTest::newRow("previous day") << QByteArray("Fr") << QDateTime({2020, 11, 13}, {0, 0}) << QDateTime({2020, 11, 14}, {0, 0});
0058         QTest::newRow("day set") << QByteArray("Fr,Sa,Su") << QDateTime({2020, 11, 7}, {0, 0}) << QDateTime({2020, 11, 8}, {0, 0});
0059 
0060         QTest::newRow("matching day range1") << QByteArray("Sa-Su") << QDateTime({2020, 11, 7}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0061         QTest::newRow("matching day range2") << QByteArray("Fr-Su") << QDateTime({2020, 11, 6}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0062         QTest::newRow("matching day range2") << QByteArray("Mo-Tu,Th-Fr") << QDateTime({2020, 11, 9}, {0, 0}) << QDateTime({2020, 11, 11}, {0, 0});
0063         QTest::newRow("day wrap around") << QByteArray("Fr-Mo") << QDateTime({2020, 11, 6}, {0, 0}) << QDateTime({2020, 11, 10}, {0, 0});
0064         QTest::newRow("day range max") << QByteArray("Mo-Su") << QDateTime({2020, 11, 2}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0065 
0066         QTest::newRow("day and time") << QByteArray("Su 20:00-22:00") << QDateTime({2020, 11, 8}, {20, 0}) << QDateTime({2020, 11, 8}, {22, 0});
0067         QTest::newRow("day and 24h time after") << QByteArray("Tu-Fr 12:00-12:00") << QDateTime({2020, 11, 10}, {12, 0}) << QDateTime({2020, 11, 11}, {12, 0});
0068         QTest::newRow("day and 24h time before") << QByteArray("Fr 19:00-19:00") << QDateTime({2020, 11, 6}, {19, 0}) << QDateTime({2020, 11, 7}, {19, 0});
0069 
0070         QTest::newRow("24/7") << QByteArray("24/7") << QDateTime() << QDateTime();
0071 
0072         QTest::newRow("current year") << QByteArray("2020") << QDateTime({2020, 1, 1}, {0, 0}) << QDateTime({2021, 1, 1}, {0, 0});
0073         QTest::newRow("overlapping year range") << QByteArray("1999-2022") << QDateTime({1999, 1, 1}, {0, 0}) << QDateTime({2023, 1, 1}, {0, 0});
0074         QTest::newRow("year set") << QByteArray("2010,2020,2030") << QDateTime({2020, 1, 1}, {0, 0}) << QDateTime({2021, 1, 1}, {0, 0});
0075         QTest::newRow("year set of ranges") << QByteArray("2010-2015,2020-2025,2030") << QDateTime({2020, 1, 1}, {0, 0}) << QDateTime({2026, 1, 1}, {0, 0});
0076         QTest::newRow("year open end") << QByteArray("2010+") << QDateTime({2010, 1, 1}, {0, 0}) << QDateTime();
0077         QTest::newRow("year interval odd") << QByteArray("2011-2031/2") << QDateTime({2021, 1, 1}, {0, 0}) << QDateTime({2022, 1, 1}, {0, 0});
0078         QTest::newRow("year interval even") << QByteArray("2010-2030/2") << QDateTime({2020, 1, 1}, {0, 0}) << QDateTime({2021, 1, 1}, {0, 0});
0079         QTest::newRow("year interval 4") << QByteArray("2004-2096/4") << QDateTime({2020, 1, 1}, {0, 0}) << QDateTime({2021, 1, 1}, {0, 0});
0080         QTest::newRow("year time") << QByteArray("2021 10:00-20:00") << QDateTime({2021, 1, 1}, {10, 0}) << QDateTime({2021, 1, 1}, {20, 0});
0081         QTest::newRow("year open end interval") << QByteArray("2016/5") << QDateTime({2021, 1, 1}, {0, 0}) << QDateTime({2022, 1, 1}, {0, 0});
0082 
0083         QTest::newRow("current month") << QByteArray("Nov") << QDateTime({2020, 11, 1}, {0, 0}) << QDateTime({2020, 12, 1}, {0, 0});
0084         QTest::newRow("next month") << QByteArray("Dec") << QDateTime({2020, 12, 1}, {0, 0}) << QDateTime({2021, 1, 1}, {0, 0});
0085         QTest::newRow("prev month") << QByteArray("Oct") << QDateTime({2021, 10, 1}, {0, 0}) << QDateTime({2021, 11, 1}, {0, 0});
0086         QTest::newRow("overlapping month range") << QByteArray("Oct-Dec") << QDateTime({2020, 10, 1}, {0, 0}) << QDateTime({2021, 1, 1}, {0, 0});
0087         QTest::newRow("month sets") << QByteArray("Oct,Nov,Dec") << QDateTime({2020, 11, 1}, {0, 0}) << QDateTime({2020, 12, 1}, {0, 0});
0088         QTest::newRow("month range max") << QByteArray("Jan-Dec") << QDateTime({2020, 1, 1}, {0, 0}) << QDateTime({2021, 1, 1}, {0, 0});
0089         QTest::newRow("month wrap") << QByteArray("Nov-Feb") << QDateTime({2020, 11, 1}, {0, 0}) << QDateTime({2021, 3, 1}, {0, 0});
0090         QTest::newRow("month wrap 2") << QByteArray("Dec-Nov") << QDateTime({2019, 12, 1}, {0, 0}) << QDateTime({2020, 12, 1}, {0, 0});
0091 
0092         QTest::newRow("month/day") << QByteArray("Nov 7") << QDateTime({2020, 11, 7}, {0, 0}) << QDateTime({2020, 11, 8}, {0, 0});
0093         QTest::newRow("next month/day") << QByteArray("Nov 8") << QDateTime({2020, 11, 8}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0094         QTest::newRow("prev month/day") << QByteArray("Nov 6") << QDateTime({2021, 11, 6}, {0, 0}) << QDateTime({2021, 11, 7}, {0, 0});
0095         QTest::newRow("month/day set")  << QByteArray("Oct 6,Nov 8,Dec 10") << QDateTime({2020, 11, 8}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0096         QTest::newRow("month/day range")  << QByteArray("Oct 6-Dec 10") << QDateTime({2020, 10, 6}, {0, 0}) << QDateTime({2020, 12, 11}, {0, 0});
0097         QTest::newRow("month/day range year wrap")  << QByteArray("Oct 6-Mar 10") << QDateTime({2020, 10, 6}, {0, 0}) << QDateTime({2021, 3, 11}, {0, 0});
0098 
0099         QTest::newRow("year/month") << QByteArray("2020 Nov") << QDateTime({2020, 11, 1}, {0, 0}) << QDateTime({2020, 12, 1}, {0, 0});
0100         QTest::newRow("year/month next") << QByteArray("2020 Dec") << QDateTime({2020, 12, 1}, {0, 0}) << QDateTime({2021, 1, 1}, {0, 0});
0101         QTest::newRow("year/month range") << QByteArray("2020 Oct-Dec") << QDateTime({2020, 10, 1}, {0, 0}) << QDateTime({2021, 1, 1}, {0, 0});
0102 
0103         QTest::newRow("full date") << QByteArray("2020 Nov 7") << QDateTime({2020, 11, 7}, {0, 0}) << QDateTime({2020, 11, 8}, {0, 0});
0104         QTest::newRow("full date next year") << QByteArray("2021 Nov 7") << QDateTime({2021, 11, 7}, {0, 0}) << QDateTime({2021, 11, 8}, {0, 0});
0105         QTest::newRow("full date range") << QByteArray("2020 Nov 6-2020 Dec 13") << QDateTime({2020, 11, 6}, {0, 0}) << QDateTime({2020, 12, 14}, {0, 0});
0106         QTest::newRow("full date range max") << QByteArray("2020 Jan 1-2020 Dec 31") << QDateTime({2020, 1, 1}, {0, 0}) << QDateTime({2021, 1, 1}, {0, 0});
0107         QTest::newRow("full date cross year") << QByteArray("2020 Nov 1-2022 Apr 1") << QDateTime({2020, 11, 1}, {0, 0}) << QDateTime({2022, 4, 2}, {0, 0});
0108 
0109         QTest::newRow("week") << QByteArray("week 45") << QDateTime({2020, 11, 2}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0110         QTest::newRow("next week") << QByteArray("week 46") << QDateTime({2020, 11, 9}, {0, 0}) << QDateTime({2020, 11, 16}, {0, 0});
0111         QTest::newRow("prev week") << QByteArray("week 44") << QDateTime({2021, 11, 1}, {0, 0}) << QDateTime({2021, 11, 8}, {0, 0});
0112         QTest::newRow("week range") << QByteArray("week 44-46") << QDateTime({2020, 10, 26}, {0, 0}) << QDateTime({2020, 11, 16}, {0, 0});
0113         QTest::newRow("week set") << QByteArray("week 42,45,46") << QDateTime({2020, 11, 2}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0114         QTest::newRow("week range max") << QByteArray("week 1-53") << QDateTime({2019, 12, 30}, {0, 0}) << QDateTime({2021, 1, 4}, {0, 0});
0115 
0116         QTest::newRow("variable time") << QByteArray("sunrise-sunset") << QDateTime({2020, 11, 8}, {7, 18}) << QDateTime({2020, 11, 8}, {16, 25});
0117         QTest::newRow("variable time 2") << QByteArray("dawn-dusk") << QDateTime({2020, 11, 8}, {6, 41}) << QDateTime({2020, 11, 8}, {17, 2});
0118         QTest::newRow("variable time with +offset") << QByteArray("(sunset+02:00)-24:00") << QDateTime({2020, 11, 7}, {18, 27}) << QDateTime({2020, 11, 8}, {0, 0});
0119         QTest::newRow("variable time with -offset") << QByteArray("(sunset-02:00)-(sunset+02:00)") << QDateTime({2020, 11, 7}, {14, 27}) << QDateTime({2020, 11, 7}, {18, 27});
0120 
0121         QTest::newRow("public holiday") << QByteArray("PH") << QDateTime({2020, 12, 25}, {0, 0}) << QDateTime({2020, 12, 26}, {0, 0});
0122         QTest::newRow("public holiday +offset") << QByteArray("PH +1 day") << QDateTime({2020, 12, 26}, {0, 0}) << QDateTime({2020, 12, 27}, {0, 0});
0123         QTest::newRow("public holiday -offset") << QByteArray("PH -1 day") << QDateTime({2020, 12, 24}, {0, 0}) << QDateTime({2020, 12, 25}, {0, 0});
0124 
0125         QTest::newRow("easter") << QByteArray("easter") << QDateTime({2021, 4, 4}, {0, 0}) << QDateTime({2021, 4, 5}, {0, 0});
0126         QTest::newRow("mixed variable/fixed date") << QByteArray("easter-May 1") << QDateTime({2021, 4, 4}, {0, 0}) << QDateTime({2021, 5, 2}, {0, 0});
0127         QTest::newRow("mixed fixed/variable date") << QByteArray("Jan 1-easter") << QDateTime({2021, 1, 1}, {0, 0}) << QDateTime({2021, 4, 5}, {0, 0});
0128         QTest::newRow("year/easter") << QByteArray("2022 easter") << QDateTime({2022, 4, 17}, {0, 0}) << QDateTime({2022, 4, 18}, {0, 0});
0129 
0130         QTest::newRow("day offset positive") << QByteArray("easter +2 days") << QDateTime({2021, 4, 6}, {0, 0}) << QDateTime({2021, 4, 7}, {0, 0});
0131         QTest::newRow("day offset negative") << QByteArray("2022 easter -3 days") << QDateTime({2022, 4, 14}, {0, 0}) << QDateTime({2022, 4, 15}, {0, 0});
0132         QTest::newRow("day offset range b") << QByteArray("easter -10 days-easter +12 days") << QDateTime({2021, 3, 25}, {0, 0}) << QDateTime({2021, 4, 17}, {0, 0});
0133         QTest::newRow("day offset range f") << QByteArray("easter -10 days-easter") << QDateTime({2021, 3, 25}, {0, 0}) << QDateTime({2021, 4, 5}, {0, 0});
0134         QTest::newRow("day offset range t") << QByteArray("easter-easter +12 days") << QDateTime({2021, 4, 4}, {0, 0}) << QDateTime({2021, 4, 17}, {0, 0});
0135 
0136         QTest::newRow("easter weekday offset negative") << QByteArray("easter -Fr") << QDateTime({2021, 4, 2}, {0, 0}) << QDateTime({2021, 4, 3}, {0, 0});
0137         QTest::newRow("easter weekday offset positive") << QByteArray("easter +Fr") << QDateTime({2021, 4, 9}, {0, 0}) << QDateTime({2021, 4, 10}, {0, 0});
0138         QTest::newRow("easter weekday offset -Su") << QByteArray("easter -Su") << QDateTime({2021, 3, 28}, {0, 0}) << QDateTime({2021, 3, 29}, {0, 0});
0139         QTest::newRow("easter weekday offset +Su") << QByteArray("easter +Su") << QDateTime({2021, 4, 11}, {0, 0}) << QDateTime({2021, 4, 12}, {0, 0});
0140 
0141         QTest::newRow("nth day") << QByteArray("Sa[1]") << QDateTime({2020, 11, 7}, {0, 0}) << QDateTime({2020, 11, 8}, {0, 0});
0142         QTest::newRow("nth day next week") << QByteArray("Sa[2]") << QDateTime({2020, 11, 14}, {0, 0}) << QDateTime({2020, 11, 15}, {0, 0});
0143         QTest::newRow("nth day next day") << QByteArray("Su[2]") << QDateTime({2020, 11, 8}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0144         QTest::newRow("nth day prev day") << QByteArray("Fr[1]") << QDateTime({2020, 12, 4}, {0, 0}) << QDateTime({2020, 12, 5}, {0, 0});
0145         QTest::newRow("nth day set") << QByteArray("Su[1,4,5]") << QDateTime({2020, 11, 22}, {0, 0}) << QDateTime({2020, 11, 23}, {0, 0});
0146         QTest::newRow("nth day 5th day") << QByteArray("Su[5]") << QDateTime({2020, 11, 29}, {0, 0}) << QDateTime({2020, 11, 30}, {0, 0});
0147         QTest::newRow("nth day last day") << QByteArray("Su[-1]") << QDateTime({2020, 11, 29}, {0, 0}) << QDateTime({2020, 11, 30}, {0, 0});
0148         QTest::newRow("nth day -3") << QByteArray("Su[-3]") << QDateTime({2020, 11, 15}, {0, 0}) << QDateTime({2020, 11, 16}, {0, 0});
0149         QTest::newRow("nth day -5") << QByteArray("Su[-5]") << QDateTime({2021, 1, 3}, {0, 0}) << QDateTime({2021, 1, 4}, {0, 0});
0150         QTest::newRow("nth day 4/-3") << QByteArray("Su[4,-3]") << QDateTime({2020, 11, 15}, {0, 0}) << QDateTime({2020, 11, 16}, {0, 0});
0151         QTest::newRow("nth day 3/-4") << QByteArray("Su[-4,3]") << QDateTime({2020, 11, 8}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0152         QTest::newRow("nth day range 2") << QByteArray("Su[1-2]") << QDateTime({2020, 11, 8}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0153         QTest::newRow("nth day range 3") << QByteArray("Su[2-4]") << QDateTime({2020, 11, 8}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0154 
0155         QTest::newRow("odd week") << QByteArray("week 1-53/2") << QDateTime({2020, 11, 2}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0156         QTest::newRow("even week") << QByteArray("week 2-52/2") <<  QDateTime({2020, 11, 9}, {0, 0}) << QDateTime({2020, 11, 16}, {0, 0});
0157         QTest::newRow("/4 week") << QByteArray("week 3-53/4") <<  QDateTime({2020, 11, 16}, {0, 0}) << QDateTime({2020, 11, 23}, {0, 0});
0158 
0159         QTest::newRow("nth day +offset") << QByteArray("Fr[1] +1 day") << QDateTime({2020, 11, 7}, {0, 0}) << QDateTime({2020, 11, 8}, {0, 0});
0160         QTest::newRow("nth day -offset") << QByteArray("Mo[-1] -1 day") << QDateTime({2020, 11, 29}, {0, 0}) << QDateTime({2020, 11, 30}, {0, 0});
0161         QTest::newRow("nth day +offset next month") << QByteArray("Su[1] -1 days") << QDateTime({2020, 12, 5}, {0, 0}) << QDateTime({2020, 12, 6}, {0, 0});
0162         QTest::newRow("nth day -offset next month") << QByteArray("Su[1] +1 days") << QDateTime({2020, 12, 7}, {0, 0}) << QDateTime({2020, 12, 8}, {0, 0});
0163 
0164         QTest::newRow("holiday and condition") << QByteArray("PH Mo") << QDateTime({2021, 4, 5}, {0, 0}) << QDateTime({2021, 4, 6}, {0, 0});
0165         QTest::newRow("holiday and condition, range") << QByteArray("PH Mo-Fr") << QDateTime({2020, 12, 25}, {0, 0}) << QDateTime({2020, 12, 26}, {0, 0});
0166 
0167         QTest::newRow("nth day month begin") << QByteArray("Nov Su[2]-Dec Su[-1] 09:00-12:00") << QDateTime({2020, 11, 8}, {9, 0}) << QDateTime({2020, 11, 8}, {12, 0});
0168         QTest::newRow("nth day month end") << QByteArray("Oct Su[1]-Nov Su[-4] 09:00-12:00") << QDateTime({2020, 11, 8}, {9, 0}) << QDateTime({2020, 11, 8}, {12, 0});
0169         QTest::newRow("nth day only end") << QByteArray("Oct 1-Nov Su[-4] 09:00-12:00") << QDateTime({2020, 11, 8}, {9, 0}) << QDateTime({2020, 11, 8}, {12, 0});
0170         QTest::newRow("nth day only end with weekday") << QByteArray("Oct 1-Nov Su[-4] Mo 09:00-12:00") << QDateTime({2020, 11, 9}, {9, 0}) << QDateTime({2020, 11, 9}, {12, 0});
0171     }
0172 
0173     void testNext()
0174     {
0175         QFETCH(QByteArray, expression);
0176         QFETCH(QDateTime, begin);
0177         QFETCH(QDateTime, end);
0178 
0179         OpeningHours oh(expression);
0180         oh.setLocation(52.5, 13.0);
0181         oh.setRegion(QStringLiteral("DE"));
0182         QCOMPARE(oh.error(), OpeningHours::NoError);
0183         auto i = oh.interval(QDateTime({2020, 11, 7}, {18, 0}));
0184         QVERIFY(i.isValid());
0185         if (i.state() == Interval::Closed) { // skip synthetic closed intervals
0186             i = oh.nextInterval(i);
0187         }
0188 
0189         QVERIFY(i.isValid());
0190         QCOMPARE(i.begin(), begin);
0191         QCOMPARE(i.end(), end);
0192         QCOMPARE(i.state(), Interval::Open);
0193     }
0194 
0195     void testNoMatch_data()
0196     {
0197         QTest::addColumn<QByteArray>("expression");
0198         QTest::newRow("year range") << QByteArray("1980-1999");
0199         QTest::newRow("full date") << QByteArray("2020 Nov 6");
0200         QTest::newRow("date range") << QByteArray("1980 Jan 1-2020 Nov 6");
0201         QTest::newRow("year/month") << QByteArray("2020 Oct");
0202         QTest::newRow("incomplete coverage") << QByteArray("Su off");
0203         QTest::newRow("past year/month range") << QByteArray("2019 Jul 22-Aug 18: Tu-Su 10:00-13:00");
0204     }
0205 
0206     void testNoMatch()
0207     {
0208         QFETCH(QByteArray, expression);
0209         OpeningHours oh(expression);
0210         QCOMPARE(oh.error(), OpeningHours::NoError);
0211         const auto i = oh.interval(QDateTime({2020, 11, 7}, {18, 0}));
0212         QVERIFY(!i.isValid());
0213     }
0214 
0215     void test247Closed()
0216     {
0217         OpeningHours oh("24/7 closed \"always closed\"");
0218         QCOMPARE(oh.error(), OpeningHours::NoError);
0219         const auto i = oh.interval(QDateTime({2020, 11, 7}, {18, 0}));
0220         QVERIFY(i.isValid());
0221         QCOMPARE(i.state(), Interval::Closed);
0222         QCOMPARE(i.comment(), QLatin1String("always closed"));
0223         QVERIFY(!i.begin().isValid());
0224         QVERIFY(!i.end().isValid());
0225     }
0226 
0227     void test247Open()
0228     {
0229         OpeningHours oh("24/7");
0230         QCOMPARE(oh.error(), OpeningHours::NoError);
0231         const auto i = oh.interval(QDateTime({2020, 11, 7}, {18, 0}));
0232         QVERIFY(i.isValid());
0233         QCOMPARE(i.state(), Interval::Open);
0234         QVERIFY(!i.begin().isValid());
0235         QVERIFY(!i.end().isValid());
0236     }
0237 
0238     void testFractions()
0239     {
0240         OpeningHours oh("14:00-15:00");
0241         QCOMPARE(oh.error(), OpeningHours::NoError);
0242         auto i = oh.interval(QDateTime({2020, 11, 7}, {15, 55, 34, 123}));
0243         i = oh.nextInterval(i);
0244         QVERIFY(i.isValid());
0245         QCOMPARE(i.begin(), QDateTime({2020, 11, 8}, {14, 0}));
0246         QCOMPARE(i.end(), QDateTime({2020, 11, 8}, {15, 0}));
0247     }
0248 
0249     void testBoundaries_data()
0250     {
0251         QTest::addColumn<QByteArray>("expression");
0252         QTest::addColumn<QDateTime>("begin");
0253         QTest::addColumn<QDateTime>("end");
0254 
0255         QTest::newRow("year") << QByteArray("2020") << QDateTime({2020, 1, 1}, {0, 0}) << QDateTime({2021, 1, 1}, {0, 0});
0256         QTest::newRow("month") << QByteArray("Nov") << QDateTime({2020, 11, 1}, {0, 0}) << QDateTime({2020, 12, 1}, {0, 0});
0257         QTest::newRow("week") << QByteArray("week 45") << QDateTime({2020, 11, 2}, {0, 0}) << QDateTime({2020, 11, 9}, {0, 0});
0258         QTest::newRow("day") << QByteArray("Nov 07") << QDateTime({2020, 11, 7}, {0, 0}) << QDateTime({2020, 11, 8}, {0, 0});
0259         QTest::newRow("hour") << QByteArray("18:00-19:00") << QDateTime({2020, 11, 7}, {18, 0}) << QDateTime({2020, 11, 7}, {19, 0});
0260     }
0261 
0262     void testBoundaries()
0263     {
0264         QFETCH(QByteArray, expression);
0265         QFETCH(QDateTime, begin);
0266         QFETCH(QDateTime, end);
0267 
0268         OpeningHours oh(expression);
0269         QCOMPARE(oh.error(), OpeningHours::NoError);
0270 
0271         const auto beginInterval = oh.interval(begin);
0272         QVERIFY(beginInterval.isValid());
0273         QCOMPARE(beginInterval.begin(), begin);
0274         QCOMPARE(beginInterval.end(), end);
0275         QVERIFY(beginInterval.contains(begin));
0276         QVERIFY(beginInterval.contains(end.addSecs(-1)));
0277         QVERIFY(!beginInterval.contains(end));
0278 
0279         const auto endInterval = oh.interval(end.addSecs(-60));
0280         QVERIFY(endInterval.isValid());
0281         QCOMPARE(endInterval.begin(), begin);
0282         QCOMPARE(endInterval.end(), end);
0283         QVERIFY(endInterval.contains(begin));
0284         QVERIFY(endInterval.contains(end.addSecs(-1)));
0285         QVERIFY(!endInterval.contains(end));
0286 
0287         QCOMPARE(beginInterval < endInterval, false);
0288         QCOMPARE(endInterval < beginInterval, false);
0289 
0290         const auto nextInterval = oh.interval(end);
0291         if (nextInterval.isValid()) {
0292             QVERIFY(endInterval < nextInterval);
0293             QVERIFY(nextInterval.begin() >= end);
0294             QVERIFY(nextInterval.end() > end);
0295         }
0296 
0297         const auto prevInterval = oh.interval(begin.addSecs(-60));
0298         if (prevInterval.isValid()) {
0299             QVERIFY(prevInterval < beginInterval);
0300             QVERIFY(prevInterval.end() <= beginInterval.begin());
0301             QVERIFY(prevInterval.begin() < beginInterval.begin());
0302         }
0303     }
0304 
0305     void testFallback()
0306     {
0307         OpeningHours oh("Mo 10:00-12:00 || \"on appointment\"");
0308         QCOMPARE(oh.error(), OpeningHours::NoError);
0309         const auto i = oh.interval(QDateTime({2020, 11, 7}, {0, 0}));
0310         QVERIFY(i.isValid());
0311         QCOMPARE(i.state(), Interval::Unknown);
0312         QCOMPARE(i.comment(), QLatin1String("on appointment"));
0313     }
0314 
0315     void testLookBack()
0316     {
0317         OpeningHours oh("Oct-Mar");
0318         QCOMPARE(oh.error(), OpeningHours::NoError);
0319         const auto i = oh.interval(QDateTime({2021, 1, 1}, {0, 0}));
0320         QVERIFY(i.isValid());
0321         QCOMPARE(i.state(), Interval::Open);
0322     }
0323 };
0324 
0325 QTEST_GUILESS_MAIN(EvaluateTest)
0326 
0327 #include "evaluatetest.moc"