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
38template <class CharT>
39static 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
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-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(loc: 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 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
281int 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

source code of libcxx/test/std/time/time.syn/formatter.year_month.pass.cpp