1 /*
2  * Copyright (c) 2019 Peter Bigot Consulting
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /* Tests where time_t requires a 64-bit value */
8 
9 #include <errno.h>
10 #include <zephyr/ztest.h>
11 #include "timeutil_test.h"
12 
13 static const struct timeutil_test_data tests[] = {
14 	/* 32-bit, but algorithm subtraction underflows */
15 	{ .ux = -2147483648,
16 	  .civil = "1901-12-13 20:45:52 Fri 347",
17 	  .tm = {
18 		  .tm_sec = 52,
19 		  .tm_min = 45,
20 		  .tm_hour = 20,
21 		  .tm_mday = 13,
22 		  .tm_mon = 11,
23 		  .tm_year = 1,
24 		  .tm_wday = 5,
25 		  .tm_yday = 346,
26 	  } },
27 	{ .ux = (time_t)-2147483649,
28 	  .civil = "1901-12-13 20:45:51 Fri 347",
29 	  .tm = {
30 		  .tm_sec = 51,
31 		  .tm_min = 45,
32 		  .tm_hour = 20,
33 		  .tm_mday = 13,
34 		  .tm_mon = 11,
35 		  .tm_year = 1,
36 		  .tm_wday = 5,
37 		  .tm_yday = 346,
38 	  } },
39 	{ .ux = (time_t)2147483648,
40 	  .civil = "2038-01-19 03:14:08 Tue 019",
41 	  .tm = {
42 		  .tm_sec = 8,
43 		  .tm_min = 14,
44 		  .tm_hour = 3,
45 		  .tm_mday = 19,
46 		  .tm_mon = 0,
47 		  .tm_year = 138,
48 		  .tm_wday = 2,
49 		  .tm_yday = 18,
50 	  } },
51 	{ .ux = (time_t)64060588799,
52 	  .civil = "3999-12-31 23:59:59 Fri 365",
53 	  .tm = {
54 		  .tm_sec = 59,
55 		  .tm_min = 59,
56 		  .tm_hour = 23,
57 		  .tm_mday = 31,
58 		  .tm_mon = 11,
59 		  .tm_year = 2099,
60 		  .tm_wday = 5,
61 		  .tm_yday = 364,
62 	  } },
63 	{ .ux = (time_t)64060588800,
64 	  .civil = "4000-01-01 00:00:00 Sat 001",
65 	  .tm = {
66 		  .tm_sec = 0,
67 		  .tm_min = 0,
68 		  .tm_hour = 0,
69 		  .tm_mday = 1,
70 		  .tm_mon = 0,
71 		  .tm_year = 2100,
72 		  .tm_wday = 6,
73 		  .tm_yday = 0,
74 	  } },
75 	/* Normal century is a common year */
76 	{ .ux = (time_t)-2208988801,
77 	  .civil = "1899-12-31 23:59:59 Sun 365",
78 	  .tm = {
79 		  .tm_sec = 59,
80 		  .tm_min = 59,
81 		  .tm_hour = 23,
82 		  .tm_mday = 31,
83 		  .tm_mon = 11,
84 		  .tm_year = -1,
85 		  .tm_wday = 0,
86 		  .tm_yday = 364,
87 	  } },
88 	{ .ux = (time_t)-2208988800,
89 	  .civil = "1900-01-01 00:00:00 Mon 001",
90 	  .tm = {
91 		  .tm_sec = 0,
92 		  .tm_min = 0,
93 		  .tm_hour = 0,
94 		  .tm_mday = 1,
95 		  .tm_mon = 0,
96 		  .tm_year = 0,
97 		  .tm_wday = 1,
98 		  .tm_yday = 0,
99 	  } },
100 	{ .ux = (time_t)-2203977600,
101 	  .civil = "1900-02-28 00:00:00 Wed 059",
102 	  .tm = {
103 		  .tm_sec = 0,
104 		  .tm_min = 0,
105 		  .tm_hour = 0,
106 		  .tm_mday = 28,
107 		  .tm_mon = 1,
108 		  .tm_year = 0,
109 		  .tm_wday = 3,
110 		  .tm_yday = 58,
111 	  } },
112 	{ .ux = (time_t)-2203891200,
113 	  .civil = "1900-03-01 00:00:00 Thu 060",
114 	  .tm = {
115 		  .tm_sec = 0,
116 		  .tm_min = 0,
117 		  .tm_hour = 0,
118 		  .tm_mday = 1,
119 		  .tm_mon = 2,
120 		  .tm_year = 0,
121 		  .tm_wday = 4,
122 		  .tm_yday = 59,
123 	  } },
124 	{ .ux = (time_t)-2177539200,
125 	  .civil = "1900-12-31 00:00:00 Mon 365",
126 	  .tm = {
127 		  .tm_sec = 0,
128 		  .tm_min = 0,
129 		  .tm_hour = 0,
130 		  .tm_mday = 31,
131 		  .tm_mon = 11,
132 		  .tm_year = 0,
133 		  .tm_wday = 1,
134 		  .tm_yday = 364,
135 	  } },
136 	{ .ux = (time_t)-2177452800,
137 	  .civil = "1901-01-01 00:00:00 Tue 001",
138 	  .tm = {
139 		  .tm_sec = 0,
140 		  .tm_min = 0,
141 		  .tm_hour = 0,
142 		  .tm_mday = 1,
143 		  .tm_mon = 0,
144 		  .tm_year = 1,
145 		  .tm_wday = 2,
146 		  .tm_yday = 0,
147 	  } },
148 
149 	/* Extrema, check against proleptic Gregorian calendar data:
150 	 * https://www.timeanddate.com/calendar/?year=1&country=22
151 	 */
152 	{ .ux = (time_t)-62167305600,
153 	  .civil = "-1-12-31 00:00:00 Fri 365",
154 	  .tm = {
155 		  .tm_sec = 0,
156 		  .tm_min = 0,
157 		  .tm_hour = 0,
158 		  .tm_mday = 31,
159 		  .tm_mon = 11,
160 		  .tm_year = -1901,
161 		  .tm_wday = 5,
162 		  .tm_yday = 364,
163 	  } },
164 	{ .ux = (time_t)-62167219200,
165 	  .civil = "0-01-01 00:00:00 Sat 001",
166 	  .tm = {
167 		  .tm_sec = 0,
168 		  .tm_min = 0,
169 		  .tm_hour = 0,
170 		  .tm_mday = 1,
171 		  .tm_mon = 0,
172 		  .tm_year = -1900,
173 		  .tm_wday = 6,
174 		  .tm_yday = 0,
175 	  } },
176 	{ .ux = (time_t)-62135596801,
177 	  .civil = "0-12-31 23:59:59 Sun 366",
178 	  .tm = {
179 		  .tm_sec = 59,
180 		  .tm_min = 59,
181 		  .tm_hour = 23,
182 		  .tm_mday = 31,
183 		  .tm_mon = 11,
184 		  .tm_year = -1900,
185 		  .tm_wday = 0,
186 		  .tm_yday = 365,
187 	  } },
188 	{ .ux = (time_t)-62135596800,
189 	  .civil = "1-01-01 00:00:00 Mon 001",
190 	  .tm = {
191 		  .tm_sec = 0,
192 		  .tm_min = 0,
193 		  .tm_hour = 0,
194 		  .tm_mday = 1,
195 		  .tm_mon = 0,
196 		  .tm_year = -1899,
197 		  .tm_wday = 1,
198 		  .tm_yday = 0,
199 	  } },
200 	{ .ux = (time_t)-62135596800,
201 	  .civil = "1-01-01 00:00:00 Mon 001",
202 	  .tm = {
203 		  .tm_sec = 0,
204 		  .tm_min = 0,
205 		  .tm_hour = 0,
206 		  .tm_mday = 1,
207 		  .tm_mon = 0,
208 		  .tm_year = -1899,
209 		  .tm_wday = 1,
210 		  .tm_yday = 0,
211 	  } },
212 };
213 
test_time32_errno_clear(void)214 static void test_time32_errno_clear(void)
215 {
216 	const struct timeutil_test_data *tp = &(const struct timeutil_test_data){
217 		.ux = 0,
218 		.civil = "1970-01-01 00:00:00 Thu 001",
219 		.tm = {
220 			.tm_sec = 0,
221 			.tm_min = 0,
222 			.tm_hour = 0,
223 			.tm_mday = 1,
224 			.tm_mon = 0,
225 			.tm_year = 70,
226 			.tm_wday = 4,
227 			.tm_yday = 0,
228 		},
229 	};
230 
231 	errno = EINVAL;
232 
233 	time_t ux = timeutil_timegm(&tp->tm);
234 
235 	zassert_equal(ux, tp->ux,
236 		      "conversion incorrect");
237 	zassert_equal(errno, 0,
238 		      "errno was not cleared");
239 }
240 
test_time32_epochm1(void)241 static void test_time32_epochm1(void)
242 {
243 	const struct timeutil_test_data *tp = &(const struct timeutil_test_data){
244 		.ux = -1,
245 		.civil = "1969-12-31 23:59:59 Wed 365",
246 		.tm = {
247 			.tm_sec = 59,
248 			.tm_min = 59,
249 			.tm_hour = 23,
250 			.tm_mday = 31,
251 			.tm_mon = 11,
252 			.tm_year = 69,
253 			.tm_wday = 3,
254 			.tm_yday = 364,
255 		},
256 	};
257 
258 	errno = EINVAL;
259 
260 	time_t ux = timeutil_timegm(&tp->tm);
261 
262 	zassert_equal(ux, tp->ux,
263 		      "conversion incorrect");
264 	zassert_equal(errno, 0,
265 		      "final errno state bad");
266 }
267 
test_time32_underflow(void)268 static void test_time32_underflow(void)
269 {
270 	const int64_t unix64 = -2147483649;
271 	const struct timeutil_test_data *tp = &(const struct timeutil_test_data){
272 		.civil = "1901-12-13 20:45:51 Fri 347",
273 		.tm = {
274 			.tm_sec = 51,
275 			.tm_min = 45,
276 			.tm_hour = 20,
277 			.tm_mday = 13,
278 			.tm_mon = 11,
279 			.tm_year = 1,
280 			.tm_wday = 5,
281 			.tm_yday = 346,
282 		},
283 	};
284 
285 	zassert_equal(timeutil_timegm64(&tp->tm), unix64,
286 		      "fullscale failed");
287 	errno = 0;
288 
289 	time_t ux = timeutil_timegm(&tp->tm);
290 
291 	zassert_equal(ux, -1,
292 		      "underflow undetected");
293 	zassert_equal(errno, ERANGE,
294 		      "final errno state bad");
295 }
296 
test_time32_overflow(void)297 static void test_time32_overflow(void)
298 {
299 	const int64_t unix64 = 2147483648;
300 	const struct timeutil_test_data *tp = &(const struct timeutil_test_data){
301 		.civil = "2038-01-19 03:14:08 Tue 019",
302 		.tm = {
303 			.tm_sec = 8,
304 			.tm_min = 14,
305 			.tm_hour = 3,
306 			.tm_mday = 19,
307 			.tm_mon = 0,
308 			.tm_year = 138,
309 			.tm_wday = 2,
310 			.tm_yday = 18,
311 		},
312 	};
313 
314 	zassert_equal(timeutil_timegm64(&tp->tm), unix64,
315 		      "fullscale failed");
316 	errno = 0;
317 
318 	time_t ux = timeutil_timegm(&tp->tm);
319 
320 	zassert_equal(ux, -1,
321 		      "overflow undetected");
322 	zassert_equal(errno, ERANGE,
323 		      "final errno state bad");
324 }
325 
ZTEST(timeutil_api,test_s64)326 ZTEST(timeutil_api, test_s64)
327 {
328 	if (sizeof(time_t) < 8U) {
329 		test_time32_errno_clear();
330 		test_time32_epochm1();
331 		test_time32_underflow();
332 		test_time32_overflow();
333 		return;
334 	}
335 	timeutil_check(tests, sizeof(tests) / sizeof(*tests));
336 }
337