From 1478be14c7bf4e688d48d78c1b4816f8b43ac69d Mon Sep 17 00:00:00 2001 From: Joel Linn Date: Wed, 9 Mar 2022 23:49:27 +0100 Subject: [PATCH] [Base] Add chrono tests --- src/xenia/base/testing/chrono_test.cc | 148 ++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 src/xenia/base/testing/chrono_test.cc diff --git a/src/xenia/base/testing/chrono_test.cc b/src/xenia/base/testing/chrono_test.cc new file mode 100644 index 000000000..a63aac53c --- /dev/null +++ b/src/xenia/base/testing/chrono_test.cc @@ -0,0 +1,148 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2022 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/base/chrono.h" + +#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#include "third_party/catch/include/catch.hpp" + +namespace xe::base::test { + +// If the tests run fast, the time duration may be zero. So we artificially +// raise it to allow for some error. +template +auto dur_bound(std::chrono::duration<_Rep, _Period> dur) { + using namespace std::chrono_literals; + return std::max>>( + dur, 1ms); +} + +TEST_CASE("WinSystemClock <-> system_clock", "[clock_cast]") { + using namespace xe::chrono; + using namespace date; + using sys_clock = std::chrono::system_clock; + + // First check some assumptions made in chrono.h + + SECTION("C++20 unix epoch") { + auto epoch = date::year{1970} / date::month{1} / date::day{1}; + std::chrono::system_clock::time_point epoch_tp{ + static_cast(epoch)}; + REQUIRE(epoch_tp.time_since_epoch().count() == 0); + } + + SECTION("Epoch delta") { + std::chrono::seconds sys_delta = WinSystemClock::unix_epoch_delta(); + REQUIRE(sys_delta.count() == INT64_C(-11644473600)); + } + + SECTION("1993/12/21") { + static constexpr sys_days sys(1993_y / dec / 21); + + static constexpr auto wsys = WinSystemClock::from_sys(sys); + REQUIRE(wsys.time_since_epoch().count() == 124009056000000000); + + REQUIRE(clock_cast(wsys) == sys); + REQUIRE(clock_cast(sys) == wsys); + } + + SECTION("2100/3/1") { + static constexpr sys_days sys(2100_y / mar / 1); + + static constexpr auto wsys = WinSystemClock::from_sys(sys); + REQUIRE(wsys.time_since_epoch().count() == 157520160000000000); + + REQUIRE(clock_cast(wsys) == sys); + REQUIRE(clock_cast(sys) == wsys); + } +} + +TEST_CASE("WinSystemClock <-> XSystemClock", "[clock_cast]") { + using namespace std::chrono_literals; + using namespace xe::chrono; + using namespace date; + using sys_clock = std::chrono::system_clock; + + SECTION("1993/12/21, clock_no_scaling = true") { + static constexpr sys_days sys(1993_y / dec / 21); + cvars::clock_no_scaling = true; + Clock::set_guest_time_scalar(1.0); + + static constexpr auto wsys = WinSystemClock::from_sys(sys); + + auto start = std::chrono::system_clock::now(); + + auto xsys = date::clock_cast(wsys); + auto wxsys = date::clock_cast(xsys); + + auto duration = dur_bound(std::chrono::system_clock::now() - start); + + auto error = wsys.time_since_epoch() - wxsys.time_since_epoch(); + REQUIRE(error < duration); + REQUIRE(error > -duration); + } + + SECTION("1993/12/21, clock_no_scaling = false") { + static constexpr sys_days sys(1993_y / dec / 21); + cvars::clock_no_scaling = false; + Clock::set_guest_time_scalar(1.0); + + static constexpr auto wsys = WinSystemClock::from_sys(sys); + + auto start = std::chrono::system_clock::now(); + + auto xsys = date::clock_cast(wsys); + auto wxsys = date::clock_cast(xsys); + + auto duration = dur_bound(std::chrono::system_clock::now() - start); + + auto error1 = wsys.time_since_epoch() - xsys.time_since_epoch(); + auto error2 = xsys.time_since_epoch() - wxsys.time_since_epoch(); + auto error3 = wsys - wxsys; + + REQUIRE(error1 < 10ms); + REQUIRE(error1 > -10ms); + REQUIRE(error2 < 10ms); + REQUIRE(error2 > -10ms); + REQUIRE(error3 < duration); + REQUIRE(error3 > -duration); + } +} + +} // namespace xe::base::test + +// only make these available now +#include "xenia/base/chrono_steady_cast.h" + +namespace xe::base::test { + +TEST_CASE("WinSystemClock <-> steady_clock", "[clock_cast]") { + using namespace xe::chrono; + using namespace date; + using sty_clock = std::chrono::steady_clock; + + // steady conversion is mostly used to convert wait times + + SECTION("now") { + auto sty = sty_clock::now(); + + // Because steady casts are imprecise, we need to allow some margin of error + auto start = sty_clock::now(); + + auto wsty = clock_cast(sty); + auto sty2 = clock_cast(wsty); + + auto duration = dur_bound(sty_clock::now() - start).count(); + auto error = std::abs((sty2 - sty).count()); + REQUIRE(error <= duration); + } +} + +} // namespace xe::base::test