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.

Reply via email to