File indexing completed on 2024-04-21 04:40:43
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 // https://bugs.kde.org/show_bug.cgi?id=452236 0116 T("2022 Mar 31-2022 Apr 16"); 0117 T2("2022 Mar 31-Apr 16", "2022 Mar 31-2022 Apr 16"); 0118 0119 // from https://wiki.openstreetmap.org/wiki/Key:opening_hours#Simple_examples 0120 T("Mo-Fr 08:00-17:30"); 0121 T("Mo-Fr 08:00-12:00,13:00-17:30"); 0122 T("Mo-Fr 08:00-12:00,13:00-17:30; Sa 08:00-12:00"); 0123 T("Mo-Fr 08:00-12:00,13:00-17:30; Sa 08:00-12:00; PH off"); 0124 T("Mo-Fr 08:00-12:00,13:00-17:30; Sa 08:00-12:00; PH 09:00-12:00"); 0125 0126 // from https://wiki.openstreetmap.org/wiki/Key:opening_hours#Examples 0127 T3("Sa-Su 00:00-24:00", nullptr, "Sa,Su 00:00-24:00"); 0128 T("Mo-Fr 08:30-20:00"); 0129 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"); 0130 T("Mo-Su 08:00-18:00; Apr 10-15 off; Jun 08:00-14:00; Aug off; Dec 25 off"); 0131 T("Mo-Sa 10:00-20:00; Tu off"); 0132 T("Mo-Sa 10:00-20:00; Tu 10:00-14:00"); 0133 T("sunrise-sunset"); 0134 T("Su 10:00+"); 0135 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"); 0136 T("Mo-Sa 08:00-13:00,14:00-17:00 || \"by appointment\""); 0137 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"); 0138 T("Mo-Su,PH 15:00-03:00; easter -2 days off"); 0139 0140 // from https://openingh.openstreetmap.de/evaluation_tool/ 0141 T("Mo-Fr 10:00-20:00; PH off"); 0142 T("Mo,Tu,Th,Fr 12:00-18:00; Sa,PH 12:00-17:00; Th[3],Th[-1] off"); 0143 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"); 0144 T3("Fr-Sa 18:00-06:00; PH off", nullptr, "Fr,Sa 18:00-06:00; PH off"); 0145 T("Mo 10:00-12:00,12:30-15:00"); 0146 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"); 0147 T("\"only after registration\"; PH off"); 0148 T("22:00-23:00; PH off"); 0149 T("08:00-11:00; PH off"); 0150 T("open; Mo 15:00-16:00 off; PH off"); 0151 T("Mo-Su 22:00-23:00; We,PH off"); 0152 T("We-Fr 10:00-24:00 open \"it is open\" || \"please call\"; PH off"); 0153 T("Mo-Fr 08:00-11:00 || Tu-Th,PH open \"Emergency only\""); 0154 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 0155 T("Mo 12:00-14:00 open \"female only\", Mo 14:00-16:00 open \"male only\"; PH off"); 0156 T("Apr: 22:00-23:00; PH off"); 0157 T("Jul-Jan: 22:00-23:00; PH off"); 0158 T("Jan-Jul: 22:00-23:00; PH off"); 0159 T2("Jul 23-Jan 3: \"needs reservation by phone\"; PH off", "Jul 23-Jan 03: \"needs reservation by phone\"; PH off"); 0160 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"); 0161 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"); 0162 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"); 0163 T("Mar Su[-1]-Dec Su[1] -2 days: 22:00-23:00; PH off"); 0164 T("Sa[1],Sa[1] +1 day 10:00-12:00 open \"first weekend in the month\"; PH off"); 0165 T("Sa[-1],Sa[-1] +1 day 10:00-12:00 open \"last weekend in the month\"; PH off"); 0166 T3("Sa-Su 00:00-24:00; PH off", nullptr, "Sa,Su 00:00-24:00; PH off"); 0167 T("Mo-Fr 00:00-24:00; PH off"); 0168 T("sunrise-sunset open \"Beware of sunburn!\"; PH off"); 0169 T("sunset-sunrise open \"Beware of vampires!\"; PH off"); 0170 T("(sunrise-00:30)-(sunrise+00:30)"); 0171 T("(sunset+01:00)-24:00 || closed \"No drink before sunset!\"; PH off"); 0172 T("22:00+; PH off"); 0173 T("Tu,PH 23:59-22:59"); 0174 T("We-Mo,PH 23:59-22:59"); 0175 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"); 0176 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"); 0177 T("2012 easter -2 days-2012 easter +2 days: open \"Around easter\"; PH off"); 0178 T("24/7 closed \"always closed\""); 0179 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"); 0180 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"); 0181 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"); 0182 T("Mo-Fr 08:00-12:00, We 14:00-18:00; Su,PH off"); // open We morning too 0183 T("Mo-Fr 08:00-12:00; We 14:00-18:00; Su,PH off"); // closed We morning 0184 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"); 0185 0186 T("We; PH off"); 0187 T("PH"); 0188 T("PH Mo-Fr"); 0189 T("PH -1 day"); 0190 T("SH"); 0191 T("SH,PH"); 0192 T("PH,SH"); 0193 T("We[1-3]"); 0194 T("We[3-5]"); 0195 T("Sa"); 0196 T("Sa[1]"); 0197 T("Sa[1-3]"); 0198 T("Su[-1,1]"); 0199 T("Tu-Th"); 0200 T("Fr-Mo"); 0201 T("Mo-Su; We \"only after registration\""); 0202 T("Oct: We[1]"); 0203 0204 // from https://github.com/dfaure/DataNovaImportScripts/blob/master/saved_opening_hours 0205 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", 0206 "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", 0207 "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"); 0208 0209 // real-world tests from Osmose that we were handling wrongly 0210 T("Tu-Fr 11:30-14:30 open, 14:30-18:00 open \"pickup only\", 18:00-22:00 open"); 0211 T("SH Tu,Th 10:00-19:00"); 0212 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"); 0213 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"); 0214 T("Mo-Sa 09:00-20:00; Su[-2,-1] 12:30-18:00"); 0215 T("Su off, Mo-Fr 08:30-13:00; Mo-Th 08:30-13:30,16:00-20:00"); 0216 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, 0217 "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"); 0218 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 0219 0220 // weekday autocorrect 0221 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"); 0222 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", 0223 "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"); 0224 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", 0225 "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"); 0226 T2("2020-2021 Mo, Tu-Fr, Sa [-1] 09:00-14:00", "2020-2021 Mo,Tu-Fr,Sa[-1] 09:00-14:00"); 0227 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"); 0228 T2("Mo Fr 09:30-12:30 13:30-18:30", "Mo,Fr 09:30-12:30,13:30-18:30"); 0229 T2("Mo Fr 09:30-12:30, 13:30-18:30 off", "Mo,Fr 09:30-12:30,13:30-18:30 off"); 0230 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"); 0231 T2("Lunes a sábado, 9:30 AM-5:30 PM", "Mo-Sa 09:30-17:30"); // bug 445784 0232 0233 // technically wrong but often found content in OSM for which we have error recovery 0234 T2("So", "Su"); 0235 T2("Ph", "PH"); 0236 T2("9:00-12:00", "09:00-12:00"); 0237 T2("Mo-Fr 09:00-18:30;Sa 09:00-17:00", "Mo-Fr 09:00-18:30; Sa 09:00-17:00"); 0238 T2("08:00-12:00;", "08:00-12:00"); 0239 T2("14:00-20:00,", "14:00-20:00"); 0240 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\""); 0241 T2("Mo-Fr 06:30-12:00, 13:00-18:00", "Mo-Fr 06:30-12:00,13:00-18:00"); // see autocorrect() 0242 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"); 0243 T2("01:00-23:00; ", "01:00-23:00"); 0244 T2("02:00-22:00,\n", "02:00-22:00"); 0245 T2("Friday 08:00-12:00", "Fr 08:00-12:00"); 0246 T2("Sat", "Sa"); 0247 T2("december", "Dec"); 0248 T2("Dec 24,25,26, Jan 1,6 off", "Dec 24,25,26,Jan 01,06 off"); 0249 T2("Dec 24,25,26 open, Jan 1,6 off", "Dec 24,25,26 open, Jan 01,06 off"); 0250 T2("Dec 6,4", "Dec 06,04"); 0251 T2("Dec 3,2,1", "Dec 03,02,01"); 0252 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", 0253 "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"); 0254 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"); 0255 0256 // Tolerance for incorrect casing 0257 T2("mo-fr 10:00-20:00", "Mo-Fr 10:00-20:00"); 0258 T2("jan-feb 10:00-20:00", "Jan-Feb 10:00-20:00"); 0259 T2("jan-feb,aug 10:00-20:00", "Jan-Feb,Aug 10:00-20:00"); 0260 T2("SUNRISE-SUNSET", "sunrise-sunset"); 0261 T2("(SUNrISE-01:00)-(SUnsET+01:00)", "(sunrise-01:00)-(sunset+01:00)"); 0262 T2("su,sh off", "Su,SH off"); 0263 T2("mo-fr CLOSED", "Mo-Fr closed"); 0264 0265 // Time correction 0266 T2("9h00-12h00", "09:00-12:00"); 0267 T2("9h-12h", "09:00-12:00"); 0268 T2("5H", "05:00"); 0269 T2("06:00am", "06:00"); 0270 T2("06:30pm", "18:30"); 0271 T2("07:00 am", "07:00"); 0272 T2("07:00 pm", "19:00"); 0273 T2("5:00AM", "05:00"); 0274 T2("5:02 PM", "17:02"); 0275 T2("10a", "10:00"); 0276 T2("10p", "22:00"); 0277 T2("12:00 am", "00:00"); 0278 T2("12:00pm", "12:00"); 0279 T2("1 a.m", "01:00"); 0280 T2("3p.m", "15:00"); 0281 T2("12:01a.m.", "00:01"); 0282 T2("12:01p.m.", "12:01"); 0283 T2("11:59a", "11:59"); 0284 T2("11:59p", "23:59"); 0285 T2("9h00-12h00,14:00-17:00", "09:00-12:00,14:00-17:00"); 0286 T2("9:00 am - 12:00 am", "09:00-24:00"); 0287 T2("9 am - 12 am", "09:00-24:00"); 0288 T2("11:00 am - 11:00 pm", "11:00-23:00"); 0289 T2("09 : 00 - 12 : 00 , 13 : 00 - 19 : 00", "09:00-12:00,13:00-19:00"); 0290 T2("10.30am - 4.30pm", "10:30-16:30"); 0291 T2("17時00分~23時30分", "17:00-23:30"); 0292 0293 // alternative range separators 0294 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"); 0295 T2("Monday to Friday 8:00AM to 4:30PM", "Mo-Fr 08:00-16:30"); 0296 T2("1pm-3pm and 7pm-11pm", "13:00-15:00,19:00-23:00"); 0297 T2("8h00 à 12h00 et 13h30 à 18h00", "08:00-12:00,13:30-18:00"); 0298 T2("Samedi et Dimanche 5h30 - 12h30 Lundi 13h45 - 15h15", "Sa,Su 05:30-12:30; Mo 13:45-15:15"); 0299 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"); 0300 T2("11:30-14:00、16:30-22:00", "11:30-14:00,16:30-22:00"); 0301 T2("Lunedì al Venerdì 08:00-13:00", "Mo-Fr 08:00-13:00"); 0302 T2("Monday through Friday 09:00 - 17:00", "Mo-Fr 09:00-17:00"); 0303 0304 // (mis)use of colon as a small-range selector separator 0305 T2("Fr: 17:00-19:00", "Fr 17:00-19:00"); 0306 T2("Fr: closed", "Fr closed"); 0307 T2("Tu-Su:07:00-00:00", "Tu-Su 07:00-24:00"); 0308 T2("Du lundi au vendredi : 9:00-18:00", "Mo-Fr 09:00-18:00"); 0309 0310 // Unicode symbols 0311 T3("Mo–Tu", "Mo-Tu", "Mo,Tu"); 0312 T2("13:41", "13:41"); 0313 T2("10:00〜19:00", "10:00-19:00"); 0314 T2("10:00-17:00", "10:00-17:00"); 0315 T2("11:00−23:00", "11:00-23:00"); 0316 T2("11:00ー15:00", "11:00-15:00"); 0317 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 0318 T2("LUNDI 08:30 – 17:00", "Mo 08:30-17:00"); 0319 T3("月,木,金,土,日 11:00-19:00", "Mo,Th,Fr,Sa,Su 11:00-19:00", "Th-Mo 11:00-19:00"); 0320 T2("月-土 09:00-18:00", "Mo-Sa 09:00-18:00"); 0321 T2("水曜日~土曜日10:00~19:00", "We-Sa 10:00-19:00"); 0322 T2("月~土 17:00~23:00", "Mo-Sa 17:00-23:00"); 0323 T2("Mo-Fr 08:00-17:00 “Visa Applications\"", "Mo-Fr 08:00-17:00 \"Visa Applications\""); 0324 T2("„nach Vereinbarung“", "\"nach Vereinbarung\""); 0325 T("\"„Termine nach Vereinbarung“\""); 0326 0327 // non-English 0328 T2("Lundi au Vendredi 8h - 17h en continu", "Mo-Fr 08:00-17:00"); 0329 T2("Lun-Ven 08:00-13:00", "Mo-Fr 08:00-13:00"); 0330 T2("Lu-Sa 08:00-13:00", "Mo-Sa 08:00-13:00"); 0331 T2("Domingo de 9: 00 am. a 1:00 pm", "Su 09:00-13:00"); 0332 T2("Gio, Sab e Dom: 9.00-12.30", "Th,Sa,Su 09:00-12:30"); 0333 T2("Segunda a Sexta 08:00h a 16:00h", "Mo-Fr 08:00-16:00"); 0334 T2("lunedi,mercoledi,venerdi,sabato 09:00-20:00", "Mo,We,Fr,Sa 09:00-20:00"); 0335 T2("Mi 08:00-18:00", "We 08:00-18:00"); 0336 T2("Du Mardi au Vendredi 11h00-13h30 Le samedi 10h-19h", "Tu-Fr 11:00-13:30; Sa 10:00-19:00"); 0337 T2("Senin-Sabtu 09:00-16:00, Minggu 09:00-18:00", "Mo-Sa 09:00-16:00, Su 09:00-18:00"); 0338 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"); 0339 T2("De février à novembre", "Feb-Nov"); 0340 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"); 0341 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"); 0342 T2("Montag & Dienstag Ruhetag", "Mo,Tu closed"); 0343 T2("Понедельник - Суббота 09:00 - 21:00", "Mo-Sa 09:00-21:00"); 0344 T2("Пон-Пт 08:00-20:00, Суб 08:00-19:00", "Mo-Fr 08:00-20:00, Sa 08:00-19:00"); 0345 T2("Ноябрь-Март", "Nov-Mar"); 0346 T2("с 08:30 до 23:00", "08:30-23:00"); 0347 T2("рассвет - сумерки", "dawn-dusk"); 0348 T2("от рассвета до сумерек", "dawn-dusk"); 0349 T2("восход - закат", "sunrise-sunset"); 0350 T2("с восхода пo закат", "sunrise-sunset"); 0351 T2("от восхода дo заката", "sunrise-sunset"); 0352 T2("Среда открыто; Пятница закрыто; Суббота неизвестно", "We open; Fr closed; Sa unknown"); 0353 T2("Вт Выходной", "Tu closed"); 0354 T2("Mo Cerrado; Tu Abierto, Fr libre", "Mo closed; Tu open, Fr closed"); 0355 0356 // recovery from wrong rule separators 0357 T2("Fr,Sa 10:00-02:00,Su 10:00-20:00", "Fr,Sa 10:00-02:00, Su 10:00-20:00"); 0358 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"); 0359 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"); 0360 T2("Mo-Fr 09:00-17:00 Sa 09:00-14:00", "Mo-Fr 09:00-17:00; Sa 09:00-14:00"); 0361 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"); 0362 T2("Mo-Sa 12:00-15:00; 18:00-24:00", "Mo-Sa 12:00-15:00,18:00-24:00"); 0363 T2("Mo-Sa 12:00-15:00; Mo-Sa 18:00-24:00", "Mo-Sa 12:00-15:00,18:00-24:00"); 0364 T2("Mo 12:00-15:00; Mo 18:00-24:00", "Mo 12:00-15:00,18:00-24:00"); 0365 T("Mo-Sa 12:00-15:00 off; 18:00-24:00"); 0366 T("Mo-Sa 12:00-15:00; Mo-Sa 18:00-24:00 closed"); 0367 T("Mo 12:00-15:00; Mo 18:00-24:00 \"comment\""); 0368 T("Sa 08:00-12:00; 11:30-13:00 off"); 0369 0370 // recovery from wrong time selector separators 0371 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", 0372 "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", 0373 "Su closed; Mo-Fr 08:00-12:30,14:00-19:00; Sa 08:00-12:30,14:30-18:00"); 0374 0375 // recovery from slashes abused as rule or timespan separators 0376 T2("09:00-12:00/13:00-19:00", "09:00-12:00,13:00-19:00"); 0377 T2("10:00 - 13:30 / 17:00 - 20:30", "10:00-13:30,17:00-20:30"); 0378 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"); 0379 0380 // Simplification of the output 0381 T3("Mo 08:00-13:00; Tu 08:00-13:00", nullptr, "Mo,Tu 08:00-13:00"); 0382 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"); 0383 T("easter +1 day 08:00-13:00; Tu,Sa,Su 08:00-13:00"); // does not simplify 0384 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"); 0385 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"); 0386 T3("Mo-We,Fr,Su 08:00-13:00", "Mo-We,Fr,Su 08:00-13:00", "Su-We,Fr 08:00-13:00"); 0387 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 0388 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 0389 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 0390 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 0391 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 0392 T3("Feb 1-Feb 29 Mo-Su 10:30-20:30; Aug 1-Aug 31 Mo-Fr 10:30-12:00; PH closed", 0393 "Feb 01-29 Mo-Su 10:30-20:30; Aug 01-31 Mo-Fr 10:30-12:00; PH closed", 0394 "Feb Mo-Su 10:30-20:30; Aug Mo-Fr 10:30-12:00; PH closed"); 0395 0396 // complex or creative 24/7 use 0397 T("06:00-01:00 open \"Dining in\" || 24/7 \"Drive-through\""); 0398 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 0399 // 24/7 as standalone small range selector not supported yet 0400 //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"); 0401 0402 // 4 digit times 0403 T2("0600-1800", "06:00-18:00"); 0404 T2("0700-2000", "07:00-20:00"); 0405 T2("Tu-Th 8:30-17:30, Fr 8:30-1700", "Tu-Th 08:30-17:30, Fr 08:30-17:00"); 0406 #undef T 0407 #undef T2 0408 #undef T3 0409 // clang-format on 0410 } 0411 0412 void testSuccess() 0413 { 0414 QFETCH(QByteArray, input); 0415 QFETCH(QByteArray, expectedOutput); 0416 QFETCH(QByteArray, expectedSimplifiedOutput); 0417 OpeningHours oh(input); 0418 QVERIFY(oh.error() != OpeningHours::SyntaxError); 0419 QCOMPARE(oh.normalizedExpression(), expectedOutput); 0420 QCOMPARE(oh.simplifiedExpression(), expectedSimplifiedOutput); 0421 // verify that simplifiedExpression() doesn't alter `oh` 0422 QCOMPARE(oh.normalizedExpression(), expectedOutput); 0423 0424 // verify the expressions we generate are parsed correctly as well 0425 OpeningHours oh2(oh.normalizedExpression()); 0426 QVERIFY(oh2.error() != OpeningHours::SyntaxError); 0427 QCOMPARE(oh2.normalizedExpression(), oh.normalizedExpression()); 0428 0429 OpeningHours oh3(oh.simplifiedExpression()); 0430 QVERIFY(oh3.error() != OpeningHours::SyntaxError); 0431 QCOMPARE(oh3.normalizedExpression(), oh.simplifiedExpression()); 0432 } 0433 0434 void testFail_data() 0435 { 0436 QTest::addColumn<QByteArray>("input"); 0437 QTest::addColumn<OpeningHours::Error>("error"); 0438 0439 #define T(x) QTest::newRow(x) << QByteArray(x) << OpeningHours::SyntaxError 0440 T("23/7"); 0441 T("24/7 geöffnet"); 0442 T("2020-2000"); 0443 T("Jan-Apr 1"); 0444 T("Feb-2020 Apr 1"); 0445 T("Apr 1-Nov"); 0446 T("Su[0]"); 0447 T("Mo[6]"); 0448 T("Mo[-0]"); 0449 T("Tu[-6]"); 0450 T("Mo[0-5]"); 0451 T("We[4-2]"); 0452 T("49:00"); 0453 T("12:61"); 0454 T("60p"); 0455 0456 T("Dec 24-Jan 1,6"); 0457 T("Mo, 1:100"); 0458 0459 // from https://wiki.openstreetmap.org/wiki/Key:opening_hours#Common_mistakes 0460 T("7/8-23"); 0461 T("07;00-2;00pm"); 0462 T("08.00-16.00, public room till 03.00 a.m"); 0463 T("09:00-21:00 TEL/072(360)3200"); 0464 T("Dining in: 6am to 11pm; Drive thru: 24/7"); 0465 T("MWThF: 1200-1800; SaSu: 1200-1700"); 0466 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"); 0467 0468 // from https://openingh.openstreetmap.de/evaluation_tool/ 0469 T("00:00-24:00 week 6 Mo-Su Feb; PH off"); 0470 T("monday, Tu, wE, TH 12:00 - 20:00 ; 14:00-16:00 Off ; closed public Holiday"); 0471 0472 // from Osmose, should fail rather than silently drop the last part 0473 T("Mo-Th, Su 17:00-01:00, Fr-Sa 1700:0300"); 0474 0475 // creative uses found in the wild 0476 T("May 01-Jun 15,Sept 01-30 Mo-Fr 10:00-18:00 Sa-Su 09:00-19:00"); 0477 T("Jul 22-Aug 18 2019: Tu-Su 10:00-13:00"); 0478 #undef T 0479 } 0480 0481 void testFail() 0482 { 0483 QFETCH(QByteArray, input); 0484 QFETCH(OpeningHours::Error, error); 0485 OpeningHours oh(input); 0486 QCOMPARE(oh.error(), error); 0487 } 0488 0489 void testValidation_data() 0490 { 0491 QTest::addColumn<QByteArray>("expression"); 0492 QTest::addColumn<OpeningHours::Error>("error"); 0493 0494 QTest::newRow("location") << QByteArray("sunrise-sunset") << OpeningHours::MissingLocation; 0495 #ifdef KOPENINGHOURS_VALIDATOR_ONLY 0496 QTest::newRow("PH") << QByteArray("PH off") << OpeningHours::NoError; 0497 #else 0498 QTest::newRow("PH") << QByteArray("PH off") << OpeningHours::MissingRegion; 0499 #endif 0500 QTest::newRow("SH") << QByteArray("SH off") << OpeningHours::UnsupportedFeature; 0501 QTest::newRow("time interval") << QByteArray("10:00-16:00/90") << OpeningHours::IncompatibleMode; 0502 QTest::newRow("time interval 2") << QByteArray("10:00-16:00/1:30") << OpeningHours::IncompatibleMode; 0503 QTest::newRow("week wrap") << QByteArray("week 45-13") << OpeningHours::UnsupportedFeature; 0504 QTest::newRow("single timepoint") << QByteArray("10:00") << OpeningHours::IncompatibleMode; 0505 QTest::newRow("month timepoint") << QByteArray("Dec 08:00") << OpeningHours::IncompatibleMode; 0506 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; 0507 0508 QTest::newRow("empty") << QByteArray("") << OpeningHours::Null; 0509 QTest::newRow("empty comment") << QByteArray("\"\"") << OpeningHours::Null; 0510 } 0511 0512 void testValidation() 0513 { 0514 QFETCH(QByteArray, expression); 0515 QFETCH(OpeningHours::Error, error); 0516 0517 OpeningHours oh(expression); 0518 QCOMPARE(oh.error(), error); 0519 (void)oh.normalizedExpression(); // don't crash 0520 (void)oh.simplifiedExpression(); // don't crash 0521 } 0522 }; 0523 0524 QTEST_GUILESS_MAIN(ParserTest) 0525 0526 #include "parsertest.moc"