]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
cb0dac05 | 2 | |
fa34123c | 3 | #include <stdlib.h> |
4d5ad9d9 | 4 | #include "env-util.h" |
1bb4b028 | 5 | #include "random-util.h" |
d68c645b | 6 | #include "serialize.h" |
1bb4b028 | 7 | #include "string-util.h" |
6accc7a2 | 8 | #include "strv.h" |
f0e2e0db | 9 | #include "tests.h" |
cf0fbc49 | 10 | #include "time-util.h" |
cb0dac05 | 11 | |
8b51c41f YW |
12 | #define TRIAL 100u |
13 | ||
4f7452a8 | 14 | TEST(parse_sec) { |
cb0dac05 LP |
15 | usec_t u; |
16 | ||
17 | assert_se(parse_sec("5s", &u) >= 0); | |
18 | assert_se(u == 5 * USEC_PER_SEC); | |
19 | assert_se(parse_sec("5s500ms", &u) >= 0); | |
20 | assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC); | |
21 | assert_se(parse_sec(" 5s 500ms ", &u) >= 0); | |
22 | assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC); | |
23 | assert_se(parse_sec(" 5.5s ", &u) >= 0); | |
24 | assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC); | |
25 | assert_se(parse_sec(" 5.5s 0.5ms ", &u) >= 0); | |
26 | assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC + 500); | |
27 | assert_se(parse_sec(" .22s ", &u) >= 0); | |
28 | assert_se(u == 220 * USEC_PER_MSEC); | |
29 | assert_se(parse_sec(" .50y ", &u) >= 0); | |
30 | assert_se(u == USEC_PER_YEAR / 2); | |
31 | assert_se(parse_sec("2.5", &u) >= 0); | |
32 | assert_se(u == 2500 * USEC_PER_MSEC); | |
33 | assert_se(parse_sec(".7", &u) >= 0); | |
34 | assert_se(u == 700 * USEC_PER_MSEC); | |
5efdbf11 LP |
35 | assert_se(parse_sec("23us", &u) >= 0); |
36 | assert_se(u == 23); | |
d0a6d7c4 LP |
37 | assert_se(parse_sec("23μs", &u) >= 0); /* greek small letter mu */ |
38 | assert_se(u == 23); | |
39 | assert_se(parse_sec("23µs", &u) >= 0); /* micro symbol */ | |
5efdbf11 | 40 | assert_se(u == 23); |
b1d6dcf5 ZJS |
41 | assert_se(parse_sec("infinity", &u) >= 0); |
42 | assert_se(u == USEC_INFINITY); | |
43 | assert_se(parse_sec(" infinity ", &u) >= 0); | |
44 | assert_se(u == USEC_INFINITY); | |
279f52a1 FB |
45 | assert_se(parse_sec("+3.1s", &u) >= 0); |
46 | assert_se(u == 3100 * USEC_PER_MSEC); | |
ed2e7967 YW |
47 | assert_se(parse_sec("3.1s.2", &u) >= 0); |
48 | assert_se(u == 3300 * USEC_PER_MSEC); | |
49 | assert_se(parse_sec("3.1 .2", &u) >= 0); | |
50 | assert_se(u == 3300 * USEC_PER_MSEC); | |
51 | assert_se(parse_sec("3.1 sec .2 sec", &u) >= 0); | |
52 | assert_se(u == 3300 * USEC_PER_MSEC); | |
53 | assert_se(parse_sec("3.1 sec 1.2 sec", &u) >= 0); | |
54 | assert_se(u == 4300 * USEC_PER_MSEC); | |
cb0dac05 LP |
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); | |
5a9fb358 LP |
61 | assert_se(parse_sec("-5s ", &u) < 0); |
62 | assert_se(parse_sec("-0.3s ", &u) < 0); | |
63 | assert_se(parse_sec("-0.0s ", &u) < 0); | |
64 | assert_se(parse_sec("-0.-0s ", &u) < 0); | |
65 | assert_se(parse_sec("0.-0s ", &u) < 0); | |
66 | assert_se(parse_sec("3.-0s ", &u) < 0); | |
b1d6dcf5 ZJS |
67 | assert_se(parse_sec(" infinity .7", &u) < 0); |
68 | assert_se(parse_sec(".3 infinity", &u) < 0); | |
279f52a1 FB |
69 | assert_se(parse_sec("3.+1s", &u) < 0); |
70 | assert_se(parse_sec("3. 1s", &u) < 0); | |
71 | assert_se(parse_sec("3.s", &u) < 0); | |
ed2e7967 YW |
72 | assert_se(parse_sec("12.34.56", &u) < 0); |
73 | assert_se(parse_sec("12..34", &u) < 0); | |
74 | assert_se(parse_sec("..1234", &u) < 0); | |
75 | assert_se(parse_sec("1234..", &u) < 0); | |
cb0dac05 LP |
76 | } |
77 | ||
4f7452a8 | 78 | TEST(parse_sec_fix_0) { |
0004f698 ZJS |
79 | usec_t u; |
80 | ||
81 | assert_se(parse_sec_fix_0("5s", &u) >= 0); | |
82 | assert_se(u == 5 * USEC_PER_SEC); | |
83 | assert_se(parse_sec_fix_0("0s", &u) >= 0); | |
def34f63 | 84 | assert_se(u == USEC_INFINITY); |
0004f698 ZJS |
85 | assert_se(parse_sec_fix_0("0", &u) >= 0); |
86 | assert_se(u == USEC_INFINITY); | |
87 | assert_se(parse_sec_fix_0(" 0", &u) >= 0); | |
88 | assert_se(u == USEC_INFINITY); | |
89 | } | |
90 | ||
4f7452a8 | 91 | TEST(parse_sec_def_infinity) { |
7b61ce3c FB |
92 | usec_t u; |
93 | ||
7b61ce3c FB |
94 | assert_se(parse_sec_def_infinity("5s", &u) >= 0); |
95 | assert_se(u == 5 * USEC_PER_SEC); | |
96 | assert_se(parse_sec_def_infinity("", &u) >= 0); | |
97 | assert_se(u == USEC_INFINITY); | |
98 | assert_se(parse_sec_def_infinity(" ", &u) >= 0); | |
99 | assert_se(u == USEC_INFINITY); | |
100 | assert_se(parse_sec_def_infinity("0s", &u) >= 0); | |
101 | assert_se(u == 0); | |
102 | assert_se(parse_sec_def_infinity("0", &u) >= 0); | |
103 | assert_se(u == 0); | |
104 | assert_se(parse_sec_def_infinity(" 0", &u) >= 0); | |
105 | assert_se(u == 0); | |
106 | assert_se(parse_sec_def_infinity("-5s", &u) < 0); | |
107 | } | |
108 | ||
4f7452a8 | 109 | TEST(parse_time) { |
519cffec LP |
110 | usec_t u; |
111 | ||
112 | assert_se(parse_time("5", &u, 1) >= 0); | |
113 | assert_se(u == 5); | |
114 | ||
115 | assert_se(parse_time("5", &u, USEC_PER_MSEC) >= 0); | |
116 | assert_se(u == 5 * USEC_PER_MSEC); | |
117 | ||
118 | assert_se(parse_time("5", &u, USEC_PER_SEC) >= 0); | |
119 | assert_se(u == 5 * USEC_PER_SEC); | |
120 | ||
121 | assert_se(parse_time("5s", &u, 1) >= 0); | |
122 | assert_se(u == 5 * USEC_PER_SEC); | |
123 | ||
124 | assert_se(parse_time("5s", &u, USEC_PER_SEC) >= 0); | |
125 | assert_se(u == 5 * USEC_PER_SEC); | |
126 | ||
127 | assert_se(parse_time("5s", &u, USEC_PER_MSEC) >= 0); | |
128 | assert_se(u == 5 * USEC_PER_SEC); | |
db4e6107 YW |
129 | |
130 | assert_se(parse_time("11111111111111y", &u, 1) == -ERANGE); | |
ed2e7967 | 131 | assert_se(parse_time("1.1111111111111y", &u, 1) >= 0); |
519cffec LP |
132 | } |
133 | ||
4f7452a8 | 134 | TEST(parse_nsec) { |
cb0dac05 LP |
135 | nsec_t u; |
136 | ||
137 | assert_se(parse_nsec("5s", &u) >= 0); | |
138 | assert_se(u == 5 * NSEC_PER_SEC); | |
139 | assert_se(parse_nsec("5s500ms", &u) >= 0); | |
140 | assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC); | |
141 | assert_se(parse_nsec(" 5s 500ms ", &u) >= 0); | |
142 | assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC); | |
143 | assert_se(parse_nsec(" 5.5s ", &u) >= 0); | |
144 | assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC); | |
145 | assert_se(parse_nsec(" 5.5s 0.5ms ", &u) >= 0); | |
146 | assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC + 500 * NSEC_PER_USEC); | |
147 | assert_se(parse_nsec(" .22s ", &u) >= 0); | |
148 | assert_se(u == 220 * NSEC_PER_MSEC); | |
149 | assert_se(parse_nsec(" .50y ", &u) >= 0); | |
150 | assert_se(u == NSEC_PER_YEAR / 2); | |
151 | assert_se(parse_nsec("2.5", &u) >= 0); | |
152 | assert_se(u == 2); | |
153 | assert_se(parse_nsec(".7", &u) >= 0); | |
154 | assert_se(u == 0); | |
fdd30a15 DM |
155 | assert_se(parse_nsec("infinity", &u) >= 0); |
156 | assert_se(u == NSEC_INFINITY); | |
157 | assert_se(parse_nsec(" infinity ", &u) >= 0); | |
158 | assert_se(u == NSEC_INFINITY); | |
279f52a1 FB |
159 | assert_se(parse_nsec("+3.1s", &u) >= 0); |
160 | assert_se(u == 3100 * NSEC_PER_MSEC); | |
ed2e7967 YW |
161 | assert_se(parse_nsec("3.1s.2", &u) >= 0); |
162 | assert_se(u == 3100 * NSEC_PER_MSEC); | |
163 | assert_se(parse_nsec("3.1 .2s", &u) >= 0); | |
164 | assert_se(u == 200 * NSEC_PER_MSEC + 3); | |
165 | assert_se(parse_nsec("3.1 sec .2 sec", &u) >= 0); | |
166 | assert_se(u == 3300 * NSEC_PER_MSEC); | |
167 | assert_se(parse_nsec("3.1 sec 1.2 sec", &u) >= 0); | |
168 | assert_se(u == 4300 * NSEC_PER_MSEC); | |
cb0dac05 LP |
169 | |
170 | assert_se(parse_nsec(" xyz ", &u) < 0); | |
171 | assert_se(parse_nsec("", &u) < 0); | |
172 | assert_se(parse_nsec(" . ", &u) < 0); | |
173 | assert_se(parse_nsec(" 5. ", &u) < 0); | |
174 | assert_se(parse_nsec(".s ", &u) < 0); | |
fdd30a15 DM |
175 | assert_se(parse_nsec(" infinity .7", &u) < 0); |
176 | assert_se(parse_nsec(".3 infinity", &u) < 0); | |
279f52a1 FB |
177 | assert_se(parse_nsec("-5s ", &u) < 0); |
178 | assert_se(parse_nsec("-0.3s ", &u) < 0); | |
179 | assert_se(parse_nsec("-0.0s ", &u) < 0); | |
180 | assert_se(parse_nsec("-0.-0s ", &u) < 0); | |
181 | assert_se(parse_nsec("0.-0s ", &u) < 0); | |
182 | assert_se(parse_nsec("3.-0s ", &u) < 0); | |
183 | assert_se(parse_nsec(" infinity .7", &u) < 0); | |
184 | assert_se(parse_nsec(".3 infinity", &u) < 0); | |
185 | assert_se(parse_nsec("3.+1s", &u) < 0); | |
186 | assert_se(parse_nsec("3. 1s", &u) < 0); | |
187 | assert_se(parse_nsec("3.s", &u) < 0); | |
ed2e7967 YW |
188 | assert_se(parse_nsec("12.34.56", &u) < 0); |
189 | assert_se(parse_nsec("12..34", &u) < 0); | |
190 | assert_se(parse_nsec("..1234", &u) < 0); | |
191 | assert_se(parse_nsec("1234..", &u) < 0); | |
db4e6107 | 192 | assert_se(parse_nsec("1111111111111y", &u) == -ERANGE); |
ed2e7967 | 193 | assert_se(parse_nsec("1.111111111111y", &u) >= 0); |
cb0dac05 LP |
194 | } |
195 | ||
2fa4092c | 196 | static void test_format_timespan_one(usec_t x, usec_t accuracy) { |
2fa4092c | 197 | char l[FORMAT_TIMESPAN_MAX]; |
4d9685be | 198 | const char *t; |
2fa4092c LP |
199 | usec_t y; |
200 | ||
41bc83ed | 201 | log_debug(USEC_FMT" (at accuracy "USEC_FMT")", x, accuracy); |
2fa4092c | 202 | |
4d9685be | 203 | assert_se(t = format_timespan(l, sizeof l, x, accuracy)); |
41bc83ed | 204 | log_debug(" = <%s>", t); |
2fa4092c | 205 | |
4d9685be | 206 | assert_se(parse_sec(t, &y) >= 0); |
41bc83ed | 207 | log_debug(" = "USEC_FMT, y); |
2fa4092c LP |
208 | |
209 | if (accuracy <= 0) | |
210 | accuracy = 1; | |
211 | ||
212 | assert_se(x / accuracy == y / accuracy); | |
213 | } | |
214 | ||
4f7452a8 | 215 | static void test_format_timespan_accuracy(usec_t accuracy) { |
f1880a4b ZJS |
216 | log_info("/* %s accuracy="USEC_FMT" */", __func__, accuracy); |
217 | ||
2fa4092c LP |
218 | test_format_timespan_one(0, accuracy); |
219 | test_format_timespan_one(1, accuracy); | |
220 | test_format_timespan_one(1*USEC_PER_SEC, accuracy); | |
221 | test_format_timespan_one(999*USEC_PER_MSEC, accuracy); | |
222 | test_format_timespan_one(1234567, accuracy); | |
223 | test_format_timespan_one(12, accuracy); | |
224 | test_format_timespan_one(123, accuracy); | |
225 | test_format_timespan_one(1234, accuracy); | |
226 | test_format_timespan_one(12345, accuracy); | |
227 | test_format_timespan_one(123456, accuracy); | |
228 | test_format_timespan_one(1234567, accuracy); | |
229 | test_format_timespan_one(12345678, accuracy); | |
230 | test_format_timespan_one(1200000, accuracy); | |
231 | test_format_timespan_one(1230000, accuracy); | |
2fa4092c LP |
232 | test_format_timespan_one(1234000, accuracy); |
233 | test_format_timespan_one(1234500, accuracy); | |
234 | test_format_timespan_one(1234560, accuracy); | |
235 | test_format_timespan_one(1234567, accuracy); | |
236 | test_format_timespan_one(986087, accuracy); | |
237 | test_format_timespan_one(500 * USEC_PER_MSEC, accuracy); | |
238 | test_format_timespan_one(9*USEC_PER_YEAR/5 - 23, accuracy); | |
b1d6dcf5 | 239 | test_format_timespan_one(USEC_INFINITY, accuracy); |
2fa4092c LP |
240 | } |
241 | ||
4f7452a8 JJ |
242 | TEST(format_timespan) { |
243 | test_format_timespan_accuracy(1); | |
244 | test_format_timespan_accuracy(USEC_PER_MSEC); | |
245 | test_format_timespan_accuracy(USEC_PER_SEC); | |
9102c625 YW |
246 | |
247 | /* See issue #23928. */ | |
3d41b6b8 | 248 | _cleanup_free_ char *buf = NULL; |
9102c625 YW |
249 | assert_se(buf = new(char, 5)); |
250 | assert_se(buf == format_timespan(buf, 5, 100005, 1000)); | |
4f7452a8 | 251 | } |
bdaeafea | 252 | |
4f7452a8 | 253 | TEST(verify_timezone) { |
bdaeafea ZJS |
254 | assert_se(verify_timezone("Europe/Berlin", LOG_DEBUG) == 0); |
255 | assert_se(verify_timezone("Australia/Sydney", LOG_DEBUG) == 0); | |
256 | assert_se(verify_timezone("Europe/Do not exist", LOG_DEBUG) == -EINVAL); | |
257 | assert_se(verify_timezone("Europe/DoNotExist", LOG_DEBUG) == -ENOENT); | |
258 | assert_se(verify_timezone("/DoNotExist", LOG_DEBUG) == -EINVAL); | |
259 | assert_se(verify_timezone("DoNotExist/", LOG_DEBUG) == -EINVAL); | |
260 | } | |
261 | ||
4f7452a8 | 262 | TEST(timezone_is_valid) { |
089fb865 MG |
263 | assert_se(timezone_is_valid("Europe/Berlin", LOG_ERR)); |
264 | assert_se(timezone_is_valid("Australia/Sydney", LOG_ERR)); | |
265 | assert_se(!timezone_is_valid("Europe/Do not exist", LOG_ERR)); | |
6accc7a2 RC |
266 | } |
267 | ||
4f7452a8 | 268 | TEST(get_timezones) { |
6accc7a2 RC |
269 | _cleanup_strv_free_ char **zones = NULL; |
270 | int r; | |
6accc7a2 RC |
271 | |
272 | r = get_timezones(&zones); | |
273 | assert_se(r == 0); | |
274 | ||
f0e2e0db | 275 | STRV_FOREACH(zone, zones) { |
dc9849b1 ZJS |
276 | r = verify_timezone(*zone, LOG_ERR); |
277 | log_debug_errno(r, "verify_timezone(\"%s\"): %m", *zone); | |
278 | assert_se(r >= 0 || r == -ENOENT); | |
f0e2e0db | 279 | } |
53f555b6 LP |
280 | } |
281 | ||
4f7452a8 | 282 | TEST(usec_add) { |
53f555b6 LP |
283 | assert_se(usec_add(0, 0) == 0); |
284 | assert_se(usec_add(1, 4) == 5); | |
285 | assert_se(usec_add(USEC_INFINITY, 5) == USEC_INFINITY); | |
286 | assert_se(usec_add(5, USEC_INFINITY) == USEC_INFINITY); | |
287 | assert_se(usec_add(USEC_INFINITY-5, 2) == USEC_INFINITY-3); | |
288 | assert_se(usec_add(USEC_INFINITY-2, 2) == USEC_INFINITY); | |
289 | assert_se(usec_add(USEC_INFINITY-1, 2) == USEC_INFINITY); | |
290 | assert_se(usec_add(USEC_INFINITY, 2) == USEC_INFINITY); | |
6accc7a2 RC |
291 | } |
292 | ||
4f7452a8 | 293 | TEST(usec_sub_unsigned) { |
54d8ef14 LP |
294 | assert_se(usec_sub_unsigned(0, 0) == 0); |
295 | assert_se(usec_sub_unsigned(0, 2) == 0); | |
296 | assert_se(usec_sub_unsigned(0, USEC_INFINITY) == 0); | |
297 | assert_se(usec_sub_unsigned(1, 0) == 1); | |
298 | assert_se(usec_sub_unsigned(1, 1) == 0); | |
299 | assert_se(usec_sub_unsigned(1, 2) == 0); | |
300 | assert_se(usec_sub_unsigned(1, 3) == 0); | |
301 | assert_se(usec_sub_unsigned(1, USEC_INFINITY) == 0); | |
302 | assert_se(usec_sub_unsigned(USEC_INFINITY-1, 0) == USEC_INFINITY-1); | |
303 | assert_se(usec_sub_unsigned(USEC_INFINITY-1, 1) == USEC_INFINITY-2); | |
304 | assert_se(usec_sub_unsigned(USEC_INFINITY-1, 2) == USEC_INFINITY-3); | |
305 | assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY-2) == 1); | |
306 | assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY-1) == 0); | |
307 | assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY) == 0); | |
308 | assert_se(usec_sub_unsigned(USEC_INFINITY, 0) == USEC_INFINITY); | |
309 | assert_se(usec_sub_unsigned(USEC_INFINITY, 1) == USEC_INFINITY); | |
310 | assert_se(usec_sub_unsigned(USEC_INFINITY, 2) == USEC_INFINITY); | |
311 | assert_se(usec_sub_unsigned(USEC_INFINITY, USEC_INFINITY) == USEC_INFINITY); | |
312 | } | |
313 | ||
4f7452a8 | 314 | TEST(usec_sub_signed) { |
54d8ef14 LP |
315 | assert_se(usec_sub_signed(0, 0) == 0); |
316 | assert_se(usec_sub_signed(4, 1) == 3); | |
317 | assert_se(usec_sub_signed(4, 4) == 0); | |
318 | assert_se(usec_sub_signed(4, 5) == 0); | |
782c6e5c | 319 | |
54d8ef14 | 320 | assert_se(usec_sub_signed(USEC_INFINITY-3, -3) == USEC_INFINITY); |
54d8ef14 LP |
321 | assert_se(usec_sub_signed(USEC_INFINITY-3, -4) == USEC_INFINITY); |
322 | assert_se(usec_sub_signed(USEC_INFINITY-3, -5) == USEC_INFINITY); | |
323 | assert_se(usec_sub_signed(USEC_INFINITY, 5) == USEC_INFINITY); | |
782c6e5c LP |
324 | |
325 | assert_se(usec_sub_signed(0, INT64_MAX) == 0); | |
326 | assert_se(usec_sub_signed(0, -INT64_MAX) == INT64_MAX); | |
327 | assert_se(usec_sub_signed(0, INT64_MIN) == (usec_t) INT64_MAX + 1); | |
328 | assert_se(usec_sub_signed(0, -(INT64_MIN+1)) == 0); | |
329 | ||
330 | assert_se(usec_sub_signed(USEC_INFINITY, INT64_MAX) == USEC_INFINITY); | |
331 | assert_se(usec_sub_signed(USEC_INFINITY, -INT64_MAX) == USEC_INFINITY); | |
332 | assert_se(usec_sub_signed(USEC_INFINITY, INT64_MIN) == USEC_INFINITY); | |
333 | assert_se(usec_sub_signed(USEC_INFINITY, -(INT64_MIN+1)) == USEC_INFINITY); | |
334 | ||
335 | assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MAX) == USEC_INFINITY-1-INT64_MAX); | |
336 | assert_se(usec_sub_signed(USEC_INFINITY-1, -INT64_MAX) == USEC_INFINITY); | |
337 | assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MIN) == USEC_INFINITY); | |
338 | assert_se(usec_sub_signed(USEC_INFINITY-1, -(INT64_MIN+1)) == USEC_INFINITY-1-((usec_t) (-(INT64_MIN+1)))); | |
04a1d84c LP |
339 | } |
340 | ||
4f7452a8 | 341 | TEST(format_timestamp) { |
8b51c41f | 342 | for (unsigned i = 0; i < TRIAL; i++) { |
89eb3d7c | 343 | char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)]; |
21b3a0fc LP |
344 | usec_t x, y; |
345 | ||
8b51c41f | 346 | x = random_u64_range(USEC_TIMESTAMP_FORMATTABLE_MAX - USEC_PER_SEC) + USEC_PER_SEC; |
21b3a0fc LP |
347 | |
348 | assert_se(format_timestamp(buf, sizeof(buf), x)); | |
41bc83ed | 349 | log_debug("%s", buf); |
21b3a0fc LP |
350 | assert_se(parse_timestamp(buf, &y) >= 0); |
351 | assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC); | |
352 | ||
ed4a5b43 FS |
353 | assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UNIX)); |
354 | log_debug("%s", buf); | |
355 | assert_se(parse_timestamp(buf, &y) >= 0); | |
356 | assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC); | |
357 | ||
7b3eb5c9 | 358 | assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC)); |
41bc83ed | 359 | log_debug("%s", buf); |
21b3a0fc LP |
360 | assert_se(parse_timestamp(buf, &y) >= 0); |
361 | assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC); | |
362 | ||
7b3eb5c9 | 363 | assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US)); |
41bc83ed | 364 | log_debug("%s", buf); |
21b3a0fc LP |
365 | assert_se(parse_timestamp(buf, &y) >= 0); |
366 | assert_se(x == y); | |
367 | ||
7b3eb5c9 | 368 | assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US_UTC)); |
41bc83ed | 369 | log_debug("%s", buf); |
21b3a0fc LP |
370 | assert_se(parse_timestamp(buf, &y) >= 0); |
371 | assert_se(x == y); | |
372 | ||
ff6db56a YW |
373 | if (x > 2 * USEC_PER_DAY) { |
374 | assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_DATE)); | |
375 | log_debug("%s", buf); | |
376 | assert_se(parse_timestamp(buf, &y) >= 0); | |
377 | assert_se(y > usec_sub_unsigned(x, 2 * USEC_PER_DAY) && y < usec_add(x, 2 * USEC_PER_DAY)); | |
378 | } | |
64f3419e | 379 | |
21b3a0fc | 380 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); |
41bc83ed | 381 | log_debug("%s", buf); |
21b3a0fc LP |
382 | assert_se(parse_timestamp(buf, &y) >= 0); |
383 | ||
384 | /* The two calls above will run with a slightly different local time. Make sure we are in the same | |
385 | * range however, but give enough leeway that this is unlikely to explode. And of course, | |
386 | * format_timestamp_relative() scales the accuracy with the distance from the current time up to one | |
387 | * month, cover for that too. */ | |
388 | assert_se(y > x ? y - x : x - y <= USEC_PER_MONTH + USEC_PER_DAY); | |
389 | } | |
390 | } | |
391 | ||
8b51c41f | 392 | static void test_format_timestamp_impl(usec_t x) { |
78b95cca | 393 | bool success, override; |
8b51c41f | 394 | const char *xx, *yy; |
3f1d4999 | 395 | usec_t y, x_sec, y_sec; |
8b51c41f YW |
396 | |
397 | xx = FORMAT_TIMESTAMP(x); | |
3f1d4999 YW |
398 | ASSERT_NOT_NULL(xx); |
399 | ASSERT_OK(parse_timestamp(xx, &y)); | |
8b51c41f | 400 | yy = FORMAT_TIMESTAMP(y); |
3f1d4999 | 401 | ASSERT_NOT_NULL(yy); |
8b51c41f | 402 | |
3f1d4999 YW |
403 | x_sec = x / USEC_PER_SEC; |
404 | y_sec = y / USEC_PER_SEC; | |
405 | success = (x_sec == y_sec) && streq(xx, yy); | |
3cf362f6 ZJS |
406 | /* Workaround for https://github.com/systemd/systemd/issues/28472 |
407 | * and https://github.com/systemd/systemd/pull/35471. */ | |
78b95cca | 408 | override = !success && |
3cf362f6 ZJS |
409 | (STRPTR_IN_SET(tzname[0], "CAT", "EAT", "WET") || |
410 | STRPTR_IN_SET(tzname[1], "CAT", "EAT", "WET")) && | |
3f1d4999 | 411 | (x_sec > y_sec ? x_sec - y_sec : y_sec - x_sec) == 3600; /* 1 hour, ignore fractional second */ |
78b95cca ZJS |
412 | log_full(success ? LOG_DEBUG : override ? LOG_WARNING : LOG_ERR, |
413 | "@" USEC_FMT " → %s → @" USEC_FMT " → %s%s", | |
414 | x, xx, y, yy, | |
415 | override ? ", ignoring." : ""); | |
416 | if (!override) { | |
3f1d4999 YW |
417 | if (!success) |
418 | log_warning("tzname[0]=\"%s\", tzname[1]=\"%s\"", tzname[0], tzname[1]); | |
419 | ASSERT_EQ(x_sec, y_sec); | |
c79e88b3 | 420 | ASSERT_STREQ(xx, yy); |
78b95cca | 421 | } |
8b51c41f YW |
422 | } |
423 | ||
424 | static void test_format_timestamp_loop(void) { | |
3cf362f6 | 425 | test_format_timestamp_impl(USEC_PER_DAY + USEC_PER_SEC); |
6bed3742 YW |
426 | test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT-1); |
427 | test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT); | |
428 | test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX-1); | |
429 | test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX); | |
8b51c41f | 430 | |
78b95cca ZJS |
431 | /* Two cases which trigger https://github.com/systemd/systemd/issues/28472 */ |
432 | test_format_timestamp_impl(1504938962980066); | |
433 | test_format_timestamp_impl(1509482094632752); | |
434 | ||
8b51c41f YW |
435 | for (unsigned i = 0; i < TRIAL; i++) { |
436 | usec_t x; | |
437 | ||
438 | x = random_u64_range(USEC_TIMESTAMP_FORMATTABLE_MAX - USEC_PER_SEC) + USEC_PER_SEC; | |
439 | test_format_timestamp_impl(x); | |
440 | } | |
441 | } | |
442 | ||
4f7452a8 | 443 | TEST(FORMAT_TIMESTAMP) { |
8b51c41f YW |
444 | test_format_timestamp_loop(); |
445 | } | |
ae7c644c | 446 | |
0b20d70d YW |
447 | static void test_format_timestamp_with_tz_one(const char *tz) { |
448 | const char *saved_tz, *colon_tz; | |
ae7c644c | 449 | |
0b20d70d | 450 | if (!timezone_is_valid(tz, LOG_DEBUG)) |
8b51c41f YW |
451 | return; |
452 | ||
0b20d70d | 453 | log_info("/* %s(%s) */", __func__, tz); |
8b51c41f YW |
454 | |
455 | saved_tz = getenv("TZ"); | |
456 | ||
0b20d70d YW |
457 | assert_se(colon_tz = strjoina(":", tz)); |
458 | assert_se(setenv("TZ", colon_tz, 1) >= 0); | |
8b51c41f YW |
459 | tzset(); |
460 | log_debug("%s: tzname[0]=%s, tzname[1]=%s", tz, strempty(tzname[0]), strempty(tzname[1])); | |
461 | ||
462 | test_format_timestamp_loop(); | |
463 | ||
464 | assert_se(set_unset_env("TZ", saved_tz, true) == 0); | |
465 | tzset(); | |
466 | } | |
467 | ||
468 | TEST(FORMAT_TIMESTAMP_with_tz) { | |
0b20d70d YW |
469 | _cleanup_strv_free_ char **timezones = NULL; |
470 | ||
e3201a69 FS |
471 | test_format_timestamp_with_tz_one("UTC"); |
472 | ||
473 | if (!slow_tests_enabled()) | |
474 | return (void) log_tests_skipped("slow tests are disabled"); | |
475 | ||
0b20d70d YW |
476 | assert_se(get_timezones(&timezones) >= 0); |
477 | STRV_FOREACH(tz, timezones) | |
478 | test_format_timestamp_with_tz_one(*tz); | |
ae7c644c ZJS |
479 | } |
480 | ||
d5e6f36c ZJS |
481 | TEST(format_timestamp_relative_full) { |
482 | char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)]; | |
483 | usec_t x; | |
484 | ||
485 | /* Years and months */ | |
486 | x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 1*USEC_PER_MONTH); | |
d65c289f | 487 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); |
d5e6f36c | 488 | log_debug("%s", buf); |
c79e88b3 | 489 | ASSERT_STREQ(buf, "1 year 1 month ago"); |
d5e6f36c | 490 | |
d65c289f MY |
491 | x = now(CLOCK_MONOTONIC) + (1*USEC_PER_YEAR + 1.5*USEC_PER_MONTH); |
492 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_MONOTONIC, false)); | |
493 | log_debug("%s", buf); | |
c79e88b3 | 494 | ASSERT_STREQ(buf, "1 year 1 month left"); |
d65c289f | 495 | |
d5e6f36c | 496 | x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH); |
d65c289f | 497 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); |
d5e6f36c | 498 | log_debug("%s", buf); |
c79e88b3 | 499 | ASSERT_STREQ(buf, "1 year 2 months ago"); |
d5e6f36c ZJS |
500 | |
501 | x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH); | |
d65c289f | 502 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); |
d5e6f36c | 503 | log_debug("%s", buf); |
c79e88b3 | 504 | ASSERT_STREQ(buf, "2 years 1 month ago"); |
d5e6f36c ZJS |
505 | |
506 | x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH); | |
d65c289f | 507 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); |
d5e6f36c | 508 | log_debug("%s", buf); |
c79e88b3 | 509 | ASSERT_STREQ(buf, "2 years 2 months ago"); |
d5e6f36c ZJS |
510 | |
511 | /* Months and days */ | |
512 | x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 1*USEC_PER_DAY); | |
d65c289f | 513 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); |
d5e6f36c | 514 | log_debug("%s", buf); |
c79e88b3 | 515 | ASSERT_STREQ(buf, "1 month 1 day ago"); |
d5e6f36c ZJS |
516 | |
517 | x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY); | |
d65c289f | 518 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); |
d5e6f36c | 519 | log_debug("%s", buf); |
c79e88b3 | 520 | ASSERT_STREQ(buf, "1 month 2 days ago"); |
d5e6f36c ZJS |
521 | |
522 | x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY); | |
d65c289f | 523 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); |
d5e6f36c | 524 | log_debug("%s", buf); |
c79e88b3 | 525 | ASSERT_STREQ(buf, "2 months 1 day ago"); |
d5e6f36c ZJS |
526 | |
527 | x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY); | |
d65c289f | 528 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); |
d5e6f36c | 529 | log_debug("%s", buf); |
c79e88b3 | 530 | ASSERT_STREQ(buf, "2 months 2 days ago"); |
d5e6f36c ZJS |
531 | |
532 | /* Weeks and days */ | |
533 | x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 1*USEC_PER_DAY); | |
d65c289f | 534 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); |
d5e6f36c | 535 | log_debug("%s", buf); |
c79e88b3 | 536 | ASSERT_STREQ(buf, "1 week 1 day ago"); |
d5e6f36c ZJS |
537 | |
538 | x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY); | |
d65c289f | 539 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); |
d5e6f36c | 540 | log_debug("%s", buf); |
c79e88b3 | 541 | ASSERT_STREQ(buf, "1 week 2 days ago"); |
d5e6f36c ZJS |
542 | |
543 | x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY); | |
d65c289f | 544 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); |
d5e6f36c | 545 | log_debug("%s", buf); |
c79e88b3 | 546 | ASSERT_STREQ(buf, "2 weeks 1 day ago"); |
d5e6f36c ZJS |
547 | |
548 | x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY); | |
d65c289f | 549 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); |
d5e6f36c | 550 | log_debug("%s", buf); |
c79e88b3 | 551 | ASSERT_STREQ(buf, "2 weeks 2 days ago"); |
d5e6f36c ZJS |
552 | } |
553 | ||
4f7452a8 | 554 | TEST(format_timestamp_relative) { |
89eb3d7c | 555 | char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)]; |
45eb4d22 AW |
556 | usec_t x; |
557 | ||
558 | /* Only testing timestamps in the past so we don't need to add some delta to account for time passing | |
559 | * by while we are running the tests (unless we're running on potatoes and 24 hours somehow passes | |
560 | * between our call to now() and format_timestamp_relative's call to now()). */ | |
561 | ||
562 | /* Years and months */ | |
563 | x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 1*USEC_PER_MONTH); | |
564 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
41bc83ed | 565 | log_debug("%s", buf); |
c79e88b3 | 566 | ASSERT_STREQ(buf, "1 year 1 month ago"); |
45eb4d22 AW |
567 | |
568 | x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH); | |
569 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
41bc83ed | 570 | log_debug("%s", buf); |
c79e88b3 | 571 | ASSERT_STREQ(buf, "1 year 2 months ago"); |
45eb4d22 AW |
572 | |
573 | x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH); | |
574 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
41bc83ed | 575 | log_debug("%s", buf); |
c79e88b3 | 576 | ASSERT_STREQ(buf, "2 years 1 month ago"); |
45eb4d22 AW |
577 | |
578 | x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH); | |
579 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
41bc83ed | 580 | log_debug("%s", buf); |
c79e88b3 | 581 | ASSERT_STREQ(buf, "2 years 2 months ago"); |
45eb4d22 AW |
582 | |
583 | /* Months and days */ | |
584 | x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 1*USEC_PER_DAY); | |
585 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
41bc83ed | 586 | log_debug("%s", buf); |
c79e88b3 | 587 | ASSERT_STREQ(buf, "1 month 1 day ago"); |
45eb4d22 AW |
588 | |
589 | x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY); | |
590 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
41bc83ed | 591 | log_debug("%s", buf); |
c79e88b3 | 592 | ASSERT_STREQ(buf, "1 month 2 days ago"); |
45eb4d22 AW |
593 | |
594 | x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY); | |
595 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
41bc83ed | 596 | log_debug("%s", buf); |
c79e88b3 | 597 | ASSERT_STREQ(buf, "2 months 1 day ago"); |
45eb4d22 AW |
598 | |
599 | x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY); | |
600 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
41bc83ed | 601 | log_debug("%s", buf); |
c79e88b3 | 602 | ASSERT_STREQ(buf, "2 months 2 days ago"); |
45eb4d22 AW |
603 | |
604 | /* Weeks and days */ | |
605 | x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 1*USEC_PER_DAY); | |
606 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
41bc83ed | 607 | log_debug("%s", buf); |
c79e88b3 | 608 | ASSERT_STREQ(buf, "1 week 1 day ago"); |
45eb4d22 AW |
609 | |
610 | x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY); | |
611 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
41bc83ed | 612 | log_debug("%s", buf); |
c79e88b3 | 613 | ASSERT_STREQ(buf, "1 week 2 days ago"); |
45eb4d22 AW |
614 | |
615 | x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY); | |
616 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
41bc83ed | 617 | log_debug("%s", buf); |
c79e88b3 | 618 | ASSERT_STREQ(buf, "2 weeks 1 day ago"); |
45eb4d22 AW |
619 | |
620 | x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY); | |
621 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
41bc83ed | 622 | log_debug("%s", buf); |
c79e88b3 | 623 | ASSERT_STREQ(buf, "2 weeks 2 days ago"); |
45eb4d22 AW |
624 | } |
625 | ||
64f3419e | 626 | static void test_format_timestamp_one(usec_t val, TimestampStyle style, const char *result) { |
1bb4b028 | 627 | char buf[FORMAT_TIMESTAMP_MAX]; |
4d9685be | 628 | const char *t; |
1bb4b028 | 629 | |
64f3419e | 630 | t = format_timestamp_style(buf, sizeof(buf), val, style); |
c79e88b3 | 631 | ASSERT_STREQ(t, result); |
1bb4b028 LP |
632 | } |
633 | ||
64f3419e LP |
634 | TEST(format_timestamp_range) { |
635 | test_format_timestamp_one(0, TIMESTAMP_UTC, NULL); | |
636 | test_format_timestamp_one(0, TIMESTAMP_DATE, NULL); | |
637 | test_format_timestamp_one(0, TIMESTAMP_US_UTC, NULL); | |
638 | ||
639 | test_format_timestamp_one(1, TIMESTAMP_UTC, "Thu 1970-01-01 00:00:00 UTC"); | |
640 | test_format_timestamp_one(1, TIMESTAMP_DATE, "Thu 1970-01-01"); | |
641 | test_format_timestamp_one(1, TIMESTAMP_US_UTC, "Thu 1970-01-01 00:00:00.000001 UTC"); | |
642 | ||
643 | test_format_timestamp_one(USEC_PER_SEC, TIMESTAMP_UTC, "Thu 1970-01-01 00:00:01 UTC"); | |
644 | test_format_timestamp_one(USEC_PER_SEC, TIMESTAMP_DATE, "Thu 1970-01-01"); | |
645 | test_format_timestamp_one(USEC_PER_SEC, TIMESTAMP_US_UTC, "Thu 1970-01-01 00:00:01.000000 UTC"); | |
1bb4b028 LP |
646 | |
647 | #if SIZEOF_TIME_T == 8 | |
64f3419e LP |
648 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_UTC, "Thu 9999-12-30 23:59:59 UTC"); |
649 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_DATE, "Thu 9999-12-30"); | |
650 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_UTC, "--- XXXX-XX-XX XX:XX:XX UTC"); | |
651 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_US_UTC, "--- XXXX-XX-XX XX:XX:XX.XXXXXX UTC"); | |
652 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_DATE, "--- XXXX-XX-XX"); | |
1bb4b028 | 653 | #elif SIZEOF_TIME_T == 4 |
bd5770da YW |
654 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_UTC, "Mon 2038-01-18 03:14:07 UTC"); |
655 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_DATE, "Mon 2038-01-18"); | |
64f3419e LP |
656 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_UTC, "--- XXXX-XX-XX XX:XX:XX UTC"); |
657 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_US_UTC, "--- XXXX-XX-XX XX:XX:XX.XXXXXX UTC"); | |
658 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_DATE, "--- XXXX-XX-XX"); | |
1bb4b028 LP |
659 | #endif |
660 | ||
64f3419e | 661 | test_format_timestamp_one(USEC_INFINITY, TIMESTAMP_UTC, NULL); |
1bb4b028 LP |
662 | } |
663 | ||
8b51c41f | 664 | static void test_parse_timestamp_one(const char *str, usec_t max_diff, usec_t expected) { |
d8f3ad62 YW |
665 | usec_t usec = USEC_INFINITY; |
666 | int r; | |
8b51c41f | 667 | |
d8f3ad62 | 668 | r = parse_timestamp(str, &usec); |
cfacd245 | 669 | log_debug("/* %s(%s): max_diff="USEC_FMT", expected="USEC_FMT", result="USEC_FMT" */", __func__, str, max_diff, expected, usec); |
d8f3ad62 | 670 | assert_se(r >= 0); |
8b51c41f YW |
671 | assert_se(usec >= expected); |
672 | assert_se(usec_sub_unsigned(usec, expected) <= max_diff); | |
673 | } | |
674 | ||
cfacd245 YW |
675 | static bool time_is_zero(usec_t usec) { |
676 | const char *s; | |
677 | ||
678 | s = FORMAT_TIMESTAMP(usec); | |
679 | return strstr(s, " 00:00:00 "); | |
680 | } | |
681 | ||
682 | static bool timezone_equal(usec_t today, usec_t target) { | |
683 | const char *s, *t, *sz, *tz; | |
684 | ||
685 | s = FORMAT_TIMESTAMP(today); | |
686 | t = FORMAT_TIMESTAMP(target); | |
687 | assert_se(sz = strrchr(s, ' ')); | |
688 | assert_se(tz = strrchr(t, ' ')); | |
689 | log_debug("%s("USEC_FMT", "USEC_FMT") -> %s, %s", __func__, today, target, s, t); | |
690 | return streq(sz, tz); | |
691 | } | |
692 | ||
d8f3ad62 | 693 | static void test_parse_timestamp_impl(const char *tz) { |
ef658a63 | 694 | usec_t today, today2, now_usec; |
8b51c41f | 695 | |
165655cb MY |
696 | /* Invalid: Ensure that systemctl reboot --when=show and --when=cancel |
697 | * will not result in ambiguities */ | |
698 | assert_se(parse_timestamp("show", NULL) == -EINVAL); | |
699 | assert_se(parse_timestamp("cancel", NULL) == -EINVAL); | |
700 | ||
8b51c41f YW |
701 | /* UTC */ |
702 | test_parse_timestamp_one("Thu 1970-01-01 00:01 UTC", 0, USEC_PER_MINUTE); | |
703 | test_parse_timestamp_one("Thu 1970-01-01 00:00:01 UTC", 0, USEC_PER_SEC); | |
704 | test_parse_timestamp_one("Thu 1970-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000); | |
705 | test_parse_timestamp_one("Thu 1970-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000); | |
706 | ||
707 | test_parse_timestamp_one("Thu 70-01-01 00:01 UTC", 0, USEC_PER_MINUTE); | |
708 | test_parse_timestamp_one("Thu 70-01-01 00:00:01 UTC", 0, USEC_PER_SEC); | |
709 | test_parse_timestamp_one("Thu 70-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000); | |
710 | test_parse_timestamp_one("Thu 70-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000); | |
711 | ||
712 | test_parse_timestamp_one("1970-01-01 00:01 UTC", 0, USEC_PER_MINUTE); | |
713 | test_parse_timestamp_one("1970-01-01 00:00:01 UTC", 0, USEC_PER_SEC); | |
714 | test_parse_timestamp_one("1970-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000); | |
715 | test_parse_timestamp_one("1970-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000); | |
716 | ||
717 | test_parse_timestamp_one("70-01-01 00:01 UTC", 0, USEC_PER_MINUTE); | |
718 | test_parse_timestamp_one("70-01-01 00:00:01 UTC", 0, USEC_PER_SEC); | |
719 | test_parse_timestamp_one("70-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000); | |
720 | test_parse_timestamp_one("70-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000); | |
721 | ||
ef658a63 | 722 | /* Examples from RFC3339 */ |
723 | test_parse_timestamp_one("1985-04-12T23:20:50.52Z", 0, 482196050 * USEC_PER_SEC + 520000); | |
724 | test_parse_timestamp_one("1996-12-19T16:39:57-08:00", 0, 851042397 * USEC_PER_SEC + 000000); | |
725 | test_parse_timestamp_one("1996-12-20T00:39:57Z", 0, 851042397 * USEC_PER_SEC + 000000); | |
726 | test_parse_timestamp_one("1990-12-31T23:59:60Z", 0, 662688000 * USEC_PER_SEC + 000000); | |
727 | test_parse_timestamp_one("1990-12-31T15:59:60-08:00", 0, 662688000 * USEC_PER_SEC + 000000); | |
6f5cf415 | 728 | assert_se(parse_timestamp("1937-01-01T12:00:27.87+00:20", NULL) == -ERANGE); /* we don't support pre-epoch timestamps */ |
ef658a63 | 729 | /* We accept timestamps without seconds as well */ |
730 | test_parse_timestamp_one("1996-12-20T00:39Z", 0, (851042397 - 57) * USEC_PER_SEC + 000000); | |
731 | test_parse_timestamp_one("1990-12-31T15:59-08:00", 0, (662688000-60) * USEC_PER_SEC + 000000); | |
732 | /* We drop day-of-week before parsing the timestamp */ | |
733 | test_parse_timestamp_one("Thu 1970-01-01T00:01 UTC", 0, USEC_PER_MINUTE); | |
734 | test_parse_timestamp_one("Thu 1970-01-01T00:00:01 UTC", 0, USEC_PER_SEC); | |
735 | test_parse_timestamp_one("Thu 1970-01-01T00:01Z", 0, USEC_PER_MINUTE); | |
736 | test_parse_timestamp_one("Thu 1970-01-01T00:00:01Z", 0, USEC_PER_SEC); | |
737 | /* RFC3339-style timezones can be welded to all formats */ | |
738 | assert_se(parse_timestamp("today UTC", &today) == 0); | |
739 | assert_se(parse_timestamp("todayZ", &today2) == 0); | |
740 | assert_se(today == today2); | |
741 | assert_se(parse_timestamp("today +0200", &today) == 0); | |
742 | assert_se(parse_timestamp("today+02:00", &today2) == 0); | |
743 | assert_se(today == today2); | |
744 | ||
745 | /* https://ijmacd.github.io/rfc3339-iso8601/ */ | |
746 | test_parse_timestamp_one("2023-09-06 12:49:27-00:00", 0, 1694004567 * USEC_PER_SEC + 000000); | |
747 | test_parse_timestamp_one("2023-09-06 12:49:27.284-00:00", 0, 1694004567 * USEC_PER_SEC + 284000); | |
748 | test_parse_timestamp_one("2023-09-06 12:49:27.284029Z", 0, 1694004567 * USEC_PER_SEC + 284029); | |
749 | test_parse_timestamp_one("2023-09-06 12:49:27.284Z", 0, 1694004567 * USEC_PER_SEC + 284000); | |
750 | test_parse_timestamp_one("2023-09-06 12:49:27.28Z", 0, 1694004567 * USEC_PER_SEC + 280000); | |
751 | test_parse_timestamp_one("2023-09-06 12:49:27.2Z", 0, 1694004567 * USEC_PER_SEC + 200000); | |
752 | test_parse_timestamp_one("2023-09-06 12:49:27Z", 0, 1694004567 * USEC_PER_SEC + 000000); | |
753 | test_parse_timestamp_one("2023-09-06 14:49:27+02:00", 0, 1694004567 * USEC_PER_SEC + 000000); | |
754 | test_parse_timestamp_one("2023-09-06 14:49:27.2+02:00", 0, 1694004567 * USEC_PER_SEC + 200000); | |
755 | test_parse_timestamp_one("2023-09-06 14:49:27.28+02:00", 0, 1694004567 * USEC_PER_SEC + 280000); | |
756 | test_parse_timestamp_one("2023-09-06 14:49:27.284+02:00", 0, 1694004567 * USEC_PER_SEC + 284000); | |
757 | test_parse_timestamp_one("2023-09-06 14:49:27.284029+02:00", 0, 1694004567 * USEC_PER_SEC + 284029); | |
758 | test_parse_timestamp_one("2023-09-06T12:49:27+00:00", 0, 1694004567 * USEC_PER_SEC + 000000); | |
759 | test_parse_timestamp_one("2023-09-06T12:49:27-00:00", 0, 1694004567 * USEC_PER_SEC + 000000); | |
760 | test_parse_timestamp_one("2023-09-06T12:49:27.284+00:00", 0, 1694004567 * USEC_PER_SEC + 284000); | |
761 | test_parse_timestamp_one("2023-09-06T12:49:27.284-00:00", 0, 1694004567 * USEC_PER_SEC + 284000); | |
762 | test_parse_timestamp_one("2023-09-06T12:49:27.284029Z", 0, 1694004567 * USEC_PER_SEC + 284029); | |
763 | test_parse_timestamp_one("2023-09-06T12:49:27.284Z", 0, 1694004567 * USEC_PER_SEC + 284000); | |
764 | test_parse_timestamp_one("2023-09-06T12:49:27.28Z", 0, 1694004567 * USEC_PER_SEC + 280000); | |
765 | test_parse_timestamp_one("2023-09-06T12:49:27.2Z", 0, 1694004567 * USEC_PER_SEC + 200000); | |
766 | test_parse_timestamp_one("2023-09-06T12:49:27Z", 0, 1694004567 * USEC_PER_SEC + 000000); | |
767 | test_parse_timestamp_one("2023-09-06T14:49:27+02:00", 0, 1694004567 * USEC_PER_SEC + 000000); | |
768 | test_parse_timestamp_one("2023-09-06T14:49:27.284+02:00", 0, 1694004567 * USEC_PER_SEC + 284000); | |
769 | test_parse_timestamp_one("2023-09-06T14:49:27.284029+02:00", 0, 1694004567 * USEC_PER_SEC + 284029); | |
770 | test_parse_timestamp_one("2023-09-06T21:34:27+08:45", 0, 1694004567 * USEC_PER_SEC + 000000); | |
771 | ||
8b51c41f YW |
772 | if (timezone_is_valid("Asia/Tokyo", LOG_DEBUG)) { |
773 | /* Asia/Tokyo (+0900) */ | |
774 | test_parse_timestamp_one("Thu 1970-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE); | |
775 | test_parse_timestamp_one("Thu 1970-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC); | |
776 | test_parse_timestamp_one("Thu 1970-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
777 | test_parse_timestamp_one("Thu 1970-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
778 | ||
779 | test_parse_timestamp_one("Thu 70-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE); | |
780 | test_parse_timestamp_one("Thu 70-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC); | |
781 | test_parse_timestamp_one("Thu 70-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
782 | test_parse_timestamp_one("Thu 70-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
783 | ||
784 | test_parse_timestamp_one("1970-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE); | |
785 | test_parse_timestamp_one("1970-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC); | |
786 | test_parse_timestamp_one("1970-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
787 | test_parse_timestamp_one("1970-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
788 | ||
789 | test_parse_timestamp_one("70-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE); | |
790 | test_parse_timestamp_one("70-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC); | |
791 | test_parse_timestamp_one("70-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
792 | test_parse_timestamp_one("70-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
d8f3ad62 | 793 | } |
8b51c41f | 794 | |
d8f3ad62 | 795 | if (streq_ptr(tz, "Asia/Tokyo")) { |
8b51c41f YW |
796 | /* JST (+0900) */ |
797 | test_parse_timestamp_one("Thu 1970-01-01 09:01 JST", 0, USEC_PER_MINUTE); | |
798 | test_parse_timestamp_one("Thu 1970-01-01 09:00:01 JST", 0, USEC_PER_SEC); | |
799 | test_parse_timestamp_one("Thu 1970-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000); | |
800 | test_parse_timestamp_one("Thu 1970-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000); | |
801 | ||
802 | test_parse_timestamp_one("Thu 70-01-01 09:01 JST", 0, USEC_PER_MINUTE); | |
803 | test_parse_timestamp_one("Thu 70-01-01 09:00:01 JST", 0, USEC_PER_SEC); | |
804 | test_parse_timestamp_one("Thu 70-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000); | |
805 | test_parse_timestamp_one("Thu 70-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000); | |
806 | ||
807 | test_parse_timestamp_one("1970-01-01 09:01 JST", 0, USEC_PER_MINUTE); | |
808 | test_parse_timestamp_one("1970-01-01 09:00:01 JST", 0, USEC_PER_SEC); | |
809 | test_parse_timestamp_one("1970-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000); | |
810 | test_parse_timestamp_one("1970-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000); | |
811 | ||
812 | test_parse_timestamp_one("70-01-01 09:01 JST", 0, USEC_PER_MINUTE); | |
813 | test_parse_timestamp_one("70-01-01 09:00:01 JST", 0, USEC_PER_SEC); | |
814 | test_parse_timestamp_one("70-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000); | |
815 | test_parse_timestamp_one("70-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000); | |
8b51c41f YW |
816 | } |
817 | ||
818 | if (timezone_is_valid("America/New_York", LOG_DEBUG)) { | |
819 | /* America/New_York (-0500) */ | |
820 | test_parse_timestamp_one("Wed 1969-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE); | |
821 | test_parse_timestamp_one("Wed 1969-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC); | |
822 | test_parse_timestamp_one("Wed 1969-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000); | |
823 | test_parse_timestamp_one("Wed 1969-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000); | |
824 | ||
825 | test_parse_timestamp_one("Wed 69-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE); | |
826 | test_parse_timestamp_one("Wed 69-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC); | |
827 | test_parse_timestamp_one("Wed 69-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000); | |
828 | test_parse_timestamp_one("Wed 69-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000); | |
829 | ||
830 | test_parse_timestamp_one("1969-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE); | |
831 | test_parse_timestamp_one("1969-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC); | |
832 | test_parse_timestamp_one("1969-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000); | |
833 | test_parse_timestamp_one("1969-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000); | |
834 | ||
835 | test_parse_timestamp_one("69-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE); | |
836 | test_parse_timestamp_one("69-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC); | |
837 | test_parse_timestamp_one("69-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000); | |
838 | test_parse_timestamp_one("69-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000); | |
d8f3ad62 | 839 | } |
8b51c41f | 840 | |
d8f3ad62 | 841 | if (streq_ptr(tz, "America/New_York")) { |
8b51c41f YW |
842 | /* EST (-0500) */ |
843 | test_parse_timestamp_one("Wed 1969-12-31 19:01 EST", 0, USEC_PER_MINUTE); | |
844 | test_parse_timestamp_one("Wed 1969-12-31 19:00:01 EST", 0, USEC_PER_SEC); | |
845 | test_parse_timestamp_one("Wed 1969-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000); | |
846 | test_parse_timestamp_one("Wed 1969-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000); | |
847 | ||
848 | test_parse_timestamp_one("Wed 69-12-31 19:01 EST", 0, USEC_PER_MINUTE); | |
849 | test_parse_timestamp_one("Wed 69-12-31 19:00:01 EST", 0, USEC_PER_SEC); | |
850 | test_parse_timestamp_one("Wed 69-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000); | |
851 | test_parse_timestamp_one("Wed 69-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000); | |
852 | ||
853 | test_parse_timestamp_one("1969-12-31 19:01 EST", 0, USEC_PER_MINUTE); | |
854 | test_parse_timestamp_one("1969-12-31 19:00:01 EST", 0, USEC_PER_SEC); | |
855 | test_parse_timestamp_one("1969-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000); | |
856 | test_parse_timestamp_one("1969-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000); | |
857 | ||
858 | test_parse_timestamp_one("69-12-31 19:01 EST", 0, USEC_PER_MINUTE); | |
859 | test_parse_timestamp_one("69-12-31 19:00:01 EST", 0, USEC_PER_SEC); | |
860 | test_parse_timestamp_one("69-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000); | |
861 | test_parse_timestamp_one("69-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000); | |
8b51c41f YW |
862 | } |
863 | ||
eb87d3e1 YW |
864 | if (timezone_is_valid("NZ", LOG_DEBUG)) { |
865 | /* NZ (+1200) */ | |
866 | test_parse_timestamp_one("Thu 1970-01-01 12:01 NZ", 0, USEC_PER_MINUTE); | |
867 | test_parse_timestamp_one("Thu 1970-01-01 12:00:01 NZ", 0, USEC_PER_SEC); | |
868 | test_parse_timestamp_one("Thu 1970-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000); | |
869 | test_parse_timestamp_one("Thu 1970-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000); | |
870 | ||
871 | test_parse_timestamp_one("Thu 70-01-01 12:01 NZ", 0, USEC_PER_MINUTE); | |
872 | test_parse_timestamp_one("Thu 70-01-01 12:00:01 NZ", 0, USEC_PER_SEC); | |
873 | test_parse_timestamp_one("Thu 70-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000); | |
874 | test_parse_timestamp_one("Thu 70-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000); | |
875 | ||
876 | test_parse_timestamp_one("1970-01-01 12:01 NZ", 0, USEC_PER_MINUTE); | |
877 | test_parse_timestamp_one("1970-01-01 12:00:01 NZ", 0, USEC_PER_SEC); | |
878 | test_parse_timestamp_one("1970-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000); | |
879 | test_parse_timestamp_one("1970-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000); | |
880 | ||
881 | test_parse_timestamp_one("70-01-01 12:01 NZ", 0, USEC_PER_MINUTE); | |
882 | test_parse_timestamp_one("70-01-01 12:00:01 NZ", 0, USEC_PER_SEC); | |
883 | test_parse_timestamp_one("70-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000); | |
884 | test_parse_timestamp_one("70-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000); | |
885 | } | |
886 | ||
8b51c41f YW |
887 | /* -06 */ |
888 | test_parse_timestamp_one("Wed 1969-12-31 18:01 -06", 0, USEC_PER_MINUTE); | |
889 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -06", 0, USEC_PER_SEC); | |
890 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000); | |
891 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000); | |
892 | ||
893 | test_parse_timestamp_one("Wed 69-12-31 18:01 -06", 0, USEC_PER_MINUTE); | |
894 | test_parse_timestamp_one("Wed 69-12-31 18:00:01 -06", 0, USEC_PER_SEC); | |
895 | test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000); | |
896 | test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000); | |
897 | ||
898 | test_parse_timestamp_one("1969-12-31 18:01 -06", 0, USEC_PER_MINUTE); | |
899 | test_parse_timestamp_one("1969-12-31 18:00:01 -06", 0, USEC_PER_SEC); | |
900 | test_parse_timestamp_one("1969-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000); | |
901 | test_parse_timestamp_one("1969-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000); | |
902 | ||
903 | test_parse_timestamp_one("69-12-31 18:01 -06", 0, USEC_PER_MINUTE); | |
904 | test_parse_timestamp_one("69-12-31 18:00:01 -06", 0, USEC_PER_SEC); | |
905 | test_parse_timestamp_one("69-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000); | |
906 | test_parse_timestamp_one("69-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000); | |
907 | ||
908 | /* -0600 */ | |
909 | test_parse_timestamp_one("Wed 1969-12-31 18:01 -0600", 0, USEC_PER_MINUTE); | |
910 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -0600", 0, USEC_PER_SEC); | |
911 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000); | |
912 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000); | |
913 | ||
914 | test_parse_timestamp_one("Wed 69-12-31 18:01 -0600", 0, USEC_PER_MINUTE); | |
915 | test_parse_timestamp_one("Wed 69-12-31 18:00:01 -0600", 0, USEC_PER_SEC); | |
916 | test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000); | |
917 | test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000); | |
918 | ||
919 | test_parse_timestamp_one("1969-12-31 18:01 -0600", 0, USEC_PER_MINUTE); | |
920 | test_parse_timestamp_one("1969-12-31 18:00:01 -0600", 0, USEC_PER_SEC); | |
921 | test_parse_timestamp_one("1969-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000); | |
922 | test_parse_timestamp_one("1969-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000); | |
923 | ||
924 | test_parse_timestamp_one("69-12-31 18:01 -0600", 0, USEC_PER_MINUTE); | |
925 | test_parse_timestamp_one("69-12-31 18:00:01 -0600", 0, USEC_PER_SEC); | |
926 | test_parse_timestamp_one("69-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000); | |
927 | test_parse_timestamp_one("69-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000); | |
928 | ||
929 | /* -06:00 */ | |
930 | test_parse_timestamp_one("Wed 1969-12-31 18:01 -06:00", 0, USEC_PER_MINUTE); | |
931 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -06:00", 0, USEC_PER_SEC); | |
932 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000); | |
933 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000); | |
934 | ||
935 | test_parse_timestamp_one("Wed 69-12-31 18:01 -06:00", 0, USEC_PER_MINUTE); | |
936 | test_parse_timestamp_one("Wed 69-12-31 18:00:01 -06:00", 0, USEC_PER_SEC); | |
937 | test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000); | |
938 | test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000); | |
939 | ||
940 | test_parse_timestamp_one("1969-12-31 18:01 -06:00", 0, USEC_PER_MINUTE); | |
941 | test_parse_timestamp_one("1969-12-31 18:00:01 -06:00", 0, USEC_PER_SEC); | |
942 | test_parse_timestamp_one("1969-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000); | |
943 | test_parse_timestamp_one("1969-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000); | |
944 | ||
945 | test_parse_timestamp_one("69-12-31 18:01 -06:00", 0, USEC_PER_MINUTE); | |
946 | test_parse_timestamp_one("69-12-31 18:00:01 -06:00", 0, USEC_PER_SEC); | |
947 | test_parse_timestamp_one("69-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000); | |
948 | test_parse_timestamp_one("69-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000); | |
949 | ||
950 | /* without date */ | |
951 | assert_se(parse_timestamp("today", &today) == 0); | |
cfacd245 YW |
952 | if (time_is_zero(today)) { |
953 | test_parse_timestamp_one("00:01", 0, today + USEC_PER_MINUTE); | |
954 | test_parse_timestamp_one("00:00:01", 0, today + USEC_PER_SEC); | |
955 | test_parse_timestamp_one("00:00:01.001", 0, today + USEC_PER_SEC + 1000); | |
956 | test_parse_timestamp_one("00:00:01.0010", 0, today + USEC_PER_SEC + 1000); | |
957 | ||
958 | if (timezone_equal(today, today + USEC_PER_DAY) && time_is_zero(today + USEC_PER_DAY)) | |
959 | test_parse_timestamp_one("tomorrow", 0, today + USEC_PER_DAY); | |
960 | if (timezone_equal(today, today - USEC_PER_DAY) && time_is_zero(today - USEC_PER_DAY)) | |
961 | test_parse_timestamp_one("yesterday", 0, today - USEC_PER_DAY); | |
962 | } | |
8b51c41f | 963 | |
eb87d3e1 YW |
964 | /* with timezone */ |
965 | if (tz) { | |
966 | _cleanup_free_ char *s = NULL; | |
967 | ||
278e3adf | 968 | ASSERT_NOT_NULL((s = strjoin("Fri 2012-11-23 23:02:15 ", tz))); |
eb87d3e1 YW |
969 | ASSERT_OK(parse_timestamp(s, NULL)); |
970 | } | |
971 | ||
8b51c41f YW |
972 | /* relative */ |
973 | assert_se(parse_timestamp("now", &now_usec) == 0); | |
974 | test_parse_timestamp_one("+5hours", USEC_PER_MINUTE, now_usec + 5 * USEC_PER_HOUR); | |
975 | if (now_usec >= 10 * USEC_PER_DAY) | |
976 | test_parse_timestamp_one("-10days", USEC_PER_MINUTE, now_usec - 10 * USEC_PER_DAY); | |
977 | test_parse_timestamp_one("2weeks left", USEC_PER_MINUTE, now_usec + 2 * USEC_PER_WEEK); | |
978 | if (now_usec >= 30 * USEC_PER_MINUTE) | |
979 | test_parse_timestamp_one("30minutes ago", USEC_PER_MINUTE, now_usec - 30 * USEC_PER_MINUTE); | |
980 | } | |
981 | ||
d8f3ad62 YW |
982 | TEST(parse_timestamp) { |
983 | test_parse_timestamp_impl(NULL); | |
984 | } | |
985 | ||
986 | static void test_parse_timestamp_with_tz_one(const char *tz) { | |
987 | const char *saved_tz, *colon_tz; | |
988 | ||
989 | if (!timezone_is_valid(tz, LOG_DEBUG)) | |
990 | return; | |
991 | ||
992 | log_info("/* %s(%s) */", __func__, tz); | |
993 | ||
994 | saved_tz = getenv("TZ"); | |
995 | ||
996 | assert_se(colon_tz = strjoina(":", tz)); | |
997 | assert_se(setenv("TZ", colon_tz, 1) >= 0); | |
998 | tzset(); | |
999 | log_debug("%s: tzname[0]=%s, tzname[1]=%s", tz, strempty(tzname[0]), strempty(tzname[1])); | |
1000 | ||
1001 | test_parse_timestamp_impl(tz); | |
1002 | ||
1003 | assert_se(set_unset_env("TZ", saved_tz, true) == 0); | |
1004 | tzset(); | |
1005 | } | |
1006 | ||
1007 | TEST(parse_timestamp_with_tz) { | |
1008 | _cleanup_strv_free_ char **timezones = NULL; | |
1009 | ||
e3201a69 FS |
1010 | test_parse_timestamp_with_tz_one("UTC"); |
1011 | ||
1012 | if (!slow_tests_enabled()) | |
1013 | return (void) log_tests_skipped("slow tests are disabled"); | |
1014 | ||
d8f3ad62 YW |
1015 | assert_se(get_timezones(&timezones) >= 0); |
1016 | STRV_FOREACH(tz, timezones) | |
1017 | test_parse_timestamp_with_tz_one(*tz); | |
1018 | } | |
1019 | ||
4f7452a8 | 1020 | TEST(deserialize_dual_timestamp) { |
9c0565b2 ZJS |
1021 | int r; |
1022 | dual_timestamp t; | |
1023 | ||
d68c645b | 1024 | r = deserialize_dual_timestamp("1234 5678", &t); |
9c0565b2 ZJS |
1025 | assert_se(r == 0); |
1026 | assert_se(t.realtime == 1234); | |
1027 | assert_se(t.monotonic == 5678); | |
1028 | ||
d68c645b | 1029 | r = deserialize_dual_timestamp("1234x 5678", &t); |
9c0565b2 ZJS |
1030 | assert_se(r == -EINVAL); |
1031 | ||
d68c645b | 1032 | r = deserialize_dual_timestamp("1234 5678y", &t); |
9c0565b2 ZJS |
1033 | assert_se(r == -EINVAL); |
1034 | ||
d68c645b | 1035 | r = deserialize_dual_timestamp("-1234 5678", &t); |
9c0565b2 ZJS |
1036 | assert_se(r == -EINVAL); |
1037 | ||
d68c645b | 1038 | r = deserialize_dual_timestamp("1234 -5678", &t); |
9c0565b2 ZJS |
1039 | assert_se(r == -EINVAL); |
1040 | ||
1041 | /* Check that output wasn't modified. */ | |
1042 | assert_se(t.realtime == 1234); | |
1043 | assert_se(t.monotonic == 5678); | |
1044 | ||
d68c645b | 1045 | r = deserialize_dual_timestamp("+123 567", &t); |
9c0565b2 ZJS |
1046 | assert_se(r == 0); |
1047 | assert_se(t.realtime == 123); | |
1048 | assert_se(t.monotonic == 567); | |
1049 | ||
1050 | /* Check that we get "infinity" on overflow. */ | |
d68c645b | 1051 | r = deserialize_dual_timestamp("18446744073709551617 0", &t); |
9c0565b2 ZJS |
1052 | assert_se(r == 0); |
1053 | assert_se(t.realtime == USEC_INFINITY); | |
1054 | assert_se(t.monotonic == 0); | |
1055 | } | |
1056 | ||
1007ec60 LP |
1057 | static void assert_similar(usec_t a, usec_t b) { |
1058 | usec_t d; | |
1059 | ||
1060 | if (a > b) | |
1061 | d = a - b; | |
1062 | else | |
1063 | d = b - a; | |
1064 | ||
060d9c61 | 1065 | assert_se(d < 10*USEC_PER_SEC); |
1007ec60 LP |
1066 | } |
1067 | ||
4f7452a8 | 1068 | TEST(usec_shift_clock) { |
1007ec60 LP |
1069 | usec_t rt, mn, bt; |
1070 | ||
1071 | rt = now(CLOCK_REALTIME); | |
1072 | mn = now(CLOCK_MONOTONIC); | |
ba4e0427 | 1073 | bt = now(CLOCK_BOOTTIME); |
1007ec60 LP |
1074 | |
1075 | assert_se(usec_shift_clock(USEC_INFINITY, CLOCK_REALTIME, CLOCK_MONOTONIC) == USEC_INFINITY); | |
1076 | ||
1077 | assert_similar(usec_shift_clock(rt + USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_MONOTONIC), mn + USEC_PER_HOUR); | |
ba4e0427 | 1078 | assert_similar(usec_shift_clock(rt + 2*USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_BOOTTIME), bt + 2*USEC_PER_HOUR); |
1007ec60 LP |
1079 | assert_se(usec_shift_clock(rt + 3*USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_REALTIME_ALARM) == rt + 3*USEC_PER_HOUR); |
1080 | ||
1081 | assert_similar(usec_shift_clock(mn + 4*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_REALTIME_ALARM), rt + 4*USEC_PER_HOUR); | |
ba4e0427 | 1082 | assert_similar(usec_shift_clock(mn + 5*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_BOOTTIME), bt + 5*USEC_PER_HOUR); |
1007ec60 LP |
1083 | assert_se(usec_shift_clock(mn + 6*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_MONOTONIC) == mn + 6*USEC_PER_HOUR); |
1084 | ||
ba4e0427 LP |
1085 | assert_similar(usec_shift_clock(bt + 7*USEC_PER_HOUR, CLOCK_BOOTTIME, CLOCK_MONOTONIC), mn + 7*USEC_PER_HOUR); |
1086 | assert_similar(usec_shift_clock(bt + 8*USEC_PER_HOUR, CLOCK_BOOTTIME, CLOCK_REALTIME_ALARM), rt + 8*USEC_PER_HOUR); | |
1087 | assert_se(usec_shift_clock(bt + 9*USEC_PER_HOUR, CLOCK_BOOTTIME, CLOCK_BOOTTIME) == bt + 9*USEC_PER_HOUR); | |
1007ec60 LP |
1088 | |
1089 | if (mn > USEC_PER_MINUTE) { | |
1090 | assert_similar(usec_shift_clock(rt - 30 * USEC_PER_SEC, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC), mn - 30 * USEC_PER_SEC); | |
ba4e0427 | 1091 | assert_similar(usec_shift_clock(rt - 50 * USEC_PER_SEC, CLOCK_REALTIME, CLOCK_BOOTTIME), bt - 50 * USEC_PER_SEC); |
1007ec60 LP |
1092 | } |
1093 | } | |
1094 | ||
4f7452a8 | 1095 | TEST(in_utc_timezone) { |
4d5ad9d9 JJ |
1096 | const char *tz = getenv("TZ"); |
1097 | ||
9a9a4f10 LP |
1098 | assert_se(setenv("TZ", ":UTC", 1) >= 0); |
1099 | assert_se(in_utc_timezone()); | |
c79e88b3 IK |
1100 | ASSERT_STREQ(tzname[0], "UTC"); |
1101 | ASSERT_STREQ(tzname[1], "UTC"); | |
9a9a4f10 LP |
1102 | assert_se(timezone == 0); |
1103 | assert_se(daylight == 0); | |
1104 | ||
437f48a4 | 1105 | assert_se(setenv("TZ", ":Europe/Berlin", 1) >= 0); |
9a9a4f10 | 1106 | assert_se(!in_utc_timezone()); |
c79e88b3 IK |
1107 | ASSERT_STREQ(tzname[0], "CET"); |
1108 | ASSERT_STREQ(tzname[1], "CEST"); | |
9a9a4f10 | 1109 | |
4d5ad9d9 JJ |
1110 | assert_se(set_unset_env("TZ", tz, true) == 0); |
1111 | tzset(); | |
9a9a4f10 LP |
1112 | } |
1113 | ||
4f7452a8 | 1114 | TEST(map_clock_usec) { |
d3926f9a LP |
1115 | usec_t nowr, x, y, z; |
1116 | ||
4f7452a8 | 1117 | x = nowr = now(CLOCK_REALTIME); /* right now */ |
d3926f9a LP |
1118 | y = map_clock_usec(x, CLOCK_REALTIME, CLOCK_MONOTONIC); |
1119 | z = map_clock_usec(y, CLOCK_MONOTONIC, CLOCK_REALTIME); | |
1120 | /* Converting forth and back will introduce inaccuracies, since we cannot query both clocks atomically, but it should be small. Even on the slowest CI smaller than 1h */ | |
1121 | ||
1122 | assert_se((z > x ? z - x : x - z) < USEC_PER_HOUR); | |
1123 | ||
1124 | assert_se(nowr < USEC_INFINITY - USEC_PER_DAY*7); /* overflow check */ | |
1125 | x = nowr + USEC_PER_DAY*7; /* 1 week from now */ | |
1126 | y = map_clock_usec(x, CLOCK_REALTIME, CLOCK_MONOTONIC); | |
b8e0dd39 | 1127 | assert_se(timestamp_is_set(y)); |
d3926f9a | 1128 | z = map_clock_usec(y, CLOCK_MONOTONIC, CLOCK_REALTIME); |
b8e0dd39 | 1129 | assert_se(timestamp_is_set(z)); |
d3926f9a LP |
1130 | assert_se((z > x ? z - x : x - z) < USEC_PER_HOUR); |
1131 | ||
1132 | assert_se(nowr > USEC_PER_DAY * 7); /* underflow check */ | |
1133 | x = nowr - USEC_PER_DAY*7; /* 1 week ago */ | |
1134 | y = map_clock_usec(x, CLOCK_REALTIME, CLOCK_MONOTONIC); | |
1135 | if (y != 0) { /* might underflow if machine is not up long enough for the monotonic clock to be beyond 1w */ | |
1136 | assert_se(y < USEC_INFINITY); | |
1137 | z = map_clock_usec(y, CLOCK_MONOTONIC, CLOCK_REALTIME); | |
b8e0dd39 | 1138 | assert_se(timestamp_is_set(z)); |
d3926f9a LP |
1139 | assert_se((z > x ? z - x : x - z) < USEC_PER_HOUR); |
1140 | } | |
1141 | } | |
1142 | ||
8b51c41f YW |
1143 | static void test_timezone_offset_change_one(const char *utc, const char *pretty) { |
1144 | usec_t x, y, z; | |
1145 | char *s; | |
1146 | ||
1147 | assert_se(parse_timestamp(utc, &x) >= 0); | |
1148 | ||
1149 | s = FORMAT_TIMESTAMP_STYLE(x, TIMESTAMP_UTC); | |
1150 | assert_se(parse_timestamp(s, &y) >= 0); | |
1151 | log_debug("%s -> " USEC_FMT " -> %s -> " USEC_FMT, utc, x, s, y); | |
c79e88b3 | 1152 | ASSERT_STREQ(s, utc); |
8b51c41f YW |
1153 | assert_se(x == y); |
1154 | ||
1155 | assert_se(parse_timestamp(pretty, &y) >= 0); | |
1156 | s = FORMAT_TIMESTAMP_STYLE(y, TIMESTAMP_PRETTY); | |
1157 | assert_se(parse_timestamp(s, &z) >= 0); | |
1158 | log_debug("%s -> " USEC_FMT " -> %s -> " USEC_FMT, pretty, y, s, z); | |
c79e88b3 | 1159 | ASSERT_STREQ(s, pretty); |
8b51c41f YW |
1160 | assert_se(x == y); |
1161 | assert_se(x == z); | |
1162 | } | |
1163 | ||
1164 | TEST(timezone_offset_change) { | |
1165 | const char *tz = getenv("TZ"); | |
1166 | ||
1167 | /* See issue #26370. */ | |
1168 | ||
1169 | if (timezone_is_valid("Africa/Casablanca", LOG_DEBUG)) { | |
1170 | assert_se(setenv("TZ", ":Africa/Casablanca", 1) >= 0); | |
1171 | tzset(); | |
1172 | log_debug("Africa/Casablanca: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1])); | |
1173 | ||
1174 | test_timezone_offset_change_one("Sun 2015-10-25 01:59:59 UTC", "Sun 2015-10-25 02:59:59 +01"); | |
1175 | test_timezone_offset_change_one("Sun 2015-10-25 02:00:00 UTC", "Sun 2015-10-25 02:00:00 +00"); | |
1176 | test_timezone_offset_change_one("Sun 2018-06-17 01:59:59 UTC", "Sun 2018-06-17 01:59:59 +00"); | |
1177 | test_timezone_offset_change_one("Sun 2018-06-17 02:00:00 UTC", "Sun 2018-06-17 03:00:00 +01"); | |
1178 | test_timezone_offset_change_one("Sun 2018-10-28 01:59:59 UTC", "Sun 2018-10-28 02:59:59 +01"); | |
1179 | test_timezone_offset_change_one("Sun 2018-10-28 02:00:00 UTC", "Sun 2018-10-28 03:00:00 +01"); | |
1180 | } | |
1181 | ||
1182 | if (timezone_is_valid("Asia/Atyrau", LOG_DEBUG)) { | |
1183 | assert_se(setenv("TZ", ":Asia/Atyrau", 1) >= 0); | |
1184 | tzset(); | |
1185 | log_debug("Asia/Atyrau: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1])); | |
1186 | ||
1187 | test_timezone_offset_change_one("Sat 2004-03-27 21:59:59 UTC", "Sun 2004-03-28 01:59:59 +04"); | |
1188 | test_timezone_offset_change_one("Sat 2004-03-27 22:00:00 UTC", "Sun 2004-03-28 03:00:00 +05"); | |
1189 | test_timezone_offset_change_one("Sat 2004-10-30 21:59:59 UTC", "Sun 2004-10-31 02:59:59 +05"); | |
1190 | test_timezone_offset_change_one("Sat 2004-10-30 22:00:00 UTC", "Sun 2004-10-31 03:00:00 +05"); | |
1191 | } | |
1192 | ||
1193 | if (timezone_is_valid("Chile/EasterIsland", LOG_DEBUG)) { | |
1194 | assert_se(setenv("TZ", ":Chile/EasterIsland", 1) >= 0); | |
1195 | tzset(); | |
1196 | log_debug("Chile/EasterIsland: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1])); | |
1197 | ||
1198 | test_timezone_offset_change_one("Sun 1981-10-11 03:59:59 UTC", "Sat 1981-10-10 20:59:59 -07"); | |
1199 | test_timezone_offset_change_one("Sun 1981-10-11 04:00:00 UTC", "Sat 1981-10-10 22:00:00 -06"); | |
1200 | test_timezone_offset_change_one("Sun 1982-03-14 02:59:59 UTC", "Sat 1982-03-13 20:59:59 -06"); | |
1201 | test_timezone_offset_change_one("Sun 1982-03-14 03:00:00 UTC", "Sat 1982-03-13 21:00:00 -06"); | |
1202 | } | |
1203 | ||
1204 | assert_se(set_unset_env("TZ", tz, true) == 0); | |
1205 | tzset(); | |
1206 | } | |
1207 | ||
6f5cf415 LP |
1208 | static usec_t absdiff(usec_t a, usec_t b) { |
1209 | return a > b ? a - b : b - a; | |
1210 | } | |
1211 | ||
1212 | TEST(mktime_or_timegm_usec) { | |
1213 | ||
1214 | usec_t n = now(CLOCK_REALTIME), m; | |
1215 | struct tm tm; | |
1216 | ||
1217 | assert_se(localtime_or_gmtime_usec(n, /* utc= */ false, &tm) >= 0); | |
1218 | assert_se(mktime_or_timegm_usec(&tm, /* utc= */ false, &m) >= 0); | |
1219 | assert_se(absdiff(n, m) < 2 * USEC_PER_DAY); | |
1220 | ||
1221 | assert_se(localtime_or_gmtime_usec(n, /* utc= */ true, &tm) >= 0); | |
1222 | assert_se(mktime_or_timegm_usec(&tm, /* utc= */ true, &m) >= 0); | |
1223 | assert_se(absdiff(n, m) < USEC_PER_SEC); | |
1224 | ||
1225 | /* This definitely should fail, because we refuse dates before the UNIX epoch */ | |
1226 | tm = (struct tm) { | |
1227 | .tm_mday = 15, | |
1228 | .tm_mon = 11, | |
1229 | .tm_year = 1969 - 1900, | |
1230 | }; | |
1231 | ||
1232 | assert_se(mktime_or_timegm_usec(&tm, /* utc= */ true, NULL) == -ERANGE); | |
1233 | } | |
1234 | ||
99839c7e | 1235 | static int intro(void) { |
1e902c34 LB |
1236 | /* Tests have hard-coded results that do not expect a specific timezone to be set by the caller */ |
1237 | assert_se(unsetenv("TZ") >= 0); | |
1238 | ||
c4834ffa LP |
1239 | log_info("realtime=" USEC_FMT "\n" |
1240 | "monotonic=" USEC_FMT "\n" | |
1241 | "boottime=" USEC_FMT "\n", | |
1242 | now(CLOCK_REALTIME), | |
1243 | now(CLOCK_MONOTONIC), | |
ba4e0427 | 1244 | now(CLOCK_BOOTTIME)); |
c4834ffa | 1245 | |
2d60169d LP |
1246 | /* Ensure time_t is signed */ |
1247 | assert_cc((time_t) -1 < (time_t) 1); | |
1248 | ||
1249 | /* Ensure TIME_T_MAX works correctly */ | |
f0e2e0db | 1250 | uintmax_t x = TIME_T_MAX; |
313cefa1 | 1251 | x++; |
f21b863e | 1252 | assert_se((time_t) x < 0); |
99839c7e LP |
1253 | |
1254 | return EXIT_SUCCESS; | |
cb0dac05 | 1255 | } |
4f7452a8 | 1256 | |
e85fdacc | 1257 | DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro); |