]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-calendarspec.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / test / test-calendarspec.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2012 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <string.h>
22
23 #include "alloc-util.h"
24 #include "calendarspec.h"
25 #include "string-util.h"
26 #include "util.h"
27
28 static void test_one(const char *input, const char *output) {
29 CalendarSpec *c;
30 _cleanup_free_ char *p = NULL, *q = NULL;
31 usec_t u;
32 char buf[FORMAT_TIMESTAMP_MAX];
33 int r;
34
35 assert_se(calendar_spec_from_string(input, &c) >= 0);
36
37 assert_se(calendar_spec_to_string(c, &p) >= 0);
38 printf("\"%s\" \"%s\"\n", input, p);
39
40 assert_se(streq(p, output));
41
42 u = now(CLOCK_REALTIME);
43 r = calendar_spec_next_usec(c, u, &u);
44 printf("Next: %s\n", r < 0 ? strerror(-r) : format_timestamp(buf, sizeof(buf), u));
45 calendar_spec_free(c);
46
47 assert_se(calendar_spec_from_string(p, &c) >= 0);
48 assert_se(calendar_spec_to_string(c, &q) >= 0);
49 calendar_spec_free(c);
50
51 assert_se(streq(q, p));
52 }
53
54 static void test_next(const char *input, const char *new_tz, usec_t after, usec_t expect) {
55 CalendarSpec *c;
56 usec_t u;
57 char *old_tz;
58 char buf[FORMAT_TIMESTAMP_MAX];
59 int r;
60
61 old_tz = getenv("TZ");
62 if (old_tz)
63 old_tz = strdupa(old_tz);
64
65 if (new_tz)
66 assert_se(setenv("TZ", new_tz, 1) >= 0);
67 else
68 assert_se(unsetenv("TZ") >= 0);
69 tzset();
70
71 assert_se(calendar_spec_from_string(input, &c) >= 0);
72
73 printf("\"%s\"\n", input);
74
75 u = after;
76 r = calendar_spec_next_usec(c, after, &u);
77 printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp_us(buf, sizeof buf, u));
78 if (expect != (usec_t)-1)
79 assert_se(r >= 0 && u == expect);
80 else
81 assert(r == -ENOENT);
82
83 calendar_spec_free(c);
84
85 if (old_tz)
86 assert_se(setenv("TZ", old_tz, 1) >= 0);
87 else
88 assert_se(unsetenv("TZ") >= 0);
89 tzset();
90 }
91
92 static void test_timestamp(void) {
93 char buf[FORMAT_TIMESTAMP_MAX];
94 _cleanup_free_ char *t = NULL;
95 CalendarSpec *c;
96 usec_t x, y;
97
98 /* Ensure that a timestamp is also a valid calendar specification. Convert forth and back */
99
100 x = now(CLOCK_REALTIME);
101
102 assert_se(format_timestamp_us(buf, sizeof(buf), x));
103 printf("%s\n", buf);
104 assert_se(calendar_spec_from_string(buf, &c) >= 0);
105 assert_se(calendar_spec_to_string(c, &t) >= 0);
106 calendar_spec_free(c);
107 printf("%s\n", t);
108
109 assert_se(parse_timestamp(t, &y) >= 0);
110 assert_se(y == x);
111 }
112
113 static void test_hourly_bug_4031(void) {
114 CalendarSpec *c;
115 usec_t n, u, w;
116 char buf[FORMAT_TIMESTAMP_MAX], zaf[FORMAT_TIMESTAMP_MAX];
117 int r;
118
119 assert_se(calendar_spec_from_string("hourly", &c) >= 0);
120 n = now(CLOCK_REALTIME);
121 assert_se((r = calendar_spec_next_usec(c, n, &u)) >= 0);
122
123 printf("Now: %s (%"PRIu64")\n", format_timestamp_us(buf, sizeof buf, n), n);
124 printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror(-r) : format_timestamp_us(buf, sizeof buf, u), u);
125
126 assert_se((r = calendar_spec_next_usec(c, u, &w)) >= 0);
127 printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror(-r) : format_timestamp_us(zaf, sizeof zaf, w), w);
128
129 assert_se(n < u);
130 assert_se(u <= n + USEC_PER_HOUR);
131 assert_se(u < w);
132 assert_se(w <= u + USEC_PER_HOUR);
133
134 calendar_spec_free(c);
135 }
136
137 int main(int argc, char* argv[]) {
138 CalendarSpec *c;
139
140 test_one("Sat,Thu,Mon-Wed,Sat-Sun", "Mon..Thu,Sat,Sun *-*-* 00:00:00");
141 test_one("Sat,Thu,Mon..Wed,Sat..Sun", "Mon..Thu,Sat,Sun *-*-* 00:00:00");
142 test_one("Mon,Sun 12-*-* 2,1:23", "Mon,Sun 2012-*-* 01,02:23:00");
143 test_one("Wed *-1", "Wed *-*-01 00:00:00");
144 test_one("Wed-Wed,Wed *-1", "Wed *-*-01 00:00:00");
145 test_one("Wed..Wed,Wed *-1", "Wed *-*-01 00:00:00");
146 test_one("Wed, 17:48", "Wed *-*-* 17:48:00");
147 test_one("Wednesday,", "Wed *-*-* 00:00:00");
148 test_one("Wed-Sat,Tue 12-10-15 1:2:3", "Tue..Sat 2012-10-15 01:02:03");
149 test_one("Wed..Sat,Tue 12-10-15 1:2:3", "Tue..Sat 2012-10-15 01:02:03");
150 test_one("*-*-7 0:0:0", "*-*-07 00:00:00");
151 test_one("10-15", "*-10-15 00:00:00");
152 test_one("monday *-12-* 17:00", "Mon *-12-* 17:00:00");
153 test_one("Mon,Fri *-*-3,1,2 *:30:45", "Mon,Fri *-*-01,02,03 *:30:45");
154 test_one("12,14,13,12:20,10,30", "*-*-* 12,13,14:10,20,30:00");
155 test_one("mon,fri *-1/2-1,3 *:30:45", "Mon,Fri *-01/2-01,03 *:30:45");
156 test_one("03-05 08:05:40", "*-03-05 08:05:40");
157 test_one("08:05:40", "*-*-* 08:05:40");
158 test_one("05:40", "*-*-* 05:40:00");
159 test_one("Sat,Sun 12-05 08:05:40", "Sat,Sun *-12-05 08:05:40");
160 test_one("Sat,Sun 08:05:40", "Sat,Sun *-*-* 08:05:40");
161 test_one("2003-03-05 05:40", "2003-03-05 05:40:00");
162 test_one("2003-03-05", "2003-03-05 00:00:00");
163 test_one("03-05", "*-03-05 00:00:00");
164 test_one("hourly", "*-*-* *:00:00");
165 test_one("daily", "*-*-* 00:00:00");
166 test_one("monthly", "*-*-01 00:00:00");
167 test_one("weekly", "Mon *-*-* 00:00:00");
168 test_one("minutely", "*-*-* *:*:00");
169 test_one("quarterly", "*-01,04,07,10-01 00:00:00");
170 test_one("semi-annually", "*-01,07-01 00:00:00");
171 test_one("annually", "*-01-01 00:00:00");
172 test_one("*:2/3", "*-*-* *:02/3:00");
173 test_one("2015-10-25 01:00:00 uTc", "2015-10-25 01:00:00 UTC");
174 test_one("2015-10-25 01:00:00 Asia/Vladivostok", "2015-10-25 01:00:00 Asia/Vladivostok");
175 test_one("weekly Pacific/Auckland", "Mon *-*-* 00:00:00 Pacific/Auckland");
176 test_one("2016-03-27 03:17:00.4200005", "2016-03-27 03:17:00.420001");
177 test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000");
178 test_one("9..11,13:00,30", "*-*-* 09..11,13:00,30:00");
179 test_one("1..3-1..3 1..3:1..3", "*-01..03-01..03 01..03:01..03:00");
180 test_one("00:00:1.125..2.125", "*-*-* 00:00:01.125000..02.125000");
181 test_one("00:00:1.0..3.8", "*-*-* 00:00:01..03");
182 test_one("00:00:01..03", "*-*-* 00:00:01..03");
183 test_one("00:00:01/2,02..03", "*-*-* 00:00:01/2,02..03");
184 test_one("*-*~1 Utc", "*-*~01 00:00:00 UTC");
185 test_one("*-*~05,3 ", "*-*~03,05 00:00:00");
186 test_one("*-*~* 00:00:00", "*-*-* 00:00:00");
187 test_one("Monday", "Mon *-*-* 00:00:00");
188 test_one("Monday *-*-*", "Mon *-*-* 00:00:00");
189 test_one("*-*-*", "*-*-* 00:00:00");
190 test_one("*:*:*", "*-*-* *:*:*");
191 test_one("*:*", "*-*-* *:*:00");
192 test_one("12:*", "*-*-* 12:*:00");
193 test_one("*:30", "*-*-* *:30:00");
194 test_one("93..00-*-*", "1993..2000-*-* 00:00:00");
195 test_one("00..07-*-*", "2000..2007-*-* 00:00:00");
196 test_one("*:20..39/5", "*-*-* *:20..35/5:00");
197 test_one("00:00:20..40/1", "*-*-* 00:00:20..40");
198 test_one("*~03/1,03..05", "*-*~03/1,03..05 00:00:00");
199 /* UNIX timestamps are always UTC */
200 test_one("@1493187147", "2017-04-26 06:12:27 UTC");
201 test_one("@1493187147 UTC", "2017-04-26 06:12:27 UTC");
202 test_one("@0", "1970-01-01 00:00:00 UTC");
203 test_one("@0 UTC", "1970-01-01 00:00:00 UTC");
204
205 test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000);
206 test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000);
207 test_next("2016-03-27 03:17:00", "EET", 12345, -1);
208 test_next("2016-03-27 03:17:00 UTC", NULL, 12345, 1459048620000000);
209 test_next("2016-03-27 03:17:00 UTC", "", 12345, 1459048620000000);
210 test_next("2016-03-27 03:17:00 UTC", "CET", 12345, 1459048620000000);
211 test_next("2016-03-27 03:17:00 UTC", "EET", 12345, 1459048620000000);
212 test_next("2016-03-27 03:17:00.420000001 UTC", "EET", 12345, 1459048620420000);
213 test_next("2016-03-27 03:17:00.4200005 UTC", "EET", 12345, 1459048620420001);
214 test_next("2015-11-13 09:11:23.42", "EET", 12345, 1447398683420000);
215 test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683420000, 1447398685190000);
216 test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683419999, 1447398683420000);
217 test_next("Sun 16:00:00", "CET", 1456041600123456, 1456066800000000);
218 test_next("*-04-31", "", 12345, -1);
219 test_next("2016-02~01 UTC", "", 12345, 1456704000000000);
220 test_next("Mon 2017-05~01..07 UTC", "", 12345, 1496016000000000);
221 test_next("Mon 2017-05~07/1 UTC", "", 12345, 1496016000000000);
222 test_next("2017-08-06 9,11,13,15,17:00 UTC", "", 1502029800000000, 1502031600000000);
223 test_next("2017-08-06 9..17/2:00 UTC", "", 1502029800000000, 1502031600000000);
224 test_next("2016-12-* 3..21/6:00 UTC", "", 1482613200000001, 1482634800000000);
225 test_next("2017-09-24 03:30:00 Pacific/Auckland", "", 12345, 1506177000000000);
226 // Due to daylight saving time - 2017-09-24 02:30:00 does not exist
227 test_next("2017-09-24 02:30:00 Pacific/Auckland", "", 12345, -1);
228 test_next("2017-04-02 02:30:00 Pacific/Auckland", "", 12345, 1491053400000000);
229 // Confirm that even though it's a time change here (backward) 02:30 happens only once
230 test_next("2017-04-02 02:30:00 Pacific/Auckland", "", 1491053400000000, -1);
231 test_next("2017-04-02 03:30:00 Pacific/Auckland", "", 12345, 1491060600000000);
232 // Confirm that timezones in the Spec work regardless of current timezone
233 test_next("2017-09-09 20:42:00 Pacific/Auckland", "", 12345, 1504946520000000);
234 test_next("2017-09-09 20:42:00 Pacific/Auckland", "EET", 12345, 1504946520000000);
235
236 assert_se(calendar_spec_from_string("test", &c) < 0);
237 assert_se(calendar_spec_from_string(" utc", &c) < 0);
238 assert_se(calendar_spec_from_string(" ", &c) < 0);
239 assert_se(calendar_spec_from_string("", &c) < 0);
240 assert_se(calendar_spec_from_string("7", &c) < 0);
241 assert_se(calendar_spec_from_string("121212:1:2", &c) < 0);
242 assert_se(calendar_spec_from_string("2000-03-05.23 00:00:00", &c) < 0);
243 assert_se(calendar_spec_from_string("2000-03-05 00:00.1:00", &c) < 0);
244 assert_se(calendar_spec_from_string("00:00:00/0.00000001", &c) < 0);
245 assert_se(calendar_spec_from_string("00:00:00.0..00.9", &c) < 0);
246 assert_se(calendar_spec_from_string("2016~11-22", &c) < 0);
247 assert_se(calendar_spec_from_string("*-*~5/5", &c) < 0);
248 assert_se(calendar_spec_from_string("Monday.. 12:00", &c) < 0);
249 assert_se(calendar_spec_from_string("Monday..", &c) < 0);
250 assert_se(calendar_spec_from_string("-00:+00/-5", &c) < 0);
251 assert_se(calendar_spec_from_string("00:+00/-5", &c) < 0);
252 assert_se(calendar_spec_from_string("2016- 11- 24 12: 30: 00", &c) < 0);
253 assert_se(calendar_spec_from_string("*~29", &c) < 0);
254 assert_se(calendar_spec_from_string("*~16..31", &c) < 0);
255 assert_se(calendar_spec_from_string("12..1/2-*", &c) < 0);
256 assert_se(calendar_spec_from_string("*:05..05", &c) < 0);
257 assert_se(calendar_spec_from_string("*:05..10/6", &c) < 0);
258 assert_se(calendar_spec_from_string("20/4:00", &c) < 0);
259 assert_se(calendar_spec_from_string("00:00/60", &c) < 0);
260 assert_se(calendar_spec_from_string("00:00:2300", &c) < 0);
261 assert_se(calendar_spec_from_string("00:00:18446744073709551615", &c) < 0);
262
263 test_timestamp();
264 test_hourly_bug_4031();
265
266 return 0;
267 }