This patch adds new unit test tst-time.cc that tests many time-related including following: tzset() gmtime() gmtime_r() localtime() localtime_r() mktime() strftime() timegm() strftime() strptime()
The test is actually based on bionics time-test.cpp as the comments in the top of the source files document. Please note that some of the tests mostly related to strptime and strftime are commented out as they fail with current version of musl. Hopefully we will enable them once we upgrade to newer version of musl. Signed-off-by: Waldemar Kozaczuk <[email protected]> --- tests/tst-time.cc | 698 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 698 insertions(+) create mode 100644 tests/tst-time.cc diff --git a/tests/tst-time.cc b/tests/tst-time.cc new file mode 100644 index 00000000..420cae3d --- /dev/null +++ b/tests/tst-time.cc @@ -0,0 +1,698 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright (C) 2020 Waldemar Kozaczuk + * + * This work is open source software, licensed under the terms of the + * BSD license as described in the LICENSE file in the top-level directory. + */ + +// This test is based on tests/string_time.cpp from the bionic project +// (https://android.googlesource.com/platform/bionic as of commit: 9c6d60d073db079a87fbeb5de3e72ac12838a480) +// PLUS some minor tweaks (mostly macros) that adapt it to run with boost unit framework +// instead of Google's test framework +// +// In addition some tests (most of them related to strptime and strftime) +// have been commented out as they do not pass on OSv. +// We hope that many of them will pass once we upgrade musl. +#include <time.h> + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <atomic> +#include <chrono> + +// gcc tests/tst-time.cc -lstdc++ -lboost_unit_test_framework -lboost_filesystem -o /tmp/a +//#define BOOST_TEST_DYN_LINK //ONLY FOR LINUX +#define BOOST_TEST_MODULE tst-time + +#include <boost/test/unit_test.hpp> +namespace utf = boost::unit_test; + +#define TEST(MODULE_NAME,TEST_NAME) BOOST_AUTO_TEST_CASE(MODULE_NAME##_##TEST_NAME) + +#define EXPECT_TRUE(EXP) BOOST_REQUIRE(EXP) +#define EXPECT_EQ(EXP1,EXP2) BOOST_CHECK_EQUAL(EXP1,EXP2) +#define EXPECT_STREQ(EXP1,EXP2) BOOST_CHECK_EQUAL(EXP1,EXP2) + +#define ASSERT_TRUE(EXP) BOOST_REQUIRE(EXP) +#define ASSERT_EQ(EXP1,EXP2) BOOST_CHECK_EQUAL(EXP1,EXP2) +#define ASSERT_STREQ(EXP1,EXP2) BOOST_CHECK_EQUAL(EXP1,EXP2) +#define ASSERT_NE(EXP1,EXP2) BOOST_REQUIRE((EXP1) != (EXP2)) +#define ASSERT_GE(EXP1,EXP2) BOOST_REQUIRE((EXP1) >= (EXP2)) +#define ASSERT_LT(EXP1,EXP2) BOOST_REQUIRE((EXP1) < (EXP2)) +#define ASSERT_LE(EXP1,EXP2) BOOST_REQUIRE((EXP1) <= (EXP2)) + +TEST(time, time) { + // Acquire time + time_t p1, t1 = time(&p1); + // valid? + ASSERT_NE(static_cast<time_t>(0), t1); + ASSERT_NE(static_cast<time_t>(-1), t1); + ASSERT_EQ(p1, t1); + + // Acquire time one+ second later + usleep(1010000); + time_t p2, t2 = time(&p2); + // valid? + ASSERT_NE(static_cast<time_t>(0), t2); + ASSERT_NE(static_cast<time_t>(-1), t2); + ASSERT_EQ(p2, t2); + + // Expect time progression + ASSERT_LT(p1, p2); + ASSERT_LE(t2 - t1, static_cast<time_t>(2)); + + // Expect nullptr call to produce same results + ASSERT_LE(t2, time(nullptr)); + ASSERT_LE(time(nullptr) - t2, static_cast<time_t>(1)); +} + +TEST(time, gmtime) { + time_t t = 0; + tm* broken_down = gmtime(&t); + ASSERT_TRUE(broken_down != nullptr); + ASSERT_EQ(0, broken_down->tm_sec); + ASSERT_EQ(0, broken_down->tm_min); + ASSERT_EQ(0, broken_down->tm_hour); + ASSERT_EQ(1, broken_down->tm_mday); + ASSERT_EQ(0, broken_down->tm_mon); + ASSERT_EQ(1970, broken_down->tm_year + 1900); +} + +TEST(time, gmtime_r) { + struct tm tm = {}; + time_t t = 0; + struct tm* broken_down = gmtime_r(&t, &tm); + ASSERT_EQ(broken_down, &tm); + ASSERT_EQ(0, broken_down->tm_sec); + ASSERT_EQ(0, broken_down->tm_min); + ASSERT_EQ(0, broken_down->tm_hour); + ASSERT_EQ(1, broken_down->tm_mday); + ASSERT_EQ(0, broken_down->tm_mon); + ASSERT_EQ(1970, broken_down->tm_year + 1900); +} + +/* TODO: FAILS on OSv +TEST(time, gmtime_no_stack_overflow_14313703) { + // Is it safe to call tzload on a thread with a small stack? + // http://b/14313703 + // https://code.google.com/p/android/issues/detail?id=61130 + pthread_attr_t a; + ASSERT_EQ(0, pthread_attr_init(&a)); + ASSERT_EQ(0, pthread_attr_setstacksize(&a, PTHREAD_STACK_MIN)); + + pthread_t t; + ASSERT_EQ(0, pthread_create(&t, &a, gmtime_no_stack_overflow_14313703_fn, nullptr)); + ASSERT_EQ(0, pthread_join(t, nullptr)); +}*/ + +TEST(time, mktime_empty_TZ) { + // tzcode used to have a bug where it didn't reinitialize some internal state. + + // Choose a time where DST is set. + struct tm t; + memset(&t, 0, sizeof(tm)); + t.tm_year = 1980 - 1900; + t.tm_mon = 6; + t.tm_mday = 2; + + setenv("TZ", "America/Los_Angeles", 1); + tzset(); + ASSERT_EQ(static_cast<time_t>(331372800U), mktime(&t)); + + memset(&t, 0, sizeof(tm)); + t.tm_year = 1980 - 1900; + t.tm_mon = 6; + t.tm_mday = 2; + + setenv("TZ", "", 1); // Implies UTC. + tzset(); + ASSERT_EQ(static_cast<time_t>(331344000U), mktime(&t)); +} + +TEST(time, mktime_10310929) { + struct tm t; + memset(&t, 0, sizeof(tm)); + t.tm_year = 200; + t.tm_mon = 2; + t.tm_mday = 10; + +#if !defined(__LP64__) + // 32-bit bionic stupidly had a signed 32-bit time_t. + ASSERT_EQ(-1, mktime(&t)); + ASSERT_EQ(EOVERFLOW, errno); +#else + // Everyone else should be using a signed 64-bit time_t. + ASSERT_GE(sizeof(time_t) * 8, 64U); + + setenv("TZ", "America/Los_Angeles", 1); + tzset(); + errno = 0; + ASSERT_EQ(static_cast<time_t>(4108348800U), mktime(&t)); + ASSERT_EQ(0, errno); + + setenv("TZ", "UTC", 1); + tzset(); + errno = 0; + ASSERT_EQ(static_cast<time_t>(4108320000U), mktime(&t)); + ASSERT_EQ(0, errno); +#endif +} + +TEST(time, mktime_EOVERFLOW) { + struct tm t; + memset(&t, 0, sizeof(tm)); + + // LP32 year range is 1901-2038, so this year is guaranteed not to overflow. + t.tm_year = 2016 - 1900; + + t.tm_mon = 2; + t.tm_mday = 10; + + errno = 0; + ASSERT_NE(static_cast<time_t>(-1), mktime(&t)); + ASSERT_EQ(0, errno); + + // This will overflow for LP32 or LP64. + t.tm_year = INT_MAX; + + errno = 0; + //ASSERT_EQ(static_cast<time_t>(-1), mktime(&t)); - fails on Linux + //ASSERT_EQ(EOVERFLOW, errno); +} + +TEST(time, strftime) { + setenv("TZ", "UTC", 1); + + struct tm t; + memset(&t, 0, sizeof(tm)); + t.tm_year = 200; + t.tm_mon = 2; + t.tm_mday = 10; + + char buf[64]; + + // Seconds since the epoch. +#if defined(__BIONIC__) || defined(__LP64__) // Not 32-bit glibc. + /* TODO: Pending musl upgrade + EXPECT_EQ(10U, strftime(buf, sizeof(buf), "%s", &t)); + EXPECT_STREQ("4108320000", buf);*/ +#endif + + // Date and time as text. + EXPECT_EQ(24U, strftime(buf, sizeof(buf), "%c", &t)); + EXPECT_STREQ("Sun Mar 10 00:00:00 2100", buf); +} + +TEST(time, strftime_null_tm_zone) { + // Netflix on Nexus Player wouldn't start (http://b/25170306). + struct tm t; + memset(&t, 0, sizeof(tm)); + + //char buf[64]; + + setenv("TZ", "America/Los_Angeles", 1); + tzset(); + + t.tm_isdst = 0; // "0 if Daylight Savings Time is not in effect". + /* TODO: Pending musl upgrade + EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t)); + EXPECT_STREQ("<PST>", buf);*/ + +#if defined(__BIONIC__) // glibc 2.19 only copes with tm_isdst being 0 and 1. + t.tm_isdst = 2; // "positive if Daylight Savings Time is in effect" + EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t)); + EXPECT_STREQ("<PDT>", buf); + + t.tm_isdst = -123; // "and negative if the information is not available". + EXPECT_EQ(2U, strftime(buf, sizeof(buf), "<%Z>", &t)); + EXPECT_STREQ("<>", buf); +#endif + + setenv("TZ", "UTC", 1); + tzset(); + + t.tm_isdst = 0; + /* TODO: Pending musl upgrade + EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t)); + EXPECT_STREQ("<UTC>", buf);*/ + +#if defined(__BIONIC__) // glibc 2.19 thinks UTC DST is "UTC". + t.tm_isdst = 1; // UTC has no DST. + EXPECT_EQ(2U, strftime(buf, sizeof(buf), "<%Z>", &t)); + EXPECT_STREQ("<>", buf); +#endif +} + +TEST(time, strftime_l) { + locale_t cloc = newlocale(LC_ALL, "C.UTF-8", nullptr); + locale_t old_locale = uselocale(cloc); + + setenv("TZ", "UTC", 1); + + struct tm t; + memset(&t, 0, sizeof(tm)); + t.tm_year = 200; + t.tm_mon = 2; + t.tm_mday = 10; + + // Date and time as text. + char buf[64]; + EXPECT_EQ(24U, strftime_l(buf, sizeof(buf), "%c", &t, cloc)); + EXPECT_STREQ("Sun Mar 10 00:00:00 2100", buf); + + uselocale(old_locale); + freelocale(cloc); +} + +TEST(time, strptime) { + setenv("TZ", "UTC", 1); + + struct tm t; + char buf[64]; + + memset(&t, 0, sizeof(t)); + strptime("11:14", "%R", &t); + strftime(buf, sizeof(buf), "%H:%M", &t); + EXPECT_STREQ("11:14", buf); + + memset(&t, 0, sizeof(t)); + strptime("09:41:53", "%T", &t); + strftime(buf, sizeof(buf), "%H:%M:%S", &t); + EXPECT_STREQ("09:41:53", buf); +} + +/* TODO: Disable until upgrade of musl +TEST(time, strptime_l) { + setenv("TZ", "UTC", 1); + + struct tm t; + char buf[64]; + + memset(&t, 0, sizeof(t)); + strptime_l("11:14", "%R", &t, LC_GLOBAL_LOCALE); + strftime_l(buf, sizeof(buf), "%H:%M", &t, LC_GLOBAL_LOCALE); + EXPECT_STREQ("11:14", buf); + + memset(&t, 0, sizeof(t)); + strptime_l("09:41:53", "%T", &t, LC_GLOBAL_LOCALE); + strftime_l(buf, sizeof(buf), "%H:%M:%S", &t, LC_GLOBAL_LOCALE); + EXPECT_STREQ("09:41:53", buf); +}*/ + +/* TODO: Disable until upgrade of musl +TEST(time, strptime_F) { + setenv("TZ", "UTC", 1); + + struct tm tm = {}; + ASSERT_EQ('\0', *strptime("2019-03-26", "%F", &tm)); + EXPECT_EQ(119, tm.tm_year); + EXPECT_EQ(2, tm.tm_mon); + EXPECT_EQ(26, tm.tm_mday); +}*/ + +/* many fail in Linux -> access violation +TEST(time, strptime_P_p) { + setenv("TZ", "UTC", 1); + + // For parsing, %P and %p are the same: case doesn't matter. + + struct tm tm = {.tm_hour = 12}; + ASSERT_EQ('\0', *strptime("AM", "%p", &tm)); + EXPECT_EQ(0, tm.tm_hour); + + tm = {.tm_hour = 12}; + ASSERT_EQ('\0', *strptime("am", "%p", &tm)); + EXPECT_EQ(0, tm.tm_hour); + + tm = {.tm_hour = 12}; + ASSERT_EQ('\0', *strptime("AM", "%P", &tm)); + EXPECT_EQ(0, tm.tm_hour); + + tm = {.tm_hour = 12}; + ASSERT_EQ('\0', *strptime("am", "%P", &tm)); + EXPECT_EQ(0, tm.tm_hour); +}*/ + +/* TODO: Disable until upgrade of musl +TEST(time, strptime_u) { + setenv("TZ", "UTC", 1); + + struct tm tm = {}; + ASSERT_EQ('\0', *strptime("2", "%u", &tm)); + EXPECT_EQ(2, tm.tm_wday); +}*/ + +/* Access violation on Linux +TEST(time, strptime_v) { + setenv("TZ", "UTC", 1); + + struct tm tm = {}; + ASSERT_EQ('\0', *strptime("26-Mar-1980", "%v", &tm)); + EXPECT_EQ(80, tm.tm_year); + EXPECT_EQ(2, tm.tm_mon); + EXPECT_EQ(26, tm.tm_mday); +}*/ + +TEST(time, strptime_V_G_g) { + setenv("TZ", "UTC", 1); + + // %V (ISO-8601 week number), %G (year of week number, without century), and + // %g (year of week number) have no effect when parsed, and are supported + // solely so that it's possible for strptime(3) to parse everything that + // strftime(3) can output. + struct tm tm = {}; + //ASSERT_EQ('\0', *strptime("1 2 3", "%V %G %g", &tm)); + struct tm zero = {}; + EXPECT_TRUE(memcmp(&tm, &zero, sizeof(tm)) == 0); +} + +#define NS_PER_S 1000000000 +TEST(time, clock_gettime) { + // Try to ensure that our vdso clock_gettime is working. + timespec ts1; + ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts1)); + timespec ts2; + ASSERT_EQ(0, syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts2)); + + // What's the difference between the two? + ts2.tv_sec -= ts1.tv_sec; + ts2.tv_nsec -= ts1.tv_nsec; + if (ts2.tv_nsec < 0) { + --ts2.tv_sec; + ts2.tv_nsec += NS_PER_S; + } + + // To try to avoid flakiness we'll accept answers within 10,000,000ns (0.01s). + ASSERT_EQ(0, ts2.tv_sec); + ASSERT_TRUE(ts2.tv_nsec < 10000000); +} + +TEST(time, clock_gettime_CLOCK_REALTIME) { + timespec ts; + ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &ts)); +} + +TEST(time, clock_gettime_CLOCK_MONOTONIC) { + timespec ts; + ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &ts)); +} + +TEST(time, clock_gettime_CLOCK_PROCESS_CPUTIME_ID) { + timespec ts; + ASSERT_EQ(0, clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)); +} + +TEST(time, clock_gettime_CLOCK_THREAD_CPUTIME_ID) { + timespec ts; + ASSERT_EQ(0, clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts)); +} + +TEST(time, clock_gettime_CLOCK_BOOTTIME) { + timespec ts; + ASSERT_EQ(0, clock_gettime(CLOCK_BOOTTIME, &ts)); +} + +TEST(time, clock_gettime_unknown) { + errno = 0; + timespec ts; + ASSERT_EQ(-1, clock_gettime(-1, &ts)); + ASSERT_EQ(EINVAL, errno); +} + +TEST(time, clock_getres_CLOCK_REALTIME) { + timespec ts; + ASSERT_EQ(0, clock_getres(CLOCK_REALTIME, &ts)); + ASSERT_EQ(1, ts.tv_nsec); + ASSERT_EQ(0, ts.tv_sec); +} + +TEST(time, clock_getres_CLOCK_MONOTONIC) { + timespec ts; + ASSERT_EQ(0, clock_getres(CLOCK_MONOTONIC, &ts)); + ASSERT_EQ(1, ts.tv_nsec); + ASSERT_EQ(0, ts.tv_sec); +} + +TEST(time, clock_getres_CLOCK_PROCESS_CPUTIME_ID) { + timespec ts; + ASSERT_EQ(0, clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts)); +} + +TEST(time, clock_getres_CLOCK_THREAD_CPUTIME_ID) { + timespec ts; + ASSERT_EQ(0, clock_getres(CLOCK_THREAD_CPUTIME_ID, &ts)); +} + +/* Fails on OSv - disable for now +TEST(time, clock_getres_CLOCK_BOOTTIME) { + timespec ts; + ASSERT_EQ(0, clock_getres(CLOCK_BOOTTIME, &ts)); + ASSERT_EQ(1, ts.tv_nsec); + ASSERT_EQ(0, ts.tv_sec); +}*/ + +TEST(time, clock_getres_unknown) { + errno = 0; + timespec ts = { -1, -1 }; + ASSERT_EQ(-1, clock_getres(-1, &ts)); + ASSERT_EQ(EINVAL, errno); + ASSERT_EQ(-1, ts.tv_nsec); + ASSERT_EQ(-1, ts.tv_sec); +} + +/*TODO: Investigate why the assert is failing on OSv +TEST(time, clock) { + // clock(3) is hard to test, but a 1s sleep should cost less than 5ms. + clock_t t0 = clock(); + sleep(1); + clock_t t1 = clock(); + ASSERT_LT(t1 - t0, 5 * (CLOCKS_PER_SEC / 1000)); +}*/ + +/* Crashes? +TEST(time, clock_getcpuclockid_current) { + clockid_t clockid; + ASSERT_EQ(0, clock_getcpuclockid(getpid(), &clockid)); + timespec ts; + ASSERT_EQ(0, clock_gettime(clockid, &ts)); +} + +TEST(time, clock_getcpuclockid_parent) { + clockid_t clockid; + ASSERT_EQ(0, clock_getcpuclockid(getppid(), &clockid)); + timespec ts; + ASSERT_EQ(0, clock_gettime(clockid, &ts)); Crashes? +}*/ + +TEST(time, nanosleep) { + auto t0 = std::chrono::steady_clock::now(); + const timespec ts = {.tv_nsec = 5000000}; + ASSERT_EQ(0, nanosleep(&ts, nullptr)); + auto t1 = std::chrono::steady_clock::now(); + ASSERT_TRUE((int64_t)std::chrono::duration_cast<std::chrono::nanoseconds> (t1-t0).count() >= 5000000); +} + +/*TODO: Fails on OSv +TEST(time, nanosleep_EINVAL) { + timespec ts = {.tv_sec = -1}; + errno = 0; + ASSERT_EQ(-1, nanosleep(&ts, nullptr)); + ASSERT_EQ(EINVAL, errno); +}*/ + +TEST(time, bug_31938693) { + // User-visible symptoms in N: + // http://b/31938693 + // https://code.google.com/p/android/issues/detail?id=225132 + + // Actual underlying bug (the code change, not the tzdata upgrade that first exposed the bug): + // http://b/31848040 + + // This isn't a great test, because very few time zones were actually affected, and there's + // no real logic to which ones were affected: it was just a coincidence of the data that came + // after them in the tzdata file. + + time_t t = 1475619727; + struct tm tm; + + setenv("TZ", "America/Los_Angeles", 1); + tzset(); + ASSERT_TRUE(localtime_r(&t, &tm) != nullptr); + EXPECT_EQ(15, tm.tm_hour); + + setenv("TZ", "Europe/London", 1); + tzset(); + ASSERT_TRUE(localtime_r(&t, &tm) != nullptr); + EXPECT_EQ(23, tm.tm_hour); + + setenv("TZ", "America/Atka", 1); + tzset(); + ASSERT_TRUE(localtime_r(&t, &tm) != nullptr); + EXPECT_EQ(13, tm.tm_hour); + + setenv("TZ", "Pacific/Apia", 1); + tzset(); + ASSERT_TRUE(localtime_r(&t, &tm) != nullptr); + EXPECT_EQ(12, tm.tm_hour); + + setenv("TZ", "Pacific/Honolulu", 1); + tzset(); + ASSERT_TRUE(localtime_r(&t, &tm) != nullptr); + EXPECT_EQ(12, tm.tm_hour); + + setenv("TZ", "Asia/Magadan", 1); + tzset(); + ASSERT_TRUE(localtime_r(&t, &tm) != nullptr); + EXPECT_EQ(9, tm.tm_hour); +} + +TEST(time, bug_31339449) { + // POSIX says localtime acts as if it calls tzset. + // tzset does two things: + // 1. it sets the time zone ctime/localtime/mktime/strftime will use. + // 2. it sets the global `tzname`. + // POSIX says localtime_r need not set `tzname` (2). + // Q: should localtime_r set the time zone (1)? + // Upstream tzcode (and glibc) answer "no", everyone else answers "yes". + + // Pick a time, any time... + time_t t = 1475619727; + + // Call tzset with a specific timezone. + setenv("TZ", "America/Atka", 1); + tzset(); + + // If we change the timezone and call localtime, localtime should use the new timezone. + setenv("TZ", "America/Los_Angeles", 1); + struct tm* tm_p = localtime(&t); + EXPECT_EQ(15, tm_p->tm_hour); + + // Reset the timezone back. + setenv("TZ", "America/Atka", 1); + tzset(); + +#if defined(__BIONIC__) + // If we change the timezone again and call localtime_r, localtime_r should use the new timezone. + setenv("TZ", "America/Los_Angeles", 1); + struct tm tm = {}; + localtime_r(&t, &tm); + EXPECT_EQ(15, tm.tm_hour); +#else + // The BSDs agree with us, but glibc gets this wrong. +#endif +} + +TEST(time, asctime) { + const struct tm tm = {}; + ASSERT_STREQ("Sun Jan 0 00:00:00 1900\n", asctime(&tm)); +} + +TEST(time, asctime_r) { + const struct tm tm = {}; + char buf[256]; + ASSERT_EQ(buf, asctime_r(&tm, buf)); + ASSERT_STREQ("Sun Jan 0 00:00:00 1900\n", buf); +} + +TEST(time, ctime) { + setenv("TZ", "UTC", 1); + const time_t t = 0; + ASSERT_STREQ("Thu Jan 1 00:00:00 1970\n", ctime(&t)); +} + +TEST(time, ctime_r) { + setenv("TZ", "UTC", 1); + const time_t t = 0; + char buf[256]; + ASSERT_EQ(buf, ctime_r(&t, buf)); + ASSERT_STREQ("Thu Jan 1 00:00:00 1970\n", buf); +} + +// https://issuetracker.google.com/37128336 +/* TODO: Disable until upgrade of musl +TEST(time, strftime_strptime_s) { + char buf[32]; + const struct tm tm0 = { .tm_mday = 1, .tm_mon = 0, .tm_year = 1982-1900 }; + + setenv("TZ", "America/Los_Angeles", 1); + strftime(buf, sizeof(buf), "<%s>", &tm0); + EXPECT_STREQ("<378720000>", buf); + + setenv("TZ", "UTC", 1); + strftime(buf, sizeof(buf), "<%s>", &tm0); + EXPECT_STREQ("<378691200>", buf); + + struct tm tm; + + setenv("TZ", "America/Los_Angeles", 1); + tzset(); + memset(&tm, 0xff, sizeof(tm)); + char* p = strptime("378720000x", "%s", &tm); + ASSERT_EQ('x', *p); + EXPECT_EQ(0, tm.tm_sec); + EXPECT_EQ(0, tm.tm_min); + EXPECT_EQ(0, tm.tm_hour); + EXPECT_EQ(1, tm.tm_mday); + EXPECT_EQ(0, tm.tm_mon); + EXPECT_EQ(82, tm.tm_year); + EXPECT_EQ(5, tm.tm_wday); + EXPECT_EQ(0, tm.tm_yday); + EXPECT_EQ(0, tm.tm_isdst); + + setenv("TZ", "UTC", 1); + tzset(); + memset(&tm, 0xff, sizeof(tm)); + p = strptime("378691200x", "%s", &tm); + ASSERT_EQ('x', *p); + EXPECT_EQ(0, tm.tm_sec); + EXPECT_EQ(0, tm.tm_min); + EXPECT_EQ(0, tm.tm_hour); + EXPECT_EQ(1, tm.tm_mday); + EXPECT_EQ(0, tm.tm_mon); + EXPECT_EQ(82, tm.tm_year); + EXPECT_EQ(5, tm.tm_wday); + EXPECT_EQ(0, tm.tm_yday); + EXPECT_EQ(0, tm.tm_isdst); +}*/ + +/* TODO: Disable until upgrade of musl +TEST(time, strptime_s_nothing) { + struct tm tm; + ASSERT_EQ(nullptr, strptime("x", "%s", &tm)); +}*/ + +TEST(time, timespec_get) { +#if __BIONIC__ + timespec ts = {}; + ASSERT_EQ(0, timespec_get(&ts, 123)); + ASSERT_EQ(TIME_UTC, timespec_get(&ts, TIME_UTC)); +#else +// GTEST_SKIP() << "glibc doesn't have timespec_get until 2.21"; +#endif +} + +TEST(time, difftime) { + ASSERT_EQ(1.0, difftime(1, 0)); +} -- 2.26.2 -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/20200826035356.201786-2-jwkozaczuk%40gmail.com.
