]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-time-util.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / test / test-time-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2013 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 "random-util.h"
22 #include "string-util.h"
23 #include "strv.h"
24 #include "time-util.h"
25
26 static void test_parse_sec(void) {
27 usec_t u;
28
29 assert_se(parse_sec("5s", &u) >= 0);
30 assert_se(u == 5 * USEC_PER_SEC);
31 assert_se(parse_sec("5s500ms", &u) >= 0);
32 assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC);
33 assert_se(parse_sec(" 5s 500ms ", &u) >= 0);
34 assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC);
35 assert_se(parse_sec(" 5.5s ", &u) >= 0);
36 assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC);
37 assert_se(parse_sec(" 5.5s 0.5ms ", &u) >= 0);
38 assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC + 500);
39 assert_se(parse_sec(" .22s ", &u) >= 0);
40 assert_se(u == 220 * USEC_PER_MSEC);
41 assert_se(parse_sec(" .50y ", &u) >= 0);
42 assert_se(u == USEC_PER_YEAR / 2);
43 assert_se(parse_sec("2.5", &u) >= 0);
44 assert_se(u == 2500 * USEC_PER_MSEC);
45 assert_se(parse_sec(".7", &u) >= 0);
46 assert_se(u == 700 * USEC_PER_MSEC);
47 assert_se(parse_sec("23us", &u) >= 0);
48 assert_se(u == 23);
49 assert_se(parse_sec("23µs", &u) >= 0);
50 assert_se(u == 23);
51 assert_se(parse_sec("infinity", &u) >= 0);
52 assert_se(u == USEC_INFINITY);
53 assert_se(parse_sec(" infinity ", &u) >= 0);
54 assert_se(u == USEC_INFINITY);
55
56 assert_se(parse_sec(" xyz ", &u) < 0);
57 assert_se(parse_sec("", &u) < 0);
58 assert_se(parse_sec(" . ", &u) < 0);
59 assert_se(parse_sec(" 5. ", &u) < 0);
60 assert_se(parse_sec(".s ", &u) < 0);
61 assert_se(parse_sec(" infinity .7", &u) < 0);
62 assert_se(parse_sec(".3 infinity", &u) < 0);
63 }
64
65 static void test_parse_sec_fix_0(void) {
66 usec_t u;
67
68 assert_se(parse_sec_fix_0("5s", &u) >= 0);
69 assert_se(u == 5 * USEC_PER_SEC);
70 assert_se(parse_sec_fix_0("0s", &u) >= 0);
71 assert_se(u == 0 * USEC_PER_SEC);
72 assert_se(parse_sec_fix_0("0", &u) >= 0);
73 assert_se(u == USEC_INFINITY);
74 assert_se(parse_sec_fix_0(" 0", &u) >= 0);
75 assert_se(u == USEC_INFINITY);
76 }
77
78 static void test_parse_time(void) {
79 usec_t u;
80
81 assert_se(parse_time("5", &u, 1) >= 0);
82 assert_se(u == 5);
83
84 assert_se(parse_time("5", &u, USEC_PER_MSEC) >= 0);
85 assert_se(u == 5 * USEC_PER_MSEC);
86
87 assert_se(parse_time("5", &u, USEC_PER_SEC) >= 0);
88 assert_se(u == 5 * USEC_PER_SEC);
89
90 assert_se(parse_time("5s", &u, 1) >= 0);
91 assert_se(u == 5 * USEC_PER_SEC);
92
93 assert_se(parse_time("5s", &u, USEC_PER_SEC) >= 0);
94 assert_se(u == 5 * USEC_PER_SEC);
95
96 assert_se(parse_time("5s", &u, USEC_PER_MSEC) >= 0);
97 assert_se(u == 5 * USEC_PER_SEC);
98 }
99
100 static void test_parse_nsec(void) {
101 nsec_t u;
102
103 assert_se(parse_nsec("5s", &u) >= 0);
104 assert_se(u == 5 * NSEC_PER_SEC);
105 assert_se(parse_nsec("5s500ms", &u) >= 0);
106 assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC);
107 assert_se(parse_nsec(" 5s 500ms ", &u) >= 0);
108 assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC);
109 assert_se(parse_nsec(" 5.5s ", &u) >= 0);
110 assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC);
111 assert_se(parse_nsec(" 5.5s 0.5ms ", &u) >= 0);
112 assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC + 500 * NSEC_PER_USEC);
113 assert_se(parse_nsec(" .22s ", &u) >= 0);
114 assert_se(u == 220 * NSEC_PER_MSEC);
115 assert_se(parse_nsec(" .50y ", &u) >= 0);
116 assert_se(u == NSEC_PER_YEAR / 2);
117 assert_se(parse_nsec("2.5", &u) >= 0);
118 assert_se(u == 2);
119 assert_se(parse_nsec(".7", &u) >= 0);
120 assert_se(u == 0);
121 assert_se(parse_nsec("infinity", &u) >= 0);
122 assert_se(u == NSEC_INFINITY);
123 assert_se(parse_nsec(" infinity ", &u) >= 0);
124 assert_se(u == NSEC_INFINITY);
125
126 assert_se(parse_nsec(" xyz ", &u) < 0);
127 assert_se(parse_nsec("", &u) < 0);
128 assert_se(parse_nsec(" . ", &u) < 0);
129 assert_se(parse_nsec(" 5. ", &u) < 0);
130 assert_se(parse_nsec(".s ", &u) < 0);
131 assert_se(parse_nsec(" infinity .7", &u) < 0);
132 assert_se(parse_nsec(".3 infinity", &u) < 0);
133 }
134
135 static void test_format_timespan_one(usec_t x, usec_t accuracy) {
136 char *r;
137 char l[FORMAT_TIMESPAN_MAX];
138 usec_t y;
139
140 log_info(USEC_FMT" (at accuracy "USEC_FMT")", x, accuracy);
141
142 r = format_timespan(l, sizeof(l), x, accuracy);
143 assert_se(r);
144
145 log_info(" = <%s>", l);
146
147 assert_se(parse_sec(l, &y) >= 0);
148
149 log_info(" = "USEC_FMT, y);
150
151 if (accuracy <= 0)
152 accuracy = 1;
153
154 assert_se(x / accuracy == y / accuracy);
155 }
156
157 static void test_format_timespan(usec_t accuracy) {
158 test_format_timespan_one(0, accuracy);
159 test_format_timespan_one(1, accuracy);
160 test_format_timespan_one(1*USEC_PER_SEC, accuracy);
161 test_format_timespan_one(999*USEC_PER_MSEC, accuracy);
162 test_format_timespan_one(1234567, accuracy);
163 test_format_timespan_one(12, accuracy);
164 test_format_timespan_one(123, accuracy);
165 test_format_timespan_one(1234, accuracy);
166 test_format_timespan_one(12345, accuracy);
167 test_format_timespan_one(123456, accuracy);
168 test_format_timespan_one(1234567, accuracy);
169 test_format_timespan_one(12345678, accuracy);
170 test_format_timespan_one(1200000, accuracy);
171 test_format_timespan_one(1230000, accuracy);
172 test_format_timespan_one(1230000, accuracy);
173 test_format_timespan_one(1234000, accuracy);
174 test_format_timespan_one(1234500, accuracy);
175 test_format_timespan_one(1234560, accuracy);
176 test_format_timespan_one(1234567, accuracy);
177 test_format_timespan_one(986087, accuracy);
178 test_format_timespan_one(500 * USEC_PER_MSEC, accuracy);
179 test_format_timespan_one(9*USEC_PER_YEAR/5 - 23, accuracy);
180 test_format_timespan_one(USEC_INFINITY, accuracy);
181 }
182
183 static void test_timezone_is_valid(void) {
184 assert_se(timezone_is_valid("Europe/Berlin"));
185 assert_se(timezone_is_valid("Australia/Sydney"));
186 assert_se(!timezone_is_valid("Europe/Do not exist"));
187 }
188
189 static void test_get_timezones(void) {
190 _cleanup_strv_free_ char **zones = NULL;
191 int r;
192 char **zone;
193
194 r = get_timezones(&zones);
195 assert_se(r == 0);
196
197 STRV_FOREACH(zone, zones)
198 assert_se(timezone_is_valid(*zone));
199 }
200
201 static void test_usec_add(void) {
202 assert_se(usec_add(0, 0) == 0);
203 assert_se(usec_add(1, 4) == 5);
204 assert_se(usec_add(USEC_INFINITY, 5) == USEC_INFINITY);
205 assert_se(usec_add(5, USEC_INFINITY) == USEC_INFINITY);
206 assert_se(usec_add(USEC_INFINITY-5, 2) == USEC_INFINITY-3);
207 assert_se(usec_add(USEC_INFINITY-2, 2) == USEC_INFINITY);
208 assert_se(usec_add(USEC_INFINITY-1, 2) == USEC_INFINITY);
209 assert_se(usec_add(USEC_INFINITY, 2) == USEC_INFINITY);
210 }
211
212 static void test_usec_sub_unsigned(void) {
213 assert_se(usec_sub_unsigned(0, 0) == 0);
214 assert_se(usec_sub_unsigned(0, 2) == 0);
215 assert_se(usec_sub_unsigned(0, USEC_INFINITY) == 0);
216 assert_se(usec_sub_unsigned(1, 0) == 1);
217 assert_se(usec_sub_unsigned(1, 1) == 0);
218 assert_se(usec_sub_unsigned(1, 2) == 0);
219 assert_se(usec_sub_unsigned(1, 3) == 0);
220 assert_se(usec_sub_unsigned(1, USEC_INFINITY) == 0);
221 assert_se(usec_sub_unsigned(USEC_INFINITY-1, 0) == USEC_INFINITY-1);
222 assert_se(usec_sub_unsigned(USEC_INFINITY-1, 1) == USEC_INFINITY-2);
223 assert_se(usec_sub_unsigned(USEC_INFINITY-1, 2) == USEC_INFINITY-3);
224 assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY-2) == 1);
225 assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY-1) == 0);
226 assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY) == 0);
227 assert_se(usec_sub_unsigned(USEC_INFINITY, 0) == USEC_INFINITY);
228 assert_se(usec_sub_unsigned(USEC_INFINITY, 1) == USEC_INFINITY);
229 assert_se(usec_sub_unsigned(USEC_INFINITY, 2) == USEC_INFINITY);
230 assert_se(usec_sub_unsigned(USEC_INFINITY, USEC_INFINITY) == USEC_INFINITY);
231 }
232
233 static void test_usec_sub_signed(void) {
234 assert_se(usec_sub_signed(0, 0) == 0);
235 assert_se(usec_sub_signed(4, 1) == 3);
236 assert_se(usec_sub_signed(4, 4) == 0);
237 assert_se(usec_sub_signed(4, 5) == 0);
238 assert_se(usec_sub_signed(USEC_INFINITY-3, -3) == USEC_INFINITY);
239 assert_se(usec_sub_signed(USEC_INFINITY-3, -3) == USEC_INFINITY);
240 assert_se(usec_sub_signed(USEC_INFINITY-3, -4) == USEC_INFINITY);
241 assert_se(usec_sub_signed(USEC_INFINITY-3, -5) == USEC_INFINITY);
242 assert_se(usec_sub_signed(USEC_INFINITY, 5) == USEC_INFINITY);
243 }
244
245 static void test_format_timestamp(void) {
246 unsigned i;
247
248 for (i = 0; i < 100; i++) {
249 char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
250 usec_t x, y;
251
252 random_bytes(&x, sizeof(x));
253 x = x % (2147483600 * USEC_PER_SEC) + 1;
254
255 assert_se(format_timestamp(buf, sizeof(buf), x));
256 log_info("%s", buf);
257 assert_se(parse_timestamp(buf, &y) >= 0);
258 assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
259
260 assert_se(format_timestamp_utc(buf, sizeof(buf), x));
261 log_info("%s", buf);
262 assert_se(parse_timestamp(buf, &y) >= 0);
263 assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
264
265 assert_se(format_timestamp_us(buf, sizeof(buf), x));
266 log_info("%s", buf);
267 assert_se(parse_timestamp(buf, &y) >= 0);
268 assert_se(x == y);
269
270 assert_se(format_timestamp_us_utc(buf, sizeof(buf), x));
271 log_info("%s", buf);
272 assert_se(parse_timestamp(buf, &y) >= 0);
273 assert_se(x == y);
274
275 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
276 log_info("%s", buf);
277 assert_se(parse_timestamp(buf, &y) >= 0);
278
279 /* The two calls above will run with a slightly different local time. Make sure we are in the same
280 * range however, but give enough leeway that this is unlikely to explode. And of course,
281 * format_timestamp_relative() scales the accuracy with the distance from the current time up to one
282 * month, cover for that too. */
283 assert_se(y > x ? y - x : x - y <= USEC_PER_MONTH + USEC_PER_DAY);
284 }
285 }
286
287 static void test_format_timestamp_utc_one(usec_t t, const char *result) {
288 char buf[FORMAT_TIMESTAMP_MAX];
289
290 assert_se(!format_timestamp_utc(buf, sizeof(buf), t) == !result);
291
292 if (result)
293 assert_se(streq(result, buf));
294 }
295
296 static void test_format_timestamp_utc(void) {
297 test_format_timestamp_utc_one(0, NULL);
298 test_format_timestamp_utc_one(1, "Thu 1970-01-01 00:00:00 UTC");
299 test_format_timestamp_utc_one(USEC_PER_SEC, "Thu 1970-01-01 00:00:01 UTC");
300
301 #if SIZEOF_TIME_T == 8
302 test_format_timestamp_utc_one(USEC_TIMESTAMP_FORMATTABLE_MAX, "Thu 9999-12-30 23:59:59 UTC");
303 #elif SIZEOF_TIME_T == 4
304 test_format_timestamp_utc_one(USEC_TIMESTAMP_FORMATTABLE_MAX, "Tue 2038-01-19 03:14:07 UTC");
305 #endif
306
307 test_format_timestamp_utc_one(USEC_TIMESTAMP_FORMATTABLE_MAX+1, NULL);
308 test_format_timestamp_utc_one(USEC_INFINITY, NULL);
309 }
310
311 static void test_dual_timestamp_deserialize(void) {
312 int r;
313 dual_timestamp t;
314
315 r = dual_timestamp_deserialize("1234 5678", &t);
316 assert_se(r == 0);
317 assert_se(t.realtime == 1234);
318 assert_se(t.monotonic == 5678);
319
320 r = dual_timestamp_deserialize("1234x 5678", &t);
321 assert_se(r == -EINVAL);
322
323 r = dual_timestamp_deserialize("1234 5678y", &t);
324 assert_se(r == -EINVAL);
325
326 r = dual_timestamp_deserialize("-1234 5678", &t);
327 assert_se(r == -EINVAL);
328
329 r = dual_timestamp_deserialize("1234 -5678", &t);
330 assert_se(r == -EINVAL);
331
332 /* Check that output wasn't modified. */
333 assert_se(t.realtime == 1234);
334 assert_se(t.monotonic == 5678);
335
336 r = dual_timestamp_deserialize("+123 567", &t);
337 assert_se(r == 0);
338 assert_se(t.realtime == 123);
339 assert_se(t.monotonic == 567);
340
341 /* Check that we get "infinity" on overflow. */
342 r = dual_timestamp_deserialize("18446744073709551617 0", &t);
343 assert_se(r == 0);
344 assert_se(t.realtime == USEC_INFINITY);
345 assert_se(t.monotonic == 0);
346 }
347
348 static void assert_similar(usec_t a, usec_t b) {
349 usec_t d;
350
351 if (a > b)
352 d = a - b;
353 else
354 d = b - a;
355
356 assert(d < 10*USEC_PER_SEC);
357 }
358
359 static void test_usec_shift_clock(void) {
360 usec_t rt, mn, bt;
361
362 rt = now(CLOCK_REALTIME);
363 mn = now(CLOCK_MONOTONIC);
364 bt = now(clock_boottime_or_monotonic());
365
366 assert_se(usec_shift_clock(USEC_INFINITY, CLOCK_REALTIME, CLOCK_MONOTONIC) == USEC_INFINITY);
367
368 assert_similar(usec_shift_clock(rt + USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_MONOTONIC), mn + USEC_PER_HOUR);
369 assert_similar(usec_shift_clock(rt + 2*USEC_PER_HOUR, CLOCK_REALTIME, clock_boottime_or_monotonic()), bt + 2*USEC_PER_HOUR);
370 assert_se(usec_shift_clock(rt + 3*USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_REALTIME_ALARM) == rt + 3*USEC_PER_HOUR);
371
372 assert_similar(usec_shift_clock(mn + 4*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_REALTIME_ALARM), rt + 4*USEC_PER_HOUR);
373 assert_similar(usec_shift_clock(mn + 5*USEC_PER_HOUR, CLOCK_MONOTONIC, clock_boottime_or_monotonic()), bt + 5*USEC_PER_HOUR);
374 assert_se(usec_shift_clock(mn + 6*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_MONOTONIC) == mn + 6*USEC_PER_HOUR);
375
376 assert_similar(usec_shift_clock(bt + 7*USEC_PER_HOUR, clock_boottime_or_monotonic(), CLOCK_MONOTONIC), mn + 7*USEC_PER_HOUR);
377 assert_similar(usec_shift_clock(bt + 8*USEC_PER_HOUR, clock_boottime_or_monotonic(), CLOCK_REALTIME_ALARM), rt + 8*USEC_PER_HOUR);
378 assert_se(usec_shift_clock(bt + 9*USEC_PER_HOUR, clock_boottime_or_monotonic(), clock_boottime_or_monotonic()) == bt + 9*USEC_PER_HOUR);
379
380 if (mn > USEC_PER_MINUTE) {
381 assert_similar(usec_shift_clock(rt - 30 * USEC_PER_SEC, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC), mn - 30 * USEC_PER_SEC);
382 assert_similar(usec_shift_clock(rt - 50 * USEC_PER_SEC, CLOCK_REALTIME, clock_boottime_or_monotonic()), bt - 50 * USEC_PER_SEC);
383 }
384 }
385
386 int main(int argc, char *argv[]) {
387 uintmax_t x;
388
389 log_info("realtime=" USEC_FMT "\n"
390 "monotonic=" USEC_FMT "\n"
391 "boottime=" USEC_FMT "\n",
392 now(CLOCK_REALTIME),
393 now(CLOCK_MONOTONIC),
394 now(clock_boottime_or_monotonic()));
395
396 test_parse_sec();
397 test_parse_sec_fix_0();
398 test_parse_time();
399 test_parse_nsec();
400 test_format_timespan(1);
401 test_format_timespan(USEC_PER_MSEC);
402 test_format_timespan(USEC_PER_SEC);
403 test_timezone_is_valid();
404 test_get_timezones();
405 test_usec_add();
406 test_usec_sub_signed();
407 test_usec_sub_unsigned();
408 test_format_timestamp();
409 test_format_timestamp_utc();
410 test_dual_timestamp_deserialize();
411 test_usec_shift_clock();
412
413 /* Ensure time_t is signed */
414 assert_cc((time_t) -1 < (time_t) 1);
415
416 /* Ensure TIME_T_MAX works correctly */
417 x = (uintmax_t) TIME_T_MAX;
418 x++;
419 assert((time_t) x < 0);
420
421 return 0;
422 }