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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14, c++17 10 // UNSUPPORTED: no-localization 11 // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME 12 13 // TODO FMT This test should not require std::to_chars(floating-point) 14 // XFAIL: availability-fp_to_chars-missing 15 16 // REQUIRES: locale.fr_FR.UTF-8 17 // REQUIRES: locale.ja_JP.UTF-8 18 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 macros 35 #include "string_literal.h" 36 #include "test_macros.h" 37 38 template <class CharT> 39 static void test_no_chrono_specs() { 40 // Valid month 41 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_day 46 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 54 template <class CharT> 55 static 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 66 template <class CharT> 67 static 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-locale 100 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 #else 133 "%b='janv.'\t" 134 #endif 135 "%B='janvier'\t" 136 "%C='19'\t" 137 #if defined(__APPLE__) 138 "%h='jan'\t" 139 #else 140 "%h='janv.'\t" 141 #endif 142 "%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 249 template <class CharT> 250 static 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 allowed 276 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 281 int main(int, char**) { 282 test<char>(); 283 284 #ifndef TEST_HAS_NO_WIDE_CHARACTERS 285 test<wchar_t>(); 286 #endif 287 288 return 0; 289 } 290