290 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-localization11// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME12 13// TODO FMT This test should not require std::to_chars(floating-point)14// XFAIL: availability-fp_to_chars-missing15 16// REQUIRES: locale.fr_FR.UTF-817// REQUIRES: locale.ja_JP.UTF-818 19// <chrono>20 21// template<class charT> struct formatter<chrono::year_month, charT>;22 23#include <chrono>24#include <format>25 26#include <cassert>27#include <concepts>28#include <locale>29#include <iostream>30#include <type_traits>31 32#include "formatter_tests.h"33#include "make_string.h"34#include "platform_support.h" // locale name macros35#include "string_literal.h"36#include "test_macros.h"37 38template <class CharT>39static void test_no_chrono_specs() {40 // Valid month41 check(SV("1970/Jan"), SV("{}"), std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{1}});42 check(SV("*1970/Jan*"), SV("{:*^10}"), std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{1}});43 check(SV("*1970/Jan"), SV("{:*>9}"), std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{1}});44 45 // Invalid month_day46 check(SV("1970/0 is not a valid month"),47 SV("{}"),48 std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{0}});49 check(SV("*1970/0 is not a valid month*"),50 SV("{:*^29}"),51 std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{0}});52}53 54template <class CharT>55static void test_invalid_values() {56 // Test that %b and %B throw an exception.57 check_exception("Formatting a month name from an invalid month number",58 SV("{:%b}"),59 std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{0}});60 61 check_exception("Formatting a month name from an invalid month number",62 SV("{:%B}"),63 std::chrono::year_month{std::chrono::year{1970}, std::chrono::month{0}});64}65 66template <class CharT>67static void test_valid_values() {68 constexpr std::basic_string_view<CharT> fmt = SV(69 "{:"70 "%%b='%b'%t"71 "%%B='%B'%t"72 "%%C='%C'%t"73 "%%h='%h'%t"74 "%%y='%y'%t"75 "%%Y='%Y'%t"76 "%%EC='%EC'%t"77 "%%Ey='%Ey'%t"78 "%%EY='%EY'%t"79 "%%Oy='%Oy'%t"80 "%n}");81 82 constexpr std::basic_string_view<CharT> lfmt = SV(83 "{:L"84 "%%b='%b'%t"85 "%%B='%B'%t"86 "%%C='%C'%t"87 "%%h='%h'%t"88 "%%y='%y'%t"89 "%%Y='%Y'%t"90 "%%EC='%EC'%t"91 "%%Ey='%Ey'%t"92 "%%EY='%EY'%t"93 "%%Oy='%Oy'%t"94 "%n}");95 96 const std::locale loc(LOCALE_ja_JP_UTF_8);97 std::locale::global(std::locale(LOCALE_fr_FR_UTF_8));98 99 // Non localized output using C-locale100 check(SV("%b='Jan'\t"101 "%B='January'\t"102 "%C='19'\t"103 "%h='Jan'\t"104 "%y='70'\t"105 "%Y='1970'\t"106 "%EC='19'\t"107 "%Ey='70'\t"108 "%EY='1970'\t"109 "%Oy='70'\t"110 "\n"),111 fmt,112 std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});113 114 check(SV("%b='May'\t"115 "%B='May'\t"116 "%C='20'\t"117 "%h='May'\t"118 "%y='04'\t"119 "%Y='2004'\t"120 "%EC='20'\t"121 "%Ey='04'\t"122 "%EY='2004'\t"123 "%Oy='04'\t"124 "\n"),125 fmt,126 std::chrono::year_month{std::chrono::year{2004}, std::chrono::May});127 128 // Use the global locale (fr_FR)129 check(SV(130#if defined(__APPLE__)131 "%b='jan'\t"132#else133 "%b='janv.'\t"134#endif135 "%B='janvier'\t"136 "%C='19'\t"137#if defined(__APPLE__)138 "%h='jan'\t"139#else140 "%h='janv.'\t"141#endif142 "%y='70'\t"143 "%Y='1970'\t"144 "%EC='19'\t"145 "%Ey='70'\t"146 "%EY='1970'\t"147 "%Oy='70'\t"148 "\n"),149 lfmt,150 std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});151 152 check(SV("%b='mai'\t"153 "%B='mai'\t"154 "%C='20'\t"155 "%h='mai'\t"156 "%y='04'\t"157 "%Y='2004'\t"158 "%EC='20'\t"159 "%Ey='04'\t"160 "%EY='2004'\t"161 "%Oy='04'\t"162 "\n"),163 lfmt,164 std::chrono::year_month{std::chrono::year{2004}, std::chrono::May});165 166 // Use supplied locale (ja_JP)167 check(loc,168 SV(169#if defined(_WIN32)170 "%b='1'\t"171#elif defined(_AIX) // defined(_WIN32)172 "%b='1月'\t"173#elif defined(__APPLE__) // defined(_WIN32)174 "%b=' 1'\t"175#else // defined(_WIN32)176 "%b=' 1月'\t"177#endif // defined(_WIN32)178 "%B='1月'\t"179 "%C='19'\t"180#if defined(_WIN32)181 "%h='1'\t"182#elif defined(_AIX) // defined(_WIN32)183 "%h='1月'\t"184#elif defined(__APPLE__) // defined(_WIN32)185 "%h=' 1'\t"186#else // defined(_WIN32)187 "%h=' 1月'\t"188#endif // defined(_WIN32)189 "%y='70'\t"190 "%Y='1970'\t"191#if defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__)192 "%EC='19'\t"193 "%Ey='70'\t"194 "%EY='1970'\t"195 "%Oy='70'\t"196#else // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__)197 "%EC='昭和'\t"198 "%Ey='45'\t"199 "%EY='昭和45年'\t"200 "%Oy='七十'\t"201#endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__)202 "\n"),203 lfmt,204 std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});205 206 check(loc,207 SV(208 209#if defined(_WIN32)210 "%b='5'\t"211#elif defined(_AIX) // defined(_WIN32)212 "%b='5月'\t"213#elif defined(__APPLE__) // defined(_WIN32)214 "%b=' 5'\t"215#else // defined(_WIN32)216 "%b=' 5月'\t"217#endif // defined(_WIN32)218 "%B='5月'\t"219 "%C='20'\t"220#if defined(_WIN32)221 "%h='5'\t"222#elif defined(_AIX) // defined(_WIN32)223 "%h='5月'\t"224#elif defined(__APPLE__) // defined(_WIN32)225 "%h=' 5'\t"226#else // defined(_WIN32)227 "%h=' 5月'\t"228#endif // defined(_WIN32)229 "%y='04'\t"230 "%Y='2004'\t"231#if defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__)232 "%EC='20'\t"233 "%Ey='04'\t"234 "%EY='2004'\t"235 "%Oy='04'\t"236#else // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__)237 "%EC='平成'\t"238 "%Ey='16'\t"239 "%EY='平成16年'\t"240 "%Oy='四'\t"241#endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__)242 "\n"),243 lfmt,244 std::chrono::year_month{std::chrono::year{2004}, std::chrono::May});245 246 std::locale::global(std::locale::classic());247}248 249template <class CharT>250static void test() {251 test_no_chrono_specs<CharT>();252 test_invalid_values<CharT>();253 test_valid_values<CharT>();254 255 check_invalid_types<CharT>(256 {SV("b"), SV("B"), SV("C"), SV("EC"), SV("Ey"), SV("EY"), SV("h"), SV("m"), SV("Om"), SV("Oy"), SV("y"), SV("Y")},257 std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});258 259 check_exception("The format specifier expects a '%' or a '}'",260 SV("{:A"),261 std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});262 check_exception("The chrono specifiers contain a '{'",263 SV("{:%%{"),264 std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});265 check_exception("End of input while parsing a conversion specifier",266 SV("{:%"),267 std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});268 check_exception("End of input while parsing the modifier E",269 SV("{:%E"),270 std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});271 check_exception("End of input while parsing the modifier O",272 SV("{:%O"),273 std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});274 275 // Precision not allowed276 check_exception("The format specifier expects a '%' or a '}'",277 SV("{:.3}"),278 std::chrono::year_month{std::chrono::year{1970}, std::chrono::January});279}280 281int main(int, char**) {282 test<char>();283 284#ifndef TEST_HAS_NO_WIDE_CHARACTERS285 test<wchar_t>();286#endif287 288 return 0;289}290