1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * SPDX-License-Identifier: MPL-2.0
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 */
13
14 #if HAVE_CMOCKA
15
16 #include <sched.h> /* IWYU pragma: keep */
17 #include <setjmp.h>
18 #include <stdarg.h>
19 #include <stddef.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #define UNIT_TESTING
25 #include <cmocka.h>
26
27 #include <isc/result.h>
28 #include <isc/time.h>
29 #include <isc/util.h>
30
31 #include "../time.c"
32
33 #define NS_PER_S 1000000000 /*%< Nanoseconds per second. */
34 #define MAX_NS (NS_PER_S - 1)
35
36 struct time_vectors {
37 isc_time_t a;
38 isc_interval_t b;
39 isc_time_t r;
40 isc_result_t result;
41 };
42
43 const struct time_vectors vectors_add[8] = {
44 { { 0, 0 }, { 0, 0 }, { 0, 0 }, ISC_R_SUCCESS },
45 { { 0, MAX_NS }, { 0, MAX_NS }, { 1, MAX_NS - 1 }, ISC_R_SUCCESS },
46 { { 0, NS_PER_S / 2 }, { 0, NS_PER_S / 2 }, { 1, 0 }, ISC_R_SUCCESS },
47 { { UINT_MAX, MAX_NS }, { 0, 0 }, { UINT_MAX, MAX_NS }, ISC_R_SUCCESS },
48 { { UINT_MAX, 0 }, { 0, MAX_NS }, { UINT_MAX, MAX_NS }, ISC_R_SUCCESS },
49 { { UINT_MAX, 0 }, { 1, 0 }, { 0, 0 }, ISC_R_RANGE },
50 { { UINT_MAX, MAX_NS }, { 0, 1 }, { 0, 0 }, ISC_R_RANGE },
51 { { UINT_MAX / 2 + 1, NS_PER_S / 2 },
52 { UINT_MAX / 2, NS_PER_S / 2 },
53 { 0, 0 },
54 ISC_R_RANGE },
55 };
56
57 const struct time_vectors vectors_sub[7] = {
58 { { 0, 0 }, { 0, 0 }, { 0, 0 }, ISC_R_SUCCESS },
59 { { 1, 0 }, { 0, MAX_NS }, { 0, 1 }, ISC_R_SUCCESS },
60 { { 1, NS_PER_S / 2 },
61 { 0, MAX_NS },
62 { 0, NS_PER_S / 2 + 1 },
63 ISC_R_SUCCESS },
64 { { UINT_MAX, MAX_NS }, { UINT_MAX, 0 }, { 0, MAX_NS }, ISC_R_SUCCESS },
65 { { 0, 0 }, { 1, 0 }, { 0, 0 }, ISC_R_RANGE },
66 { { 0, 0 }, { 0, MAX_NS }, { 0, 0 }, ISC_R_RANGE },
67 };
68
69 static void
isc_time_add_test(void ** state)70 isc_time_add_test(void **state) {
71 UNUSED(state);
72
73 for (size_t i = 0; i < ARRAY_SIZE(vectors_add); i++) {
74 isc_time_t r = { UINT_MAX, UINT_MAX };
75 isc_result_t result = isc_time_add(&(vectors_add[i].a),
76 &(vectors_add[i].b), &r);
77 assert_int_equal(result, vectors_add[i].result);
78 if (result != ISC_R_SUCCESS) {
79 continue;
80 }
81
82 assert_int_equal(r.seconds, vectors_add[i].r.seconds);
83 assert_int_equal(r.nanoseconds, vectors_add[i].r.nanoseconds);
84 }
85
86 expect_assert_failure((void)isc_time_add(&(isc_time_t){ 0, MAX_NS + 1 },
87 &(isc_interval_t){ 0, 0 },
88 &(isc_time_t){ 0, 0 }));
89 expect_assert_failure((void)isc_time_add(
90 &(isc_time_t){ 0, 0 }, &(isc_interval_t){ 0, MAX_NS + 1 },
91 &(isc_time_t){ 0, 0 }));
92
93 expect_assert_failure((void)isc_time_add((isc_time_t *)NULL,
94 &(isc_interval_t){ 0, 0 },
95 &(isc_time_t){ 0, 0 }));
96 expect_assert_failure((void)isc_time_add(&(isc_time_t){ 0, 0 },
97 (isc_interval_t *)NULL,
98 &(isc_time_t){ 0, 0 }));
99 expect_assert_failure((void)isc_time_add(
100 &(isc_time_t){ 0, 0 }, &(isc_interval_t){ 0, 0 }, NULL));
101 }
102
103 static void
isc_time_sub_test(void ** state)104 isc_time_sub_test(void **state) {
105 UNUSED(state);
106
107 for (size_t i = 0; i < ARRAY_SIZE(vectors_sub); i++) {
108 isc_time_t r = { UINT_MAX, UINT_MAX };
109 isc_result_t result = isc_time_subtract(
110 &(vectors_sub[i].a), &(vectors_sub[i].b), &r);
111 assert_int_equal(result, vectors_sub[i].result);
112 if (result != ISC_R_SUCCESS) {
113 continue;
114 }
115 assert_int_equal(r.seconds, vectors_sub[i].r.seconds);
116 assert_int_equal(r.nanoseconds, vectors_sub[i].r.nanoseconds);
117 }
118
119 expect_assert_failure((void)isc_time_subtract(
120 &(isc_time_t){ 0, MAX_NS + 1 }, &(isc_interval_t){ 0, 0 },
121 &(isc_time_t){ 0, 0 }));
122 expect_assert_failure((void)isc_time_subtract(
123 &(isc_time_t){ 0, 0 }, &(isc_interval_t){ 0, MAX_NS + 1 },
124 &(isc_time_t){ 0, 0 }));
125
126 expect_assert_failure((void)isc_time_subtract((isc_time_t *)NULL,
127 &(isc_interval_t){ 0, 0 },
128 &(isc_time_t){ 0, 0 }));
129 expect_assert_failure((void)isc_time_subtract(&(isc_time_t){ 0, 0 },
130 (isc_interval_t *)NULL,
131 &(isc_time_t){ 0, 0 }));
132 expect_assert_failure((void)isc_time_subtract(
133 &(isc_time_t){ 0, 0 }, &(isc_interval_t){ 0, 0 }, NULL));
134 }
135
136 /* parse http time stamp */
137 static void
isc_time_parsehttptimestamp_test(void ** state)138 isc_time_parsehttptimestamp_test(void **state) {
139 isc_result_t result;
140 isc_time_t t, x;
141 char buf[ISC_FORMATHTTPTIMESTAMP_SIZE];
142
143 UNUSED(state);
144
145 setenv("TZ", "America/Los_Angeles", 1);
146 result = isc_time_now(&t);
147 assert_int_equal(result, ISC_R_SUCCESS);
148
149 isc_time_formathttptimestamp(&t, buf, sizeof(buf));
150 result = isc_time_parsehttptimestamp(buf, &x);
151 assert_int_equal(result, ISC_R_SUCCESS);
152 assert_int_equal(isc_time_seconds(&t), isc_time_seconds(&x));
153 }
154
155 /* print UTC in ISO8601 */
156 static void
isc_time_formatISO8601_test(void ** state)157 isc_time_formatISO8601_test(void **state) {
158 isc_result_t result;
159 isc_time_t t;
160 char buf[64];
161
162 UNUSED(state);
163
164 setenv("TZ", "America/Los_Angeles", 1);
165 result = isc_time_now(&t);
166 assert_int_equal(result, ISC_R_SUCCESS);
167
168 /* check formatting: yyyy-mm-ddThh:mm:ssZ */
169 memset(buf, 'X', sizeof(buf));
170 isc_time_formatISO8601(&t, buf, sizeof(buf));
171 assert_int_equal(strlen(buf), 20);
172 assert_int_equal(buf[4], '-');
173 assert_int_equal(buf[7], '-');
174 assert_int_equal(buf[10], 'T');
175 assert_int_equal(buf[13], ':');
176 assert_int_equal(buf[16], ':');
177 assert_int_equal(buf[19], 'Z');
178
179 /* check time conversion correctness */
180 memset(buf, 'X', sizeof(buf));
181 isc_time_settoepoch(&t);
182 isc_time_formatISO8601(&t, buf, sizeof(buf));
183 assert_string_equal(buf, "1970-01-01T00:00:00Z");
184
185 memset(buf, 'X', sizeof(buf));
186 isc_time_set(&t, 1450000000, 123000000);
187 isc_time_formatISO8601(&t, buf, sizeof(buf));
188 assert_string_equal(buf, "2015-12-13T09:46:40Z");
189 }
190
191 /* print UTC in ISO8601 with milliseconds */
192 static void
isc_time_formatISO8601ms_test(void ** state)193 isc_time_formatISO8601ms_test(void **state) {
194 isc_result_t result;
195 isc_time_t t;
196 char buf[64];
197
198 UNUSED(state);
199
200 setenv("TZ", "America/Los_Angeles", 1);
201 result = isc_time_now(&t);
202 assert_int_equal(result, ISC_R_SUCCESS);
203
204 /* check formatting: yyyy-mm-ddThh:mm:ss.sssZ */
205 memset(buf, 'X', sizeof(buf));
206 isc_time_formatISO8601ms(&t, buf, sizeof(buf));
207 assert_int_equal(strlen(buf), 24);
208 assert_int_equal(buf[4], '-');
209 assert_int_equal(buf[7], '-');
210 assert_int_equal(buf[10], 'T');
211 assert_int_equal(buf[13], ':');
212 assert_int_equal(buf[16], ':');
213 assert_int_equal(buf[19], '.');
214 assert_int_equal(buf[23], 'Z');
215
216 /* check time conversion correctness */
217 memset(buf, 'X', sizeof(buf));
218 isc_time_settoepoch(&t);
219 isc_time_formatISO8601ms(&t, buf, sizeof(buf));
220 assert_string_equal(buf, "1970-01-01T00:00:00.000Z");
221
222 memset(buf, 'X', sizeof(buf));
223 isc_time_set(&t, 1450000000, 123000000);
224 isc_time_formatISO8601ms(&t, buf, sizeof(buf));
225 assert_string_equal(buf, "2015-12-13T09:46:40.123Z");
226 }
227
228 /* print UTC in ISO8601 with microseconds */
229 static void
isc_time_formatISO8601us_test(void ** state)230 isc_time_formatISO8601us_test(void **state) {
231 isc_result_t result;
232 isc_time_t t;
233 char buf[64];
234
235 UNUSED(state);
236
237 setenv("TZ", "America/Los_Angeles", 1);
238 result = isc_time_now_hires(&t);
239 assert_int_equal(result, ISC_R_SUCCESS);
240
241 /* check formatting: yyyy-mm-ddThh:mm:ss.ssssssZ */
242 memset(buf, 'X', sizeof(buf));
243 isc_time_formatISO8601us(&t, buf, sizeof(buf));
244 assert_int_equal(strlen(buf), 27);
245 assert_int_equal(buf[4], '-');
246 assert_int_equal(buf[7], '-');
247 assert_int_equal(buf[10], 'T');
248 assert_int_equal(buf[13], ':');
249 assert_int_equal(buf[16], ':');
250 assert_int_equal(buf[19], '.');
251 assert_int_equal(buf[26], 'Z');
252
253 /* check time conversion correctness */
254 memset(buf, 'X', sizeof(buf));
255 isc_time_settoepoch(&t);
256 isc_time_formatISO8601us(&t, buf, sizeof(buf));
257 assert_string_equal(buf, "1970-01-01T00:00:00.000000Z");
258
259 memset(buf, 'X', sizeof(buf));
260 isc_time_set(&t, 1450000000, 123456000);
261 isc_time_formatISO8601us(&t, buf, sizeof(buf));
262 assert_string_equal(buf, "2015-12-13T09:46:40.123456Z");
263 }
264
265 /* print local time in ISO8601 */
266 static void
isc_time_formatISO8601L_test(void ** state)267 isc_time_formatISO8601L_test(void **state) {
268 isc_result_t result;
269 isc_time_t t;
270 char buf[64];
271
272 UNUSED(state);
273
274 setenv("TZ", "America/Los_Angeles", 1);
275 result = isc_time_now(&t);
276 assert_int_equal(result, ISC_R_SUCCESS);
277
278 /* check formatting: yyyy-mm-ddThh:mm:ss */
279 memset(buf, 'X', sizeof(buf));
280 isc_time_formatISO8601L(&t, buf, sizeof(buf));
281 assert_int_equal(strlen(buf), 19);
282 assert_int_equal(buf[4], '-');
283 assert_int_equal(buf[7], '-');
284 assert_int_equal(buf[10], 'T');
285 assert_int_equal(buf[13], ':');
286 assert_int_equal(buf[16], ':');
287
288 /* check time conversion correctness */
289 memset(buf, 'X', sizeof(buf));
290 isc_time_settoepoch(&t);
291 isc_time_formatISO8601L(&t, buf, sizeof(buf));
292 assert_string_equal(buf, "1969-12-31T16:00:00");
293
294 memset(buf, 'X', sizeof(buf));
295 isc_time_set(&t, 1450000000, 123000000);
296 isc_time_formatISO8601L(&t, buf, sizeof(buf));
297 assert_string_equal(buf, "2015-12-13T01:46:40");
298 }
299
300 /* print local time in ISO8601 with milliseconds */
301 static void
isc_time_formatISO8601Lms_test(void ** state)302 isc_time_formatISO8601Lms_test(void **state) {
303 isc_result_t result;
304 isc_time_t t;
305 char buf[64];
306
307 UNUSED(state);
308
309 setenv("TZ", "America/Los_Angeles", 1);
310 result = isc_time_now(&t);
311 assert_int_equal(result, ISC_R_SUCCESS);
312
313 /* check formatting: yyyy-mm-ddThh:mm:ss.sss */
314 memset(buf, 'X', sizeof(buf));
315 isc_time_formatISO8601Lms(&t, buf, sizeof(buf));
316 assert_int_equal(strlen(buf), 23);
317 assert_int_equal(buf[4], '-');
318 assert_int_equal(buf[7], '-');
319 assert_int_equal(buf[10], 'T');
320 assert_int_equal(buf[13], ':');
321 assert_int_equal(buf[16], ':');
322 assert_int_equal(buf[19], '.');
323
324 /* check time conversion correctness */
325 memset(buf, 'X', sizeof(buf));
326 isc_time_settoepoch(&t);
327 isc_time_formatISO8601Lms(&t, buf, sizeof(buf));
328 assert_string_equal(buf, "1969-12-31T16:00:00.000");
329
330 memset(buf, 'X', sizeof(buf));
331 isc_time_set(&t, 1450000000, 123000000);
332 isc_time_formatISO8601Lms(&t, buf, sizeof(buf));
333 assert_string_equal(buf, "2015-12-13T01:46:40.123");
334 }
335
336 /* print local time in ISO8601 with microseconds */
337 static void
isc_time_formatISO8601Lus_test(void ** state)338 isc_time_formatISO8601Lus_test(void **state) {
339 isc_result_t result;
340 isc_time_t t;
341 char buf[64];
342
343 UNUSED(state);
344
345 setenv("TZ", "America/Los_Angeles", 1);
346 result = isc_time_now_hires(&t);
347 assert_int_equal(result, ISC_R_SUCCESS);
348
349 /* check formatting: yyyy-mm-ddThh:mm:ss.ssssss */
350 memset(buf, 'X', sizeof(buf));
351 isc_time_formatISO8601Lus(&t, buf, sizeof(buf));
352 assert_int_equal(strlen(buf), 26);
353 assert_int_equal(buf[4], '-');
354 assert_int_equal(buf[7], '-');
355 assert_int_equal(buf[10], 'T');
356 assert_int_equal(buf[13], ':');
357 assert_int_equal(buf[16], ':');
358 assert_int_equal(buf[19], '.');
359
360 /* check time conversion correctness */
361 memset(buf, 'X', sizeof(buf));
362 isc_time_settoepoch(&t);
363 isc_time_formatISO8601Lus(&t, buf, sizeof(buf));
364 assert_string_equal(buf, "1969-12-31T16:00:00.000000");
365
366 memset(buf, 'X', sizeof(buf));
367 isc_time_set(&t, 1450000000, 123456000);
368 isc_time_formatISO8601Lus(&t, buf, sizeof(buf));
369 assert_string_equal(buf, "2015-12-13T01:46:40.123456");
370 }
371
372 /* print UTC time as yyyymmddhhmmsssss */
373 static void
isc_time_formatshorttimestamp_test(void ** state)374 isc_time_formatshorttimestamp_test(void **state) {
375 isc_result_t result;
376 isc_time_t t;
377 char buf[64];
378
379 UNUSED(state);
380
381 setenv("TZ", "America/Los_Angeles", 1);
382 result = isc_time_now(&t);
383 assert_int_equal(result, ISC_R_SUCCESS);
384
385 /* check formatting: yyyymmddhhmmsssss */
386 memset(buf, 'X', sizeof(buf));
387 isc_time_formatshorttimestamp(&t, buf, sizeof(buf));
388 assert_int_equal(strlen(buf), 17);
389
390 /* check time conversion correctness */
391 memset(buf, 'X', sizeof(buf));
392 isc_time_settoepoch(&t);
393 isc_time_formatshorttimestamp(&t, buf, sizeof(buf));
394 assert_string_equal(buf, "19700101000000000");
395
396 memset(buf, 'X', sizeof(buf));
397 isc_time_set(&t, 1450000000, 123000000);
398 isc_time_formatshorttimestamp(&t, buf, sizeof(buf));
399 assert_string_equal(buf, "20151213094640123");
400 }
401
402 int
main(void)403 main(void) {
404 const struct CMUnitTest tests[] = {
405 cmocka_unit_test(isc_time_add_test),
406 cmocka_unit_test(isc_time_sub_test),
407 cmocka_unit_test(isc_time_parsehttptimestamp_test),
408 cmocka_unit_test(isc_time_formatISO8601_test),
409 cmocka_unit_test(isc_time_formatISO8601ms_test),
410 cmocka_unit_test(isc_time_formatISO8601us_test),
411 cmocka_unit_test(isc_time_formatISO8601L_test),
412 cmocka_unit_test(isc_time_formatISO8601Lms_test),
413 cmocka_unit_test(isc_time_formatISO8601Lus_test),
414 cmocka_unit_test(isc_time_formatshorttimestamp_test),
415 };
416
417 return (cmocka_run_group_tests(tests, NULL, NULL));
418 }
419
420 #else /* HAVE_CMOCKA */
421
422 #include <stdio.h>
423
424 int
main(void)425 main(void) {
426 printf("1..0 # Skipped: cmocka not available\n");
427 return (SKIPPED_TEST_EXIT_CODE);
428 }
429
430 #endif /* if HAVE_CMOCKA */
431