1 | //===----------------------------------------------------------------------===// |
2 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
3 | // See https://llvm.org/LICENSE.txt for license information. |
4 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
5 | // |
6 | //===----------------------------------------------------------------------===// |
7 | |
8 | #ifndef TEST_STD_UTILITIES_FORMAT_FORMAT_RANGE_FORMAT_RANGE_FORMATTER_FORMAT_FUNCTIONS_TESTS_H |
9 | #define TEST_STD_UTILITIES_FORMAT_FORMAT_RANGE_FORMAT_RANGE_FORMATTER_FORMAT_FUNCTIONS_TESTS_H |
10 | |
11 | #include <algorithm> |
12 | #include <array> |
13 | #include <charconv> |
14 | #include <concepts> |
15 | #include <deque> |
16 | #include <format> |
17 | #include <list> |
18 | #include <ranges> |
19 | #include <span> |
20 | #include <tuple> |
21 | #include <vector> |
22 | |
23 | #include "format.functions.common.h" |
24 | #include "make_string.h" |
25 | #include "platform_support.h" // locale name macros |
26 | #include "test_iterators.h" |
27 | #include "test_macros.h" |
28 | |
29 | // |
30 | // Char |
31 | // |
32 | |
33 | template <class CharT, class TestFunction, class ExceptionTest> |
34 | void test_char_default(TestFunction check, ExceptionTest check_exception, auto&& input) { |
35 | // Note when no range-underlying-spec is present the char is escaped, |
36 | check(SV("['H', 'e', 'l', 'l', 'o']" ), SV("{}" ), input); |
37 | check(SV("['H', 'e', 'l', 'l', 'o']^42" ), SV("{}^42" ), input); |
38 | check(SV("['H', 'e', 'l', 'l', 'o']^42" ), SV("{:}^42" ), input); |
39 | |
40 | // when one is present there is no escaping, |
41 | check(SV("[H, e, l, l, o]" ), SV("{::}" ), input); |
42 | check(SV("[H, e, l, l, o]" ), SV("{::<}" ), input); |
43 | // unless forced by the type specifier. |
44 | check(SV("['H', 'e', 'l', 'l', 'o']" ), SV("{::?}" ), input); |
45 | check(SV("['H', 'e', 'l', 'l', 'o']" ), SV("{::<?}" ), input); |
46 | |
47 | // ***** underlying has no format-spec |
48 | |
49 | // *** align-fill & width *** |
50 | check(SV("['H', 'e', 'l', 'l', 'o'] " ), SV("{:30}" ), input); |
51 | check(SV("['H', 'e', 'l', 'l', 'o']*****" ), SV("{:*<30}" ), input); |
52 | check(SV("__['H', 'e', 'l', 'l', 'o']___" ), SV("{:_^30}" ), input); |
53 | check(SV("#####['H', 'e', 'l', 'l', 'o']" ), SV("{:#>30}" ), input); |
54 | |
55 | check(SV("['H', 'e', 'l', 'l', 'o'] " ), SV("{:{}}" ), input, 30); |
56 | check(SV("['H', 'e', 'l', 'l', 'o']*****" ), SV("{:*<{}}" ), input, 30); |
57 | check(SV("__['H', 'e', 'l', 'l', 'o']___" ), SV("{:_^{}}" ), input, 30); |
58 | check(SV("#####['H', 'e', 'l', 'l', 'o']" ), SV("{:#>{}}" ), input, 30); |
59 | |
60 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
61 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
62 | |
63 | // *** sign *** |
64 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
65 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
66 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
67 | |
68 | // *** alternate form *** |
69 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
70 | |
71 | // *** zero-padding *** |
72 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
73 | |
74 | // *** precision *** |
75 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
76 | |
77 | // *** locale-specific form *** |
78 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
79 | |
80 | // *** n |
81 | check(SV("__'H', 'e', 'l', 'l', 'o'___" ), SV("{:_^28n}" ), input); |
82 | |
83 | // *** type *** |
84 | check_exception("Type m requires a pair or a tuple with two elements" , SV("{:m}" ), input); |
85 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
86 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
87 | |
88 | // ***** Only underlying has a format-spec |
89 | check(SV("[H , e , l , l , o ]" ), SV("{::4}" ), input); |
90 | check(SV("[H***, e***, l***, l***, o***]" ), SV("{::*<4}" ), input); |
91 | check(SV("[_H__, _e__, _l__, _l__, _o__]" ), SV("{::_^4}" ), input); |
92 | check(SV("[:::H, :::e, :::l, :::l, :::o]" ), SV("{:::>4}" ), input); |
93 | |
94 | check(SV("[H , e , l , l , o ]" ), SV("{::{}}" ), input, 4); |
95 | check(SV("[H***, e***, l***, l***, o***]" ), SV("{::*<{}}" ), input, 4); |
96 | check(SV("[_H__, _e__, _l__, _l__, _o__]" ), SV("{::_^{}}" ), input, 4); |
97 | check(SV("[:::H, :::e, :::l, :::l, :::o]" ), SV("{:::>{}}" ), input, 4); |
98 | |
99 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
100 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
101 | |
102 | // *** sign *** |
103 | check_exception("The format specifier for a character does not allow the sign option" , SV("{::-}" ), input); |
104 | check_exception("The format specifier for a character does not allow the sign option" , SV("{::+}" ), input); |
105 | check_exception("The format specifier for a character does not allow the sign option" , SV("{:: }" ), input); |
106 | |
107 | check(SV("[72, 101, 108, 108, 111]" ), SV("{::-d}" ), input); |
108 | check(SV("[+72, +101, +108, +108, +111]" ), SV("{::+d}" ), input); |
109 | check(SV("[ 72, 101, 108, 108, 111]" ), SV("{:: d}" ), input); |
110 | |
111 | // *** alternate form *** |
112 | check_exception("The format specifier for a character does not allow the alternate form option" , SV("{::#}" ), input); |
113 | |
114 | check(SV("[0x48, 0x65, 0x6c, 0x6c, 0x6f]" ), SV("{::#x}" ), input); |
115 | |
116 | // *** zero-padding *** |
117 | check_exception("The format specifier for a character does not allow the zero-padding option" , SV("{::05}" ), input); |
118 | |
119 | check(SV("[00110, 00145, 00154, 00154, 00157]" ), SV("{::05o}" ), input); |
120 | |
121 | // *** precision *** |
122 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
123 | |
124 | // *** locale-specific form *** |
125 | check(SV("[H, e, l, l, o]" ), SV("{::L}" ), input); |
126 | |
127 | // *** type *** |
128 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("bBcdoxX?" )) |
129 | check_exception("The type option contains an invalid value for a character formatting argument" , fmt, input); |
130 | |
131 | // ***** Both have a format-spec |
132 | check(SV("^^[:H, :e, :l, :l, :o]^^^" ), SV("{:^^25::>2}" ), input); |
133 | check(SV("^^[:H, :e, :l, :l, :o]^^^" ), SV("{:^^{}::>2}" ), input, 25); |
134 | check(SV("^^[:H, :e, :l, :l, :o]^^^" ), SV("{:^^{}::>{}}" ), input, 25, 2); |
135 | |
136 | check_exception( |
137 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}::>2}" ), input); |
138 | check_exception( |
139 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}::>{}}" ), input, 25); |
140 | } |
141 | |
142 | template <class CharT, class TestFunction, class ExceptionTest> |
143 | void test_char_string(TestFunction check, ExceptionTest check_exception, auto&& input) { |
144 | check(SV("Hello" ), SV("{:s}" ), input); |
145 | |
146 | // ***** underlying has no format-spec |
147 | |
148 | // *** align-fill & width *** |
149 | check(SV("Hello " ), SV("{:8s}" ), input); |
150 | check(SV("Hello***" ), SV("{:*<8s}" ), input); |
151 | check(SV("_Hello__" ), SV("{:_^8s}" ), input); |
152 | check(SV("###Hello" ), SV("{:#>8s}" ), input); |
153 | |
154 | check(SV("Hello " ), SV("{:{}s}" ), input, 8); |
155 | check(SV("Hello***" ), SV("{:*<{}s}" ), input, 8); |
156 | check(SV("_Hello__" ), SV("{:_^{}s}" ), input, 8); |
157 | check(SV("###Hello" ), SV("{:#>{}s}" ), input, 8); |
158 | |
159 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<s}" ), input); |
160 | check_exception("The fill option contains an invalid value" , SV("{:{<s}" ), input); |
161 | |
162 | // *** sign *** |
163 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-s}" ), input); |
164 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+s}" ), input); |
165 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: s}" ), input); |
166 | |
167 | // *** alternate form *** |
168 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#s}" ), input); |
169 | |
170 | // *** zero-padding *** |
171 | check_exception("The width option should not have a leading zero" , SV("{:0s}" ), input); |
172 | |
173 | // *** precision *** |
174 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.s}" ), input); |
175 | |
176 | // *** locale-specific form *** |
177 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:Ls}" ), input); |
178 | |
179 | // *** n |
180 | check_exception("The n option and type s can't be used together" , SV("{:ns}" ), input); |
181 | |
182 | // *** type *** |
183 | check_exception("Type m requires a pair or a tuple with two elements" , SV("{:m}" ), input); |
184 | check_exception("The type option contains an invalid value for a character formatting argument" , SV("{::<s}" ), input); |
185 | |
186 | // ***** Only underlying has a format-spec |
187 | check_exception("Type s and an underlying format specification can't be used together" , SV("{:s:}" ), input); |
188 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("bBcdoxX?" )) |
189 | check_exception("The type option contains an invalid value for a character formatting argument" , fmt, input); |
190 | |
191 | // ***** Both have a format-spec |
192 | check_exception("Type s and an underlying format specification can't be used together" , SV("{:5s:5}" ), input); |
193 | } |
194 | |
195 | template <class CharT, class TestFunction, class ExceptionTest> |
196 | void test_char_escaped_string(TestFunction check, ExceptionTest check_exception, auto&& input) { |
197 | check(SV(R"("\"Hello'")" ), SV("{:?s}" ), input); |
198 | |
199 | // ***** underlying has no format-spec |
200 | |
201 | // *** align-fill & width *** |
202 | check(SV(R"("\"Hello'" )" ), SV("{:13?s}" ), input); |
203 | check(SV(R"("\"Hello'"***)" ), SV("{:*<13?s}" ), input); |
204 | check(SV(R"(_"\"Hello'"__)" ), SV("{:_^13?s}" ), input); |
205 | check(SV(R"(###"\"Hello'")" ), SV("{:#>13?s}" ), input); |
206 | |
207 | check(SV(R"("\"Hello'" )" ), SV("{:{}?s}" ), input, 13); |
208 | check(SV(R"("\"Hello'"***)" ), SV("{:*<{}?s}" ), input, 13); |
209 | check(SV(R"(_"\"Hello'"__)" ), SV("{:_^{}?s}" ), input, 13); |
210 | check(SV(R"(###"\"Hello'")" ), SV("{:#>{}?s}" ), input, 13); |
211 | |
212 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<?s}" ), input); |
213 | check_exception("The fill option contains an invalid value" , SV("{:{<?s}" ), input); |
214 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::<?s}" ), input); |
215 | |
216 | // *** sign *** |
217 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-?s}" ), input); |
218 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+?s}" ), input); |
219 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: ?s}" ), input); |
220 | |
221 | // *** alternate form *** |
222 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#?s}" ), input); |
223 | |
224 | // *** zero-padding *** |
225 | check_exception("The width option should not have a leading zero" , SV("{:0?s}" ), input); |
226 | |
227 | // *** precision *** |
228 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.?s}" ), input); |
229 | |
230 | // *** locale-specific form *** |
231 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L?s}" ), input); |
232 | |
233 | // *** n |
234 | check_exception("The n option and type ?s can't be used together" , SV("{:n?s}" ), input); |
235 | |
236 | // *** type *** |
237 | check_exception("Type m requires a pair or a tuple with two elements" , SV("{:m}" ), input); |
238 | |
239 | // ***** Only underlying has a format-spec |
240 | check_exception("Type ?s and an underlying format specification can't be used together" , SV("{:?s:}" ), input); |
241 | |
242 | // ***** Both have a format-spec |
243 | check_exception("Type ?s and an underlying format specification can't be used together" , SV("{:5?s:5}" ), input); |
244 | } |
245 | |
246 | template <class CharT, class TestFunction, class ExceptionTest> |
247 | void test_char(TestFunction check, ExceptionTest check_exception) { |
248 | test_char_default<CharT>( |
249 | check, check_exception, std::array{CharT('H'), CharT('e'), CharT('l'), CharT('l'), CharT('o')}); |
250 | |
251 | // This tests two different implementations in libc++. A basic_string_view |
252 | // formatter if the range is contiguous, a basic_string otherwise. |
253 | test_char_escaped_string<CharT>( |
254 | check, |
255 | check_exception, |
256 | std::array{CharT('"'), CharT('H'), CharT('e'), CharT('l'), CharT('l'), CharT('o'), CharT('\'')}); |
257 | test_char_escaped_string<CharT>( |
258 | check, |
259 | check_exception, |
260 | std::list{CharT('"'), CharT('H'), CharT('e'), CharT('l'), CharT('l'), CharT('o'), CharT('\'')}); |
261 | |
262 | // This tests two different implementations in libc++. A basic_string_view |
263 | // formatter if the range is contiguous, a basic_string otherwise. |
264 | test_char_string<CharT>( |
265 | check, check_exception, std::array{CharT('H'), CharT('e'), CharT('l'), CharT('l'), CharT('o')}); |
266 | test_char_string<CharT>( |
267 | check, check_exception, std::list{CharT('H'), CharT('e'), CharT('l'), CharT('l'), CharT('o')}); |
268 | } |
269 | |
270 | // |
271 | // char -> wchar_t |
272 | // |
273 | |
274 | #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
275 | template <class TestFunction, class ExceptionTest> |
276 | void test_char_to_wchar(TestFunction check, ExceptionTest check_exception) { |
277 | test_char_default<wchar_t>(check, check_exception, std::array{'H', 'e', 'l', 'l', 'o'}); |
278 | |
279 | // The types s and ?s may only be used when using range_formatter<T, charT> |
280 | // where the types T and charT are the same. This means this can't be used for |
281 | // range_formatter<wchar_t, char> even when formatter<wchar_t, char> has a |
282 | // debug-enabled specialization. |
283 | |
284 | using CharT = wchar_t; |
285 | check_exception( |
286 | "Type s requires character type as formatting argument" , SV("{:s}" ), std::array{'H', 'e', 'l', 'l', 'o'}); |
287 | check_exception( |
288 | "Type ?s requires character type as formatting argument" , SV("{:?s}" ), std::array{'H', 'e', 'l', 'l', 'o'}); |
289 | } |
290 | #endif |
291 | |
292 | // |
293 | // Bool |
294 | // |
295 | |
296 | template <class CharT, class TestFunction, class ExceptionTest> |
297 | void test_bool(TestFunction check, ExceptionTest check_exception) { |
298 | std::array input{true, true, false}; |
299 | |
300 | check(SV("[true, true, false]" ), SV("{}" ), input); |
301 | check(SV("[true, true, false]^42" ), SV("{}^42" ), input); |
302 | check(SV("[true, true, false]^42" ), SV("{:}^42" ), input); |
303 | |
304 | // ***** underlying has no format-spec |
305 | |
306 | // *** align-fill & width *** |
307 | check(SV("[true, true, false] " ), SV("{:24}" ), input); |
308 | check(SV("[true, true, false]*****" ), SV("{:*<24}" ), input); |
309 | check(SV("__[true, true, false]___" ), SV("{:_^24}" ), input); |
310 | check(SV("#####[true, true, false]" ), SV("{:#>24}" ), input); |
311 | |
312 | check(SV("[true, true, false] " ), SV("{:{}}" ), input, 24); |
313 | check(SV("[true, true, false]*****" ), SV("{:*<{}}" ), input, 24); |
314 | check(SV("__[true, true, false]___" ), SV("{:_^{}}" ), input, 24); |
315 | check(SV("#####[true, true, false]" ), SV("{:#>{}}" ), input, 24); |
316 | |
317 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
318 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
319 | |
320 | // *** sign *** |
321 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
322 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
323 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
324 | |
325 | // *** alternate form *** |
326 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
327 | |
328 | // *** zero-padding *** |
329 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
330 | |
331 | // *** precision *** |
332 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
333 | |
334 | // *** locale-specific form *** |
335 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
336 | |
337 | // *** n |
338 | check(SV("__true, true, false___" ), SV("{:_^22n}" ), input); |
339 | |
340 | // *** type *** |
341 | check_exception("Type m requires a pair or a tuple with two elements" , SV("{:m}" ), input); |
342 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
343 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
344 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
345 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
346 | |
347 | // ***** Only underlying has a format-spec |
348 | check(SV("[true , true , false ]" ), SV("{::7}" ), input); |
349 | check(SV("[true***, true***, false**]" ), SV("{::*<7}" ), input); |
350 | check(SV("[_true__, _true__, _false_]" ), SV("{::_^7}" ), input); |
351 | check(SV("[:::true, :::true, ::false]" ), SV("{:::>7}" ), input); |
352 | |
353 | check(SV("[true , true , false ]" ), SV("{::{}}" ), input, 7); |
354 | check(SV("[true***, true***, false**]" ), SV("{::*<{}}" ), input, 7); |
355 | check(SV("[_true__, _true__, _false_]" ), SV("{::_^{}}" ), input, 7); |
356 | check(SV("[:::true, :::true, ::false]" ), SV("{:::>{}}" ), input, 7); |
357 | |
358 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
359 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
360 | |
361 | // *** sign *** |
362 | check_exception("The format specifier for a bool does not allow the sign option" , SV("{::-}" ), input); |
363 | check_exception("The format specifier for a bool does not allow the sign option" , SV("{::+}" ), input); |
364 | check_exception("The format specifier for a bool does not allow the sign option" , SV("{:: }" ), input); |
365 | |
366 | check(SV("[1, 1, 0]" ), SV("{::-d}" ), input); |
367 | check(SV("[+1, +1, +0]" ), SV("{::+d}" ), input); |
368 | check(SV("[ 1, 1, 0]" ), SV("{:: d}" ), input); |
369 | |
370 | // *** alternate form *** |
371 | check_exception("The format specifier for a bool does not allow the alternate form option" , SV("{::#}" ), input); |
372 | |
373 | check(SV("[0x1, 0x1, 0x0]" ), SV("{::#x}" ), input); |
374 | |
375 | // *** zero-padding *** |
376 | check_exception("The format specifier for a bool does not allow the zero-padding option" , SV("{::05}" ), input); |
377 | |
378 | check(SV("[00001, 00001, 00000]" ), SV("{::05o}" ), input); |
379 | |
380 | // *** precision *** |
381 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
382 | |
383 | // *** locale-specific form *** |
384 | check(SV("[true, true, false]" ), SV("{::L}" ), input); |
385 | |
386 | // *** type *** |
387 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("bBdosxX" )) |
388 | check_exception("The type option contains an invalid value for a bool formatting argument" , fmt, input); |
389 | |
390 | // ***** Both have a format-spec |
391 | check(SV("^^[:::true, :::true, ::false]^^^" ), SV("{:^^32::>7}" ), input); |
392 | check(SV("^^[:::true, :::true, ::false]^^^" ), SV("{:^^{}::>7}" ), input, 32); |
393 | check(SV("^^[:::true, :::true, ::false]^^^" ), SV("{:^^{}::>{}}" ), input, 32, 7); |
394 | |
395 | check_exception( |
396 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}::>5}" ), input); |
397 | check_exception( |
398 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}::>{}}" ), input, 32); |
399 | } |
400 | |
401 | // |
402 | // Integral |
403 | // |
404 | |
405 | template <class CharT, class TestFunction, class ExceptionTest> |
406 | void test_int(TestFunction check, ExceptionTest check_exception, auto&& input) { |
407 | check(SV("[1, 2, 42, -42]" ), SV("{}" ), input); |
408 | check(SV("[1, 2, 42, -42]^42" ), SV("{}^42" ), input); |
409 | check(SV("[1, 2, 42, -42]^42" ), SV("{:}^42" ), input); |
410 | |
411 | // ***** underlying has no format-spec |
412 | |
413 | // *** align-fill & width *** |
414 | check(SV("[1, 2, 42, -42] " ), SV("{:20}" ), input); |
415 | check(SV("[1, 2, 42, -42]*****" ), SV("{:*<20}" ), input); |
416 | check(SV("__[1, 2, 42, -42]___" ), SV("{:_^20}" ), input); |
417 | check(SV("#####[1, 2, 42, -42]" ), SV("{:#>20}" ), input); |
418 | |
419 | check(SV("[1, 2, 42, -42] " ), SV("{:{}}" ), input, 20); |
420 | check(SV("[1, 2, 42, -42]*****" ), SV("{:*<{}}" ), input, 20); |
421 | check(SV("__[1, 2, 42, -42]___" ), SV("{:_^{}}" ), input, 20); |
422 | check(SV("#####[1, 2, 42, -42]" ), SV("{:#>{}}" ), input, 20); |
423 | |
424 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
425 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
426 | |
427 | // *** sign *** |
428 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
429 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
430 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
431 | |
432 | // *** alternate form *** |
433 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
434 | |
435 | // *** zero-padding *** |
436 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
437 | |
438 | // *** precision *** |
439 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
440 | |
441 | // *** locale-specific form *** |
442 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
443 | |
444 | // *** n |
445 | check(SV("__1, 2, 42, -42___" ), SV("{:_^18n}" ), input); |
446 | |
447 | // *** type *** |
448 | check_exception("Type m requires a pair or a tuple with two elements" , SV("{:m}" ), input); |
449 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
450 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
451 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
452 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
453 | |
454 | // ***** Only underlying has a format-spec |
455 | check(SV("[ 1, 2, 42, -42]" ), SV("{::5}" ), input); |
456 | check(SV("[1****, 2****, 42***, -42**]" ), SV("{::*<5}" ), input); |
457 | check(SV("[__1__, __2__, _42__, _-42_]" ), SV("{::_^5}" ), input); |
458 | check(SV("[::::1, ::::2, :::42, ::-42]" ), SV("{:::>5}" ), input); |
459 | |
460 | check(SV("[ 1, 2, 42, -42]" ), SV("{::{}}" ), input, 5); |
461 | check(SV("[1****, 2****, 42***, -42**]" ), SV("{::*<{}}" ), input, 5); |
462 | check(SV("[__1__, __2__, _42__, _-42_]" ), SV("{::_^{}}" ), input, 5); |
463 | check(SV("[::::1, ::::2, :::42, ::-42]" ), SV("{:::>{}}" ), input, 5); |
464 | |
465 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
466 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
467 | |
468 | // *** sign *** |
469 | check(SV("[1, 2, 42, -42]" ), SV("{::-}" ), input); |
470 | check(SV("[+1, +2, +42, -42]" ), SV("{::+}" ), input); |
471 | check(SV("[ 1, 2, 42, -42]" ), SV("{:: }" ), input); |
472 | |
473 | // *** alternate form *** |
474 | check(SV("[0x1, 0x2, 0x2a, -0x2a]" ), SV("{::#x}" ), input); |
475 | |
476 | // *** zero-padding *** |
477 | check(SV("[00001, 00002, 00042, -0042]" ), SV("{::05}" ), input); |
478 | check(SV("[00001, 00002, 0002a, -002a]" ), SV("{::05x}" ), input); |
479 | check(SV("[0x001, 0x002, 0x02a, -0x2a]" ), SV("{::#05x}" ), input); |
480 | |
481 | // *** precision *** |
482 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
483 | |
484 | // *** locale-specific form *** |
485 | check(SV("[1, 2, 42, -42]" ), SV("{::L}" ), input); // does nothing in this test, but is accepted. |
486 | |
487 | // *** type *** |
488 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("bBcdoxX" )) |
489 | check_exception("The type option contains an invalid value for an integer formatting argument" , fmt, input); |
490 | |
491 | // ***** Both have a format-spec |
492 | check(SV("^^[::::1, ::::2, :::42, ::-42]^^^" ), SV("{:^^33::>5}" ), input); |
493 | check(SV("^^[::::1, ::::2, :::42, ::-42]^^^" ), SV("{:^^{}::>5}" ), input, 33); |
494 | check(SV("^^[::::1, ::::2, :::42, ::-42]^^^" ), SV("{:^^{}::>{}}" ), input, 33, 5); |
495 | |
496 | check_exception( |
497 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}::>5}" ), input); |
498 | check_exception( |
499 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}::>{}}" ), input, 33); |
500 | } |
501 | |
502 | template <class CharT, class TestFunction, class ExceptionTest> |
503 | void test_int(TestFunction check, ExceptionTest check_exception) { |
504 | test_int<CharT>(check, check_exception, std::array{1, 2, 42, -42}); |
505 | test_int<CharT>(check, check_exception, std::list{1, 2, 42, -42}); |
506 | test_int<CharT>(check, check_exception, std::vector{1, 2, 42, -42}); |
507 | std::array input{1, 2, 42, -42}; |
508 | test_int<CharT>(check, check_exception, std::span{input}); |
509 | } |
510 | |
511 | // |
512 | // Floating point |
513 | // |
514 | |
515 | template <class CharT, class TestFunction, class ExceptionTest> |
516 | void test_floating_point(TestFunction check, ExceptionTest check_exception, auto&& input) { |
517 | check(SV("[-42.5, 0, 1.25, 42.5]" ), SV("{}" ), input); |
518 | check(SV("[-42.5, 0, 1.25, 42.5]^42" ), SV("{}^42" ), input); |
519 | check(SV("[-42.5, 0, 1.25, 42.5]^42" ), SV("{:}^42" ), input); |
520 | |
521 | // ***** underlying has no format-spec |
522 | |
523 | // *** align-fill & width *** |
524 | check(SV("[-42.5, 0, 1.25, 42.5] " ), SV("{:27}" ), input); |
525 | check(SV("[-42.5, 0, 1.25, 42.5]*****" ), SV("{:*<27}" ), input); |
526 | check(SV("__[-42.5, 0, 1.25, 42.5]___" ), SV("{:_^27}" ), input); |
527 | check(SV("#####[-42.5, 0, 1.25, 42.5]" ), SV("{:#>27}" ), input); |
528 | |
529 | check(SV("[-42.5, 0, 1.25, 42.5] " ), SV("{:{}}" ), input, 27); |
530 | check(SV("[-42.5, 0, 1.25, 42.5]*****" ), SV("{:*<{}}" ), input, 27); |
531 | check(SV("__[-42.5, 0, 1.25, 42.5]___" ), SV("{:_^{}}" ), input, 27); |
532 | check(SV("#####[-42.5, 0, 1.25, 42.5]" ), SV("{:#>{}}" ), input, 27); |
533 | |
534 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
535 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
536 | |
537 | // *** sign *** |
538 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
539 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
540 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
541 | |
542 | // *** alternate form *** |
543 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
544 | |
545 | // *** zero-padding *** |
546 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
547 | |
548 | // *** precision *** |
549 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
550 | |
551 | // *** locale-specific form *** |
552 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
553 | |
554 | // *** n |
555 | check(SV("__-42.5, 0, 1.25, 42.5___" ), SV("{:_^25n}" ), input); |
556 | |
557 | // *** type *** |
558 | check_exception("Type m requires a pair or a tuple with two elements" , SV("{:m}" ), input); |
559 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
560 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
561 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
562 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
563 | |
564 | // ***** Only underlying has a format-spec |
565 | check(SV("[-42.5, 0, 1.25, 42.5]" ), SV("{::5}" ), input); |
566 | check(SV("[-42.5, 0****, 1.25*, 42.5*]" ), SV("{::*<5}" ), input); |
567 | check(SV("[-42.5, __0__, 1.25_, 42.5_]" ), SV("{::_^5}" ), input); |
568 | check(SV("[-42.5, ::::0, :1.25, :42.5]" ), SV("{:::>5}" ), input); |
569 | |
570 | check(SV("[-42.5, 0, 1.25, 42.5]" ), SV("{::{}}" ), input, 5); |
571 | check(SV("[-42.5, 0****, 1.25*, 42.5*]" ), SV("{::*<{}}" ), input, 5); |
572 | check(SV("[-42.5, __0__, 1.25_, 42.5_]" ), SV("{::_^{}}" ), input, 5); |
573 | check(SV("[-42.5, ::::0, :1.25, :42.5]" ), SV("{:::>{}}" ), input, 5); |
574 | |
575 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
576 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
577 | |
578 | // *** sign *** |
579 | check(SV("[-42.5, 0, 1.25, 42.5]" ), SV("{::-}" ), input); |
580 | check(SV("[-42.5, +0, +1.25, +42.5]" ), SV("{::+}" ), input); |
581 | check(SV("[-42.5, 0, 1.25, 42.5]" ), SV("{:: }" ), input); |
582 | |
583 | // *** alternate form *** |
584 | check(SV("[-42.5, 0., 1.25, 42.5]" ), SV("{::#}" ), input); |
585 | |
586 | // *** zero-padding *** |
587 | check(SV("[-42.5, 00000, 01.25, 042.5]" ), SV("{::05}" ), input); |
588 | check(SV("[-42.5, 0000., 01.25, 042.5]" ), SV("{::#05}" ), input); |
589 | |
590 | // *** precision *** |
591 | check(SV("[-42, 0, 1.2, 42]" ), SV("{::.2}" ), input); |
592 | check(SV("[-42.500, 0.000, 1.250, 42.500]" ), SV("{::.3f}" ), input); |
593 | |
594 | check(SV("[-42, 0, 1.2, 42]" ), SV("{::.{}}" ), input, 2); |
595 | check(SV("[-42.500, 0.000, 1.250, 42.500]" ), SV("{::.{}f}" ), input, 3); |
596 | |
597 | check_exception("The precision option does not contain a value or an argument index" , SV("{::.}" ), input); |
598 | |
599 | // *** locale-specific form *** |
600 | check(SV("[-42.5, 0, 1.25, 42.5]" ), SV("{::L}" ), input); // does not require locales present |
601 | #ifndef TEST_HAS_NO_LOCALIZATION |
602 | // TODO FMT Enable with locale testing active |
603 | # if 0 |
604 | std::locale::global(std::locale(LOCALE_fr_FR_UTF_8)); |
605 | check(SV("[-42,5, 0, 1,25, 42,5]" ), SV("{::L}" ), input); |
606 | |
607 | std::locale::global(std::locale(LOCALE_en_US_UTF_8)); |
608 | check(SV("[-42.5, 0, 1.25, 42.5]" ), SV("{::L}" ), input); |
609 | |
610 | std::locale::global(std::locale::classic()); |
611 | # endif |
612 | #endif // TEST_HAS_NO_LOCALIZATION |
613 | |
614 | // *** type *** |
615 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("aAeEfFgG" )) |
616 | check_exception("The type option contains an invalid value for a floating-point formatting argument" , fmt, input); |
617 | |
618 | // ***** Both have a format-spec |
619 | check(SV("^^[-42.5, ::::0, :1.25, :42.5]^^^" ), SV("{:^^33::>5}" ), input); |
620 | check(SV("^^[-42.5, ::::0, :1.25, :42.5]^^^" ), SV("{:^^{}::>5}" ), input, 33); |
621 | check(SV("^^[-42.5, ::::0, :1.25, :42.5]^^^" ), SV("{:^^{}::>{}}" ), input, 33, 5); |
622 | |
623 | check(SV("^^[::-42, ::::0, ::1.2, :::42]^^^" ), SV("{:^^33::>5.2}" ), input); |
624 | check(SV("^^[::-42, ::::0, ::1.2, :::42]^^^" ), SV("{:^^{}::>5.2}" ), input, 33); |
625 | check(SV("^^[::-42, ::::0, ::1.2, :::42]^^^" ), SV("{:^^{}::>{}.2}" ), input, 33, 5); |
626 | check(SV("^^[::-42, ::::0, ::1.2, :::42]^^^" ), SV("{:^^{}::>{}.{}}" ), input, 33, 5, 2); |
627 | |
628 | check_exception( |
629 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}::>5.2}" ), input); |
630 | check_exception( |
631 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}::>{}.2}" ), input, 33); |
632 | check_exception( |
633 | "The argument index value is too large for the number of arguments supplied" , |
634 | SV("{:^^{}::>{}.{}}" ), |
635 | input, |
636 | 33, |
637 | 5); |
638 | } |
639 | |
640 | template <class CharT, class TestFunction, class ExceptionTest> |
641 | void test_floating_point(TestFunction check, ExceptionTest check_exception) { |
642 | test_floating_point<CharT>(check, check_exception, std::array{-42.5f, 0.0f, 1.25f, 42.5f}); |
643 | test_floating_point<CharT>(check, check_exception, std::vector{-42.5, 0.0, 1.25, 42.5}); |
644 | |
645 | std::array input{-42.5l, 0.0l, 1.25l, 42.5l}; |
646 | test_floating_point<CharT>(check, check_exception, std::span{input}); |
647 | } |
648 | |
649 | // |
650 | // Pointer |
651 | // |
652 | |
653 | template <class CharT, class TestFunction, class ExceptionTest> |
654 | void test_pointer(TestFunction check, ExceptionTest check_exception, auto&& input) { |
655 | check(SV("[0x0]" ), SV("{}" ), input); |
656 | check(SV("[0x0]^42" ), SV("{}^42" ), input); |
657 | check(SV("[0x0]^42" ), SV("{:}^42" ), input); |
658 | |
659 | // ***** underlying has no format-spec |
660 | |
661 | // *** align-fill & width *** |
662 | check(SV("[0x0] " ), SV("{:10}" ), input); |
663 | check(SV("[0x0]*****" ), SV("{:*<10}" ), input); |
664 | check(SV("__[0x0]___" ), SV("{:_^10}" ), input); |
665 | check(SV("#####[0x0]" ), SV("{:#>10}" ), input); |
666 | |
667 | check(SV("[0x0] " ), SV("{:{}}" ), input, 10); |
668 | check(SV("[0x0]*****" ), SV("{:*<{}}" ), input, 10); |
669 | check(SV("__[0x0]___" ), SV("{:_^{}}" ), input, 10); |
670 | check(SV("#####[0x0]" ), SV("{:#>{}}" ), input, 10); |
671 | |
672 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
673 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
674 | |
675 | // *** sign *** |
676 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
677 | |
678 | // *** alternate form *** |
679 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
680 | |
681 | // *** zero-padding *** |
682 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
683 | |
684 | // *** precision *** |
685 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
686 | |
687 | // *** locale-specific form *** |
688 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
689 | |
690 | // *** n |
691 | check(SV("_0x0_" ), SV("{:_^5n}" ), input); |
692 | |
693 | // *** type *** |
694 | check_exception("Type m requires a pair or a tuple with two elements" , SV("{:m}" ), input); |
695 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
696 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
697 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
698 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
699 | |
700 | // ***** Only underlying has a format-spec |
701 | check(SV("[ 0x0]" ), SV("{::5}" ), input); |
702 | check(SV("[0x0**]" ), SV("{::*<5}" ), input); |
703 | check(SV("[_0x0_]" ), SV("{::_^5}" ), input); |
704 | check(SV("[::0x0]" ), SV("{:::>5}" ), input); |
705 | |
706 | check(SV("[ 0x0]" ), SV("{::{}}" ), input, 5); |
707 | check(SV("[0x0**]" ), SV("{::*<{}}" ), input, 5); |
708 | check(SV("[_0x0_]" ), SV("{::_^{}}" ), input, 5); |
709 | check(SV("[::0x0]" ), SV("{:::>{}}" ), input, 5); |
710 | |
711 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
712 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
713 | |
714 | // *** sign *** |
715 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::-}" ), input); |
716 | |
717 | // *** alternate form *** |
718 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::#}" ), input); |
719 | |
720 | // *** zero-padding *** |
721 | check(SV("[0x0000]" ), SV("{::06}" ), input); |
722 | check(SV("[0x0000]" ), SV("{::06p}" ), input); |
723 | check(SV("[0X0000]" ), SV("{::06P}" ), input); |
724 | |
725 | // *** precision *** |
726 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
727 | |
728 | // *** locale-specific form *** |
729 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::L}" ), input); |
730 | |
731 | // *** type *** |
732 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("pP" )) |
733 | check_exception("The type option contains an invalid value for a pointer formatting argument" , fmt, input); |
734 | |
735 | // ***** Both have a format-spec |
736 | check(SV("^^[::0x0]^^^" ), SV("{:^^12::>5}" ), input); |
737 | check(SV("^^[::0x0]^^^" ), SV("{:^^{}::>5}" ), input, 12); |
738 | check(SV("^^[::0x0]^^^" ), SV("{:^^{}::>{}}" ), input, 12, 5); |
739 | |
740 | check(SV("^^[::0x0]^^^" ), SV("{:^^12::>5}" ), input); |
741 | check(SV("^^[::0x0]^^^" ), SV("{:^^{}::>5}" ), input, 12); |
742 | check(SV("^^[::0x0]^^^" ), SV("{:^^{}::>{}}" ), input, 12, 5); |
743 | |
744 | check_exception( |
745 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}::>5}" ), input); |
746 | check_exception( |
747 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}::>{}}" ), input, 12); |
748 | } |
749 | |
750 | template <class CharT, class TestFunction, class ExceptionTest> |
751 | void test_pointer(TestFunction check, ExceptionTest check_exception) { |
752 | test_pointer<CharT>(check, check_exception, std::array{nullptr}); |
753 | test_pointer<CharT>(check, check_exception, std::array{static_cast<const void*>(0)}); |
754 | test_pointer<CharT>(check, check_exception, std::array{static_cast<void*>(0)}); |
755 | } |
756 | |
757 | // |
758 | // String |
759 | // |
760 | |
761 | template <class CharT, class TestFunction, class ExceptionTest> |
762 | void test_string(TestFunction check, ExceptionTest check_exception, auto&& input) { |
763 | check(SV(R"(["Hello", "world"])" ), SV("{}" ), input); |
764 | check(SV(R"(["Hello", "world"]^42)" ), SV("{}^42" ), input); |
765 | check(SV(R"(["Hello", "world"]^42)" ), SV("{:}^42" ), input); |
766 | |
767 | // ***** underlying has no format-spec |
768 | |
769 | // *** align-fill & width *** |
770 | check(SV(R"(["Hello", "world"] )" ), SV("{:23}" ), input); |
771 | check(SV(R"(["Hello", "world"]*****)" ), SV("{:*<23}" ), input); |
772 | check(SV(R"(__["Hello", "world"]___)" ), SV("{:_^23}" ), input); |
773 | check(SV(R"(#####["Hello", "world"])" ), SV("{:#>23}" ), input); |
774 | |
775 | check(SV(R"(["Hello", "world"] )" ), SV("{:{}}" ), input, 23); |
776 | check(SV(R"(["Hello", "world"]*****)" ), SV("{:*<{}}" ), input, 23); |
777 | check(SV(R"(__["Hello", "world"]___)" ), SV("{:_^{}}" ), input, 23); |
778 | check(SV(R"(#####["Hello", "world"])" ), SV("{:#>{}}" ), input, 23); |
779 | |
780 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
781 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
782 | |
783 | // *** sign *** |
784 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
785 | |
786 | // *** alternate form *** |
787 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
788 | |
789 | // *** zero-padding *** |
790 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
791 | |
792 | // *** precision *** |
793 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
794 | |
795 | // *** locale-specific form *** |
796 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
797 | |
798 | // *** n |
799 | check(SV(R"(_"Hello", "world"_)" ), SV("{:_^18n}" ), input); |
800 | |
801 | // *** type *** |
802 | check_exception("Type m requires a pair or a tuple with two elements" , SV("{:m}" ), input); |
803 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
804 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
805 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
806 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
807 | |
808 | // ***** Only underlying has a format-spec |
809 | check(SV(R"([Hello , world ])" ), SV("{::8}" ), input); |
810 | check(SV(R"([Hello***, world***])" ), SV("{::*<8}" ), input); |
811 | check(SV(R"([_Hello__, _world__])" ), SV("{::_^8}" ), input); |
812 | check(SV(R"([:::Hello, :::world])" ), SV("{:::>8}" ), input); |
813 | |
814 | check(SV(R"([Hello , world ])" ), SV("{::{}}" ), input, 8); |
815 | check(SV(R"([Hello***, world***])" ), SV("{::*<{}}" ), input, 8); |
816 | check(SV(R"([_Hello__, _world__])" ), SV("{::_^{}}" ), input, 8); |
817 | check(SV(R"([:::Hello, :::world])" ), SV("{:::>{}}" ), input, 8); |
818 | |
819 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
820 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
821 | |
822 | // *** sign *** |
823 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::-}" ), input); |
824 | |
825 | // *** alternate form *** |
826 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::#}" ), input); |
827 | |
828 | // *** zero-padding *** |
829 | check_exception("The width option should not have a leading zero" , SV("{::05}" ), input); |
830 | |
831 | // *** precision *** |
832 | check(SV(R"([Hel, wor])" ), SV("{::.3}" ), input); |
833 | |
834 | check(SV(R"([Hel, wor])" ), SV("{::.{}}" ), input, 3); |
835 | |
836 | check_exception("The precision option does not contain a value or an argument index" , SV("{::.}" ), input); |
837 | |
838 | // *** locale-specific form *** |
839 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::L}" ), input); |
840 | |
841 | // *** type *** |
842 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("s?" )) |
843 | check_exception("The type option contains an invalid value for a string formatting argument" , fmt, input); |
844 | |
845 | // ***** Both have a format-spec |
846 | check(SV(R"(^^[:::Hello, :::world]^^^)" ), SV("{:^^25::>8}" ), input); |
847 | check(SV(R"(^^[:::Hello, :::world]^^^)" ), SV("{:^^{}::>8}" ), input, 25); |
848 | check(SV(R"(^^[:::Hello, :::world]^^^)" ), SV("{:^^{}::>{}}" ), input, 25, 8); |
849 | |
850 | check(SV(R"(^^[:::Hello, :::world]^^^)" ), SV("{:^^25::>8}" ), input); |
851 | check(SV(R"(^^[:::Hello, :::world]^^^)" ), SV("{:^^{}::>8}" ), input, 25); |
852 | check(SV(R"(^^[:::Hello, :::world]^^^)" ), SV("{:^^{}::>{}}" ), input, 25, 8); |
853 | |
854 | check_exception( |
855 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}::>8}" ), input); |
856 | check_exception( |
857 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}::>{}}" ), input, 25); |
858 | } |
859 | |
860 | template <class CharT, class TestFunction, class ExceptionTest> |
861 | void test_string(TestFunction check, ExceptionTest check_exception) { |
862 | test_string<CharT>(check, check_exception, std::array{CSTR("Hello" ), CSTR("world" )}); |
863 | test_string<CharT>(check, check_exception, std::array{STR("Hello" ), STR("world" )}); |
864 | test_string<CharT>(check, check_exception, std::array{SV("Hello" ), SV("world" )}); |
865 | } |
866 | |
867 | // |
868 | // Handle |
869 | // |
870 | |
871 | template <class CharT, class TestFunction, class ExceptionTest> |
872 | void test_status(TestFunction check, ExceptionTest check_exception) { |
873 | std::array input{status::foo, status::bar, status::foobar}; |
874 | |
875 | check(SV("[0xaaaa, 0x5555, 0xaa55]" ), SV("{}" ), input); |
876 | check(SV("[0xaaaa, 0x5555, 0xaa55]^42" ), SV("{}^42" ), input); |
877 | check(SV("[0xaaaa, 0x5555, 0xaa55]^42" ), SV("{:}^42" ), input); |
878 | |
879 | // ***** underlying has no format-spec |
880 | |
881 | // *** align-fill & width *** |
882 | check(SV("[0xaaaa, 0x5555, 0xaa55] " ), SV("{:29}" ), input); |
883 | check(SV("[0xaaaa, 0x5555, 0xaa55]*****" ), SV("{:*<29}" ), input); |
884 | check(SV("__[0xaaaa, 0x5555, 0xaa55]___" ), SV("{:_^29}" ), input); |
885 | check(SV("#####[0xaaaa, 0x5555, 0xaa55]" ), SV("{:#>29}" ), input); |
886 | |
887 | check(SV("[0xaaaa, 0x5555, 0xaa55] " ), SV("{:{}}" ), input, 29); |
888 | check(SV("[0xaaaa, 0x5555, 0xaa55]*****" ), SV("{:*<{}}" ), input, 29); |
889 | check(SV("__[0xaaaa, 0x5555, 0xaa55]___" ), SV("{:_^{}}" ), input, 29); |
890 | check(SV("#####[0xaaaa, 0x5555, 0xaa55]" ), SV("{:#>{}}" ), input, 29); |
891 | |
892 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
893 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
894 | |
895 | // *** sign *** |
896 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
897 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
898 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
899 | |
900 | // *** alternate form *** |
901 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
902 | |
903 | // *** zero-padding *** |
904 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
905 | |
906 | // *** precision *** |
907 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
908 | |
909 | // *** locale-specific form *** |
910 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
911 | |
912 | // *** n |
913 | check(SV("__0xaaaa, 0x5555, 0xaa55___" ), SV("{:_^27n}" ), input); |
914 | |
915 | // *** type *** |
916 | check_exception("Type m requires a pair or a tuple with two elements" , SV("{:m}" ), input); |
917 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
918 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
919 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
920 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
921 | |
922 | // ***** Only underlying has a format-spec |
923 | check_exception("The type option contains an invalid value for a status formatting argument" , SV("{::*<7}" ), input); |
924 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("sxX" )) |
925 | check_exception("The type option contains an invalid value for a status formatting argument" , fmt, input); |
926 | |
927 | check(SV("[0xaaaa, 0x5555, 0xaa55]" ), SV("{::x}" ), input); |
928 | check(SV("[0XAAAA, 0X5555, 0XAA55]" ), SV("{::X}" ), input); |
929 | check(SV("[foo, bar, foobar]" ), SV("{::s}" ), input); |
930 | |
931 | // ***** Both have a format-spec |
932 | check(SV("^^[0XAAAA, 0X5555, 0XAA55]^^^" ), SV("{:^^29:X}" ), input); |
933 | check(SV("^^[0XAAAA, 0X5555, 0XAA55]^^^" ), SV("{:^^{}:X}" ), input, 29); |
934 | |
935 | check_exception("The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:X}" ), input); |
936 | } |
937 | |
938 | // |
939 | // Pair |
940 | // |
941 | |
942 | template <class CharT, class TestFunction, class ExceptionTest> |
943 | void test_pair_tuple(TestFunction check, ExceptionTest check_exception, auto&& input) { |
944 | // [format.range.formatter]/3 |
945 | // For range_formatter<T, charT>, the format-spec in a |
946 | // range-underlying-spec, if any, is interpreted by formatter<T, charT>. |
947 | // |
948 | // template<class ParseContext> |
949 | // constexpr typename ParseContext::iterator |
950 | // parse(ParseContext& ctx); |
951 | // [format.tuple]/7 |
952 | // ... if e.set_debug_format() is a valid expression, calls |
953 | // e.set_debug_format(). |
954 | // So when there is no range-underlying-spec, there is no need to call parse |
955 | // thus the char element is not escaped. |
956 | // TODO FMT P2733 addresses this issue. |
957 | check(SV("[(1, 'a'), (42, '*')]" ), SV("{}" ), input); |
958 | check(SV("[(1, 'a'), (42, '*')]^42" ), SV("{}^42" ), input); |
959 | check(SV("[(1, 'a'), (42, '*')]^42" ), SV("{:}^42" ), input); |
960 | |
961 | // ***** underlying has no format-spec |
962 | |
963 | // *** align-fill & width *** |
964 | check(SV("[(1, 'a'), (42, '*')] " ), SV("{:26}" ), input); |
965 | check(SV("[(1, 'a'), (42, '*')]*****" ), SV("{:*<26}" ), input); |
966 | check(SV("__[(1, 'a'), (42, '*')]___" ), SV("{:_^26}" ), input); |
967 | check(SV("#####[(1, 'a'), (42, '*')]" ), SV("{:#>26}" ), input); |
968 | |
969 | check(SV("[(1, 'a'), (42, '*')] " ), SV("{:{}}" ), input, 26); |
970 | check(SV("[(1, 'a'), (42, '*')]*****" ), SV("{:*<{}}" ), input, 26); |
971 | check(SV("__[(1, 'a'), (42, '*')]___" ), SV("{:_^{}}" ), input, 26); |
972 | check(SV("#####[(1, 'a'), (42, '*')]" ), SV("{:#>{}}" ), input, 26); |
973 | |
974 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
975 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
976 | |
977 | // *** sign *** |
978 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
979 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
980 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
981 | |
982 | // *** alternate form *** |
983 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
984 | |
985 | // *** zero-padding *** |
986 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
987 | |
988 | // *** precision *** |
989 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
990 | |
991 | // *** locale-specific form *** |
992 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
993 | |
994 | // *** n |
995 | check(SV("__(1, 'a'), (42, '*')___" ), SV("{:_^24n}" ), input); |
996 | check(SV("__(1, 'a'), (42, '*')___" ), SV("{:_^24nm}" ), input); // m should have no effect |
997 | |
998 | // *** type *** |
999 | check(SV("__{(1, 'a'), (42, '*')}___" ), SV("{:_^26m}" ), input); |
1000 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
1001 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
1002 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
1003 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
1004 | |
1005 | // ***** Only underlying has a format-spec |
1006 | check(SV("[(1, 'a') , (42, '*') ]" ), SV("{::11}" ), input); |
1007 | check(SV("[(1, 'a')***, (42, '*')**]" ), SV("{::*<11}" ), input); |
1008 | check(SV("[_(1, 'a')__, _(42, '*')_]" ), SV("{::_^11}" ), input); |
1009 | check(SV("[###(1, 'a'), ##(42, '*')]" ), SV("{::#>11}" ), input); |
1010 | |
1011 | check(SV("[(1, 'a') , (42, '*') ]" ), SV("{::{}}" ), input, 11); |
1012 | check(SV("[(1, 'a')***, (42, '*')**]" ), SV("{::*<{}}" ), input, 11); |
1013 | check(SV("[_(1, 'a')__, _(42, '*')_]" ), SV("{::_^{}}" ), input, 11); |
1014 | check(SV("[###(1, 'a'), ##(42, '*')]" ), SV("{::#>{}}" ), input, 11); |
1015 | |
1016 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
1017 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
1018 | |
1019 | // *** sign *** |
1020 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::-}" ), input); |
1021 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::+}" ), input); |
1022 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:: }" ), input); |
1023 | |
1024 | // *** alternate form *** |
1025 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::#}" ), input); |
1026 | |
1027 | // *** zero-padding *** |
1028 | check_exception("The width option should not have a leading zero" , SV("{::05}" ), input); |
1029 | |
1030 | // *** precision *** |
1031 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
1032 | |
1033 | // *** locale-specific form *** |
1034 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::L}" ), input); |
1035 | |
1036 | // *** type *** |
1037 | check(SV("[1: 'a', 42: '*']" ), SV("{::m}" ), input); |
1038 | check(SV("[1, 'a', 42, '*']" ), SV("{::n}" ), input); |
1039 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("" )) |
1040 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
1041 | |
1042 | // ***** Both have a format-spec |
1043 | check(SV("^^[###(1, 'a'), ##(42, '*')]^^^" ), SV("{:^^31:#>11}" ), input); |
1044 | check(SV("^^[###(1, 'a'), ##(42, '*')]^^^" ), SV("{:^^31:#>11}" ), input); |
1045 | check(SV("^^[###(1, 'a'), ##(42, '*')]^^^" ), SV("{:^^{}:#>11}" ), input, 31); |
1046 | check(SV("^^[###(1, 'a'), ##(42, '*')]^^^" ), SV("{:^^{}:#>{}}" ), input, 31, 11); |
1047 | |
1048 | check_exception( |
1049 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>5}" ), input); |
1050 | check_exception( |
1051 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>{}}" ), input, 31); |
1052 | |
1053 | check(SV("1: 'a', 42: '*'" ), SV("{:n:m}" ), input); |
1054 | check(SV("1, 'a', 42, '*'" ), SV("{:n:n}" ), input); |
1055 | check(SV("{1: 'a', 42: '*'}" ), SV("{:m:m}" ), input); |
1056 | check(SV("{1, 'a', 42, '*'}" ), SV("{:m:n}" ), input); |
1057 | } |
1058 | |
1059 | template <class CharT, class TestFunction, class ExceptionTest> |
1060 | void test_pair_tuple(TestFunction check, ExceptionTest check_exception) { |
1061 | test_pair_tuple<CharT>( |
1062 | check, check_exception, std::array{std::make_pair(1, CharT('a')), std::make_pair(42, CharT('*'))}); |
1063 | test_pair_tuple<CharT>( |
1064 | check, check_exception, std::array{std::make_tuple(1, CharT('a')), std::make_tuple(42, CharT('*'))}); |
1065 | } |
1066 | |
1067 | // |
1068 | // Tuple 1 |
1069 | // |
1070 | |
1071 | template <class CharT, class TestFunction, class ExceptionTest> |
1072 | void test_tuple_int(TestFunction check, ExceptionTest check_exception) { |
1073 | std::array input{std::make_tuple(args: 42), std::make_tuple(args: 99)}; |
1074 | |
1075 | check(SV("[(42), (99)]" ), SV("{}" ), input); |
1076 | check(SV("[(42), (99)]^42" ), SV("{}^42" ), input); |
1077 | check(SV("[(42), (99)]^42" ), SV("{:}^42" ), input); |
1078 | |
1079 | // ***** underlying has no format-spec |
1080 | |
1081 | // *** align-fill & width *** |
1082 | check(SV("[(42), (99)] " ), SV("{:17}" ), input); |
1083 | check(SV("[(42), (99)]*****" ), SV("{:*<17}" ), input); |
1084 | check(SV("__[(42), (99)]___" ), SV("{:_^17}" ), input); |
1085 | check(SV("#####[(42), (99)]" ), SV("{:#>17}" ), input); |
1086 | |
1087 | check(SV("[(42), (99)] " ), SV("{:{}}" ), input, 17); |
1088 | check(SV("[(42), (99)]*****" ), SV("{:*<{}}" ), input, 17); |
1089 | check(SV("__[(42), (99)]___" ), SV("{:_^{}}" ), input, 17); |
1090 | check(SV("#####[(42), (99)]" ), SV("{:#>{}}" ), input, 17); |
1091 | |
1092 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
1093 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
1094 | |
1095 | // *** sign *** |
1096 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
1097 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
1098 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
1099 | |
1100 | // *** alternate form *** |
1101 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
1102 | |
1103 | // *** zero-padding *** |
1104 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
1105 | |
1106 | // *** precision *** |
1107 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
1108 | |
1109 | // *** locale-specific form *** |
1110 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
1111 | |
1112 | // *** n |
1113 | check(SV("__(42), (99)___" ), SV("{:_^15n}" ), input); |
1114 | |
1115 | // *** type *** |
1116 | check_exception("Type m requires a pair or a tuple with two elements" , SV("{:m}" ), input); |
1117 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
1118 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
1119 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
1120 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
1121 | |
1122 | // ***** Only underlying has a format-spec |
1123 | check(SV("[(42) , (99) ]" ), SV("{::7}" ), input); |
1124 | check(SV("[(42)***, (99)***]" ), SV("{::*<7}" ), input); |
1125 | check(SV("[_(42)__, _(99)__]" ), SV("{::_^7}" ), input); |
1126 | check(SV("[###(42), ###(99)]" ), SV("{::#>7}" ), input); |
1127 | |
1128 | check(SV("[(42) , (99) ]" ), SV("{::{}}" ), input, 7); |
1129 | check(SV("[(42)***, (99)***]" ), SV("{::*<{}}" ), input, 7); |
1130 | check(SV("[_(42)__, _(99)__]" ), SV("{::_^{}}" ), input, 7); |
1131 | check(SV("[###(42), ###(99)]" ), SV("{::#>{}}" ), input, 7); |
1132 | |
1133 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
1134 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
1135 | |
1136 | // *** sign *** |
1137 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::-}" ), input); |
1138 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::+}" ), input); |
1139 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:: }" ), input); |
1140 | |
1141 | // *** alternate form *** |
1142 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::#}" ), input); |
1143 | |
1144 | // *** zero-padding *** |
1145 | check_exception("The width option should not have a leading zero" , SV("{::05}" ), input); |
1146 | |
1147 | // *** precision *** |
1148 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
1149 | |
1150 | // *** locale-specific form *** |
1151 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::L}" ), input); |
1152 | |
1153 | // *** type *** |
1154 | check(SV("[42, 99]" ), SV("{::n}" ), input); |
1155 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("" )) |
1156 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
1157 | |
1158 | // ***** Both have a format-spec |
1159 | check(SV("^^[###(42), ###(99)]^^^" ), SV("{:^^23:#>7}" ), input); |
1160 | check(SV("^^[###(42), ###(99)]^^^" ), SV("{:^^23:#>7}" ), input); |
1161 | check(SV("^^[###(42), ###(99)]^^^" ), SV("{:^^{}:#>7}" ), input, 23); |
1162 | check(SV("^^[###(42), ###(99)]^^^" ), SV("{:^^{}:#>{}}" ), input, 23, 7); |
1163 | |
1164 | check_exception( |
1165 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>5}" ), input); |
1166 | check_exception( |
1167 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>{}}" ), input, 23); |
1168 | } |
1169 | |
1170 | // |
1171 | // Tuple 3 |
1172 | // |
1173 | |
1174 | template <class CharT, class TestFunction, class ExceptionTest> |
1175 | void test_tuple_int_int_int(TestFunction check, ExceptionTest check_exception) { |
1176 | std::array input{std::make_tuple(args: 42, args: 99, args: 0), std::make_tuple(args: 1, args: 10, args: 100)}; |
1177 | |
1178 | check(SV("[(42, 99, 0), (1, 10, 100)]" ), SV("{}" ), input); |
1179 | check(SV("[(42, 99, 0), (1, 10, 100)]^42" ), SV("{}^42" ), input); |
1180 | check(SV("[(42, 99, 0), (1, 10, 100)]^42" ), SV("{:}^42" ), input); |
1181 | |
1182 | // ***** underlying has no format-spec |
1183 | |
1184 | // *** align-fill & width *** |
1185 | check(SV("[(42, 99, 0), (1, 10, 100)] " ), SV("{:32}" ), input); |
1186 | check(SV("[(42, 99, 0), (1, 10, 100)]*****" ), SV("{:*<32}" ), input); |
1187 | check(SV("__[(42, 99, 0), (1, 10, 100)]___" ), SV("{:_^32}" ), input); |
1188 | check(SV("#####[(42, 99, 0), (1, 10, 100)]" ), SV("{:#>32}" ), input); |
1189 | |
1190 | check(SV("[(42, 99, 0), (1, 10, 100)] " ), SV("{:{}}" ), input, 32); |
1191 | check(SV("[(42, 99, 0), (1, 10, 100)]*****" ), SV("{:*<{}}" ), input, 32); |
1192 | check(SV("__[(42, 99, 0), (1, 10, 100)]___" ), SV("{:_^{}}" ), input, 32); |
1193 | check(SV("#####[(42, 99, 0), (1, 10, 100)]" ), SV("{:#>{}}" ), input, 32); |
1194 | |
1195 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
1196 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
1197 | |
1198 | // *** sign *** |
1199 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
1200 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
1201 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
1202 | |
1203 | // *** alternate form *** |
1204 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
1205 | |
1206 | // *** zero-padding *** |
1207 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
1208 | |
1209 | // *** precision *** |
1210 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
1211 | |
1212 | // *** locale-specific form *** |
1213 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
1214 | |
1215 | // *** n |
1216 | check(SV("__(42, 99, 0), (1, 10, 100)___" ), SV("{:_^30n}" ), input); |
1217 | |
1218 | // *** type *** |
1219 | check_exception("Type m requires a pair or a tuple with two elements" , SV("{:m}" ), input); |
1220 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
1221 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
1222 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
1223 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
1224 | |
1225 | // ***** Only underlying has a format-spec |
1226 | check(SV("[(42, 99, 0) , (1, 10, 100) ]" ), SV("{::14}" ), input); |
1227 | check(SV("[(42, 99, 0)***, (1, 10, 100)**]" ), SV("{::*<14}" ), input); |
1228 | check(SV("[_(42, 99, 0)__, _(1, 10, 100)_]" ), SV("{::_^14}" ), input); |
1229 | check(SV("[###(42, 99, 0), ##(1, 10, 100)]" ), SV("{::#>14}" ), input); |
1230 | |
1231 | check(SV("[(42, 99, 0) , (1, 10, 100) ]" ), SV("{::{}}" ), input, 14); |
1232 | check(SV("[(42, 99, 0)***, (1, 10, 100)**]" ), SV("{::*<{}}" ), input, 14); |
1233 | check(SV("[_(42, 99, 0)__, _(1, 10, 100)_]" ), SV("{::_^{}}" ), input, 14); |
1234 | check(SV("[###(42, 99, 0), ##(1, 10, 100)]" ), SV("{::#>{}}" ), input, 14); |
1235 | |
1236 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
1237 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
1238 | |
1239 | // *** sign *** |
1240 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::-}" ), input); |
1241 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::+}" ), input); |
1242 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:: }" ), input); |
1243 | |
1244 | // *** alternate form *** |
1245 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::#}" ), input); |
1246 | |
1247 | // *** zero-padding *** |
1248 | check_exception("The width option should not have a leading zero" , SV("{::05}" ), input); |
1249 | |
1250 | // *** precision *** |
1251 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
1252 | |
1253 | // *** locale-specific form *** |
1254 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::L}" ), input); |
1255 | |
1256 | // *** type *** |
1257 | check(SV("[42, 99, 0, 1, 10, 100]" ), SV("{::n}" ), input); |
1258 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("s" )) |
1259 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
1260 | |
1261 | // ***** Both have a format-spec |
1262 | check(SV("^^[###(42, 99, 0), ##(1, 10, 100)]^^^" ), SV("{:^^37:#>14}" ), input); |
1263 | check(SV("^^[###(42, 99, 0), ##(1, 10, 100)]^^^" ), SV("{:^^37:#>14}" ), input); |
1264 | check(SV("^^[###(42, 99, 0), ##(1, 10, 100)]^^^" ), SV("{:^^{}:#>14}" ), input, 37); |
1265 | check(SV("^^[###(42, 99, 0), ##(1, 10, 100)]^^^" ), SV("{:^^{}:#>{}}" ), input, 37, 14); |
1266 | |
1267 | check_exception( |
1268 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>5}" ), input); |
1269 | check_exception( |
1270 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>{}}" ), input, 37); |
1271 | } |
1272 | |
1273 | // |
1274 | // Ranges |
1275 | // |
1276 | |
1277 | template <class CharT, class TestFunction, class ExceptionTest> |
1278 | void test_with_ranges(TestFunction check, ExceptionTest check_exception, auto&& iter) { |
1279 | std::ranges::subrange range{std::move(iter), std::default_sentinel}; |
1280 | test_int<CharT>(check, check_exception, std::move(range)); |
1281 | } |
1282 | |
1283 | template <class CharT, class TestFunction, class ExceptionTest> |
1284 | void test_with_ranges(TestFunction check, ExceptionTest check_exception) { |
1285 | std::array input{1, 2, 42, -42}; |
1286 | test_with_ranges<CharT>( |
1287 | check, check_exception, std::counted_iterator{cpp20_input_iterator<int*>(input.data()), input.size()}); |
1288 | test_with_ranges<CharT>( |
1289 | check, check_exception, std::counted_iterator{forward_iterator<int*>(input.data()), input.size()}); |
1290 | test_with_ranges<CharT>( |
1291 | check, check_exception, std::counted_iterator{bidirectional_iterator<int*>(input.data()), input.size()}); |
1292 | test_with_ranges<CharT>( |
1293 | check, check_exception, std::counted_iterator{random_access_iterator<int*>(input.data()), input.size()}); |
1294 | test_with_ranges<CharT>( |
1295 | check, check_exception, std::counted_iterator{contiguous_iterator<int*>(input.data()), input.size()}); |
1296 | } |
1297 | |
1298 | // |
1299 | // Adaptor |
1300 | // |
1301 | |
1302 | template <class CharT> |
1303 | class non_contiguous { |
1304 | // A deque iterator is random access, but not contiguous. |
1305 | using adaptee = std::deque<CharT>; |
1306 | |
1307 | public: |
1308 | using iterator = typename adaptee::iterator; |
1309 | using pointer = typename adaptee::pointer; |
1310 | |
1311 | iterator begin() { return data_.begin(); } |
1312 | iterator end() { return data_.end(); } |
1313 | |
1314 | explicit non_contiguous(adaptee&& data) : data_(std::move(data)) {} |
1315 | |
1316 | private: |
1317 | adaptee data_; |
1318 | }; |
1319 | |
1320 | template <class CharT> |
1321 | class contiguous { |
1322 | // A vector iterator is contiguous. |
1323 | using adaptee = std::vector<CharT>; |
1324 | |
1325 | public: |
1326 | using iterator = typename adaptee::iterator; |
1327 | using pointer = typename adaptee::pointer; |
1328 | |
1329 | iterator begin() { return data_.begin(); } |
1330 | iterator end() { return data_.end(); } |
1331 | |
1332 | explicit contiguous(adaptee&& data) : data_(std::move(data)) {} |
1333 | |
1334 | private: |
1335 | adaptee data_; |
1336 | }; |
1337 | |
1338 | // This tests two different implementations in libc++. A basic_string_view |
1339 | // formatter if the range is contiguous, a basic_string otherwise. |
1340 | template <class CharT, class TestFunction, class ExceptionTest> |
1341 | void test_adaptor(TestFunction check, ExceptionTest check_exception) { |
1342 | static_assert(std::format_kind<non_contiguous<CharT>> == std::range_format::sequence); |
1343 | static_assert(std::ranges::sized_range<non_contiguous<CharT>>); |
1344 | static_assert(!std::ranges::contiguous_range<non_contiguous<CharT>>); |
1345 | test_char_string<CharT>( |
1346 | check, |
1347 | check_exception, |
1348 | non_contiguous<CharT>{std::deque{CharT('H'), CharT('e'), CharT('l'), CharT('l'), CharT('o')}}); |
1349 | |
1350 | static_assert(std::format_kind<contiguous<CharT>> == std::range_format::sequence); |
1351 | static_assert(std::ranges::sized_range<contiguous<CharT>>); |
1352 | static_assert(std::ranges::contiguous_range<contiguous<CharT>>); |
1353 | test_char_string<CharT>(check, |
1354 | check_exception, |
1355 | contiguous<CharT>{std::vector{CharT('H'), CharT('e'), CharT('l'), CharT('l'), CharT('o')}}); |
1356 | } |
1357 | |
1358 | // |
1359 | // Driver |
1360 | // |
1361 | |
1362 | template <class CharT, class TestFunction, class ExceptionTest> |
1363 | void format_tests(TestFunction check, ExceptionTest check_exception) { |
1364 | test_char<CharT>(check, check_exception); |
1365 | #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
1366 | if (std::same_as<CharT, wchar_t>) // avoid testing twice |
1367 | test_char_to_wchar(check, check_exception); |
1368 | #endif |
1369 | test_bool<CharT>(check, check_exception); |
1370 | test_int<CharT>(check, check_exception); |
1371 | test_floating_point<CharT>(check, check_exception); |
1372 | test_pointer<CharT>(check, check_exception); |
1373 | test_string<CharT>(check, check_exception); |
1374 | |
1375 | test_status<CharT>(check, check_exception); // Has its own handler with its own parser |
1376 | |
1377 | test_pair_tuple<CharT>(check, check_exception); |
1378 | test_tuple_int<CharT>(check, check_exception); |
1379 | test_tuple_int_int_int<CharT>(check, check_exception); |
1380 | |
1381 | test_with_ranges<CharT>(check, check_exception); |
1382 | |
1383 | test_adaptor<CharT>(check, check_exception); |
1384 | } |
1385 | |
1386 | #endif // TEST_STD_UTILITIES_FORMAT_FORMAT_RANGE_FORMAT_RANGE_FORMATTER_FORMAT_FUNCTIONS_TESTS_H |
1387 | |