test: refactor date formatter tests.
- Add tests for global locale. - Warn about missing locales. - Downgrade REQUIRE to CHECK. - Skip tests if localized formatting does not work as expected.pull/1959/head
parent
ea17a66dfc
commit
6225db0a48
150
test/date.cpp
150
test/date.cpp
|
@ -1,13 +1,23 @@
|
||||||
#include "util/date.hpp"
|
#include "util/date.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <ctime>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#if __has_include(<catch2/catch_test_macros.hpp>)
|
#if __has_include(<catch2/catch_test_macros.hpp>)
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include <catch2/matchers/catch_matchers_all.hpp>
|
#include <catch2/matchers/catch_matchers_all.hpp>
|
||||||
#else
|
#else
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
#endif
|
#endif
|
||||||
#include <chrono>
|
|
||||||
#include <stdexcept>
|
#ifndef SKIP
|
||||||
|
#define SKIP(...) \
|
||||||
|
WARN(__VA_ARGS__); \
|
||||||
|
return
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace std::literals::chrono_literals;
|
using namespace std::literals::chrono_literals;
|
||||||
|
|
||||||
|
@ -18,39 +28,79 @@ using namespace std::literals::chrono_literals;
|
||||||
const date::zoned_time<std::chrono::seconds> TEST_TIME = date::zoned_time{
|
const date::zoned_time<std::chrono::seconds> TEST_TIME = date::zoned_time{
|
||||||
"UTC", date::local_days{date::Monday[1] / date::January / 2022} + 13h + 4min + 5s};
|
"UTC", date::local_days{date::Monday[1] / date::January / 2022} + 13h + 4min + 5s};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the date formatted with LC_TIME=en_US is within expectations.
|
||||||
|
*
|
||||||
|
* The check expects Glibc output style and will fail with FreeBSD (different implementation)
|
||||||
|
* or musl (no implementation).
|
||||||
|
*/
|
||||||
|
static const bool LC_TIME_is_sane = []() {
|
||||||
|
try {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss.imbue(std::locale("en_US.UTF-8"));
|
||||||
|
|
||||||
|
time_t t = 1641211200;
|
||||||
|
std::tm tm = *std::gmtime(&t);
|
||||||
|
|
||||||
|
ss << std::put_time(&tm, "%x %X");
|
||||||
|
return ss.str() == "01/03/2022 12:00:00 PM";
|
||||||
|
} catch (std::exception &) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
TEST_CASE("Format UTC time", "[clock][util]") {
|
TEST_CASE("Format UTC time", "[clock][util]") {
|
||||||
const auto loc = std::locale("C");
|
const auto loc = std::locale("C");
|
||||||
const auto tm = TEST_TIME;
|
const auto tm = TEST_TIME;
|
||||||
|
|
||||||
REQUIRE(fmt::format(loc, "{}", tm).empty()); // no format specified
|
CHECK(fmt::format(loc, "{}", tm).empty()); // no format specified
|
||||||
REQUIRE(fmt::format(loc, "{:%c %Z}", tm) == "Mon Jan 3 13:04:05 2022 UTC");
|
CHECK(fmt::format(loc, "{:%c %Z}", tm) == "Mon Jan 3 13:04:05 2022 UTC");
|
||||||
REQUIRE(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405");
|
CHECK(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405");
|
||||||
|
|
||||||
|
if (!LC_TIME_is_sane) {
|
||||||
|
SKIP("Locale support check failed, skip tests");
|
||||||
|
}
|
||||||
|
|
||||||
/* Test a few locales that are most likely to be present */
|
/* Test a few locales that are most likely to be present */
|
||||||
SECTION("US locale") {
|
SECTION("US locale") {
|
||||||
try {
|
try {
|
||||||
const auto loc = std::locale("en_US");
|
const auto loc = std::locale("en_US.UTF-8");
|
||||||
|
|
||||||
REQUIRE(fmt::format(loc, "{}", tm).empty()); // no format specified
|
CHECK(fmt::format(loc, "{}", tm).empty()); // no format specified
|
||||||
REQUIRE_THAT(fmt::format(loc, "{:%c}", tm), // HowardHinnant/date#704
|
CHECK_THAT(fmt::format(loc, "{:%c}", tm), // HowardHinnant/date#704
|
||||||
Catch::Matchers::StartsWith("Mon 03 Jan 2022 01:04:05 PM"));
|
Catch::Matchers::StartsWith("Mon 03 Jan 2022 01:04:05 PM"));
|
||||||
REQUIRE(fmt::format(loc, "{:%x %X}", tm) == "01/03/2022 01:04:05 PM");
|
CHECK(fmt::format(loc, "{:%x %X}", tm) == "01/03/2022 01:04:05 PM");
|
||||||
REQUIRE(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405");
|
CHECK(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405");
|
||||||
} catch (const std::runtime_error&) {
|
} catch (const std::runtime_error &) {
|
||||||
// locale not found; ignore
|
WARN("Locale en_US not found, skip tests");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SECTION("GB locale") {
|
SECTION("GB locale") {
|
||||||
try {
|
try {
|
||||||
const auto loc = std::locale("en_GB");
|
const auto loc = std::locale("en_GB.UTF-8");
|
||||||
|
|
||||||
REQUIRE(fmt::format(loc, "{}", tm).empty()); // no format specified
|
CHECK(fmt::format(loc, "{}", tm).empty()); // no format specified
|
||||||
REQUIRE_THAT(fmt::format(loc, "{:%c}", tm), // HowardHinnant/date#704
|
CHECK_THAT(fmt::format(loc, "{:%c}", tm), // HowardHinnant/date#704
|
||||||
Catch::Matchers::StartsWith("Mon 03 Jan 2022 13:04:05"));
|
Catch::Matchers::StartsWith("Mon 03 Jan 2022 13:04:05"));
|
||||||
REQUIRE(fmt::format(loc, "{:%x %X}", tm) == "03/01/22 13:04:05");
|
CHECK(fmt::format(loc, "{:%x %X}", tm) == "03/01/22 13:04:05");
|
||||||
REQUIRE(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405");
|
CHECK(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405");
|
||||||
} catch (const std::runtime_error&) {
|
} catch (const std::runtime_error &) {
|
||||||
// locale not found; ignore
|
WARN("Locale en_GB not found, skip tests");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("Global locale") {
|
||||||
|
try {
|
||||||
|
const auto loc = std::locale::global(std::locale("en_US.UTF-8"));
|
||||||
|
|
||||||
|
CHECK(fmt::format("{}", tm).empty()); // no format specified
|
||||||
|
CHECK_THAT(fmt::format("{:%c}", tm), // HowardHinnant/date#704
|
||||||
|
Catch::Matchers::StartsWith("Mon 03 Jan 2022 01:04:05 PM"));
|
||||||
|
CHECK(fmt::format("{:%x %X}", tm) == "01/03/2022 01:04:05 PM");
|
||||||
|
CHECK(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405");
|
||||||
|
|
||||||
|
std::locale::global(loc);
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
WARN("Locale en_US not found, skip tests");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,36 +109,54 @@ TEST_CASE("Format zoned time", "[clock][util]") {
|
||||||
const auto loc = std::locale("C");
|
const auto loc = std::locale("C");
|
||||||
const auto tm = date::zoned_time{"America/New_York", TEST_TIME};
|
const auto tm = date::zoned_time{"America/New_York", TEST_TIME};
|
||||||
|
|
||||||
REQUIRE(fmt::format(loc, "{}", tm).empty()); // no format specified
|
CHECK(fmt::format(loc, "{}", tm).empty()); // no format specified
|
||||||
REQUIRE(fmt::format(loc, "{:%c %Z}", tm) == "Mon Jan 3 08:04:05 2022 EST");
|
CHECK(fmt::format(loc, "{:%c %Z}", tm) == "Mon Jan 3 08:04:05 2022 EST");
|
||||||
REQUIRE(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405");
|
CHECK(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405");
|
||||||
|
|
||||||
|
if (!LC_TIME_is_sane) {
|
||||||
|
SKIP("Locale support check failed, skip tests");
|
||||||
|
}
|
||||||
|
|
||||||
/* Test a few locales that are most likely to be present */
|
/* Test a few locales that are most likely to be present */
|
||||||
SECTION("US locale") {
|
SECTION("US locale") {
|
||||||
try {
|
try {
|
||||||
const auto loc = std::locale("en_US");
|
const auto loc = std::locale("en_US.UTF-8");
|
||||||
|
|
||||||
REQUIRE(fmt::format(loc, "{}", tm).empty()); // no format specified
|
CHECK(fmt::format(loc, "{}", tm).empty()); // no format specified
|
||||||
REQUIRE_THAT(fmt::format(loc, "{:%c}", tm), // HowardHinnant/date#704
|
CHECK_THAT(fmt::format(loc, "{:%c}", tm), // HowardHinnant/date#704
|
||||||
Catch::Matchers::StartsWith("Mon 03 Jan 2022 08:04:05 AM"));
|
Catch::Matchers::StartsWith("Mon 03 Jan 2022 08:04:05 AM"));
|
||||||
REQUIRE(fmt::format(loc, "{:%x %X}", tm) == "01/03/2022 08:04:05 AM");
|
CHECK(fmt::format(loc, "{:%x %X}", tm) == "01/03/2022 08:04:05 AM");
|
||||||
REQUIRE(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405");
|
CHECK(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405");
|
||||||
} catch (const std::runtime_error&) {
|
} catch (const std::runtime_error &) {
|
||||||
// locale not found; ignore
|
WARN("Locale en_US not found, skip tests");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("GB locale") {
|
SECTION("GB locale") {
|
||||||
try {
|
try {
|
||||||
const auto loc = std::locale("en_GB");
|
const auto loc = std::locale("en_GB.UTF-8");
|
||||||
|
|
||||||
REQUIRE(fmt::format(loc, "{}", tm).empty()); // no format specified
|
CHECK(fmt::format(loc, "{}", tm).empty()); // no format specified
|
||||||
REQUIRE_THAT(fmt::format(loc, "{:%c}", tm), // HowardHinnant/date#704
|
CHECK_THAT(fmt::format(loc, "{:%c}", tm), // HowardHinnant/date#704
|
||||||
Catch::Matchers::StartsWith("Mon 03 Jan 2022 08:04:05"));
|
Catch::Matchers::StartsWith("Mon 03 Jan 2022 08:04:05"));
|
||||||
REQUIRE(fmt::format(loc, "{:%x %X}", tm) == "03/01/22 08:04:05");
|
CHECK(fmt::format(loc, "{:%x %X}", tm) == "03/01/22 08:04:05");
|
||||||
REQUIRE(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405");
|
CHECK(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405");
|
||||||
} catch (const std::runtime_error&) {
|
} catch (const std::runtime_error &) {
|
||||||
// locale not found; ignore
|
WARN("Locale en_GB not found, skip tests");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("Global locale") {
|
||||||
|
try {
|
||||||
|
const auto loc = std::locale::global(std::locale("en_US.UTF-8"));
|
||||||
|
|
||||||
|
CHECK(fmt::format("{}", tm).empty()); // no format specified
|
||||||
|
CHECK_THAT(fmt::format("{:%c}", tm), // HowardHinnant/date#704
|
||||||
|
Catch::Matchers::StartsWith("Mon 03 Jan 2022 08:04:05 AM"));
|
||||||
|
CHECK(fmt::format("{:%x %X}", tm) == "01/03/2022 08:04:05 AM");
|
||||||
|
CHECK(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405");
|
||||||
|
|
||||||
|
std::locale::global(loc);
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
WARN("Locale en_US not found, skip tests");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue