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_FMTMAP_FORMAT_FUNCTIONS_TESTS_H |
9 | #define TEST_STD_UTILITIES_FORMAT_FORMAT_RANGE_FORMAT_RANGE_FMTMAP_FORMAT_FUNCTIONS_TESTS_H |
10 | |
11 | #include <algorithm> |
12 | #include <format> |
13 | #include <map> |
14 | #include <unordered_map> |
15 | |
16 | #include "format.functions.common.h" |
17 | #include "make_string.h" |
18 | #include "platform_support.h" // locale name macros |
19 | #include "test_macros.h" |
20 | |
21 | // |
22 | // Char |
23 | // |
24 | |
25 | template <class CharT, class TestFunction, class ExceptionTest> |
26 | void test_char(TestFunction check, ExceptionTest check_exception) { |
27 | std::map<CharT, CharT> input{{CharT('a'), CharT('A')}, {CharT('c'), CharT('C')}, {CharT('b'), CharT('B')}}; |
28 | |
29 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}" ), SV("{}" ), input); |
30 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}^42" ), SV("{}^42" ), input); |
31 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}^42" ), SV("{:}^42" ), input); |
32 | |
33 | // ***** underlying has no format-spec |
34 | |
35 | // *** align-fill & width *** |
36 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'} " ), SV("{:35}" ), input); |
37 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}*****" ), SV("{:*<35}" ), input); |
38 | check(SV("__{'a': 'A', 'b': 'B', 'c': 'C'}___" ), SV("{:_^35}" ), input); |
39 | check(SV("#####{'a': 'A', 'b': 'B', 'c': 'C'}" ), SV("{:#>35}" ), input); |
40 | |
41 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'} " ), SV("{:{}}" ), input, 35); |
42 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}*****" ), SV("{:*<{}}" ), input, 35); |
43 | check(SV("__{'a': 'A', 'b': 'B', 'c': 'C'}___" ), SV("{:_^{}}" ), input, 35); |
44 | check(SV("#####{'a': 'A', 'b': 'B', 'c': 'C'}" ), SV("{:#>{}}" ), input, 35); |
45 | |
46 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
47 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
48 | |
49 | // *** sign *** |
50 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
51 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
52 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
53 | |
54 | // *** alternate form *** |
55 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
56 | |
57 | // *** zero-padding *** |
58 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
59 | |
60 | // *** precision *** |
61 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
62 | |
63 | // *** locale-specific form *** |
64 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
65 | |
66 | // *** n |
67 | check(SV("__'a': 'A', 'b': 'B', 'c': 'C'___" ), SV("{:_^33n}" ), input); |
68 | |
69 | // *** type *** |
70 | check(SV("__{'a': 'A', 'b': 'B', 'c': 'C'}___" ), SV("{:_^35m}" ), input); // the m type does the same as the default. |
71 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
72 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
73 | |
74 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
75 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
76 | |
77 | // ***** Only underlying has a format-spec |
78 | |
79 | check(SV("{'a': 'A' , 'b': 'B' , 'c': 'C' }" ), SV("{::13}" ), input); |
80 | check(SV("{'a': 'A'*****, 'b': 'B'*****, 'c': 'C'*****}" ), SV("{::*<13}" ), input); |
81 | check(SV("{__'a': 'A'___, __'b': 'B'___, __'c': 'C'___}" ), SV("{::_^13}" ), input); |
82 | check(SV("{#####'a': 'A', #####'b': 'B', #####'c': 'C'}" ), SV("{::#>13}" ), input); |
83 | |
84 | check(SV("{'a': 'A' , 'b': 'B' , 'c': 'C' }" ), SV("{::{}}" ), input, 13); |
85 | check(SV("{'a': 'A'*****, 'b': 'B'*****, 'c': 'C'*****}" ), SV("{::*<{}}" ), input, 13); |
86 | check(SV("{__'a': 'A'___, __'b': 'B'___, __'c': 'C'___}" ), SV("{::_^{}}" ), input, 13); |
87 | check(SV("{#####'a': 'A', #####'b': 'B', #####'c': 'C'}" ), SV("{::#>{}}" ), input, 13); |
88 | |
89 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
90 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
91 | |
92 | // *** sign *** |
93 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::-}" ), input); |
94 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::+}" ), input); |
95 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:: }" ), input); |
96 | |
97 | // *** alternate form *** |
98 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::#}" ), input); |
99 | |
100 | // *** zero-padding *** |
101 | check_exception("The width option should not have a leading zero" , SV("{::05}" ), input); |
102 | |
103 | // *** precision *** |
104 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
105 | |
106 | // *** locale-specific form *** |
107 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::L}" ), input); |
108 | |
109 | // *** type *** |
110 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}" ), SV("{::m}" ), input); |
111 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}" ), SV("{::n}" ), input); |
112 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
113 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
114 | |
115 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
116 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
117 | |
118 | // ***** Both have a format-spec |
119 | check(SV("^^{###'a': 'A', ###'b': 'B', ###'c': 'C'}^^^" ), SV("{:^^44:#>11}" ), input); |
120 | check(SV("^^{###'a': 'A', ###'b': 'B', ###'c': 'C'}^^^" ), SV("{:^^{}:#>11}" ), input, 44); |
121 | check(SV("^^{###'a': 'A', ###'b': 'B', ###'c': 'C'}^^^" ), SV("{:^^{}:#>{}}" ), input, 44, 11); |
122 | |
123 | check_exception( |
124 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>11}" ), input); |
125 | check_exception( |
126 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>{}}" ), input, 44); |
127 | } |
128 | |
129 | // |
130 | // char -> wchar_t |
131 | // |
132 | |
133 | #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
134 | template <class TestFunction, class ExceptionTest> |
135 | void test_char_to_wchar(TestFunction check, ExceptionTest check_exception) { |
136 | std::map<char, char> input{{'a', 'A'}, {'c', 'C'}, {'b', 'B'}}; |
137 | |
138 | using CharT = wchar_t; |
139 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}" ), SV("{}" ), input); |
140 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}^42" ), SV("{}^42" ), input); |
141 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}^42" ), SV("{:}^42" ), input); |
142 | |
143 | // ***** underlying has no format-spec |
144 | |
145 | // *** align-fill & width *** |
146 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'} " ), SV("{:35}" ), input); |
147 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}*****" ), SV("{:*<35}" ), input); |
148 | check(SV("__{'a': 'A', 'b': 'B', 'c': 'C'}___" ), SV("{:_^35}" ), input); |
149 | check(SV("#####{'a': 'A', 'b': 'B', 'c': 'C'}" ), SV("{:#>35}" ), input); |
150 | |
151 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'} " ), SV("{:{}}" ), input, 35); |
152 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}*****" ), SV("{:*<{}}" ), input, 35); |
153 | check(SV("__{'a': 'A', 'b': 'B', 'c': 'C'}___" ), SV("{:_^{}}" ), input, 35); |
154 | check(SV("#####{'a': 'A', 'b': 'B', 'c': 'C'}" ), SV("{:#>{}}" ), input, 35); |
155 | |
156 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
157 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
158 | |
159 | // *** sign *** |
160 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
161 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
162 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
163 | |
164 | // *** alternate form *** |
165 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
166 | |
167 | // *** zero-padding *** |
168 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
169 | |
170 | // *** precision *** |
171 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
172 | |
173 | // *** locale-specific form *** |
174 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
175 | |
176 | // *** n |
177 | check(SV("__'a': 'A', 'b': 'B', 'c': 'C'___" ), SV("{:_^33n}" ), input); |
178 | |
179 | // *** type *** |
180 | check(SV("__{'a': 'A', 'b': 'B', 'c': 'C'}___" ), SV("{:_^35m}" ), input); // the m type does the same as the default. |
181 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
182 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
183 | |
184 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
185 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
186 | |
187 | // ***** Only underlying has a format-spec |
188 | check(SV("{'a': 'A' , 'b': 'B' , 'c': 'C' }" ), SV("{::13}" ), input); |
189 | check(SV("{'a': 'A'*****, 'b': 'B'*****, 'c': 'C'*****}" ), SV("{::*<13}" ), input); |
190 | check(SV("{__'a': 'A'___, __'b': 'B'___, __'c': 'C'___}" ), SV("{::_^13}" ), input); |
191 | check(SV("{#####'a': 'A', #####'b': 'B', #####'c': 'C'}" ), SV("{::#>13}" ), input); |
192 | |
193 | check(SV("{'a': 'A' , 'b': 'B' , 'c': 'C' }" ), SV("{::{}}" ), input, 13); |
194 | check(SV("{'a': 'A'*****, 'b': 'B'*****, 'c': 'C'*****}" ), SV("{::*<{}}" ), input, 13); |
195 | check(SV("{__'a': 'A'___, __'b': 'B'___, __'c': 'C'___}" ), SV("{::_^{}}" ), input, 13); |
196 | check(SV("{#####'a': 'A', #####'b': 'B', #####'c': 'C'}" ), SV("{::#>{}}" ), input, 13); |
197 | |
198 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
199 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
200 | |
201 | // *** sign *** |
202 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::-}" ), input); |
203 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::+}" ), input); |
204 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:: }" ), input); |
205 | |
206 | // *** alternate form *** |
207 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::#}" ), input); |
208 | |
209 | // *** zero-padding *** |
210 | check_exception("The width option should not have a leading zero" , SV("{::05}" ), input); |
211 | |
212 | // *** precision *** |
213 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
214 | |
215 | // *** locale-specific form *** |
216 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::L}" ), input); |
217 | |
218 | // *** type *** |
219 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}" ), SV("{::m}" ), input); |
220 | check(SV("{'a': 'A', 'b': 'B', 'c': 'C'}" ), SV("{::n}" ), input); |
221 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
222 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
223 | |
224 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
225 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
226 | |
227 | // ***** Both have a format-spec |
228 | check(SV("^^{###'a': 'A', ###'b': 'B', ###'c': 'C'}^^^" ), SV("{:^^44:#>11}" ), input); |
229 | check(SV("^^{###'a': 'A', ###'b': 'B', ###'c': 'C'}^^^" ), SV("{:^^{}:#>11}" ), input, 44); |
230 | check(SV("^^{###'a': 'A', ###'b': 'B', ###'c': 'C'}^^^" ), SV("{:^^{}:#>{}}" ), input, 44, 11); |
231 | |
232 | check_exception( |
233 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>11}" ), input); |
234 | check_exception( |
235 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>{}}" ), input, 44); |
236 | } |
237 | #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS |
238 | |
239 | // |
240 | // Bool |
241 | // |
242 | template <class CharT, class TestFunction, class ExceptionTest> |
243 | void test_bool(TestFunction check, ExceptionTest check_exception) { |
244 | // duplicates are stored in order of insertion |
245 | std::multimap<bool, int> input{{true, 42}, {false, 0}, {true, 1}}; |
246 | |
247 | check(SV("{false: 0, true: 42, true: 1}" ), SV("{}" ), input); |
248 | check(SV("{false: 0, true: 42, true: 1}^42" ), SV("{}^42" ), input); |
249 | check(SV("{false: 0, true: 42, true: 1}^42" ), SV("{:}^42" ), input); |
250 | |
251 | // ***** underlying has no format-spec |
252 | |
253 | // *** align-fill & width *** |
254 | check(SV("{false: 0, true: 42, true: 1} " ), SV("{:34}" ), input); |
255 | check(SV("{false: 0, true: 42, true: 1}*****" ), SV("{:*<34}" ), input); |
256 | check(SV("__{false: 0, true: 42, true: 1}___" ), SV("{:_^34}" ), input); |
257 | check(SV("#####{false: 0, true: 42, true: 1}" ), SV("{:#>34}" ), input); |
258 | |
259 | check(SV("{false: 0, true: 42, true: 1} " ), SV("{:{}}" ), input, 34); |
260 | check(SV("{false: 0, true: 42, true: 1}*****" ), SV("{:*<{}}" ), input, 34); |
261 | check(SV("__{false: 0, true: 42, true: 1}___" ), SV("{:_^{}}" ), input, 34); |
262 | check(SV("#####{false: 0, true: 42, true: 1}" ), SV("{:#>{}}" ), input, 34); |
263 | |
264 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
265 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
266 | |
267 | // *** sign *** |
268 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
269 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
270 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
271 | |
272 | // *** alternate form *** |
273 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
274 | |
275 | // *** zero-padding *** |
276 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
277 | |
278 | // *** precision *** |
279 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
280 | |
281 | // *** locale-specific form *** |
282 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
283 | |
284 | // *** n |
285 | check(SV("__false: 0, true: 42, true: 1___" ), SV("{:_^32n}" ), input); |
286 | |
287 | // *** type *** |
288 | check(SV("__{false: 0, true: 42, true: 1}___" ), SV("{:_^34m}" ), input); // the m type does the same as the default. |
289 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
290 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
291 | |
292 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
293 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
294 | |
295 | // ***** Only underlying has a format-spec |
296 | check(SV("{false: 0 , true: 42 , true: 1 }" ), SV("{::10}" ), input); |
297 | check(SV("{false: 0**, true: 42**, true: 1***}" ), SV("{::*<10}" ), input); |
298 | check(SV("{_false: 0_, _true: 42_, _true: 1__}" ), SV("{::_^10}" ), input); |
299 | check(SV("{##false: 0, ##true: 42, ###true: 1}" ), SV("{::#>10}" ), input); |
300 | |
301 | check(SV("{false: 0 , true: 42 , true: 1 }" ), SV("{::{}}" ), input, 10); |
302 | check(SV("{false: 0**, true: 42**, true: 1***}" ), SV("{::*<{}}" ), input, 10); |
303 | check(SV("{_false: 0_, _true: 42_, _true: 1__}" ), SV("{::_^{}}" ), input, 10); |
304 | check(SV("{##false: 0, ##true: 42, ###true: 1}" ), SV("{::#>{}}" ), input, 10); |
305 | |
306 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
307 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
308 | |
309 | // *** sign *** |
310 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::-}" ), input); |
311 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::+}" ), input); |
312 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:: }" ), input); |
313 | |
314 | // *** alternate form *** |
315 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::#}" ), input); |
316 | |
317 | // *** zero-padding *** |
318 | check_exception("The width option should not have a leading zero" , SV("{::05}" ), input); |
319 | |
320 | // *** precision *** |
321 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
322 | |
323 | // *** locale-specific form *** |
324 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::L}" ), input); |
325 | |
326 | // *** type *** |
327 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("" )) |
328 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
329 | |
330 | // ***** Both have a format-spec |
331 | check(SV("^^{##false: 0, ##true: 42, ###true: 1}^^^" ), SV("{:^^41:#>10}" ), input); |
332 | check(SV("^^{##false: 0, ##true: 42, ###true: 1}^^^" ), SV("{:^^{}:#>10}" ), input, 41); |
333 | check(SV("^^{##false: 0, ##true: 42, ###true: 1}^^^" ), SV("{:^^{}:#>{}}" ), input, 41, 10); |
334 | |
335 | check_exception( |
336 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>10}" ), input); |
337 | check_exception( |
338 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>{}}" ), input, 41); |
339 | } |
340 | |
341 | // |
342 | // Integral |
343 | // |
344 | |
345 | template <class CharT, class TestFunction, class ExceptionTest> |
346 | void test_int(TestFunction check, ExceptionTest check_exception, auto&& input) { |
347 | check(SV("{-42: 42, 1: -1, 42: -42}" ), SV("{}" ), input); |
348 | check(SV("{-42: 42, 1: -1, 42: -42}^42" ), SV("{}^42" ), input); |
349 | check(SV("{-42: 42, 1: -1, 42: -42}^42" ), SV("{:}^42" ), input); |
350 | |
351 | // ***** underlying has no format-spec |
352 | |
353 | // *** align-fill & width *** |
354 | check(SV("{-42: 42, 1: -1, 42: -42} " ), SV("{:30}" ), input); |
355 | check(SV("{-42: 42, 1: -1, 42: -42}*****" ), SV("{:*<30}" ), input); |
356 | check(SV("__{-42: 42, 1: -1, 42: -42}___" ), SV("{:_^30}" ), input); |
357 | check(SV("#####{-42: 42, 1: -1, 42: -42}" ), SV("{:#>30}" ), input); |
358 | |
359 | check(SV("{-42: 42, 1: -1, 42: -42} " ), SV("{:{}}" ), input, 30); |
360 | check(SV("{-42: 42, 1: -1, 42: -42}*****" ), SV("{:*<{}}" ), input, 30); |
361 | check(SV("__{-42: 42, 1: -1, 42: -42}___" ), SV("{:_^{}}" ), input, 30); |
362 | check(SV("#####{-42: 42, 1: -1, 42: -42}" ), SV("{:#>{}}" ), input, 30); |
363 | |
364 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
365 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
366 | |
367 | // *** sign *** |
368 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
369 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
370 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
371 | |
372 | // *** alternate form *** |
373 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
374 | |
375 | // *** zero-padding *** |
376 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
377 | |
378 | // *** precision *** |
379 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
380 | |
381 | // *** locale-specific form *** |
382 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
383 | |
384 | // *** n |
385 | check(SV("__-42: 42, 1: -1, 42: -42___" ), SV("{:_^28n}" ), input); |
386 | |
387 | // *** type *** |
388 | check(SV("__{-42: 42, 1: -1, 42: -42}___" ), SV("{:_^30m}" ), input); // the m type does the same as the default. |
389 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
390 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
391 | |
392 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
393 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
394 | |
395 | // ***** Only underlying has a format-spec |
396 | check(SV("{-42: 42 , 1: -1 , 42: -42 }" ), SV("{::10}" ), input); |
397 | check(SV("{-42: 42***, 1: -1*****, 42: -42***}" ), SV("{::*<10}" ), input); |
398 | check(SV("{_-42: 42__, __1: -1___, _42: -42__}" ), SV("{::_^10}" ), input); |
399 | check(SV("{###-42: 42, #####1: -1, ###42: -42}" ), SV("{::#>10}" ), input); |
400 | |
401 | check(SV("{-42: 42 , 1: -1 , 42: -42 }" ), SV("{::{}}" ), input, 10); |
402 | check(SV("{-42: 42***, 1: -1*****, 42: -42***}" ), SV("{::*<{}}" ), input, 10); |
403 | check(SV("{_-42: 42__, __1: -1___, _42: -42__}" ), SV("{::_^{}}" ), input, 10); |
404 | check(SV("{###-42: 42, #####1: -1, ###42: -42}" ), SV("{::#>{}}" ), input, 10); |
405 | |
406 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
407 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
408 | |
409 | // *** sign *** |
410 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::-}" ), input); |
411 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::+}" ), input); |
412 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:: }" ), input); |
413 | |
414 | // *** alternate form *** |
415 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::#}" ), input); |
416 | |
417 | // *** zero-padding *** |
418 | check_exception("The width option should not have a leading zero" , SV("{::05}" ), input); |
419 | |
420 | // *** precision *** |
421 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
422 | |
423 | // *** locale-specific form *** |
424 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::L}" ), input); |
425 | |
426 | // *** type *** |
427 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("" )) |
428 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
429 | |
430 | // ***** Both have a format-spec |
431 | check(SV("^^{###-42: 42, #####1: -1, ###42: -42}^^^" ), SV("{:^^41:#>10}" ), input); |
432 | check(SV("^^{###-42: 42, #####1: -1, ###42: -42}^^^" ), SV("{:^^{}:#>10}" ), input, 41); |
433 | check(SV("^^{###-42: 42, #####1: -1, ###42: -42}^^^" ), SV("{:^^{}:#>{}}" ), input, 41, 10); |
434 | |
435 | check_exception( |
436 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>10}" ), input); |
437 | check_exception( |
438 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>{}}" ), input, 41); |
439 | } |
440 | |
441 | template <class CharT, class TestFunction, class ExceptionTest> |
442 | void test_int(TestFunction check, ExceptionTest check_exception) { |
443 | test_int<CharT>(check, check_exception, std::map<int, int>{{1, -1}, {42, -42}, {-42, 42}}); |
444 | } |
445 | |
446 | // |
447 | // Floating point |
448 | // |
449 | |
450 | template <class CharT, class TestFunction, class ExceptionTest> |
451 | void test_floating_point(TestFunction check, ExceptionTest check_exception) { |
452 | std::map<double, double> input{{1.0, -1.0}, {-42, 42}}; |
453 | |
454 | check(SV("{-42: 42, 1: -1}" ), SV("{}" ), input); |
455 | check(SV("{-42: 42, 1: -1}^42" ), SV("{}^42" ), input); |
456 | check(SV("{-42: 42, 1: -1}^42" ), SV("{:}^42" ), input); |
457 | |
458 | // ***** underlying has no format-spec |
459 | |
460 | // *** align-fill & width *** |
461 | check(SV("{-42: 42, 1: -1} " ), SV("{:21}" ), input); |
462 | check(SV("{-42: 42, 1: -1}*****" ), SV("{:*<21}" ), input); |
463 | check(SV("__{-42: 42, 1: -1}___" ), SV("{:_^21}" ), input); |
464 | check(SV("#####{-42: 42, 1: -1}" ), SV("{:#>21}" ), input); |
465 | |
466 | check(SV("{-42: 42, 1: -1} " ), SV("{:{}}" ), input, 21); |
467 | check(SV("{-42: 42, 1: -1}*****" ), SV("{:*<{}}" ), input, 21); |
468 | check(SV("__{-42: 42, 1: -1}___" ), SV("{:_^{}}" ), input, 21); |
469 | check(SV("#####{-42: 42, 1: -1}" ), SV("{:#>{}}" ), input, 21); |
470 | |
471 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
472 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
473 | |
474 | // *** sign *** |
475 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
476 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
477 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
478 | |
479 | // *** alternate form *** |
480 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
481 | |
482 | // *** zero-padding *** |
483 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
484 | |
485 | // *** precision *** |
486 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
487 | |
488 | // *** locale-specific form *** |
489 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
490 | |
491 | // *** n |
492 | check(SV("__-42: 42, 1: -1___" ), SV("{:_^19n}" ), input); |
493 | |
494 | // *** type *** |
495 | check(SV("__{-42: 42, 1: -1}___" ), SV("{:_^21m}" ), input); // the m type does the same as the default. |
496 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
497 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
498 | |
499 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
500 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
501 | |
502 | // ***** Only underlying has a format-spec |
503 | check(SV("{-42: 42 , 1: -1 }" ), SV("{::10}" ), input); |
504 | check(SV("{-42: 42***, 1: -1*****}" ), SV("{::*<10}" ), input); |
505 | check(SV("{_-42: 42__, __1: -1___}" ), SV("{::_^10}" ), input); |
506 | check(SV("{###-42: 42, #####1: -1}" ), SV("{::#>10}" ), input); |
507 | |
508 | check(SV("{-42: 42 , 1: -1 }" ), SV("{::{}}" ), input, 10); |
509 | check(SV("{-42: 42***, 1: -1*****}" ), SV("{::*<{}}" ), input, 10); |
510 | check(SV("{_-42: 42__, __1: -1___}" ), SV("{::_^{}}" ), input, 10); |
511 | check(SV("{###-42: 42, #####1: -1}" ), SV("{::#>{}}" ), input, 10); |
512 | |
513 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
514 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
515 | |
516 | // *** sign *** |
517 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::-}" ), input); |
518 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::+}" ), input); |
519 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:: }" ), input); |
520 | |
521 | // *** alternate form *** |
522 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::#}" ), input); |
523 | |
524 | // *** zero-padding *** |
525 | check_exception("The width option should not have a leading zero" , SV("{::05}" ), input); |
526 | |
527 | // *** precision *** |
528 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
529 | |
530 | // *** locale-specific form *** |
531 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::L}" ), input); |
532 | |
533 | // *** type *** |
534 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("" )) |
535 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
536 | |
537 | // ***** Both have a format-spec |
538 | check(SV("^^{###-42: 42, #####1: -1}^^^" ), SV("{:^^29:#>10}" ), input); |
539 | check(SV("^^{###-42: 42, #####1: -1}^^^" ), SV("{:^^{}:#>10}" ), input, 29); |
540 | check(SV("^^{###-42: 42, #####1: -1}^^^" ), SV("{:^^{}:#>{}}" ), input, 29, 10); |
541 | |
542 | check_exception( |
543 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>10}" ), input); |
544 | check_exception( |
545 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>{}}" ), input, 29); |
546 | } |
547 | |
548 | // |
549 | // Pointer |
550 | // |
551 | |
552 | template <class CharT, class TestFunction, class ExceptionTest> |
553 | void test_pointer(TestFunction check, ExceptionTest check_exception) { |
554 | std::unordered_map<const void*, std::nullptr_t> input{{0, 0}}; |
555 | |
556 | check(SV("{0x0: 0x0}" ), SV("{}" ), input); |
557 | check(SV("{0x0: 0x0}^42" ), SV("{}^42" ), input); |
558 | check(SV("{0x0: 0x0}^42" ), SV("{:}^42" ), input); |
559 | |
560 | // ***** underlying has no format-spec |
561 | |
562 | // *** align-fill & width *** |
563 | check(SV("{0x0: 0x0} " ), SV("{:15}" ), input); |
564 | check(SV("{0x0: 0x0}*****" ), SV("{:*<15}" ), input); |
565 | check(SV("__{0x0: 0x0}___" ), SV("{:_^15}" ), input); |
566 | check(SV("#####{0x0: 0x0}" ), SV("{:#>15}" ), input); |
567 | |
568 | check(SV("{0x0: 0x0} " ), SV("{:{}}" ), input, 15); |
569 | check(SV("{0x0: 0x0}*****" ), SV("{:*<{}}" ), input, 15); |
570 | check(SV("__{0x0: 0x0}___" ), SV("{:_^{}}" ), input, 15); |
571 | check(SV("#####{0x0: 0x0}" ), SV("{:#>{}}" ), input, 15); |
572 | |
573 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
574 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
575 | |
576 | // *** sign *** |
577 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
578 | |
579 | // *** alternate form *** |
580 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
581 | |
582 | // *** zero-padding *** |
583 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
584 | |
585 | // *** precision *** |
586 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
587 | |
588 | // *** locale-specific form *** |
589 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
590 | |
591 | // *** n |
592 | check(SV("__0x0: 0x0___" ), SV("{:_^13n}" ), input); |
593 | |
594 | // *** type *** |
595 | check(SV("__{0x0: 0x0}___" ), SV("{:_^15m}" ), input); // the m type does the same as the default. |
596 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
597 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
598 | |
599 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
600 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
601 | |
602 | // ***** Only underlying has a format-spec |
603 | check(SV("{0x0: 0x0 }" ), SV("{::13}" ), input); |
604 | check(SV("{0x0: 0x0*****}" ), SV("{::*<13}" ), input); |
605 | check(SV("{__0x0: 0x0___}" ), SV("{::_^13}" ), input); |
606 | check(SV("{#####0x0: 0x0}" ), SV("{::#>13}" ), input); |
607 | |
608 | check(SV("{0x0: 0x0 }" ), SV("{::{}}" ), input, 13); |
609 | check(SV("{0x0: 0x0*****}" ), SV("{::*<{}}" ), input, 13); |
610 | check(SV("{__0x0: 0x0___}" ), SV("{::_^{}}" ), input, 13); |
611 | check(SV("{#####0x0: 0x0}" ), SV("{::#>{}}" ), input, 13); |
612 | |
613 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
614 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
615 | |
616 | // *** sign *** |
617 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::-}" ), input); |
618 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::+}" ), input); |
619 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:: }" ), input); |
620 | |
621 | // *** alternate form *** |
622 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::#}" ), input); |
623 | |
624 | // *** zero-padding *** |
625 | check_exception("The width option should not have a leading zero" , SV("{::05}" ), input); |
626 | |
627 | // *** precision *** |
628 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
629 | |
630 | // *** locale-specific form *** |
631 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::L}" ), input); |
632 | |
633 | // *** type *** |
634 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("" )) |
635 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
636 | |
637 | // ***** Both have a format-spec |
638 | check(SV("^^{###0x0: 0x0}^^^" ), SV("{:^^18:#>11}" ), input); |
639 | check(SV("^^{###0x0: 0x0}^^^" ), SV("{:^^{}:#>11}" ), input, 18); |
640 | check(SV("^^{###0x0: 0x0}^^^" ), SV("{:^^{}:#>{}}" ), input, 18, 11); |
641 | |
642 | check_exception( |
643 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>11}" ), input); |
644 | check_exception( |
645 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>{}}" ), input, 18); |
646 | } |
647 | |
648 | // |
649 | // String |
650 | // |
651 | |
652 | template <class CharT, class TestFunction, class ExceptionTest> |
653 | void test_string(TestFunction check, ExceptionTest check_exception) { |
654 | std::map<std::basic_string<CharT>, std::basic_string<CharT>> input{ |
655 | {STR("hello" ), STR("HELLO" )}, {STR("world" ), STR("WORLD" )}}; |
656 | |
657 | check(SV(R"({"hello": "HELLO", "world": "WORLD"})" ), SV("{}" ), input); |
658 | check(SV(R"({"hello": "HELLO", "world": "WORLD"}^42)" ), SV("{}^42" ), input); |
659 | check(SV(R"({"hello": "HELLO", "world": "WORLD"}^42)" ), SV("{:}^42" ), input); |
660 | |
661 | // ***** underlying has no format-spec |
662 | |
663 | // *** align-fill & width *** |
664 | check(SV(R"({"hello": "HELLO", "world": "WORLD"} )" ), SV("{:41}" ), input); |
665 | check(SV(R"({"hello": "HELLO", "world": "WORLD"}*****)" ), SV("{:*<41}" ), input); |
666 | check(SV(R"(__{"hello": "HELLO", "world": "WORLD"}___)" ), SV("{:_^41}" ), input); |
667 | check(SV(R"(#####{"hello": "HELLO", "world": "WORLD"})" ), SV("{:#>41}" ), input); |
668 | |
669 | check(SV(R"({"hello": "HELLO", "world": "WORLD"} )" ), SV("{:{}}" ), input, 41); |
670 | check(SV(R"({"hello": "HELLO", "world": "WORLD"}*****)" ), SV("{:*<{}}" ), input, 41); |
671 | check(SV(R"(__{"hello": "HELLO", "world": "WORLD"}___)" ), SV("{:_^{}}" ), input, 41); |
672 | check(SV(R"(#####{"hello": "HELLO", "world": "WORLD"})" ), SV("{:#>{}}" ), input, 41); |
673 | |
674 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
675 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
676 | |
677 | // *** sign *** |
678 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
679 | |
680 | // *** alternate form *** |
681 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
682 | |
683 | // *** zero-padding *** |
684 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
685 | |
686 | // *** precision *** |
687 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
688 | |
689 | // *** locale-specific form *** |
690 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
691 | |
692 | // *** n |
693 | check(SV(R"(__"hello": "HELLO", "world": "WORLD"___)" ), SV("{:_^39n}" ), input); |
694 | |
695 | // *** type *** |
696 | check(SV(R"(__{"hello": "HELLO", "world": "WORLD"}___)" ), SV("{:_^41m}" ), input); |
697 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
698 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
699 | |
700 | for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s" )) |
701 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
702 | |
703 | // ***** Only underlying has a format-spec |
704 | check(SV(R"({"hello": "HELLO" , "world": "WORLD" })" ), SV("{::21}" ), input); |
705 | check(SV(R"({"hello": "HELLO"*****, "world": "WORLD"*****})" ), SV("{::*<21}" ), input); |
706 | check(SV(R"({__"hello": "HELLO"___, __"world": "WORLD"___})" ), SV("{::_^21}" ), input); |
707 | check(SV(R"({#####"hello": "HELLO", #####"world": "WORLD"})" ), SV("{::#>21}" ), input); |
708 | |
709 | check(SV(R"({"hello": "HELLO" , "world": "WORLD" })" ), SV("{::{}}" ), input, 21); |
710 | check(SV(R"({"hello": "HELLO"*****, "world": "WORLD"*****})" ), SV("{::*<{}}" ), input, 21); |
711 | check(SV(R"({__"hello": "HELLO"___, __"world": "WORLD"___})" ), SV("{::_^{}}" ), input, 21); |
712 | check(SV(R"({#####"hello": "HELLO", #####"world": "WORLD"})" ), SV("{::#>{}}" ), input, 21); |
713 | |
714 | check_exception("The format string contains an invalid escape sequence" , SV("{::}<}" ), input); |
715 | check_exception("The fill option contains an invalid value" , SV("{::{<}" ), input); |
716 | |
717 | // *** sign *** |
718 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::-}" ), input); |
719 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::+}" ), input); |
720 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:: }" ), input); |
721 | |
722 | // *** alternate form *** |
723 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::#}" ), input); |
724 | |
725 | // *** zero-padding *** |
726 | check_exception("The width option should not have a leading zero" , SV("{::05}" ), input); |
727 | |
728 | // *** precision *** |
729 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::.}" ), input); |
730 | |
731 | // *** locale-specific form *** |
732 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{::L}" ), input); |
733 | |
734 | // *** type *** |
735 | for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("" )) |
736 | check_exception("The format specifier should consume the input or end with a '}'" , fmt, input); |
737 | |
738 | // ***** Both have a format-spec |
739 | |
740 | check(SV(R"(^^{#####"hello": "HELLO", #####"world": "WORLD"}^^^)" ), SV("{:^^51:#>21}" ), input); |
741 | check(SV(R"(^^{#####"hello": "HELLO", #####"world": "WORLD"}^^^)" ), SV("{:^^{}:#>21}" ), input, 51); |
742 | check(SV(R"(^^{#####"hello": "HELLO", #####"world": "WORLD"}^^^)" ), SV("{:^^{}:#>{}}" ), input, 51, 21); |
743 | |
744 | check_exception( |
745 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>21}" ), input); |
746 | check_exception( |
747 | "The argument index value is too large for the number of arguments supplied" , SV("{:^^{}:#>{}}" ), input, 51); |
748 | } |
749 | |
750 | // |
751 | // Handle |
752 | // |
753 | |
754 | template <class CharT, class TestFunction, class ExceptionTest> |
755 | void test_status(TestFunction check, ExceptionTest check_exception) { |
756 | std::unordered_multimap<status, status> input{{status::foobar, status::foo}, {status::foobar, status::bar}}; |
757 | |
758 | check(SV("{0xaa55: 0xaaaa, 0xaa55: 0x5555}" ), SV("{}" ), input); |
759 | check(SV("{0xaa55: 0xaaaa, 0xaa55: 0x5555}^42" ), SV("{}^42" ), input); |
760 | check(SV("{0xaa55: 0xaaaa, 0xaa55: 0x5555}^42" ), SV("{:}^42" ), input); |
761 | |
762 | // ***** underlying has no format-spec |
763 | |
764 | // *** align-fill & width *** |
765 | check(SV("{0xaa55: 0xaaaa, 0xaa55: 0x5555} " ), SV("{:37}" ), input); |
766 | check(SV("{0xaa55: 0xaaaa, 0xaa55: 0x5555}*****" ), SV("{:*<37}" ), input); |
767 | check(SV("__{0xaa55: 0xaaaa, 0xaa55: 0x5555}___" ), SV("{:_^37}" ), input); |
768 | check(SV("#####{0xaa55: 0xaaaa, 0xaa55: 0x5555}" ), SV("{:#>37}" ), input); |
769 | |
770 | check(SV("{0xaa55: 0xaaaa, 0xaa55: 0x5555} " ), SV("{:{}}" ), input, 37); |
771 | check(SV("{0xaa55: 0xaaaa, 0xaa55: 0x5555}*****" ), SV("{:*<{}}" ), input, 37); |
772 | check(SV("__{0xaa55: 0xaaaa, 0xaa55: 0x5555}___" ), SV("{:_^{}}" ), input, 37); |
773 | check(SV("#####{0xaa55: 0xaaaa, 0xaa55: 0x5555}" ), SV("{:#>{}}" ), input, 37); |
774 | |
775 | check_exception("The format string contains an invalid escape sequence" , SV("{:}<}" ), input); |
776 | check_exception("The fill option contains an invalid value" , SV("{:{<}" ), input); |
777 | |
778 | // *** sign *** |
779 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:-}" ), input); |
780 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:+}" ), input); |
781 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{: }" ), input); |
782 | |
783 | // *** alternate form *** |
784 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:#}" ), input); |
785 | |
786 | // *** zero-padding *** |
787 | check_exception("The width option should not have a leading zero" , SV("{:0}" ), input); |
788 | |
789 | // *** precision *** |
790 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:.}" ), input); |
791 | |
792 | // *** locale-specific form *** |
793 | check_exception("The format specifier should consume the input or end with a '}'" , SV("{:L}" ), input); |
794 | |
795 | // *** n |
796 | check(SV("__0xaa55: 0xaaaa, 0xaa55: 0x5555___" ), SV("{:_^35n}" ), input); |
797 | |
798 | // *** type *** |
799 | check(SV("__{0xaa55: 0xaaaa, 0xaa55: 0x5555}___" ), SV("{:_^37}" ), input); // the m type does the same as the default. |
800 | check_exception("Type s requires character type as formatting argument" , SV("{:s}" ), input); |
801 | check_exception("Type ?s requires character type as formatting argument" , SV("{:?s}" ), input); |
802 | |
803 | // Underlying can't have a format-spec |
804 | } |
805 | |
806 | // |
807 | // Adaptor |
808 | // |
809 | |
810 | class adaptor { |
811 | using adaptee = std::map<int, int>; |
812 | |
813 | public: |
814 | using key_type = typename adaptee::key_type; |
815 | using mapped_type = typename adaptee::mapped_type; |
816 | using iterator = typename adaptee::iterator; |
817 | |
818 | iterator begin() { return data_.begin(); } |
819 | iterator end() { return data_.end(); } |
820 | |
821 | explicit adaptor(std::map<int, int>&& data) : data_(std::move(data)) {} |
822 | |
823 | private: |
824 | adaptee data_; |
825 | }; |
826 | |
827 | static_assert(std::format_kind<adaptor> == std::range_format::map); |
828 | |
829 | template <class CharT, class TestFunction, class ExceptionTest> |
830 | void test_adaptor(TestFunction check, ExceptionTest check_exception) { |
831 | test_int<CharT>(check, check_exception, adaptor{std::map<int, int>{{1, -1}, {42, -42}, {-42, 42}}}); |
832 | } |
833 | |
834 | // |
835 | // Driver |
836 | // |
837 | |
838 | template <class CharT, class TestFunction, class ExceptionTest> |
839 | void format_tests(TestFunction check, ExceptionTest check_exception) { |
840 | test_char<CharT>(check, check_exception); |
841 | #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
842 | if (std::same_as<CharT, wchar_t>) // avoid testing twice |
843 | test_char_to_wchar(check, check_exception); |
844 | #endif |
845 | test_bool<CharT>(check, check_exception); |
846 | test_int<CharT>(check, check_exception); |
847 | test_floating_point<CharT>(check, check_exception); |
848 | test_pointer<CharT>(check, check_exception); |
849 | test_string<CharT>(check, check_exception); |
850 | |
851 | test_status<CharT>(check, check_exception); |
852 | |
853 | test_adaptor<CharT>(check, check_exception); |
854 | } |
855 | |
856 | #endif // TEST_STD_UTILITIES_FORMAT_FORMAT_RANGE_FORMAT_RANGE_FMTMAP_FORMAT_FUNCTIONS_TESTS_H |
857 | |