|  | /* | 
|  | * Copyright (c) 2019 Peter Bigot Consulting | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | /* Tests where time_t requires a 64-bit value */ | 
|  |  | 
|  | #include <errno.h> | 
|  | #include <ztest.h> | 
|  | #include "timeutil_test.h" | 
|  |  | 
|  | static const struct timeutil_test_data tests[] = { | 
|  | /* 32-bit, but algorithm subtraction underflows */ | 
|  | { .ux = -2147483648, | 
|  | .civil = "1901-12-13 20:45:52 Fri 347", | 
|  | .tm = { | 
|  | .tm_sec = 52, | 
|  | .tm_min = 45, | 
|  | .tm_hour = 20, | 
|  | .tm_mday = 13, | 
|  | .tm_mon = 11, | 
|  | .tm_year = 1, | 
|  | .tm_wday = 5, | 
|  | .tm_yday = 346, | 
|  | } }, | 
|  | { .ux = (time_t)-2147483649, | 
|  | .civil = "1901-12-13 20:45:51 Fri 347", | 
|  | .tm = { | 
|  | .tm_sec = 51, | 
|  | .tm_min = 45, | 
|  | .tm_hour = 20, | 
|  | .tm_mday = 13, | 
|  | .tm_mon = 11, | 
|  | .tm_year = 1, | 
|  | .tm_wday = 5, | 
|  | .tm_yday = 346, | 
|  | } }, | 
|  | { .ux = (time_t)2147483648, | 
|  | .civil = "2038-01-19 03:14:08 Tue 019", | 
|  | .tm = { | 
|  | .tm_sec = 8, | 
|  | .tm_min = 14, | 
|  | .tm_hour = 3, | 
|  | .tm_mday = 19, | 
|  | .tm_mon = 0, | 
|  | .tm_year = 138, | 
|  | .tm_wday = 2, | 
|  | .tm_yday = 18, | 
|  | } }, | 
|  | { .ux = (time_t)64060588799, | 
|  | .civil = "3999-12-31 23:59:59 Fri 365", | 
|  | .tm = { | 
|  | .tm_sec = 59, | 
|  | .tm_min = 59, | 
|  | .tm_hour = 23, | 
|  | .tm_mday = 31, | 
|  | .tm_mon = 11, | 
|  | .tm_year = 2099, | 
|  | .tm_wday = 5, | 
|  | .tm_yday = 364, | 
|  | } }, | 
|  | { .ux = (time_t)64060588800, | 
|  | .civil = "4000-01-01 00:00:00 Sat 001", | 
|  | .tm = { | 
|  | .tm_sec = 0, | 
|  | .tm_min = 0, | 
|  | .tm_hour = 0, | 
|  | .tm_mday = 1, | 
|  | .tm_mon = 0, | 
|  | .tm_year = 2100, | 
|  | .tm_wday = 6, | 
|  | .tm_yday = 0, | 
|  | } }, | 
|  | /* Normal century is a common year */ | 
|  | { .ux = (time_t)-2208988801, | 
|  | .civil = "1899-12-31 23:59:59 Sun 365", | 
|  | .tm = { | 
|  | .tm_sec = 59, | 
|  | .tm_min = 59, | 
|  | .tm_hour = 23, | 
|  | .tm_mday = 31, | 
|  | .tm_mon = 11, | 
|  | .tm_year = -1, | 
|  | .tm_wday = 0, | 
|  | .tm_yday = 364, | 
|  | } }, | 
|  | { .ux = (time_t)-2208988800, | 
|  | .civil = "1900-01-01 00:00:00 Mon 001", | 
|  | .tm = { | 
|  | .tm_sec = 0, | 
|  | .tm_min = 0, | 
|  | .tm_hour = 0, | 
|  | .tm_mday = 1, | 
|  | .tm_mon = 0, | 
|  | .tm_year = 0, | 
|  | .tm_wday = 1, | 
|  | .tm_yday = 0, | 
|  | } }, | 
|  | { .ux = (time_t)-2203977600, | 
|  | .civil = "1900-02-28 00:00:00 Wed 059", | 
|  | .tm = { | 
|  | .tm_sec = 0, | 
|  | .tm_min = 0, | 
|  | .tm_hour = 0, | 
|  | .tm_mday = 28, | 
|  | .tm_mon = 1, | 
|  | .tm_year = 0, | 
|  | .tm_wday = 3, | 
|  | .tm_yday = 58, | 
|  | } }, | 
|  | { .ux = (time_t)-2203891200, | 
|  | .civil = "1900-03-01 00:00:00 Thu 060", | 
|  | .tm = { | 
|  | .tm_sec = 0, | 
|  | .tm_min = 0, | 
|  | .tm_hour = 0, | 
|  | .tm_mday = 1, | 
|  | .tm_mon = 2, | 
|  | .tm_year = 0, | 
|  | .tm_wday = 4, | 
|  | .tm_yday = 59, | 
|  | } }, | 
|  | { .ux = (time_t)-2177539200, | 
|  | .civil = "1900-12-31 00:00:00 Mon 365", | 
|  | .tm = { | 
|  | .tm_sec = 0, | 
|  | .tm_min = 0, | 
|  | .tm_hour = 0, | 
|  | .tm_mday = 31, | 
|  | .tm_mon = 11, | 
|  | .tm_year = 0, | 
|  | .tm_wday = 1, | 
|  | .tm_yday = 364, | 
|  | } }, | 
|  | { .ux = (time_t)-2177452800, | 
|  | .civil = "1901-01-01 00:00:00 Tue 001", | 
|  | .tm = { | 
|  | .tm_sec = 0, | 
|  | .tm_min = 0, | 
|  | .tm_hour = 0, | 
|  | .tm_mday = 1, | 
|  | .tm_mon = 0, | 
|  | .tm_year = 1, | 
|  | .tm_wday = 2, | 
|  | .tm_yday = 0, | 
|  | } }, | 
|  |  | 
|  | /* Extrema, check against proleptic Gregorian calendar data: | 
|  | * https://www.timeanddate.com/calendar/?year=1&country=22 | 
|  | */ | 
|  | { .ux = (time_t)-62167305600, | 
|  | .civil = "-1-12-31 00:00:00 Fri 365", | 
|  | .tm = { | 
|  | .tm_sec = 0, | 
|  | .tm_min = 0, | 
|  | .tm_hour = 0, | 
|  | .tm_mday = 31, | 
|  | .tm_mon = 11, | 
|  | .tm_year = -1901, | 
|  | .tm_wday = 5, | 
|  | .tm_yday = 364, | 
|  | } }, | 
|  | { .ux = (time_t)-62167219200, | 
|  | .civil = "0-01-01 00:00:00 Sat 001", | 
|  | .tm = { | 
|  | .tm_sec = 0, | 
|  | .tm_min = 0, | 
|  | .tm_hour = 0, | 
|  | .tm_mday = 1, | 
|  | .tm_mon = 0, | 
|  | .tm_year = -1900, | 
|  | .tm_wday = 6, | 
|  | .tm_yday = 0, | 
|  | } }, | 
|  | { .ux = (time_t)-62135596801, | 
|  | .civil = "0-12-31 23:59:59 Sun 366", | 
|  | .tm = { | 
|  | .tm_sec = 59, | 
|  | .tm_min = 59, | 
|  | .tm_hour = 23, | 
|  | .tm_mday = 31, | 
|  | .tm_mon = 11, | 
|  | .tm_year = -1900, | 
|  | .tm_wday = 0, | 
|  | .tm_yday = 365, | 
|  | } }, | 
|  | { .ux = (time_t)-62135596800, | 
|  | .civil = "1-01-01 00:00:00 Mon 001", | 
|  | .tm = { | 
|  | .tm_sec = 0, | 
|  | .tm_min = 0, | 
|  | .tm_hour = 0, | 
|  | .tm_mday = 1, | 
|  | .tm_mon = 0, | 
|  | .tm_year = -1899, | 
|  | .tm_wday = 1, | 
|  | .tm_yday = 0, | 
|  | } }, | 
|  | { .ux = (time_t)-62135596800, | 
|  | .civil = "1-01-01 00:00:00 Mon 001", | 
|  | .tm = { | 
|  | .tm_sec = 0, | 
|  | .tm_min = 0, | 
|  | .tm_hour = 0, | 
|  | .tm_mday = 1, | 
|  | .tm_mon = 0, | 
|  | .tm_year = -1899, | 
|  | .tm_wday = 1, | 
|  | .tm_yday = 0, | 
|  | } }, | 
|  | }; | 
|  |  | 
|  | static void test_time32_errno_clear(void) | 
|  | { | 
|  | const struct timeutil_test_data *tp = &(const struct timeutil_test_data){ | 
|  | .ux = 0, | 
|  | .civil = "1970-01-01 00:00:00 Thu 001", | 
|  | .tm = { | 
|  | .tm_sec = 0, | 
|  | .tm_min = 0, | 
|  | .tm_hour = 0, | 
|  | .tm_mday = 1, | 
|  | .tm_mon = 0, | 
|  | .tm_year = 70, | 
|  | .tm_wday = 4, | 
|  | .tm_yday = 0, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | errno = EINVAL; | 
|  |  | 
|  | time_t ux = timeutil_timegm(&tp->tm); | 
|  |  | 
|  | zassert_equal(ux, tp->ux, | 
|  | "conversion incorrect"); | 
|  | zassert_equal(errno, 0, | 
|  | "errno was not cleared"); | 
|  | } | 
|  |  | 
|  | static void test_time32_epochm1(void) | 
|  | { | 
|  | const struct timeutil_test_data *tp = &(const struct timeutil_test_data){ | 
|  | .ux = -1, | 
|  | .civil = "1969-12-31 23:59:59 Wed 365", | 
|  | .tm = { | 
|  | .tm_sec = 59, | 
|  | .tm_min = 59, | 
|  | .tm_hour = 23, | 
|  | .tm_mday = 31, | 
|  | .tm_mon = 11, | 
|  | .tm_year = 69, | 
|  | .tm_wday = 3, | 
|  | .tm_yday = 364, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | errno = EINVAL; | 
|  |  | 
|  | time_t ux = timeutil_timegm(&tp->tm); | 
|  |  | 
|  | zassert_equal(ux, tp->ux, | 
|  | "conversion incorrect"); | 
|  | zassert_equal(errno, 0, | 
|  | "final errno state bad"); | 
|  | } | 
|  |  | 
|  | static void test_time32_underflow(void) | 
|  | { | 
|  | const int64_t unix64 = -2147483649; | 
|  | const struct timeutil_test_data *tp = &(const struct timeutil_test_data){ | 
|  | .civil = "1901-12-13 20:45:51 Fri 347", | 
|  | .tm = { | 
|  | .tm_sec = 51, | 
|  | .tm_min = 45, | 
|  | .tm_hour = 20, | 
|  | .tm_mday = 13, | 
|  | .tm_mon = 11, | 
|  | .tm_year = 1, | 
|  | .tm_wday = 5, | 
|  | .tm_yday = 346, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | zassert_equal(timeutil_timegm64(&tp->tm), unix64, | 
|  | "fullscale failed"); | 
|  | errno = 0; | 
|  |  | 
|  | time_t ux = timeutil_timegm(&tp->tm); | 
|  |  | 
|  | zassert_equal(ux, -1, | 
|  | "underflow undetected"); | 
|  | zassert_equal(errno, ERANGE, | 
|  | "final errno state bad"); | 
|  | } | 
|  |  | 
|  | static void test_time32_overflow(void) | 
|  | { | 
|  | const int64_t unix64 = 2147483648; | 
|  | const struct timeutil_test_data *tp = &(const struct timeutil_test_data){ | 
|  | .civil = "2038-01-19 03:14:08 Tue 019", | 
|  | .tm = { | 
|  | .tm_sec = 8, | 
|  | .tm_min = 14, | 
|  | .tm_hour = 3, | 
|  | .tm_mday = 19, | 
|  | .tm_mon = 0, | 
|  | .tm_year = 138, | 
|  | .tm_wday = 2, | 
|  | .tm_yday = 18, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | zassert_equal(timeutil_timegm64(&tp->tm), unix64, | 
|  | "fullscale failed"); | 
|  | errno = 0; | 
|  |  | 
|  | time_t ux = timeutil_timegm(&tp->tm); | 
|  |  | 
|  | zassert_equal(ux, -1, | 
|  | "overflow undetected"); | 
|  | zassert_equal(errno, ERANGE, | 
|  | "final errno state bad"); | 
|  | } | 
|  |  | 
|  | void test_s64(void) | 
|  | { | 
|  | if (sizeof(time_t) < 8U) { | 
|  | test_time32_errno_clear(); | 
|  | test_time32_epochm1(); | 
|  | test_time32_underflow(); | 
|  | test_time32_overflow(); | 
|  | return; | 
|  | } | 
|  | timeutil_check(tests, sizeof(tests) / sizeof(*tests)); | 
|  | } |