brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.4 KiB · b474fe5 Raw
128 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710// UNSUPPORTED: no-filesystem, no-localization, no-tzdb, has-no-zdump11// REQUIRES: long_tests12 13// XFAIL: libcpp-has-no-experimental-tzdb14// XFAIL: availability-tzdb-missing15 16#include <chrono>17#include <format>18#include <fstream>19#include <cassert>20 21#include "filesystem_test_helper.h"22#include "assert_macros.h"23#include "concat_macros.h"24 25// The year range to validate. The dates used in practice are expected to be26// inside the tested range.27constexpr std::chrono::year first{1800};28constexpr std::chrono::year last{sizeof(time_t) == 8 ? 2100 : 2037};29 30// A custom sys_info class that also stores the name of the time zone.31// Its formatter matches the output of zdump.32struct sys_info : public std::chrono::sys_info {33  sys_info(std::string_view name_, std::chrono::sys_info info) : std::chrono::sys_info{info}, name{name_} {}34 35  std::string name;36};37 38template <>39struct std::formatter<sys_info, char> {40  template <class ParseContext>41  constexpr typename ParseContext::iterator parse(ParseContext& ctx) {42    return ctx.begin();43  }44 45  template <class FormatContext>46  typename FormatContext::iterator format(const sys_info& info, FormatContext& ctx) const {47    using namespace std::literals::chrono_literals;48 49    // Every "sys_info" entry of zdump consists of 2 lines.50    // - 1 for first second of the range51    // - 1 for last second of the range52    // For example:53    // Africa/Casablanca  Sun Mar 25 02:00:00 2018 UT = Sun Mar 25 03:00:00 2018 +01 isdst=1 gmtoff=360054    // Africa/Casablanca  Sun May 13 01:59:59 2018 UT = Sun May 13 02:59:59 2018 +01 isdst=1 gmtoff=360055 56    if (info.begin != std::chrono::sys_seconds::min())57      ctx.advance_to(std::format_to(58          ctx.out(),59          "{}  {:%a %b %e %H:%M:%S %Y} UT = {:%a %b %e %H:%M:%S %Y} {} isdst={:d} gmtoff={:%Q}\n",60          info.name,61          info.begin,62          info.begin + info.offset,63          info.abbrev,64          info.save != 0s,65          info.offset));66 67    if (info.end != std::chrono::sys_seconds::max())68      ctx.advance_to(std::format_to(69          ctx.out(),70          "{}  {:%a %b %e %H:%M:%S %Y} UT = {:%a %b %e %H:%M:%S %Y} {} isdst={:d} gmtoff={:%Q}\n",71          info.name,72          info.end - 1s,73          info.end - 1s + info.offset,74          info.abbrev,75          info.save != 0s,76          info.offset));77 78    return ctx.out();79  }80};81 82void process(std::ostream& stream, const std::chrono::time_zone& zone) {83  using namespace std::literals::chrono_literals;84 85  constexpr auto begin = std::chrono::time_point_cast<std::chrono::seconds>(86      static_cast<std::chrono::sys_days>(std::chrono::year_month_day{first, std::chrono::January, 1d}));87  constexpr auto end = std::chrono::time_point_cast<std::chrono::seconds>(88      static_cast<std::chrono::sys_days>(std::chrono::year_month_day{last, std::chrono::January, 1d}));89 90  std::chrono::sys_seconds s = begin;91  do {92    sys_info info{zone.name(), zone.get_info(s)};93 94    if (info.end >= end)95      info.end = std::chrono::sys_seconds::max();96 97    stream << std::format("{}", info);98    s = info.end;99  } while (s != std::chrono::sys_seconds::max());100}101 102// This test compares the output of the zdump against the output based on the103// standard library implementation. It tests all available time zones and104// validates them. The specification of how to use the IANA database is limited105// and the real database contains quite a number of "interesting" cases.106int main(int, const char**) {107  scoped_test_env env;108  const std::string file = env.create_file("zdump.txt");109 110  const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();111  for (const auto& zone : tzdb.zones) {112    std::stringstream libcxx;113    process(libcxx, zone);114 115    int result = std::system(std::format("zdump -V -c{},{} {} > {}", first, last, zone.name(), file).c_str());116    assert(result == 0);117 118    std::stringstream zdump;119    zdump << std::ifstream(file).rdbuf();120 121    TEST_REQUIRE(122        libcxx.str() == zdump.str(),123        TEST_WRITE_CONCATENATED("\nTZ=", zone.name(), "\nlibc++\n", libcxx.str(), "|\n\nzdump\n", zdump.str(), "|"));124  }125 126  return 0;127}128