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, 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 check(SV("-32767"), SV("{}"), std::chrono::year{-32'767}); 41 check(SV("-1000"), SV("{}"), std::chrono::year{-1000}); 42 check(SV("-0100"), SV("{}"), std::chrono::year{-100}); 43 check(SV("-0010"), SV("{}"), std::chrono::year{-10}); 44 check(SV("-0001"), SV("{}"), std::chrono::year{-1}); 45 check(SV("0000"), SV("{}"), std::chrono::year{0}); 46 check(SV("0001"), SV("{}"), std::chrono::year{1}); 47 check(SV("0010"), SV("{}"), std::chrono::year{10}); 48 check(SV("0100"), SV("{}"), std::chrono::year{100}); 49 check(SV("1000"), SV("{}"), std::chrono::year{1000}); 50 check(SV("32727"), SV("{}"), std::chrono::year{32'727}); 51 52 // Invalid year 53 check(SV("-32768 is not a valid year"), SV("{}"), std::chrono::year{-32'768}); 54 check(SV("-32768 is not a valid year"), SV("{}"), std::chrono::year{32'768}); 55 } 56 57 template <class CharT> 58 static void test_valid_values() { 59 constexpr std::basic_string_view<CharT> fmt = SV( 60 "{:" 61 "%%C='%C'%t" 62 "%%EC='%EC'%t" 63 "%%y='%y'%t" 64 "%%Ey='%Ey'%t" 65 "%%Oy='%Oy'%t" 66 "%%Y='%Y'%t" 67 "%%EY='%EY'%t" 68 "%n}"); 69 constexpr std::basic_string_view<CharT> lfmt = SV( 70 "{:L" 71 "%%C='%C'%t" 72 "%%EC='%EC'%t" 73 "%%y='%y'%t" 74 "%%Ey='%Ey'%t" 75 "%%Oy='%Oy'%t" 76 "%%Y='%Y'%t" 77 "%%EY='%EY'%t" 78 "%n}"); 79 80 const std::locale loc(LOCALE_ja_JP_UTF_8); 81 std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); 82 83 // Non localized output using C-locale 84 check(SV("%C='00'\t" 85 #if defined(__APPLE__) || defined(_WIN32) || defined(__FreeBSD__) 86 "%EC='00'\t" 87 #else 88 "%EC='0'\t" 89 #endif 90 "%y='00'\t" 91 "%Ey='00'\t" 92 "%Oy='00'\t" 93 "%Y='0000'\t" 94 #if defined(__APPLE__) || defined(_WIN32) || defined(__FreeBSD__) 95 "%EY='0000'\t" 96 #elif defined(_AIX) 97 "%EY=''\t" 98 #else 99 "%EY='0'\t" 100 #endif 101 "\n"), 102 fmt, 103 std::chrono::year{0}); 104 105 check(SV("%C='19'\t" 106 "%EC='19'\t" 107 "%y='70'\t" 108 "%Ey='70'\t" 109 "%Oy='70'\t" 110 "%Y='1970'\t" 111 "%EY='1970'\t" 112 "\n"), 113 fmt, 114 std::chrono::year{1970}); 115 116 check(SV("%C='20'\t" 117 "%EC='20'\t" 118 "%y='38'\t" 119 "%Ey='38'\t" 120 "%Oy='38'\t" 121 "%Y='2038'\t" 122 "%EY='2038'\t" 123 "\n"), 124 fmt, 125 std::chrono::year{2038}); 126 127 // Use the global locale (fr_FR) 128 check(SV("%C='00'\t" 129 #if defined(__APPLE__) || defined(_WIN32) || defined(__FreeBSD__) 130 "%EC='00'\t" 131 #else 132 "%EC='0'\t" 133 #endif 134 "%y='00'\t" 135 "%Ey='00'\t" 136 "%Oy='00'\t" 137 "%Y='0000'\t" 138 #if defined(__APPLE__) || defined(_WIN32) || defined(__FreeBSD__) 139 "%EY='0000'\t" 140 #elif defined(_AIX) 141 "%EY=''\t" 142 #else 143 "%EY='0'\t" 144 #endif 145 "\n"), 146 lfmt, 147 std::chrono::year{0}); 148 149 check(SV("%C='19'\t" 150 "%EC='19'\t" 151 "%y='70'\t" 152 "%Ey='70'\t" 153 "%Oy='70'\t" 154 "%Y='1970'\t" 155 "%EY='1970'\t" 156 "\n"), 157 lfmt, 158 std::chrono::year{1970}); 159 160 check(SV("%C='20'\t" 161 "%EC='20'\t" 162 "%y='38'\t" 163 "%Ey='38'\t" 164 "%Oy='38'\t" 165 "%Y='2038'\t" 166 "%EY='2038'\t" 167 "\n"), 168 lfmt, 169 std::chrono::year{2038}); 170 171 // Use supplied locale (ja_JP). This locale has a different alternate. 172 #if defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) 173 174 check(SV("%C='00'\t" 175 # if defined(__APPLE__) || defined(_WIN32) || defined(__FreeBSD__) 176 "%EC='00'\t" 177 # else 178 "%EC='0'\t" 179 # endif 180 "%y='00'\t" 181 "%Ey='00'\t" 182 "%Oy='00'\t" 183 "%Y='0000'\t" 184 # if defined(_AIX) 185 "%EY=''\t" 186 # else 187 "%EY='0000'\t" 188 # endif 189 "\n"), 190 lfmt, 191 std::chrono::year{0}); 192 193 check(SV("%C='19'\t" 194 "%EC='19'\t" 195 "%y='70'\t" 196 "%Ey='70'\t" 197 "%Oy='70'\t" 198 "%Y='1970'\t" 199 "%EY='1970'\t" 200 "\n"), 201 lfmt, 202 std::chrono::year{1970}); 203 204 check(SV("%C='20'\t" 205 "%EC='20'\t" 206 "%y='38'\t" 207 "%Ey='38'\t" 208 "%Oy='38'\t" 209 "%Y='2038'\t" 210 "%EY='2038'\t" 211 "\n"), 212 lfmt, 213 std::chrono::year{2038}); 214 215 #else // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) 216 check(loc, 217 SV("%C='00'\t" 218 "%EC='紀元前'\t" 219 "%y='00'\t" 220 // https://sourceware.org/bugzilla/show_bug.cgi?id=23758 221 # if defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29 222 "%Ey='1'\t" 223 # else 224 "%Ey='01'\t" 225 # endif 226 "%Oy='〇'\t" 227 "%Y='0000'\t" 228 // https://sourceware.org/bugzilla/show_bug.cgi?id=23758 229 # if defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29 230 "%EY='紀元前1年'\t" 231 # else 232 "%EY='紀元前01年'\t" 233 # endif 234 "\n"), 235 lfmt, 236 std::chrono::year{0}); 237 238 check(loc, 239 SV("%C='19'\t" 240 "%EC='昭和'\t" 241 "%y='70'\t" 242 "%Ey='45'\t" 243 "%Oy='七十'\t" 244 "%Y='1970'\t" 245 "%EY='昭和45年'\t" 246 "\n"), 247 lfmt, 248 std::chrono::year{1970}); 249 250 // Note this test will fail if the Reiwa era ends before 2038. 251 check(loc, 252 SV("%C='20'\t" 253 "%EC='令和'\t" 254 "%y='38'\t" 255 "%Ey='20'\t" 256 "%Oy='三十八'\t" 257 "%Y='2038'\t" 258 "%EY='令和20年'\t" 259 "\n"), 260 lfmt, 261 std::chrono::year{2038}); 262 #endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32) || defined(__FreeBSD__) 263 264 std::locale::global(std::locale::classic()); 265 } 266 267 template <class CharT> 268 static void test_padding() { 269 constexpr std::basic_string_view<CharT> fmt = SV("{:%%C='%C'%t%%y='%y'%t%%Y='%Y'%t%n}"); 270 check(SV("%C='-100'\t%y='99'\t%Y='-9999'\t\n"), fmt, std::chrono::year{-9'999}); 271 check(SV("%C='-10'\t%y='99'\t%Y='-0999'\t\n"), fmt, std::chrono::year{-999}); 272 check(SV("%C='-1'\t%y='99'\t%Y='-0099'\t\n"), fmt, std::chrono::year{-99}); 273 check(SV("%C='-1'\t%y='09'\t%Y='-0009'\t\n"), fmt, std::chrono::year{-9}); 274 check(SV("%C='00'\t%y='00'\t%Y='0000'\t\n"), fmt, std::chrono::year{0}); 275 check(SV("%C='00'\t%y='09'\t%Y='0009'\t\n"), fmt, std::chrono::year{9}); 276 check(SV("%C='00'\t%y='99'\t%Y='0099'\t\n"), fmt, std::chrono::year{99}); 277 check(SV("%C='09'\t%y='99'\t%Y='0999'\t\n"), fmt, std::chrono::year{999}); 278 check(SV("%C='99'\t%y='99'\t%Y='9999'\t\n"), fmt, std::chrono::year{9'999}); 279 check(SV("%C='100'\t%y='00'\t%Y='10000'\t\n"), fmt, std::chrono::year{10'000}); 280 } 281 282 template <class CharT> 283 static void test() { 284 test_no_chrono_specs<CharT>(); 285 test_valid_values<CharT>(); 286 test_padding<CharT>(); 287 check_invalid_types<CharT>( 288 {SV("C"), SV("y"), SV("Y"), SV("EC"), SV("Ey"), SV("EY"), SV("Oy")}, std::chrono::year{1970}); 289 290 check_exception("The format specifier expects a '%' or a '}'", SV("{:A"), std::chrono::year{1970}); 291 check_exception("The chrono specifiers contain a '{'", SV("{:%%{"), std::chrono::year{1970}); 292 check_exception("End of input while parsing a conversion specifier", SV("{:%"), std::chrono::year{1970}); 293 check_exception("End of input while parsing the modifier E", SV("{:%E"), std::chrono::year{1970}); 294 check_exception("End of input while parsing the modifier O", SV("{:%O"), std::chrono::year{1970}); 295 296 // Precision not allowed 297 check_exception("The format specifier expects a '%' or a '}'", SV("{:.3}"), std::chrono::year{1970}); 298 } 299 300 int main(int, char**) { 301 test<char>(); 302 303 #ifndef TEST_HAS_NO_WIDE_CHARACTERS 304 test<wchar_t>(); 305 #endif 306 307 return 0; 308 } 309