I will commit, but I think you forgot to patch the makefile to actually build this test? If that's true please send a followup patch.
-- Nadav Har'El [email protected] On Wed, Aug 26, 2020 at 6:54 AM Waldemar Kozaczuk <[email protected]> wrote: > 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 > . > -- 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/CANEVyjts5-ut%3DPV5ivZWVTmFfCFPn0_yk9fRKnJTs1emQ-T%2B4A%40mail.gmail.com.
