1 | //===-- Unittests for mktime ----------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "src/__support/CPP/limits.h" // INT_MAX |
10 | #include "src/time/mktime.h" |
11 | #include "src/time/time_utils.h" |
12 | #include "test/UnitTest/ErrnoSetterMatcher.h" |
13 | #include "test/UnitTest/Test.h" |
14 | #include "test/src/time/TmHelper.h" |
15 | #include "test/src/time/TmMatcher.h" |
16 | |
17 | using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; |
18 | using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; |
19 | using LIBC_NAMESPACE::time_utils::Month; |
20 | |
21 | static inline constexpr int tm_year(int year) { |
22 | return year - TimeConstants::TIME_YEAR_BASE; |
23 | } |
24 | |
25 | TEST(LlvmLibcMkTime, FailureSetsErrno) { |
26 | struct tm tm_data { |
27 | .tm_sec = INT_MAX, .tm_min = INT_MAX, .tm_hour = INT_MAX, |
28 | .tm_mday = INT_MAX, .tm_mon = INT_MAX - 1, .tm_year = tm_year(INT_MAX), |
29 | .tm_wday = 0, .tm_yday = 0, .tm_isdst = 0 |
30 | }; |
31 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); |
32 | } |
33 | |
34 | TEST(LlvmLibcMkTime, InvalidSeconds) { |
35 | { |
36 | // -1 second from 1970-01-01 00:00:00 returns 1969-12-31 23:59:59. |
37 | struct tm tm_data { |
38 | .tm_sec = -1, .tm_min = 0, .tm_hour = 0, .tm_mday = 1, |
39 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 1970), .tm_wday = 0, |
40 | .tm_yday = 0, .tm_isdst = 0 |
41 | }; |
42 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Succeeds(-1)); |
43 | EXPECT_TM_EQ((tm{.tm_sec = 59, |
44 | .tm_min = 59, |
45 | .tm_hour = 23, |
46 | .tm_mday = 31, |
47 | .tm_mon = Month::DECEMBER, |
48 | .tm_year = tm_year(1969), |
49 | .tm_wday = 3, |
50 | .tm_yday = 364, |
51 | .tm_isdst = 0}), |
52 | tm_data); |
53 | } |
54 | |
55 | { |
56 | // 60 seconds from 1970-01-01 00:00:00 returns 1970-01-01 00:01:00. |
57 | struct tm tm_data { |
58 | .tm_sec = 60, .tm_min = 0, .tm_hour = 0, .tm_mday = 1, |
59 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 1970), .tm_wday = 0, |
60 | .tm_yday = 0, .tm_isdst = 0 |
61 | }; |
62 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Succeeds(60)); |
63 | EXPECT_TM_EQ((tm{.tm_sec = 0, |
64 | .tm_min = 1, |
65 | .tm_hour = 0, |
66 | .tm_mday = 1, |
67 | .tm_mon = Month::JANUARY, |
68 | .tm_year = tm_year(1970), |
69 | .tm_wday = 4, |
70 | .tm_yday = 0, |
71 | .tm_isdst = 0}), |
72 | tm_data); |
73 | } |
74 | } |
75 | |
76 | TEST(LlvmLibcMkTime, InvalidMinutes) { |
77 | { |
78 | // -1 minute from 1970-01-01 00:00:00 returns 1969-12-31 23:59:00. |
79 | struct tm tm_data { |
80 | .tm_sec = 0, .tm_min = -1, .tm_hour = 0, .tm_mday = 1, |
81 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 1970), .tm_wday = 0, |
82 | .tm_yday = 0, .tm_isdst = 0 |
83 | }; |
84 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), |
85 | Succeeds(-TimeConstants::SECONDS_PER_MIN)); |
86 | EXPECT_TM_EQ((tm{.tm_sec = 0, |
87 | .tm_min = 59, |
88 | .tm_hour = 23, |
89 | .tm_mday = 31, |
90 | .tm_mon = Month::DECEMBER, |
91 | .tm_year = tm_year(1969), |
92 | .tm_wday = 3, |
93 | .tm_yday = 0, |
94 | .tm_isdst = 0}), |
95 | tm_data); |
96 | } |
97 | |
98 | { |
99 | // 60 minutes from 1970-01-01 00:00:00 returns 1970-01-01 01:00:00. |
100 | struct tm tm_data { |
101 | .tm_sec = 0, .tm_min = 60, .tm_hour = 0, .tm_mday = 1, |
102 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 1970), .tm_wday = 0, |
103 | .tm_yday = 0, .tm_isdst = 0 |
104 | }; |
105 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), |
106 | Succeeds(60 * TimeConstants::SECONDS_PER_MIN)); |
107 | EXPECT_TM_EQ((tm{.tm_sec = 0, |
108 | .tm_min = 0, |
109 | .tm_hour = 1, |
110 | .tm_mday = 1, |
111 | .tm_mon = Month::JANUARY, |
112 | .tm_year = tm_year(1970), |
113 | .tm_wday = 4, |
114 | .tm_yday = 0, |
115 | .tm_isdst = 0}), |
116 | tm_data); |
117 | } |
118 | } |
119 | |
120 | TEST(LlvmLibcMkTime, InvalidHours) { |
121 | { |
122 | // -1 hour from 1970-01-01 00:00:00 returns 1969-12-31 23:00:00. |
123 | struct tm tm_data { |
124 | .tm_sec = 0, .tm_min = 0, .tm_hour = -1, .tm_mday = 1, |
125 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 1970), .tm_wday = 0, |
126 | .tm_yday = 0, .tm_isdst = 0 |
127 | }; |
128 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), |
129 | Succeeds(-TimeConstants::SECONDS_PER_HOUR)); |
130 | EXPECT_TM_EQ((tm{.tm_sec = 0, |
131 | .tm_min = 0, |
132 | .tm_hour = 23, |
133 | .tm_mday = 31, |
134 | .tm_mon = Month::DECEMBER, |
135 | .tm_year = tm_year(1969), |
136 | .tm_wday = 3, |
137 | .tm_yday = 0, |
138 | .tm_isdst = 0}), |
139 | tm_data); |
140 | } |
141 | |
142 | { |
143 | // 24 hours from 1970-01-01 00:00:00 returns 1970-01-02 00:00:00. |
144 | struct tm tm_data { |
145 | .tm_sec = 0, .tm_min = 0, .tm_hour = 24, .tm_mday = 1, |
146 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 1970), .tm_wday = 0, |
147 | .tm_yday = 0, .tm_isdst = 0 |
148 | }; |
149 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), |
150 | Succeeds(24 * TimeConstants::SECONDS_PER_HOUR)); |
151 | EXPECT_TM_EQ((tm{.tm_sec = 0, |
152 | .tm_min = 0, |
153 | .tm_hour = 0, |
154 | .tm_mday = 2, |
155 | .tm_mon = Month::JANUARY, |
156 | .tm_year = tm_year(1970), |
157 | .tm_wday = 5, |
158 | .tm_yday = 0, |
159 | .tm_isdst = 0}), |
160 | tm_data); |
161 | } |
162 | } |
163 | |
164 | TEST(LlvmLibcMkTime, InvalidYear) { |
165 | // -1 year from 1970-01-01 00:00:00 returns 1969-01-01 00:00:00. |
166 | struct tm tm_data { |
167 | .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 1, |
168 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 1969), .tm_wday = 0, |
169 | .tm_yday = 0, .tm_isdst = 0 |
170 | }; |
171 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), |
172 | Succeeds(-TimeConstants::DAYS_PER_NON_LEAP_YEAR * |
173 | TimeConstants::SECONDS_PER_DAY)); |
174 | EXPECT_TM_EQ((tm{.tm_sec = 0, |
175 | .tm_min = 0, |
176 | .tm_hour = 0, |
177 | .tm_mday = 1, |
178 | .tm_mon = Month::JANUARY, |
179 | .tm_year = tm_year(1969), |
180 | .tm_wday = 3, |
181 | .tm_yday = 0, |
182 | .tm_isdst = 0}), |
183 | tm_data); |
184 | } |
185 | |
186 | TEST(LlvmLibcMkTime, InvalidEndOf32BitEpochYear) { |
187 | if (sizeof(time_t) != 4) |
188 | return; |
189 | { |
190 | // 2038-01-19 03:14:08 tests overflow of the second in 2038. |
191 | struct tm tm_data { |
192 | .tm_sec = 8, .tm_min = 14, .tm_hour = 3, .tm_mday = 19, |
193 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 2038), .tm_wday = 0, |
194 | .tm_yday = 0, .tm_isdst = 0 |
195 | }; |
196 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); |
197 | } |
198 | |
199 | { |
200 | // 2038-01-19 03:15:07 tests overflow of the minute in 2038. |
201 | struct tm tm_data { |
202 | .tm_sec = 7, .tm_min = 15, .tm_hour = 3, .tm_mday = 19, |
203 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 2038), .tm_wday = 0, |
204 | .tm_yday = 0, .tm_isdst = 0 |
205 | }; |
206 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); |
207 | } |
208 | |
209 | { |
210 | // 2038-01-19 04:14:07 tests overflow of the hour in 2038. |
211 | struct tm tm_data { |
212 | .tm_sec = 7, .tm_min = 14, .tm_hour = 4, .tm_mday = 19, |
213 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 2038), .tm_wday = 0, |
214 | .tm_yday = 0, .tm_isdst = 0 |
215 | }; |
216 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); |
217 | } |
218 | |
219 | { |
220 | // 2038-01-20 03:14:07 tests overflow of the day in 2038. |
221 | struct tm tm_data { |
222 | .tm_sec = 7, .tm_min = 14, .tm_hour = 3, .tm_mday = 20, |
223 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 2038), .tm_wday = 0, |
224 | .tm_yday = 0, .tm_isdst = 0 |
225 | }; |
226 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); |
227 | } |
228 | |
229 | { |
230 | // 2038-02-19 03:14:07 tests overflow of the month in 2038. |
231 | struct tm tm_data { |
232 | .tm_sec = 7, .tm_min = 14, .tm_hour = 3, .tm_mday = 19, |
233 | .tm_mon = Month::FEBRUARY, .tm_year = tm_year(year: 2038), .tm_wday = 0, |
234 | .tm_yday = 0, .tm_isdst = 0 |
235 | }; |
236 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); |
237 | } |
238 | |
239 | { |
240 | // 2039-01-19 03:14:07 tests overflow of the year. |
241 | struct tm tm_data { |
242 | .tm_sec = 7, .tm_min = 14, .tm_hour = 3, .tm_mday = 19, |
243 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 2039), .tm_wday = 0, |
244 | .tm_yday = 0, .tm_isdst = 0 |
245 | }; |
246 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Fails(EOVERFLOW)); |
247 | } |
248 | } |
249 | |
250 | TEST(LlvmLibcMkTime, InvalidMonths) { |
251 | { |
252 | // -1 month from 1970-01-01 00:00:00 returns 1969-12-01 00:00:00. |
253 | struct tm tm_data { |
254 | .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 0, .tm_mon = -1, |
255 | .tm_year = tm_year(year: 1970), .tm_wday = 0, .tm_yday = 0, .tm_isdst = 0 |
256 | }; |
257 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), |
258 | Succeeds(-32 * TimeConstants::SECONDS_PER_DAY)); |
259 | EXPECT_TM_EQ((tm{.tm_sec = 0, |
260 | .tm_min = 0, |
261 | .tm_hour = 0, |
262 | .tm_mday = 1, |
263 | .tm_mon = Month::DECEMBER, |
264 | .tm_year = tm_year(1969), |
265 | .tm_wday = 1, |
266 | .tm_yday = 0, |
267 | .tm_isdst = 0}), |
268 | tm_data); |
269 | } |
270 | |
271 | { |
272 | // 1970-13-01 00:00:00 returns 1971-01-01 00:00:00. |
273 | struct tm tm_data { |
274 | .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 1, .tm_mon = 12, |
275 | .tm_year = tm_year(year: 1970), .tm_wday = 0, .tm_yday = 0, .tm_isdst = 0 |
276 | }; |
277 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), |
278 | Succeeds(TimeConstants::DAYS_PER_NON_LEAP_YEAR * |
279 | TimeConstants::SECONDS_PER_DAY)); |
280 | EXPECT_TM_EQ((tm{.tm_sec = 0, |
281 | .tm_min = 0, |
282 | .tm_hour = 0, |
283 | .tm_mday = 1, |
284 | .tm_mon = Month::JANUARY, |
285 | .tm_year = tm_year(1971), |
286 | .tm_wday = 5, |
287 | .tm_yday = 0, |
288 | .tm_isdst = 0}), |
289 | tm_data); |
290 | } |
291 | } |
292 | |
293 | TEST(LlvmLibcMkTime, InvalidDays) { |
294 | { |
295 | // -1 day from 1970-01-01 00:00:00 returns 1969-12-31 00:00:00. |
296 | struct tm tm_data { |
297 | .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = (1 - 1), |
298 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 1970), .tm_wday = 0, |
299 | .tm_yday = 0, .tm_isdst = 0 |
300 | }; |
301 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), |
302 | Succeeds(-1 * TimeConstants::SECONDS_PER_DAY)); |
303 | EXPECT_TM_EQ((tm{.tm_sec = 0, |
304 | .tm_min = 0, |
305 | .tm_hour = 0, |
306 | .tm_mday = 31, |
307 | .tm_mon = Month::DECEMBER, |
308 | .tm_year = tm_year(1969), |
309 | .tm_wday = 3, |
310 | .tm_yday = 0, |
311 | .tm_isdst = 0}), |
312 | tm_data); |
313 | } |
314 | |
315 | { |
316 | // 1970-01-32 00:00:00 returns 1970-02-01 00:00:00. |
317 | struct tm tm_data { |
318 | .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 32, |
319 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 1970), .tm_wday = 0, |
320 | .tm_yday = 0, .tm_isdst = 0 |
321 | }; |
322 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), |
323 | Succeeds(31 * TimeConstants::SECONDS_PER_DAY)); |
324 | EXPECT_TM_EQ((tm{.tm_sec = 0, |
325 | .tm_min = 0, |
326 | .tm_hour = 0, |
327 | .tm_mday = 1, |
328 | .tm_mon = Month::FEBRUARY, |
329 | .tm_year = tm_year(1970), |
330 | .tm_wday = 0, |
331 | .tm_yday = 0, |
332 | .tm_isdst = 0}), |
333 | tm_data); |
334 | } |
335 | |
336 | { |
337 | // 1970-02-29 00:00:00 returns 1970-03-01 00:00:00. |
338 | struct tm tm_data { |
339 | .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 29, |
340 | .tm_mon = Month::FEBRUARY, .tm_year = tm_year(year: 1970), .tm_wday = 0, |
341 | .tm_yday = 0, .tm_isdst = 0 |
342 | }; |
343 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), |
344 | Succeeds(59 * TimeConstants::SECONDS_PER_DAY)); |
345 | EXPECT_TM_EQ((tm{.tm_sec = 0, |
346 | .tm_min = 0, |
347 | .tm_hour = 0, |
348 | .tm_mday = 1, |
349 | .tm_mon = Month::MARCH, |
350 | .tm_year = tm_year(1970), |
351 | .tm_wday = 0, |
352 | .tm_yday = 0, |
353 | .tm_isdst = 0}), |
354 | tm_data); |
355 | } |
356 | |
357 | { |
358 | // 1972-02-30 00:00:00 returns 1972-03-01 00:00:00. |
359 | struct tm tm_data { |
360 | .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 30, |
361 | .tm_mon = Month::FEBRUARY, .tm_year = tm_year(year: 1972), .tm_wday = 0, |
362 | .tm_yday = 0, .tm_isdst = 0 |
363 | }; |
364 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), |
365 | Succeeds(((2 * TimeConstants::DAYS_PER_NON_LEAP_YEAR) + 60) * |
366 | TimeConstants::SECONDS_PER_DAY)); |
367 | EXPECT_TM_EQ((tm{.tm_sec = 0, |
368 | .tm_min = 0, |
369 | .tm_hour = 0, |
370 | .tm_mday = 1, |
371 | .tm_mon = Month::MARCH, |
372 | .tm_year = tm_year(1972), |
373 | .tm_wday = 3, |
374 | .tm_yday = 0, |
375 | .tm_isdst = 0}), |
376 | tm_data); |
377 | } |
378 | } |
379 | |
380 | TEST(LlvmLibcMkTime, EndOf32BitEpochYear) { |
381 | // Test for maximum value of a signed 32-bit integer. |
382 | // Test implementation can encode time for Tue 19 January 2038 03:14:07 UTC. |
383 | struct tm tm_data { |
384 | .tm_sec = 7, .tm_min = 14, .tm_hour = 3, .tm_mday = 19, |
385 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 2038), .tm_wday = 0, |
386 | .tm_yday = 0, .tm_isdst = 0 |
387 | }; |
388 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Succeeds(0x7FFFFFFF)); |
389 | EXPECT_TM_EQ((tm{.tm_sec = 7, |
390 | .tm_min = 14, |
391 | .tm_hour = 3, |
392 | .tm_mday = 19, |
393 | .tm_mon = Month::JANUARY, |
394 | .tm_year = tm_year(2038), |
395 | .tm_wday = 2, |
396 | .tm_yday = 7, |
397 | .tm_isdst = 0}), |
398 | tm_data); |
399 | } |
400 | |
401 | TEST(LlvmLibcMkTime, Max64BitYear) { |
402 | if (sizeof(time_t) == 4) |
403 | return; |
404 | { |
405 | // Mon Jan 1 12:50:50 2170 (200 years from 1970), |
406 | struct tm tm_data { |
407 | .tm_sec = 50, .tm_min = 50, .tm_hour = 12, .tm_mday = 1, |
408 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 2170), .tm_wday = 0, |
409 | .tm_yday = 0, .tm_isdst = 0 |
410 | }; |
411 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Succeeds(6311479850)); |
412 | EXPECT_TM_EQ((tm{.tm_sec = 50, |
413 | .tm_min = 50, |
414 | .tm_hour = 12, |
415 | .tm_mday = 1, |
416 | .tm_mon = Month::JANUARY, |
417 | .tm_year = tm_year(2170), |
418 | .tm_wday = 1, |
419 | .tm_yday = 50, |
420 | .tm_isdst = 0}), |
421 | tm_data); |
422 | } |
423 | |
424 | { |
425 | // Test for Tue Jan 1 12:50:50 in 2,147,483,647th year. |
426 | struct tm tm_data { |
427 | .tm_sec = 50, .tm_min = 50, .tm_hour = 12, .tm_mday = 1, |
428 | .tm_mon = Month::JANUARY, .tm_year = tm_year(year: 2147483647), .tm_wday = 0, |
429 | .tm_yday = 0, .tm_isdst = 0 |
430 | }; |
431 | EXPECT_THAT(LIBC_NAMESPACE::mktime(&tm_data), Succeeds(67767976202043050)); |
432 | EXPECT_TM_EQ((tm{.tm_sec = 50, |
433 | .tm_min = 50, |
434 | .tm_hour = 12, |
435 | .tm_mday = 1, |
436 | .tm_mon = Month::JANUARY, |
437 | .tm_year = tm_year(2147483647), |
438 | .tm_wday = 2, |
439 | .tm_yday = 50, |
440 | .tm_isdst = 0}), |
441 | tm_data); |
442 | } |
443 | } |
444 | |