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