text: // Copyright (c) Microsoft Corporation.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  
  // test <chrono> C++11 header
  #define TEST_NAME "<chrono>"
  
  #include "tdefs.h"
  #include <chrono>
  #include <iostream>
  #include <time.h>
  #include <typeinfo>
  
  namespace {
  
      void t_common_type() {
          typedef STD common_type<signed char, unsigned char> c_sc_uc;
          CHECK_TYPE(c_sc_uc::type, int);
          typedef STD common_type<int, float> c_i_f;
          CHECK_TYPE(c_i_f::type, float);
          typedef STD common_type<long long, unsigned long long> c_ll_ull;
          CHECK_TYPE(c_ll_ull::type, unsigned long long);
  
          typedef STD chrono::duration<int, STD ratio<2, 3>> di;
          typedef STD chrono::duration<long, STD ratio<4, 9>> dl;
          typedef STD ratio<2, 9> r;
          typedef STD common_type<di, dl> c_di_dl;
          CHECK_TYPE(c_di_dl::type::rep, long);
          CHECK_TYPE(c_di_dl::type::period, r);
  
          typedef STD chrono::time_point<STD chrono::system_clock, di> ti;
          typedef STD chrono::time_point<STD chrono::system_clock, dl> tl;
          typedef STD chrono::time_point<STD chrono::system_clock, c_di_dl::type> res;
          typedef STD common_type<ti, tl> c_ti_tl;
          CHECK_TYPE(c_ti_tl::type, res);
      }
  
      void t_treat_as_floating_point() {
          CHECK_INT(STD chrono::treat_as_floating_point<char>::value, false);
          CHECK_INT(STD chrono::treat_as_floating_point<short>::value, false);
          CHECK_INT(STD chrono::treat_as_floating_point<unsigned int>::value, false);
          CHECK_INT(STD chrono::treat_as_floating_point<int>::value, false);
          CHECK_INT(STD chrono::treat_as_floating_point<long>::value, false);
          CHECK_INT(STD chrono::treat_as_floating_point<unsigned long>::value, false);
          CHECK_INT(STD chrono::treat_as_floating_point<float>::value, true);
          CHECK_INT(STD chrono::treat_as_floating_point<double>::value, true);
          CHECK_INT(STD chrono::treat_as_floating_point<long double>::value, true);
      }
  
      void t_duration_values() {
          typedef STD chrono::duration_values<int> d_i;
          CHECK_INT(d_i::zero(), 0);
          CHECK_INT(d_i::min(), STD numeric_limits<int>::lowest());
          CHECK_INT(d_i::max(), STD numeric_limits<int>::max());
  
          typedef STD chrono::duration_values<double> d_d;
          CHECK_INT(d_d::zero(), 0.0);
          CHECK_INT(d_d::min(), STD numeric_limits<double>::lowest());
          CHECK_INT(d_d::max(), STD numeric_limits<double>::max());
      }
  
      template <class Rep, class Period>
      void test_arithmetic_op(const STD chrono::duration<Rep, Period>& d1, const STD chrono::duration<Rep, Period>& d2) {
          CHECK_INT(d1.count(), d2.count());
      }
  
      void t_duration() {
          // nested typedefs
          typedef STD ratio<1, 1> r_1_1;
          typedef STD chrono::duration<int, r_1_1> d_i_r_1_1;
          CHECK_TYPE(d_i_r_1_1::rep, int);
          CHECK_TYPE(d_i_r_1_1::period, r_1_1);
  
          typedef STD ratio<1, 60> r_1_60;
          typedef STD chrono::duration<long, r_1_60> d_l_r_1_60;
          CHECK_TYPE(d_l_r_1_60::rep, long);
          CHECK_TYPE(d_l_r_1_60::period, r_1_60);
  
          // constructors
          d_i_r_1_1 d0(0L);
          CHECK_INT(d0.count(), 0);
          d_i_r_1_1 d1(1L);
          CHECK_INT(d1.count(), 1);
  
          d_l_r_1_60 d2(d1);
          CHECK_INT(d2.count(), 60);
  
          // copy and assign
          d_i_r_1_1 d3(d1);
          CHECK_INT(d3.count(), d1.count());
          d3 = d0;
          CHECK_INT(d3.count(), d0.count());
  
          // arithmetic member functions
          CHECK_INT((+d1).count(), d1.count());
          CHECK_INT(d1.count(), 1);
          CHECK_INT((-d1).count(), -d1.count());
          CHECK_INT(d1.count(), 1);
  
          CHECK_INT((++d1).count(), 2);
          CHECK_INT(d1.count(), 2);
          CHECK_INT((d1++).count(), 2);
          CHECK_INT(d1.count(), 3);
  
          CHECK_INT((--d1).count(), 2);
          CHECK_INT(d1.count(), 2);
          CHECK_INT((d1--).count(), 2);
          CHECK_INT(d1.count(), 1);
  
          d3 += d1;
          CHECK_INT(d3.count(), 1);
          d3 -= d1;
          CHECK_INT(d3.count(), 0);
  
          d1 *= 4;
          CHECK_INT(d1.count(), 4);
          d1 /= 2;
          CHECK_INT(d1.count(), 2);
          d1 %= 2;
          CHECK_INT(d1.count(), 0);
  
          // arithmetic non-member functions
          typedef STD chrono::duration<int, STD ratio<2, 3>> di;
          typedef STD chrono::duration<long, STD ratio<4, 9>> dl;
          di d4(3);
          dl d5(4);
          STD chrono::duration<long, STD ratio<2, 9>> res_plus(17);
          test_arithmetic_op(d4 + d5, res_plus);
          STD chrono::duration<long, STD ratio<2, 9>> res_minus(1);
          test_arithmetic_op(d4 - d5, res_minus);
  
          STD chrono::duration<long, STD ratio<2, 3>> res_times(6);
          test_arithmetic_op(d4 * 2L, res_times);
          test_arithmetic_op(2L * d4, res_times);
  
          STD chrono::duration<long, STD ratio<2, 3>> res_divide0(1);
          test_arithmetic_op(d4 / 3L, res_divide0);
          CHECK_TYPE(d4 / d5, long);
          CHECK_INT(d4 / d5, 1);
  
          // comparisons
          di d6(6);
          dl d7(9);
          CHECK_INT(d6 == d7, true);
          CHECK_INT(d4 == d5, false);
          CHECK_INT(d6 != d7, false);
          CHECK_INT(d4 != d5, true);
  
          CHECK_INT(d6 < d7, false);
          CHECK_INT(d4 < d5, false);
          CHECK_INT(d5 < d4, true);
          CHECK_INT(d6 <= d7, true);
          CHECK_INT(d4 <= d5, false);
          CHECK_INT(d5 <= d4, true);
  
          CHECK_INT(d6 > d7, false);
          CHECK_INT(d4 > d5, true);
          CHECK_INT(d5 > d4, false);
          CHECK_INT(d6 >= d7, true);
          CHECK_INT(d4 >= d5, true);
          CHECK_INT(d5 >= d4, false);
  
          // special values
          typedef STD chrono::duration_values<int> dvi;
          CHECK_INT(di::zero().count(), dvi::zero());
          CHECK_INT(di::min().count(), dvi::min());
          CHECK_INT(di::max().count(), dvi::max());
  
          // duration_cast
          d5 = STD chrono::duration_cast<dl>(d4);
          CHECK_INT(d5.count(), 4);
  
          // convenience typedefs
          STD chrono::minutes mins = STD chrono::duration_cast<STD chrono::minutes>(STD chrono::hours(1));
          CHECK_INT(mins.count(), 60);
          STD chrono::seconds secs = STD chrono::duration_cast<STD chrono::seconds>(STD chrono::minutes(1));
          CHECK_INT(secs.count(), 60);
          STD chrono::milliseconds msecs = STD chrono::duration_cast<STD chrono::milliseconds>(STD chrono::seconds(1));
          CHECK_INT(msecs.count(), 1000);
          STD chrono::microseconds mmsecs =
              STD chrono::duration_cast<STD chrono::microseconds>(STD chrono::milliseconds(1));
          CHECK_INT(mmsecs.count(), 1000);
      }
  
      template <class Clock>
      void test_clock(bool tp_known, bool steady_known, bool steady) {
          typedef STD chrono::duration<typename Clock::rep, typename Clock::period> dur;
          CHECK_TYPE(typename Clock::duration, dur);
          typedef STD chrono::time_point<Clock, typename Clock::duration> tp;
          if (tp_known)
              CHECK_TYPE(typename Clock::time_point, tp);
          static_assert(STD is_same_v<decltype(Clock::is_steady), const bool>, "incorrect is_steady type");
          if (steady_known)
              CHECK_INT(Clock::is_steady, steady);
          CHECK_INT(Clock::now() < Clock::time_point::max(), true);
      }
  
      void t_clocks() {
          test_clock<STD chrono::high_resolution_clock>(false, false, false);
          test_clock<STD chrono::system_clock>(true, false, false);
          test_clock<STD chrono::steady_clock>(false, true, true);
          CHECK_INT(STD chrono::system_clock::duration::min() <= STD chrono::system_clock::duration::zero(), true);
  
          time_t t = time(nullptr);
  
          STD chrono::system_clock::time_point tp = STD chrono::system_clock::from_time_t(t);
          CHECK_INT(t, STD chrono::system_clock::to_time_t(tp));
      }
  
      struct my_clock {
          typedef int rep;
          typedef STD ratio<2, 1> period;
          typedef STD chrono::duration<rep, period> duration;
          typedef STD chrono::time_point<my_clock> time_point;
          static const bool is_steady = false;
  
          static time_point now() {
              return time_point(duration(3));
          }
      };
  
      void t_time_point() {
          typedef long rep;
          typedef STD ratio<1, 1> r_1_1;
          typedef STD chrono::duration<rep, r_1_1> dur;
          typedef STD chrono::duration<int, STD ratio<2, 1>> dur1;
          typedef STD chrono::time_point<my_clock, dur> tp;
          typedef STD chrono::time_point<my_clock, dur1> tp1;
  
          // nested typedefs
          CHECK_TYPE(tp::clock, my_clock);
          CHECK_TYPE(tp::duration, dur);
          CHECK_TYPE(tp::rep, rep);
          CHECK_TYPE(tp::period, r_1_1);
  
          bool is_steady = my_clock::is_steady; // to quiet diagnostics
          if (is_steady)
              my_clock::now();
  
          // constructors, time_since_epoch
          tp t0;
          CHECK_INT(t0.time_since_epoch() == tp::duration::zero(), true);
          dur d1(1);
          tp t1(d1);
          CHECK_INT(t1.time_since_epoch() == d1, true);
          STD chrono::minutes d2(1);
          tp t2(d2);
          CHECK_INT(t2.time_since_epoch() == d2, true);
  
          // arithmetic member functions
          t1 += dur1(1);
          CHECK_INT(t1.time_since_epoch() == dur(3), true);
          t1 -= dur1(1);
          CHECK_INT(t1.time_since_epoch() == dur(1), true);
  
          // arithmetic member functions
          CHECK_INT((t1 + dur1(1)).time_since_epoch() == dur(3), true);
          CHECK_INT((dur1(1) + t1).time_since_epoch() == dur(3), true);
          CHECK_INT((t1 - dur1(1)).time_since_epoch() == dur(-1), true);
          tp1 t3(dur1(2));
          CHECK_INT(t1 - t3 == dur(-3), true);
  
          // comparisons
          tp t4(dur(1));
          tp t5(dur(2));
          tp1 t6(dur1(1));
          CHECK_INT(t5 == t6, true);
          CHECK_INT(t4 == t6, false);
          CHECK_INT(t5 != t6, false);
          CHECK_INT(t4 != t6, true);
  
          CHECK_INT(t5 < t6, false);
          CHECK_INT(t4 < t6, true);
          CHECK_INT(t5 < t4, false);
          CHECK_INT(t5 <= t6, true);
          CHECK_INT(t4 <= t6, true);
          CHECK_INT(t5 <= t4, false);
  
          CHECK_INT(t5 > t6, false);
          CHECK_INT(t4 > t6, false);
          CHECK_INT(t5 > t4, true);
          CHECK_INT(t5 >= t6, true);
          CHECK_INT(t4 >= t6, false);
          CHECK_INT(t5 >= t4, true);
  
          // special values
          CHECK_INT(tp::min() == tp(dur::min()), true);
          CHECK_INT(tp::max() == tp(dur::max()), true);
  
          // time_point_cast
          CHECK_INT(STD chrono::time_point_cast<dur1>(t5) == t6, true);
  
          // time_t conversions
          time_t t = time(nullptr);
          if (t != -1) {
              STD chrono::system_clock::time_point now = STD chrono::system_clock::from_time_t(t);
              CHECK_INT(t == STD chrono::system_clock::to_time_t(now), true);
          }
      }
  
  } // unnamed namespace
  
  void test_main() {
      t_common_type();
      t_treat_as_floating_point();
      t_duration_values();
      t_duration();
      t_clocks();
      t_time_point();
  }
  