//===----------------------------------------------------------------------===// // // 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: GCC-ALWAYS_INLINE-FIXME // TODO FMT This test should not require std::to_chars(floating-point) // XFAIL: availability-fp_to_chars-missing // REQUIRES: locale.fr_FR.UTF-8 // REQUIRES: locale.ja_JP.UTF-8 // // template struct formatter; #include #include #include #include #include #include #include #include "formatter_tests.h" #include "make_string.h" #include "platform_support.h" // locale name macros #include "string_literal.h" #include "test_macros.h" template 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 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 static void test_valid_values() { constexpr std::basic_string_view 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 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) || defined(__FreeBSD__) "%EC='19'\t" "%Ey='70'\t" "%EY='1970'\t" "%Oy='70'\t" #else // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) "%EC='昭和'\t" "%Ey='45'\t" "%EY='昭和45年'\t" "%Oy='七十'\t" #endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) "\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) || defined(__FreeBSD__) "%EC='20'\t" "%Ey='04'\t" "%EY='2004'\t" "%Oy='04'\t" #else // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) "%EC='平成'\t" "%Ey='16'\t" "%EY='平成16年'\t" "%Oy='四'\t" #endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) "\n"), lfmt, std::chrono::year_month{std::chrono::year{2004}, std::chrono::May}); std::locale::global(std::locale::classic()); } template static void test() { test_no_chrono_specs(); test_invalid_values(); test_valid_values(); check_invalid_types( {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("The format specifier expects a '%' or a '}'", SV("{:A"), std::chrono::year_month{std::chrono::year{1970}, std::chrono::January}); check_exception("The chrono specifiers contain a '{'", SV("{:%%{"), std::chrono::year_month{std::chrono::year{1970}, std::chrono::January}); check_exception("End of input while parsing a conversion specifier", 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("The format specifier expects a '%' or a '}'", SV("{:.3}"), std::chrono::year_month{std::chrono::year{1970}, std::chrono::January}); } int main(int, char**) { test(); #ifndef TEST_HAS_NO_WIDE_CHARACTERS test(); #endif return 0; }