File indexing completed on 2024-05-05 08:52:01
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/OpeningHours> 0008 0009 #include <QTest> 0010 0011 using namespace KOpeningHours; 0012 0013 class ParserTest : public QObject 0014 { 0015 Q_OBJECT 0016 private Q_SLOTS: 0017 void testSuccess_data() 0018 { 0019 QTest::addColumn<QByteArray>("input"); 0020 QTest::addColumn<QByteArray>("expectedOutput"); 0021 QTest::addColumn<QByteArray>("expectedSimplifiedOutput"); 0022 0023 // clang-format off 0024 #define T(x) QTest::newRow(x) << QByteArray(x) << QByteArray(x) << QByteArray(x) 0025 #define T2(x, y) QTest::newRow(x) << QByteArray(x) << QByteArray(y) << QByteArray(y) 0026 #define T3(x, y, z) QTest::newRow(x) << QByteArray(x) << QByteArray(y ? y : x) << QByteArray(z) 0027 T("24/7"); 0028 T("24/7 \"comment\""); 0029 T("24/7 closed"); 0030 T("24/7 unknown \"comment\""); 0031 T("unknown \"comment\""); 0032 T("off"); 0033 T("Dec off"); 0034 T("Dec 25 off"); 0035 0036 // Don't repeat the month when it's the same (#446224) 0037 T("Dec 25-26 off"); 0038 T("Dec 24-26,31 off"); 0039 T2("Jan 1,6 off", "Jan 01,06 off"); 0040 T("Dec 24,25,26"); 0041 T("Jan 03,Dec 04,24 off"); 0042 T2("Jan 03, Dec 04, 24 off", "Jan 03,Dec 04,24 off"); 0043 T2("07:30-20:00; Jan 03,13,23,Dec 04,14,24 off", "07:30-20:00; Jan 03,13,23,Dec 04,14,24 off"); 0044 0045 // But do repeat the year and the month, when a year is specified 0046 T2("2023 Apr 26,28 08:00-09:00; PH off", "2023 Apr 26,2023 Apr 28 08:00-09:00; PH off"); // input was incorrect, the year and month must be repeated 0047 T2("2021 Dec 26-28,30-31,2022 Jan 02-03 off", "2021 Dec 26-28,2021 Dec 30-31,2022 Jan 02-03 off"); 0048 T2("2021 Dec 22, 26-28, 29, 31, 2022 Jan 02-03 off", "2021 Dec 22,2021 Dec 26-28,2021 Dec 29,2021 Dec 31,2022 Jan 02-03 off"); 0049 T("2021 Dec 26-28, Dec 30-31,2022 Jan 02-03 off"); // note that this means Dec 30-31 every year, not just in 2021 (says https://openingh.openstreetmap.de/evaluation_tool/) 0050 T("2023 Apr 26, Apr 28 09:00-10:00; PH off"); // note that this means Apr 28 every year, not just in 2023 (says https://openingh.openstreetmap.de/evaluation_tool/) 0051 0052 T("Dec 08:00"); 0053 T("Dec 08:00-14:00"); 0054 T("easter off"); 0055 T("easter +1 day off"); 0056 T("easter -2 days off"); 0057 T2("whitsun off", "easter +49 days off"); 0058 T2("whitsun +1 day off", "easter +50 days off"); 0059 T("2020"); 0060 T("2020-2021"); 0061 T("1970-2022/2"); 0062 T("2020+"); 0063 T("2010,2020,2030"); 0064 T("2010-2015,2020-2025,2030"); 0065 T("2020-2022 Dec"); 0066 T("2020 Dec-2022 Dec"); 0067 T("2020-2022 Dec 24-26"); 0068 T("2020 Dec 24-26"); 0069 T("2021 10:00-20:00"); 0070 T("PH off || open"); // https://openingh.openstreetmap.de/evaluation_tool/ says this means always open... bug in opening.js? 0071 T("PH off || unknown \"foo\""); 0072 T("2020 Jan-Apr"); 0073 T("1980-2030/4"); 0074 T("\"comment\""); 0075 T("PH off || 2020 open"); 0076 T("Mo[1-2,4]"); 0077 T2("We[-1] + 2 days", "We[-1] +2 days"); 0078 T("10:00-16:00/15"); 0079 T2("10:00-16:00/90", "10:00-16:00/01:30"); 0080 T2("10:00-16:00/1:30", "10:00-16:00/01:30"); 0081 T("10:00-10:00"); 0082 T("PH off || open || unknown"); 0083 T("10:00-12:00+"); 0084 T("Jun 15-Aug 15 Mo-Fr 10:00-12:30"); 0085 T2("Dec 01 +Su", "Dec 01 Su[1]"); 0086 T2("Dec 01 -Su 08:00-12:00", "Dec 01 Su[-1] 08:00-12:00"); 0087 T("Aug Mo[1]-Aug Sa[-1] closed"); 0088 T("2020/2"); 0089 T("\"Außerhalb der Semesterferien\": Mo-Fr 08:00-22:00; Sa,Su 10:00-20:00; \"Innerhalb der Semesterferien\": Mo-Fr 08:00-18:00; Sa,Su 10:00-16:00"); 0090 T("PH Mo-Th 14:00-23:00"); 0091 T2("Mo-Th PH 14:00-23:00", "PH Mo-Th 14:00-23:00"); 0092 T("PH Fr,SH Fr 11:30-02:00"); 0093 T2("PH Fr, SH Fr 11:30-02:00", "PH Fr,SH Fr 11:30-02:00"); 0094 T2("PH Th,Fr, SH Tu,Fr 11:30-02:00", "PH Th,Fr,SH Tu,Fr 11:30-02:00"); 0095 T3("Mo-Th 17:00-23:00, Mo-Th SH 14:00-23:00, Fr 14:00-02:00, Sa 11:30-22:00, Su 11:30-22:00, PH Mo-Th 11:30-23:00, PH Fr, SH Fr 11:30-02:00, PH Sa-Su 11:30-22:00", 0096 "Mo-Th 17:00-23:00, SH Mo-Th 14:00-23:00, Fr 14:00-02:00, Sa 11:30-22:00, Su 11:30-22:00, PH Mo-Th 11:30-23:00, PH Fr,SH Fr 11:30-02:00, PH Sa-Su 11:30-22:00", 0097 "Mo-Th 17:00-23:00, SH Mo-Th 14:00-23:00, Fr 14:00-02:00, Sa,Su 11:30-22:00, PH Mo-Th 11:30-23:00, PH Fr,SH Fr 11:30-02:00, PH Sa-Su 11:30-22:00"); 0098 T("Sa,Su,PH,Mo"); 0099 T2("Tu-Fr 10:00-17:00; Th 10:00-20:00; Sa,Su,PH Mo 11:00-18:00", "Tu-Fr 10:00-17:00; Th 10:00-20:00; Sa,Su,PH,Mo 11:00-18:00"); 0100 T2("Mo,We,Th PH off", "PH Mo,We,Th off"); 0101 T2("PH closed \"\"", "PH closed"); 0102 T("Mar 01-Mar Su[-1] 17:00-18:00; PH off"); 0103 T("Mar 01-Mar Su[-2] Mo 17:00-18:00; PH off"); 0104 T("Oct Su[-1]-Dec 31 08:00-18:00"); 0105 T("Oct Su[-1]-Dec 31 Su 08:00-18:00"); 0106 T("Mar Su[1]-Oct Su[1]: 11:00-20:00; PH 11:00-20:00"); 0107 T2("Mo 20:00-26:00", "Mo 20:00-26:00"); // https://github.com/osm-fr/osmose-backend/issues/1344 0108 0109 // https://bugs.kde.org/show_bug.cgi?id=445963 0110 T("Th[1-2] 09:30-11:45"); 0111 T("Th[1,2] 09:30-11:45"); 0112 T("Mo[1,3,-1]"); // order as desired, -1 means last 0113 T("Mo[1,3,2]"); // currently not normalized 0114 0115 // from https://wiki.openstreetmap.org/wiki/Key:opening_hours#Simple_examples 0116 T("Mo-Fr 08:00-17:30"); 0117 T("Mo-Fr 08:00-12:00,13:00-17:30"); 0118 T("Mo-Fr 08:00-12:00,13:00-17:30; Sa 08:00-12:00"); 0119 T("Mo-Fr 08:00-12:00,13:00-17:30; Sa 08:00-12:00; PH off"); 0120 T("Mo-Fr 08:00-12:00,13:00-17:30; Sa 08:00-12:00; PH 09:00-12:00"); 0121 0122 // from https://wiki.openstreetmap.org/wiki/Key:opening_hours#Examples 0123 T3("Sa-Su 00:00-24:00", nullptr, "Sa,Su 00:00-24:00"); 0124 T("Mo-Fr 08:30-20:00"); 0125 T("Mo 10:00-12:00,12:30-15:00; Tu-Fr 08:00-12:00,12:30-15:00; Sa 08:00-12:00"); 0126 T("Mo-Su 08:00-18:00; Apr 10-15 off; Jun 08:00-14:00; Aug off; Dec 25 off"); 0127 T("Mo-Sa 10:00-20:00; Tu off"); 0128 T("Mo-Sa 10:00-20:00; Tu 10:00-14:00"); 0129 T("sunrise-sunset"); 0130 T("Su 10:00+"); 0131 T2("week 1-53/2 Fr 09:00-12:00; week 2-52/2 We 09:00-12:00", "week 01-53/2 Fr 09:00-12:00; week 02-52/2 We 09:00-12:00"); 0132 T("Mo-Sa 08:00-13:00,14:00-17:00 || \"by appointment\""); 0133 T3("Su-Tu 11:00-01:00, We-Th 11:00-03:00, Fr 11:00-06:00, Sa 11:00-07:00", nullptr, "Su-Tu 11:00-01:00, We,Th 11:00-03:00, Fr 11:00-06:00, Sa 11:00-07:00"); 0134 T("Mo-Su,PH 15:00-03:00; easter -2 days off"); 0135 0136 // from https://openingh.openstreetmap.de/evaluation_tool/ 0137 T("Mo-Fr 10:00-20:00; PH off"); 0138 T("Mo,Tu,Th,Fr 12:00-18:00; Sa,PH 12:00-17:00; Th[3],Th[-1] off"); 0139 T("00:00-24:00; Tu-Su,PH 08:30-09:00 off; Tu-Su 14:00-14:30 off; Mo 08:00-13:00 off"); 0140 T3("Fr-Sa 18:00-06:00; PH off", nullptr, "Fr,Sa 18:00-06:00; PH off"); 0141 T("Mo 10:00-12:00,12:30-15:00"); 0142 T("Mo 10:00-12:00,12:30-15:00; Tu-Fr 08:00-12:00,12:30-15:00; Sa 08:00-12:00"); 0143 T("\"only after registration\"; PH off"); 0144 T("22:00-23:00; PH off"); 0145 T("08:00-11:00; PH off"); 0146 T("open; Mo 15:00-16:00 off; PH off"); 0147 T("Mo-Su 22:00-23:00; We,PH off"); 0148 T("We-Fr 10:00-24:00 open \"it is open\" || \"please call\"; PH off"); 0149 T("Mo-Fr 08:00-11:00 || Tu-Th,PH open \"Emergency only\""); 0150 T3("Tu-Th,We 22:00-23:00 open \"Hot meals\"; PH off", nullptr, "Tu-Th 22:00-23:00 open \"Hot meals\"; PH off"); // We redundant 0151 T("Mo 12:00-14:00 open \"female only\", Mo 14:00-16:00 open \"male only\"; PH off"); 0152 T("Apr: 22:00-23:00; PH off"); 0153 T("Jul-Jan: 22:00-23:00; PH off"); 0154 T("Jan-Jul: 22:00-23:00; PH off"); 0155 T2("Jul 23-Jan 3: \"needs reservation by phone\"; PH off", "Jul 23-Jan 03: \"needs reservation by phone\"; PH off"); 0156 T2("Jul 23-Jan 3: 22:00-23:00 \"Please make a reservation by phone.\"; PH off", "Jul 23-Jan 03: 22:00-23:00 \"Please make a reservation by phone.\"; PH off"); 0157 T2("Jul 23-Jan 3: 08:00-11:00 \"Please make a reservation by phone.\"; PH off", "Jul 23-Jan 03: 08:00-11:00 \"Please make a reservation by phone.\"; PH off"); 0158 T2("Jan 23-Jul 3: 22:00-23:00 \"Please make a reservation by phone.\"; PH off", "Jan 23-Jul 03: 22:00-23:00 \"Please make a reservation by phone.\"; PH off"); 0159 T("Mar Su[-1]-Dec Su[1] -2 days: 22:00-23:00; PH off"); 0160 T("Sa[1],Sa[1] +1 day 10:00-12:00 open \"first weekend in the month\"; PH off"); 0161 T("Sa[-1],Sa[-1] +1 day 10:00-12:00 open \"last weekend in the month\"; PH off"); 0162 T3("Sa-Su 00:00-24:00; PH off", nullptr, "Sa,Su 00:00-24:00; PH off"); 0163 T("Mo-Fr 00:00-24:00; PH off"); 0164 T("sunrise-sunset open \"Beware of sunburn!\"; PH off"); 0165 T("sunset-sunrise open \"Beware of vampires!\"; PH off"); 0166 T("(sunrise-00:30)-(sunrise+00:30)"); 0167 T("(sunset+01:00)-24:00 || closed \"No drink before sunset!\"; PH off"); 0168 T("22:00+; PH off"); 0169 T("Tu,PH 23:59-22:59"); 0170 T("We-Mo,PH 23:59-22:59"); 0171 T2("week 2-52/2 We 00:00-24:00; week 1-53/2 Sa 00:00-24:00; PH off", "week 02-52/2 We 00:00-24:00; week 01-53/2 Sa 00:00-24:00; PH off"); 0172 T2("week 4-16 We 00:00-24:00; week 38-42 Sa 00:00-24:00; PH off", "week 04-16 We 00:00-24:00; week 38-42 Sa 00:00-24:00; PH off"); 0173 T("2012 easter -2 days-2012 easter +2 days: open \"Around easter\"; PH off"); 0174 T("24/7 closed \"always closed\""); 0175 T2("2013,2015,2050-2053,2055/2,2020-2029/3,2060+ Jan 1", "2013,2015,2050-2053,2055/2,2020-2029/3,2060+ Jan 01"); 0176 T2("Jan 23-Feb 11,Feb 12 00:00-24:00; PH off", "Jan 23-Feb 11,Feb 12 00:00-24:00; PH off"); 0177 T("Apr-Oct Su[2] 14:00-18:00; Aug Su[-1] -1 day 10:00-18:00; Aug Su[-1] 10:00-18:00; PH off"); 0178 T("Mo-Fr 08:00-12:00, We 14:00-18:00; Su,PH off"); // open We morning too 0179 T("Mo-Fr 08:00-12:00; We 14:00-18:00; Su,PH off"); // closed We morning 0180 T2("April-September; Mo-Fr 09:00-13:00, 14:00-18:00, Sa 10:00-13:00", "Apr-Sep; Mo-Fr 09:00-13:00,14:00-18:00, Sa 10:00-13:00"); 0181 0182 T("We; PH off"); 0183 T("PH"); 0184 T("PH Mo-Fr"); 0185 T("PH -1 day"); 0186 T("SH"); 0187 T("SH,PH"); 0188 T("PH,SH"); 0189 T("We[1-3]"); 0190 T("We[3-5]"); 0191 T("Sa"); 0192 T("Sa[1]"); 0193 T("Sa[1-3]"); 0194 T("Su[-1,1]"); 0195 T("Tu-Th"); 0196 T("Fr-Mo"); 0197 T("Mo-Su; We \"only after registration\""); 0198 T("Oct: We[1]"); 0199 0200 // from https://github.com/dfaure/DataNovaImportScripts/blob/master/saved_opening_hours 0201 T3("Mo-Tu,Th-Fr 09:30-12:00; 2020 Dec 28 off; 2020 Dec 22,2020 Dec 29 off; We 15:00-17:00; 2020 Dec 23,2020 Dec 30 off; 2020 Dec 24,2020 Dec 31 off; Sa 10:00-12:00; 2020 Dec 26,2021 Jan 02 off; PH off", 0202 "Mo-Tu,Th-Fr 09:30-12:00; 2020 Dec 28 off; 2020 Dec 22,2020 Dec 29 off; We 15:00-17:00; 2020 Dec 23,2020 Dec 30 off; 2020 Dec 24,2020 Dec 31 off; Sa 10:00-12:00; 2020 Dec 26,2021 Jan 02 off; PH off", 0203 "Mo,Tu,Th,Fr 09:30-12:00; 2020 Dec 28 off; 2020 Dec 22,2020 Dec 29 off; We 15:00-17:00; 2020 Dec 23,2020 Dec 30 off; 2020 Dec 24,2020 Dec 31 off; Sa 10:00-12:00; 2020 Dec 26,2021 Jan 02 off; PH off"); 0204 0205 // real-world tests from Osmose that we were handling wrongly 0206 T("Tu-Fr 11:30-14:30 open, 14:30-18:00 open \"pickup only\", 18:00-22:00 open"); 0207 T("SH Tu,Th 10:00-19:00"); 0208 T2("Apr-Sep 09:00-19:00; Mar-Oct. 09:00-18:00; Nov.-Feb. 09:00-17:00", "Apr-Sep 09:00-19:00; Mar-Oct 09:00-18:00; Nov-Feb 09:00-17:00"); 0209 T2("week 23-37 12:30-15:00,20:00-23:00; week 01-22,38-53 off", "week 23-37 12:30-15:00,20:00-23:00; week 01-22,38-53 off"); 0210 T("Mo-Sa 09:00-20:00; Su[-2,-1] 12:30-18:00"); 0211 T("Su off, Mo-Fr 08:30-13:00; Mo-Th 08:30-13:30,16:00-20:00"); 0212 T3("Mo-Tu 09:00-12:00,14:00-18:00, We closed, Th-Sa 09:00-12:00,14:00-18:00; Su 09:30-12:30,14:30-18:00", nullptr, 0213 "Mo,Tu 09:00-12:00,14:00-18:00, We closed, Th-Sa 09:00-12:00,14:00-18:00; Su 09:30-12:30,14:30-18:00"); 0214 T2("SH Sep-Jun Mo 10:52-15:52", "SH, Sep-Jun Mo 10:52-15:52"); // likely incorrect, but at least no information loss 0215 0216 // weekday autocorrect 0217 T2("Tu, Th 13:30-19:00; SH Tu, Th 10:00-19:00; Fr 13:30-18:00; SH Fr 10:00-18:00; We, Sa 10:00-18:00; SH We, Sa 10:00-18:00", "Tu,Th 13:30-19:00; SH Tu,Th 10:00-19:00; Fr 13:30-18:00; SH Fr 10:00-18:00; We,Sa 10:00-18:00; SH We,Sa 10:00-18:00"); 0218 T2("Mar Su[-1] - Oct Su[-1] - 1 days: Th 09:00-18:00, Tu 15:00-18:00; Sa 09:00-12:00; Oct Su[-1] - Mar Su[-1] - 1 days: Tu 09:00-17:00, Th 09:00-17:00, Sa 09:00-12:00; Mo, We, Fr, Su, PH Off", 0219 "Mar Su[-1]-Oct Su[-1] -1 day: Th 09:00-18:00, Tu 15:00-18:00; Sa 09:00-12:00; Oct Su[-1]-Mar Su[-1] -1 day: Tu 09:00-17:00, Th 09:00-17:00, Sa 09:00-12:00; Mo,We,Fr,Su,PH off"); 0220 T2("Sep 16-Jun 15: Tu-Fr, Sa, Su [1,3] 09:00-14:00; Jun 16-Sep 15: Sa, Su [1,3] 13:00-19:00; Mo off, Su [2,4] off", 0221 "Sep 16-Jun 15: Tu-Fr,Sa,Su[1,3] 09:00-14:00; Jun 16-Sep 15: Sa,Su[1,3] 13:00-19:00; Mo off, Su[2,4] off"); 0222 T2("2020-2021 Mo, Tu-Fr, Sa [-1] 09:00-14:00", "2020-2021 Mo,Tu-Fr,Sa[-1] 09:00-14:00"); 0223 T2("week 1-3 Mo[2], Tu-Fr, Sa [-1] 09:00-14:00", "week 01-03 Mo[2],Tu-Fr,Sa[-1] 09:00-14:00"); 0224 T2("Mo Fr 09:30-12:30 13:30-18:30", "Mo,Fr 09:30-12:30,13:30-18:30"); 0225 T2("Mo Fr 09:30-12:30, 13:30-18:30 off", "Mo,Fr 09:30-12:30,13:30-18:30 off"); 0226 T2("Mo, We, Fr 06:30-21:30; Tu, Th 09:00-21:30; Sa 09:00-17:00; Su 09:00-14:00", "Mo,We,Fr 06:30-21:30; Tu,Th 09:00-21:30; Sa 09:00-17:00; Su 09:00-14:00"); 0227 T2("Lunes a sábado, 9:30 AM-5:30 PM", "Mo-Sa 09:30-17:30"); // bug 445784 0228 0229 // technically wrong but often found content in OSM for which we have error recovery 0230 T2("So", "Su"); 0231 T2("Ph", "PH"); 0232 T2("9:00-12:00", "09:00-12:00"); 0233 T2("Mo-Fr 09:00-18:30;Sa 09:00-17:00", "Mo-Fr 09:00-18:30; Sa 09:00-17:00"); 0234 T2("08:00-12:00;", "08:00-12:00"); 0235 T2("14:00-20:00,", "14:00-20:00"); 0236 T2("Mo 14:00-21:00; Tu-Th 10:00-21:00; Fr 10:00-18:00;Su, PH off|| \"Samstag zweimal im Monat, Details siehe Webseite\"", "Mo 14:00-21:00; Tu-Th 10:00-21:00; Fr 10:00-18:00; Su,PH off || \"Samstag zweimal im Monat, Details siehe Webseite\""); 0237 T2("Mo-Fr 06:30-12:00, 13:00-18:00", "Mo-Fr 06:30-12:00,13:00-18:00"); // see autocorrect() 0238 T2("we-mo 11:30-14:00, 17:30-22:00; tu off", "We-Mo 11:30-14:00,17:30-22:00; Tu off"); 0239 T2("01:00-23:00; ", "01:00-23:00"); 0240 T2("02:00-22:00,\n", "02:00-22:00"); 0241 T2("Friday 08:00-12:00", "Fr 08:00-12:00"); 0242 T2("Sat", "Sa"); 0243 T2("december", "Dec"); 0244 T2("Dec 24,25,26, Jan 1,6 off", "Dec 24,25,26,Jan 01,06 off"); 0245 T2("Dec 24,25,26 open, Jan 1,6 off", "Dec 24,25,26 open, Jan 01,06 off"); 0246 T2("Dec 6,4", "Dec 06,04"); 0247 T2("Dec 3,2,1", "Dec 03,02,01"); 0248 T2("07:30-20:00; Jan 03, 13, 23, Feb 03, 13, 23, Mar 03, 13, 23, Apr 03, 13, 23, Jun 03, 13, 23, Jul 03, 13, 23, Aug 03, 13, 23, Sep 03, 13, 23, Oct 03, 13, 23, Nov 03, 13, 23, Dec 03, 13, 23 off", 0249 "07:30-20:00; Jan 03,13,23,Feb 03,13,23,Mar 03,13,23,Apr 03,13,23,Jun 03,13,23,Jul 03,13,23,Aug 03,13,23,Sep 03,13,23,Oct 03,13,23,Nov 03,13,23,Dec 03,13,23 off"); 0250 T2("Apr, May, Oct, Nov, Dec: Mo-Su, 10:00-19:00; Jun-Sep: Mo-Su:10:00-20:00", "Apr,May,Oct,Nov,Dec: Mo-Su, 10:00-19:00; Jun-Sep: Mo-Su 10:00-20:00"); 0251 0252 // Tolerance for incorrect casing 0253 T2("mo-fr 10:00-20:00", "Mo-Fr 10:00-20:00"); 0254 T2("jan-feb 10:00-20:00", "Jan-Feb 10:00-20:00"); 0255 T2("jan-feb,aug 10:00-20:00", "Jan-Feb,Aug 10:00-20:00"); 0256 T2("SUNRISE-SUNSET", "sunrise-sunset"); 0257 T2("(SUNrISE-01:00)-(SUnsET+01:00)", "(sunrise-01:00)-(sunset+01:00)"); 0258 T2("su,sh off", "Su,SH off"); 0259 T2("mo-fr CLOSED", "Mo-Fr closed"); 0260 0261 // Time correction 0262 T2("9h00-12h00", "09:00-12:00"); 0263 T2("9h-12h", "09:00-12:00"); 0264 T2("5H", "05:00"); 0265 T2("06:00am", "06:00"); 0266 T2("06:30pm", "18:30"); 0267 T2("07:00 am", "07:00"); 0268 T2("07:00 pm", "19:00"); 0269 T2("5:00AM", "05:00"); 0270 T2("5:02 PM", "17:02"); 0271 T2("10a", "10:00"); 0272 T2("10p", "22:00"); 0273 T2("12:00 am", "00:00"); 0274 T2("12:00pm", "12:00"); 0275 T2("1 a.m", "01:00"); 0276 T2("3p.m", "15:00"); 0277 T2("12:01a.m.", "00:01"); 0278 T2("12:01p.m.", "12:01"); 0279 T2("11:59a", "11:59"); 0280 T2("11:59p", "23:59"); 0281 T2("9h00-12h00,14:00-17:00", "09:00-12:00,14:00-17:00"); 0282 T2("9:00 am - 12:00 am", "09:00-24:00"); 0283 T2("9 am - 12 am", "09:00-24:00"); 0284 T2("11:00 am - 11:00 pm", "11:00-23:00"); 0285 T2("09 : 00 - 12 : 00 , 13 : 00 - 19 : 00", "09:00-12:00,13:00-19:00"); 0286 T2("10.30am - 4.30pm", "10:30-16:30"); 0287 T2("17時00分~23時30分", "17:00-23:30"); 0288 0289 // alternative range separators 0290 T2("Mo-Fri 10am to 7pm, Saturday 11am to 6pm, Sun 11am to 4pm", "Mo-Fr 10:00-19:00, Sa 11:00-18:00, Su 11:00-16:00"); 0291 T2("Monday to Friday 8:00AM to 4:30PM", "Mo-Fr 08:00-16:30"); 0292 T2("1pm-3pm and 7pm-11pm", "13:00-15:00,19:00-23:00"); 0293 T2("8h00 à 12h00 et 13h30 à 18h00", "08:00-12:00,13:30-18:00"); 0294 T2("Samedi et Dimanche 5h30 - 12h30 Lundi 13h45 - 15h15", "Sa,Su 05:30-12:30; Mo 13:45-15:15"); 0295 T2("Mo-Th 11:00-20:00 Friday & Saturday 11:00-21:00 Sunday 12:00-19:00", "Mo-Th 11:00-20:00; Fr,Sa 11:00-21:00; Su 12:00-19:00"); 0296 T2("11:30-14:00、16:30-22:00", "11:30-14:00,16:30-22:00"); 0297 T2("Lunedì al Venerdì 08:00-13:00", "Mo-Fr 08:00-13:00"); 0298 T2("Monday through Friday 09:00 - 17:00", "Mo-Fr 09:00-17:00"); 0299 0300 // (mis)use of colon as a small-range selector separator 0301 T2("Fr: 17:00-19:00", "Fr 17:00-19:00"); 0302 T2("Fr: closed", "Fr closed"); 0303 T2("Tu-Su:07:00-00:00", "Tu-Su 07:00-24:00"); 0304 T2("Du lundi au vendredi : 9:00-18:00", "Mo-Fr 09:00-18:00"); 0305 0306 // Unicode symbols 0307 T3("Mo–Tu", "Mo-Tu", "Mo,Tu"); 0308 T2("13:41", "13:41"); 0309 T2("10:00〜19:00", "10:00-19:00"); 0310 T2("10:00-17:00", "10:00-17:00"); 0311 T2("11:00−23:00", "11:00-23:00"); 0312 T2("11:00ー15:00", "11:00-15:00"); 0313 T2("We 09:00-18:00\xC2\xA0; Sa 09:00-19:00", "We 09:00-18:00; Sa 09:00-19:00"); // weird space 0314 T2("LUNDI 08:30 – 17:00", "Mo 08:30-17:00"); 0315 T3("月,木,金,土,日 11:00-19:00", "Mo,Th,Fr,Sa,Su 11:00-19:00", "Th-Mo 11:00-19:00"); 0316 T2("月-土 09:00-18:00", "Mo-Sa 09:00-18:00"); 0317 T2("水曜日~土曜日10:00~19:00", "We-Sa 10:00-19:00"); 0318 T2("月~土 17:00~23:00", "Mo-Sa 17:00-23:00"); 0319 T2("Mo-Fr 08:00-17:00 “Visa Applications\"", "Mo-Fr 08:00-17:00 \"Visa Applications\""); 0320 T2("„nach Vereinbarung“", "\"nach Vereinbarung\""); 0321 T("\"„Termine nach Vereinbarung“\""); 0322 0323 // non-English 0324 T2("Lundi au Vendredi 8h - 17h en continu", "Mo-Fr 08:00-17:00"); 0325 T2("Lun-Ven 08:00-13:00", "Mo-Fr 08:00-13:00"); 0326 T2("Lu-Sa 08:00-13:00", "Mo-Sa 08:00-13:00"); 0327 T2("Domingo de 9: 00 am. a 1:00 pm", "Su 09:00-13:00"); 0328 T2("Gio, Sab e Dom: 9.00-12.30", "Th,Sa,Su 09:00-12:30"); 0329 T2("Segunda a Sexta 08:00h a 16:00h", "Mo-Fr 08:00-16:00"); 0330 T2("lunedi,mercoledi,venerdi,sabato 09:00-20:00", "Mo,We,Fr,Sa 09:00-20:00"); 0331 T2("Mi 08:00-18:00", "We 08:00-18:00"); 0332 T2("Du Mardi au Vendredi 11h00-13h30 Le samedi 10h-19h", "Tu-Fr 11:00-13:30; Sa 10:00-19:00"); 0333 T2("Senin-Sabtu 09:00-16:00, Minggu 09:00-18:00", "Mo-Sa 09:00-16:00, Su 09:00-18:00"); 0334 T2("Lundi-samedi 8H00-12H00 16H00-20H00 dimanche,jours fériés 9H00-12H00 17H00-20H00", "Mo-Sa 08:00-12:00,16:00-20:00; Su,PH 09:00-12:00,17:00-20:00"); 0335 T2("De février à novembre", "Feb-Nov"); 0336 T3("Me,Je,Ve 8h-12h30, 14h-19h; Sa 8h-12h30, 14h-18h", "We,Th,Fr 08:00-12:30,14:00-19:00; Sa 08:00-12:30,14:00-18:00", "We-Fr 08:00-12:30,14:00-19:00; Sa 08:00-12:30,14:00-18:00"); 0337 T2("Mo-Fr: 10:00-18:30 Uhr Sa: 10:00-13:30 Uhr", "Mo-Fr 10:00-18:30; Sa 10:00-13:30"); 0338 T2("Montag & Dienstag Ruhetag", "Mo,Tu closed"); 0339 T2("Понедельник - Суббота 09:00 - 21:00", "Mo-Sa 09:00-21:00"); 0340 T2("Пон-Пт 08:00-20:00, Суб 08:00-19:00", "Mo-Fr 08:00-20:00, Sa 08:00-19:00"); 0341 T2("Ноябрь-Март", "Nov-Mar"); 0342 T2("с 08:30 до 23:00", "08:30-23:00"); 0343 T2("рассвет - сумерки", "dawn-dusk"); 0344 T2("от рассвета до сумерек", "dawn-dusk"); 0345 T2("восход - закат", "sunrise-sunset"); 0346 T2("с восхода пo закат", "sunrise-sunset"); 0347 T2("от восхода дo заката", "sunrise-sunset"); 0348 T2("Среда открыто; Пятница закрыто; Суббота неизвестно", "We open; Fr closed; Sa unknown"); 0349 T2("Вт Выходной", "Tu closed"); 0350 T2("Mo Cerrado; Tu Abierto, Fr libre", "Mo closed; Tu open, Fr closed"); 0351 0352 // recovery from wrong rule separators 0353 T2("Fr,Sa 10:00-02:00,Su 10:00-20:00", "Fr,Sa 10:00-02:00, Su 10:00-20:00"); 0354 T2("tu-sa 12:00-14:30,mo-sa 18:30-22:00", "Tu-Sa 12:00-14:30, Mo-Sa 18:30-22:00"); 0355 T2("Mo 07:00-12:00,Tu 15:00-20:00,We 07:00-12:00,Fr 15:00-20:00", "Mo 07:00-12:00, Tu 15:00-20:00, We 07:00-12:00, Fr 15:00-20:00"); 0356 T2("Mo-Fr 09:00-17:00 Sa 09:00-14:00", "Mo-Fr 09:00-17:00; Sa 09:00-14:00"); 0357 T2("Friday 11AM–2:30AM Saturday 10AM–3:30AM Sunday 9AM–4:30AM", "Fr 11:00-02:30; Sa 10:00-03:30; Su 09:00-04:30"); 0358 T2("Mo-Sa 12:00-15:00; 18:00-24:00", "Mo-Sa 12:00-15:00,18:00-24:00"); 0359 T2("Mo-Sa 12:00-15:00; Mo-Sa 18:00-24:00", "Mo-Sa 12:00-15:00,18:00-24:00"); 0360 T2("Mo 12:00-15:00; Mo 18:00-24:00", "Mo 12:00-15:00,18:00-24:00"); 0361 T("Mo-Sa 12:00-15:00 off; 18:00-24:00"); 0362 T("Mo-Sa 12:00-15:00; Mo-Sa 18:00-24:00 closed"); 0363 T("Mo 12:00-15:00; Mo 18:00-24:00 \"comment\""); 0364 T("Sa 08:00-12:00; 11:30-13:00 off"); 0365 0366 // recovery from wrong time selector separators 0367 T3("Dimanche Fermé Lundi 08:00 – 12:30 14:00 – 19:00 Mardi 08:00 – 12:30 14:00 – 19:00 Mercredi 08:00 – 12:30 14:00 – 19:00 Jeudi 08:00 – 12:30 14:00 – 19:00 Vendredi 08:00 – 12:30 14:00 – 19:00 Samedi 08:00 – 12:30 14:30 – 18:00", 0368 "Su closed; Mo 08:00-12:30,14:00-19:00; Tu 08:00-12:30,14:00-19:00; We 08:00-12:30,14:00-19:00; Th 08:00-12:30,14:00-19:00; Fr 08:00-12:30,14:00-19:00; Sa 08:00-12:30,14:30-18:00", 0369 "Su closed; Mo-Fr 08:00-12:30,14:00-19:00; Sa 08:00-12:30,14:30-18:00"); 0370 0371 // recovery from slashes abused as rule or timespan separators 0372 T2("09:00-12:00/13:00-19:00", "09:00-12:00,13:00-19:00"); 0373 T2("10:00 - 13:30 / 17:00 - 20:30", "10:00-13:30,17:00-20:30"); 0374 T2("Mo-Fr 6:00-18:00 / Sa 6:00-13:00 / So 7:00-17:00", "Mo-Fr 06:00-18:00; Sa 06:00-13:00; Su 07:00-17:00"); 0375 0376 // Simplification of the output 0377 T3("Mo 08:00-13:00; Tu 08:00-13:00", nullptr, "Mo,Tu 08:00-13:00"); 0378 T3("Mo-Th 08:00-13:00; Sa[1],Su[-1] 08:00-13:00", "Mo-Th 08:00-13:00; Sa[1],Su[-1] 08:00-13:00", "Mo-Th,Sa[1],Su[-1] 08:00-13:00"); 0379 T("easter +1 day 08:00-13:00; Tu,Sa,Su 08:00-13:00"); // does not simplify 0380 T3("Mo-Sa 12:00-15:00, Mo-Sa 18:00-24:00", "Mo-Sa 12:00-15:00, Mo-Sa 18:00-24:00", "Mo-Sa 12:00-15:00,18:00-24:00"); 0381 T3("Mo 12:00-15:00, Mo 18:00-24:00", "Mo 12:00-15:00, Mo 18:00-24:00", "Mo 12:00-15:00,18:00-24:00"); 0382 T3("Mo-We,Fr,Su 08:00-13:00", "Mo-We,Fr,Su 08:00-13:00", "Su-We,Fr 08:00-13:00"); 0383 T3("Mo,We,Th,Tu,Sa 08:00-13:00", "Mo,We,Th,Tu,Sa 08:00-13:00", "Mo-Th,Sa 08:00-13:00"); // reordering 0384 T3("Mo-Fr,Tu,We 08:00-13:00", "Mo-Fr,Tu,We 08:00-13:00", "Mo-Fr 08:00-13:00"); // Tu,We already included 0385 T3("Sa-Mo 10:00-23:00, Th 10:00-23:00", "Sa-Mo 10:00-23:00, Th 10:00-23:00", "Sa-Mo,Th 10:00-23:00"); // beginDay > endDay 0386 T3("Sa-Mo 10:00-23:00, Fr 10:00-23:00", "Sa-Mo 10:00-23:00, Fr 10:00-23:00", "Fr-Mo 10:00-23:00"); // beginDay > endDay 0387 T3("Su-Th 10:00-23:00, Fr-Sa 10:00-23:00", "Su-Th 10:00-23:00, Fr-Sa 10:00-23:00", "Mo-Su 10:00-23:00"); // beginDay > endDay 0388 T3("Feb 1-Feb 29 Mo-Su 10:30-20:30; Aug 1-Aug 31 Mo-Fr 10:30-12:00; PH closed", 0389 "Feb 01-29 Mo-Su 10:30-20:30; Aug 01-31 Mo-Fr 10:30-12:00; PH closed", 0390 "Feb Mo-Su 10:30-20:30; Aug Mo-Fr 10:30-12:00; PH closed"); 0391 0392 // complex or creative 24/7 use 0393 T("06:00-01:00 open \"Dining in\" || 24/7 \"Drive-through\""); 0394 T2("Friday and Saturday 24/7 Sunday-Thursday 4:00 am to 12:00 am", "Fr,Sa 00:00-24:00; Su-Th 04:00-24:00"); // bug 445962 0395 // 24/7 as standalone small range selector not supported yet 0396 //T2("Apr-Oct: 24/7; Nov-Mar: Mo-Su 06:00-22:00", "Apr-Oct: 00:00-24:00; Nov-Mar: Mo-Su 06:00-22:00"); 0397 0398 // 4 digit times 0399 T2("0600-1800", "06:00-18:00"); 0400 T2("0700-2000", "07:00-20:00"); 0401 T2("Tu-Th 8:30-17:30, Fr 8:30-1700", "Tu-Th 08:30-17:30, Fr 08:30-17:00"); 0402 #undef T 0403 #undef T2 0404 #undef T3 0405 // clang-format on 0406 } 0407 0408 void testSuccess() 0409 { 0410 QFETCH(QByteArray, input); 0411 QFETCH(QByteArray, expectedOutput); 0412 QFETCH(QByteArray, expectedSimplifiedOutput); 0413 OpeningHours oh(input); 0414 QVERIFY(oh.error() != OpeningHours::SyntaxError); 0415 QCOMPARE(oh.normalizedExpression(), expectedOutput); 0416 QCOMPARE(oh.simplifiedExpression(), expectedSimplifiedOutput); 0417 // verify that simplifiedExpression() doesn't alter `oh` 0418 QCOMPARE(oh.normalizedExpression(), expectedOutput); 0419 0420 // verify the expressions we generate are parsed correctly as well 0421 OpeningHours oh2(oh.normalizedExpression()); 0422 QVERIFY(oh2.error() != OpeningHours::SyntaxError); 0423 QCOMPARE(oh2.normalizedExpression(), oh.normalizedExpression()); 0424 0425 OpeningHours oh3(oh.simplifiedExpression()); 0426 QVERIFY(oh3.error() != OpeningHours::SyntaxError); 0427 QCOMPARE(oh3.normalizedExpression(), oh.simplifiedExpression()); 0428 } 0429 0430 void testFail_data() 0431 { 0432 QTest::addColumn<QByteArray>("input"); 0433 QTest::addColumn<OpeningHours::Error>("error"); 0434 0435 #define T(x) QTest::newRow(x) << QByteArray(x) << OpeningHours::SyntaxError 0436 T("23/7"); 0437 T("24/7 geöffnet"); 0438 T("2020-2000"); 0439 T("Jan-Apr 1"); 0440 T("Feb-2020 Apr 1"); 0441 T("Apr 1-Nov"); 0442 T("Su[0]"); 0443 T("Mo[6]"); 0444 T("Mo[-0]"); 0445 T("Tu[-6]"); 0446 T("Mo[0-5]"); 0447 T("We[4-2]"); 0448 T("49:00"); 0449 T("12:61"); 0450 T("60p"); 0451 0452 T("Dec 24-Jan 1,6"); 0453 T("Mo, 1:100"); 0454 0455 // from https://wiki.openstreetmap.org/wiki/Key:opening_hours#Common_mistakes 0456 T("7/8-23"); 0457 T("07;00-2;00pm"); 0458 T("08.00-16.00, public room till 03.00 a.m"); 0459 T("09:00-21:00 TEL/072(360)3200"); 0460 T("Dining in: 6am to 11pm; Drive thru: 24/7"); 0461 T("MWThF: 1200-1800; SaSu: 1200-1700"); 0462 T("BAR: Su-Mo 18:00-02:00; Tu-Th 18:00-03:00; Fr-Sa 18:00-04:00; CLUB: Tu-Th 20:00-03:00; Fr-Sa 20:00-04:00"); 0463 0464 // from https://openingh.openstreetmap.de/evaluation_tool/ 0465 T("00:00-24:00 week 6 Mo-Su Feb; PH off"); 0466 T("monday, Tu, wE, TH 12:00 - 20:00 ; 14:00-16:00 Off ; closed public Holiday"); 0467 0468 // from Osmose, should fail rather than silently drop the last part 0469 T("Mo-Th, Su 17:00-01:00, Fr-Sa 1700:0300"); 0470 0471 // creative uses found in the wild 0472 T("May 01-Jun 15,Sept 01-30 Mo-Fr 10:00-18:00 Sa-Su 09:00-19:00"); 0473 T("Jul 22-Aug 18 2019: Tu-Su 10:00-13:00"); 0474 #undef T 0475 } 0476 0477 void testFail() 0478 { 0479 QFETCH(QByteArray, input); 0480 QFETCH(OpeningHours::Error, error); 0481 OpeningHours oh(input); 0482 QCOMPARE(oh.error(), error); 0483 } 0484 0485 void testValidation_data() 0486 { 0487 QTest::addColumn<QByteArray>("expression"); 0488 QTest::addColumn<OpeningHours::Error>("error"); 0489 0490 QTest::newRow("location") << QByteArray("sunrise-sunset") << OpeningHours::MissingLocation; 0491 #ifdef KOPENINGHOURS_VALIDATOR_ONLY 0492 QTest::newRow("PH") << QByteArray("PH off") << OpeningHours::NoError; 0493 #else 0494 QTest::newRow("PH") << QByteArray("PH off") << OpeningHours::MissingRegion; 0495 #endif 0496 QTest::newRow("SH") << QByteArray("SH off") << OpeningHours::UnsupportedFeature; 0497 QTest::newRow("time interval") << QByteArray("10:00-16:00/90") << OpeningHours::IncompatibleMode; 0498 QTest::newRow("time interval 2") << QByteArray("10:00-16:00/1:30") << OpeningHours::IncompatibleMode; 0499 QTest::newRow("week wrap") << QByteArray("week 45-13") << OpeningHours::UnsupportedFeature; 0500 QTest::newRow("single timepoint") << QByteArray("10:00") << OpeningHours::IncompatibleMode; 0501 QTest::newRow("month timepoint") << QByteArray("Dec 08:00") << OpeningHours::IncompatibleMode; 0502 QTest::newRow("wide range selector comment") << QByteArray("\"Außerhalb der Semesterferien\": Mo-Fr 08:00-22:00; Sa-Su 10:00-20:00; \"Innerhalb der Semesterferien\": Mo-Fr 08:00-18:00; Sa-Su 10:00-16:00;") << OpeningHours::UnsupportedFeature; 0503 0504 QTest::newRow("empty") << QByteArray("") << OpeningHours::Null; 0505 QTest::newRow("empty comment") << QByteArray("\"\"") << OpeningHours::Null; 0506 } 0507 0508 void testValidation() 0509 { 0510 QFETCH(QByteArray, expression); 0511 QFETCH(OpeningHours::Error, error); 0512 0513 OpeningHours oh(expression); 0514 QCOMPARE(oh.error(), error); 0515 (void)oh.normalizedExpression(); // don't crash 0516 (void)oh.simplifiedExpression(); // don't crash 0517 } 0518 }; 0519 0520 QTEST_GUILESS_MAIN(ParserTest) 0521 0522 #include "parsertest.moc"