Files
clang-p2996/libcxx/test/std/time/time.syn/formatter.year_month.pass.cpp
Mark de Wever 105fef5dca [libc++][chrono] Add calendar type formatters.
Some of the calendar types have landed before, this adds the missing
set. Note this does not complete the implementation of the chrono
formatters.

This removes the `chrono` header for some transitive include in C++17
mode. This is needed to avoid inclusion cycles.

Partially implements:
- P1361 Integration of chrono with text formatting
- P2372 Fixing locale handling in chrono formatters

Reviewed By: #libc, ldionne

Differential Revision: https://reviews.llvm.org/D137022
2022-12-24 15:11:41 +01:00

289 lines
8.6 KiB
C++

//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
// UNSUPPORTED: libcpp-has-no-incomplete-format
// TODO FMT It seems GCC uses too much memory in the CI and fails.
// UNSUPPORTED: gcc-12
// REQUIRES: locale.fr_FR.UTF-8
// REQUIRES: locale.ja_JP.UTF-8
// <chrono>
// template<class charT> struct formatter<chrono::year_month, charT>;
#include <chrono>
#include <format>
#include <cassert>
#include <concepts>
#include <locale>
#include <iostream>
#include <type_traits>
#include "formatter_tests.h"
#include "make_string.h"
#include "platform_support.h" // locale name macros
#include "string_literal.h"
#include "test_macros.h"
template <class CharT>
static void test_no_chrono_specs() {
// Valid month
check(SV("1970/Jan"), SV("{}"), std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{1}});
check(SV("*1970/Jan*"), SV("{:*^10}"), std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{1}});
check(SV("*1970/Jan"), SV("{:*>9}"), std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{1}});
// Invalid month_day
check(SV("1970/0 is not a valid month"),
SV("{}"),
std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{0}});
check(SV("*1970/0 is not a valid month*"),
SV("{:*^29}"),
std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{0}});
}
template <class CharT>
static void test_invalid_values() {
// Test that %b and %B throw an exception.
check_exception("formatting a month name from an invalid month number",
SV("{:%b}"),
std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{0}});
check_exception("formatting a month name from an invalid month number",
SV("{:%B}"),
std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{0}});
}
template <class CharT>
static void test_valid_values() {
constexpr std::basic_string_view<CharT> fmt = SV(
"{:"
"%%b='%b'%t"
"%%B='%B'%t"
"%%C='%C'%t"
"%%h='%h'%t"
"%%y='%y'%t"
"%%Y='%Y'%t"
"%%EC='%EC'%t"
"%%Ey='%Ey'%t"
"%%EY='%EY'%t"
"%%Oy='%Oy'%t"
"%n}");
constexpr std::basic_string_view<CharT> lfmt = SV(
"{:L"
"%%b='%b'%t"
"%%B='%B'%t"
"%%C='%C'%t"
"%%h='%h'%t"
"%%y='%y'%t"
"%%Y='%Y'%t"
"%%EC='%EC'%t"
"%%Ey='%Ey'%t"
"%%EY='%EY'%t"
"%%Oy='%Oy'%t"
"%n}");
const std::locale loc(LOCALE_ja_JP_UTF_8);
std::locale::global(std::locale(LOCALE_fr_FR_UTF_8));
// Non localized output using C-locale
check(SV("%b='Jan'\t"
"%B='January'\t"
"%C='19'\t"
"%h='Jan'\t"
"%y='70'\t"
"%Y='1970'\t"
"%EC='19'\t"
"%Ey='70'\t"
"%EY='1970'\t"
"%Oy='70'\t"
"\n"),
fmt,
std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
check(SV("%b='May'\t"
"%B='May'\t"
"%C='20'\t"
"%h='May'\t"
"%y='04'\t"
"%Y='2004'\t"
"%EC='20'\t"
"%Ey='04'\t"
"%EY='2004'\t"
"%Oy='04'\t"
"\n"),
fmt,
std::chrono::year_month{std::chrono::year{2004}, std::chrono::May});
// Use the global locale (fr_FR)
check(SV(
#if defined(__APPLE__)
"%b='jan'\t"
#else
"%b='janv.'\t"
#endif
"%B='janvier'\t"
"%C='19'\t"
#if defined(__APPLE__)
"%h='jan'\t"
#else
"%h='janv.'\t"
#endif
"%y='70'\t"
"%Y='1970'\t"
"%EC='19'\t"
"%Ey='70'\t"
"%EY='1970'\t"
"%Oy='70'\t"
"\n"),
lfmt,
std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
check(SV("%b='mai'\t"
"%B='mai'\t"
"%C='20'\t"
"%h='mai'\t"
"%y='04'\t"
"%Y='2004'\t"
"%EC='20'\t"
"%Ey='04'\t"
"%EY='2004'\t"
"%Oy='04'\t"
"\n"),
lfmt,
std::chrono::year_month{std::chrono::year{2004}, std::chrono::May});
// Use supplied locale (ja_JP)
check(loc,
SV(
#if defined(_WIN32)
"%b='1'\t"
#elif defined(_AIX) // defined(_WIN32)
"%b='1月'\t"
#elif defined(__APPLE__) // defined(_WIN32)
"%b=' 1'\t"
#else // defined(_WIN32)
"%b=' 1月'\t"
#endif // defined(_WIN32)
"%B='1月'\t"
"%C='19'\t"
#if defined(_WIN32)
"%h='1'\t"
#elif defined(_AIX) // defined(_WIN32)
"%h='1月'\t"
#elif defined(__APPLE__) // defined(_WIN32)
"%h=' 1'\t"
#else // defined(_WIN32)
"%h=' 1月'\t"
#endif // defined(_WIN32)
"%y='70'\t"
"%Y='1970'\t"
#if defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
"%EC='19'\t"
"%Ey='70'\t"
"%EY='1970'\t"
"%Oy='70'\t"
#else // defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
"%EC='昭和'\t"
"%Ey='45'\t"
"%EY='昭和45年'\t"
"%Oy='七十'\t"
#endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
"\n"),
lfmt,
std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
check(loc,
SV(
#if defined(_WIN32)
"%b='5'\t"
#elif defined(_AIX) // defined(_WIN32)
"%b='5月'\t"
#elif defined(__APPLE__) // defined(_WIN32)
"%b=' 5'\t"
#else // defined(_WIN32)
"%b=' 5月'\t"
#endif // defined(_WIN32)
"%B='5月'\t"
"%C='20'\t"
#if defined(_WIN32)
"%h='5'\t"
#elif defined(_AIX) // defined(_WIN32)
"%h='5月'\t"
#elif defined(__APPLE__) // defined(_WIN32)
"%h=' 5'\t"
#else // defined(_WIN32)
"%h=' 5月'\t"
#endif // defined(_WIN32)
"%y='04'\t"
"%Y='2004'\t"
#if defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
"%EC='20'\t"
"%Ey='04'\t"
"%EY='2004'\t"
"%Oy='04'\t"
#else // defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
"%EC='平成'\t"
"%Ey='16'\t"
"%EY='平成16年'\t"
"%Oy='四'\t"
#endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
"\n"),
lfmt,
std::chrono::year_month{std::chrono::year{2004}, std::chrono::May});
std::locale::global(std::locale::classic());
}
template <class CharT>
static void test() {
test_no_chrono_specs<CharT>();
test_invalid_values<CharT>();
test_valid_values<CharT>();
check_invalid_types<CharT>(
{SV("b"), SV("B"), SV("C"), SV("EC"), SV("Ey"), SV("EY"), SV("h"), SV("m"), SV("Om"), SV("Oy"), SV("y"), SV("Y")},
std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
check_exception("Expected '%' or '}' in the chrono format-string",
SV("{:A"),
std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
check_exception("The chrono-specs contains a '{'",
SV("{:%%{"),
std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
check_exception("End of input while parsing the modifier chrono conversion-spec",
SV("{:%"),
std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
check_exception("End of input while parsing the modifier E",
SV("{:%E"),
std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
check_exception("End of input while parsing the modifier O",
SV("{:%O"),
std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
// Precision not allowed
check_exception("Expected '%' or '}' in the chrono format-string",
SV("{:.3}"),
std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}