]>
Commit | Line | Data |
---|---|---|
37a4c5c2 | 1 | // { dg-options "-fexec-charset=UTF-8" } |
1d9454ab | 2 | // { dg-do run { target c++20 } } |
51d702f3 | 3 | // { dg-add-options no_pch } |
1d9454ab JW |
4 | |
5 | #include <format> | |
02e86035 JW |
6 | |
7 | #ifndef __cpp_lib_format | |
8 | # error "Feature test macro for std::format is missing in <format>" | |
cdf45e00 | 9 | #elif __cpp_lib_format < 202110L |
02e86035 | 10 | # error "Feature test macro for std::format has wrong value in <format>" |
96f789d2 | 11 | #elif __cplusplus > 202302L && __cpp_lib_format < 202311L |
3836df7e | 12 | # error "Feature test macro for std::format has wrong value in <format>" |
02e86035 JW |
13 | #endif |
14 | ||
74a0dab1 JW |
15 | #ifndef __cpp_lib_format_uchar |
16 | # error "Feature test macro for formatting chars as integers is missing in <format>" | |
17 | #elif __cpp_lib_format_uchar < 202311L | |
18 | # error "Feature test macro for formatting chars as integers has wrong value in <format>" | |
19 | #endif | |
20 | ||
02e86035 JW |
21 | #undef __cpp_lib_format |
22 | #include <version> | |
23 | #ifndef __cpp_lib_format | |
24 | # error "Feature test macro for std::format is missing in <version>" | |
cdf45e00 | 25 | #elif __cpp_lib_format < 202110L |
02e86035 | 26 | # error "Feature test macro for std::format has wrong value in <version>" |
96f789d2 | 27 | #elif __cplusplus > 202302L && __cpp_lib_format < 202311L |
3836df7e | 28 | # error "Feature test macro for std::format has wrong value in <version>" |
02e86035 JW |
29 | #endif |
30 | ||
74a0dab1 JW |
31 | #ifndef __cpp_lib_format_uchar |
32 | # error "Feature test macro for formatting chars as integers is missing in <version>" | |
33 | #elif __cpp_lib_format_uchar < 202311L | |
34 | # error "Feature test macro for formatting chars as integers has wrong value in <version>" | |
35 | #endif | |
36 | ||
1d9454ab JW |
37 | #include <string> |
38 | #include <limits> | |
39 | #include <cstdint> | |
ce86d967 | 40 | #include <cstdio> |
1d9454ab JW |
41 | #include <testsuite_hooks.h> |
42 | ||
43 | void | |
44 | test_no_args() | |
45 | { | |
46 | std::string s; | |
47 | s = std::format("disco"); | |
48 | VERIFY( s == "disco" ); | |
49 | ||
50 | s = std::format("}} machine {{ funk }} specialists {{"); | |
51 | VERIFY( s == "} machine { funk } specialists {" ); | |
52 | ||
53 | s = std::format("128bpm }}"); | |
54 | VERIFY( s == "128bpm }" ); | |
55 | } | |
56 | ||
57 | void | |
58 | test_unescaped() | |
59 | { | |
60 | #ifdef __cpp_exceptions | |
61 | for (auto f : { "{", "}", "{{{", "{{}", "}{", "{{{{{" }) | |
62 | try { | |
63 | (void) std::vformat(f, std::make_format_args()); | |
64 | VERIFY( false ); | |
65 | } catch (const std::format_error& e) { | |
66 | std::string what = e.what(); | |
67 | VERIFY( what.find("unmatched") != what.npos ); | |
68 | } | |
69 | #endif | |
70 | } | |
71 | ||
72 | struct brit_punc : std::numpunct<char> | |
73 | { | |
74 | std::string do_grouping() const override { return "\3\3"; } | |
75 | char do_thousands_sep() const override { return ','; } | |
76 | std::string do_truename() const override { return "yes mate"; } | |
77 | std::string do_falsename() const override { return "nah bruv"; } | |
78 | }; | |
79 | ||
80 | void | |
81 | test_std_examples() | |
82 | { | |
83 | using namespace std; | |
84 | ||
85 | string s = format("{0}-{{", 8); // value of s is "8-{" | |
86 | VERIFY( s == "8-{" ); | |
87 | ||
88 | // align | |
89 | { | |
90 | char c = 120; | |
91 | string s0 = format("{:6}", 42); | |
92 | VERIFY(s0 == " 42"); | |
93 | string s1 = format("{:6}", 'x'); | |
94 | VERIFY(s1 == "x "); | |
95 | string s2 = format("{:*<6}", 'x'); | |
96 | VERIFY(s2 == "x*****"); | |
97 | string s3 = format("{:*>6}", 'x'); | |
98 | VERIFY(s3 == "*****x"); | |
99 | string s4 = format("{:*^6}", 'x'); | |
100 | VERIFY(s4 == "**x***"); | |
101 | string s5 = format("{:6d}", c); | |
102 | VERIFY(s5 == " 120"); | |
103 | string s6 = format("{:6}", true); | |
104 | VERIFY(s6 == "true "); | |
37a4c5c2 JW |
105 | string s7 = format("{:*<6.3}", "123456"); |
106 | VERIFY( s7 == "123***" ); | |
107 | string s8 = format("{:02}", 1234); | |
108 | VERIFY( s8 == "1234" ); | |
109 | string s9 = format("{:*<}", "12"); | |
110 | VERIFY( s9 == "12" ); | |
111 | string sA = format("{:*<6}", "12345678"); | |
112 | VERIFY( sA == "12345678" ); | |
113 | string sB = format("{:🤡^6}", "x"); | |
114 | VERIFY( sB == "🤡🤡x🤡🤡🤡" ); | |
115 | string sC = format("{:*^6}", "🤡🤡🤡"); | |
116 | VERIFY( sC == "🤡🤡🤡" ); | |
1d9454ab JW |
117 | } |
118 | ||
119 | // sign | |
120 | { | |
121 | double inf = numeric_limits<double>::infinity(); | |
122 | double nan = numeric_limits<double>::quiet_NaN(); | |
123 | string s0 = format("{0:},{0:+},{0:-},{0: }", 1); | |
124 | VERIFY(s0 == "1,+1,1, 1"); | |
125 | string s1 = format("{0:},{0:+},{0:-},{0: }", -1); | |
126 | VERIFY(s1 == "-1,-1,-1,-1"); | |
127 | string s2 = format("{0:},{0:+},{0:-},{0: }", inf); | |
128 | VERIFY(s2 == "inf,+inf,inf, inf"); | |
129 | string s3 = format("{0:},{0:+},{0:-},{0: }", nan); | |
130 | VERIFY(s3 == "nan,+nan,nan, nan"); | |
131 | } | |
132 | ||
133 | // alternate form and zero fill | |
134 | { | |
135 | char c = 120; | |
136 | string s1 = format("{:+06d}", c); | |
137 | VERIFY(s1 == "+00120"); | |
138 | string s2 = format("{:#06x}", 0xa); | |
139 | VERIFY(s2 == "0x000a"); | |
140 | string s3 = format("{:<06}", -42); | |
141 | VERIFY(s3 == "-42 "); // 0 is ignored because of < alignment | |
142 | } | |
143 | ||
144 | // integer presentation types | |
145 | { | |
146 | // Change global locale so "{:L}" adds digit separators. | |
147 | std::locale::global(std::locale({}, new brit_punc)); | |
148 | ||
149 | string s0 = format("{}", 42); | |
150 | VERIFY(s0 == "42"); | |
151 | string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42); | |
152 | VERIFY(s1 == "101010 42 52 2a"); | |
153 | string s2 = format("{0:#x} {0:#X}", 42); | |
154 | VERIFY(s2 == "0x2a 0X2A"); | |
155 | string s3 = format("{:L}", 1234); | |
156 | VERIFY(s3 == "1,234"); | |
157 | ||
48e21e87 JW |
158 | // Test locale's "byte-and-a-half" grouping (Imperial word? tribble?). |
159 | string s4 = format("{:#Lx}", 0xfffff); | |
160 | VERIFY(s4 == "0xff,fff"); | |
161 | ||
1d9454ab JW |
162 | // Restore |
163 | std::locale::global(std::locale::classic()); | |
f89cfdb2 JW |
164 | |
165 | string s5 = format("{}", -100); // PR libstdc++/114325 | |
166 | VERIFY(s5 == "-100"); | |
167 | string s6 = format("{:d} {:d}", -123, 999); | |
168 | VERIFY(s6 == "-123 999"); | |
1d9454ab JW |
169 | } |
170 | } | |
171 | ||
172 | void | |
173 | test_alternate_forms() | |
174 | { | |
175 | std::string s; | |
176 | ||
177 | s = std::format("{0:#b} {0:+#B} {0:#o} {0:#x} {0:+#X} {0: #d}", 42); | |
178 | VERIFY( s == "0b101010 +0B101010 052 0x2a +0X2A 42" ); | |
179 | s = std::format("{0:#b} {0:+#B} {0:#o} {0:#x} {0:+#X} {0: #d}", 0); | |
180 | VERIFY( s == "0b0 +0B0 0 0x0 +0X0 0" ); | |
181 | ||
182 | s = std::format("{0:+#012g} {0:+#014g} {0:+#014g}", 1234.0); | |
183 | VERIFY( s == "+00001234.00 +0000001234.00 +0000001234.00" ); | |
184 | s = std::format("{0:+#0{1}g} {0:+#0{2}g} {0:+#0{2}g}", 1234.5, 12, 14); | |
185 | VERIFY( s == "+00001234.50 +0000001234.50 +0000001234.50" ); | |
186 | ||
187 | s = std::format("{:#.2g}", -0.0); | |
188 | VERIFY( s == "-0.0" ); | |
50bc490c JW |
189 | |
190 | // PR libstdc++/108046 | |
191 | s = std::format("{0:#.0} {0:#.1} {0:#.0g}", 10.0); | |
192 | VERIFY( s == "1.e+01 1.e+01 1.e+01" ); | |
a57439d6 JW |
193 | |
194 | // PR libstdc++/113512 | |
195 | s = std::format("{:#.3g}", 0.025); | |
196 | VERIFY( s == "0.0250" ); | |
197 | s = std::format("{:#07.3g}", 0.02); | |
198 | VERIFY( s == "00.0200" ); | |
1d9454ab JW |
199 | } |
200 | ||
d07bce47 JW |
201 | void |
202 | test_infnan() | |
203 | { | |
204 | double inf = std::numeric_limits<double>::infinity(); | |
205 | double nan = std::numeric_limits<double>::quiet_NaN(); | |
206 | std::string s; | |
207 | s = std::format("{0} {0:e} {0:E} {0:f} {0:F} {0:g} {0:G} {0:a} {0:A}", inf); | |
208 | VERIFY( s == "inf inf INF inf INF inf INF inf INF" ); | |
209 | s = std::format("{0} {0:e} {0:E} {0:f} {0:F} {0:g} {0:G} {0:a} {0:A}", nan); | |
210 | VERIFY( s == "nan nan NAN nan NAN nan NAN nan NAN" ); | |
211 | } | |
212 | ||
1d9454ab JW |
213 | struct euro_punc : std::numpunct<char> |
214 | { | |
215 | std::string do_grouping() const override { return "\3\3"; } | |
216 | char do_thousands_sep() const override { return '.'; } | |
217 | char do_decimal_point() const override { return ','; } | |
218 | }; | |
219 | ||
220 | void | |
221 | test_locale() | |
222 | { | |
223 | // The default C locale. | |
224 | std::locale cloc = std::locale::classic(); | |
225 | // A custom locale using comma digit separators. | |
226 | std::locale bloc(cloc, new brit_punc); | |
227 | // A custom locale using period digit separators. | |
228 | std::locale eloc(cloc, new euro_punc); | |
229 | ||
230 | std::string s; | |
231 | ||
232 | // Change the global locale: | |
233 | std::locale::global(bloc); | |
234 | // Format using the global locale: | |
235 | s = std::format("{0:L} {0:Lx} {0:Lb}", 12345); | |
236 | VERIFY( s == "12,345 3,039 11,000,000,111,001" ); | |
237 | s = std::format("{0:L} {0:.7Lg} {0:La}", 12345.6789); | |
238 | VERIFY( s == "12,345.6789 12,345.68 1.81cd6e631f8a1p+13" ); | |
239 | ||
240 | s = std::format("{0:s} {0:L} {1:Ls} {0:Ld}", true, false); | |
241 | VERIFY( s == "true yes mate nah bruv 1" ); | |
242 | ||
243 | // Format using a specific locale: | |
244 | s = std::format(eloc, "{0:L} {0:Lx} {0:Lb}", 12345); | |
245 | VERIFY( s == "12.345 3.039 11.000.000.111.001" ); | |
246 | s = std::format(eloc, "{0:L} {0:.7LG} {0:La}", 12345.6789); | |
247 | VERIFY( s == "12.345,6789 12.345,68 1,81cd6e631f8a1p+13" ); | |
248 | ||
249 | s = std::format(eloc, "{0:#Lg} {0:+#.3Lg} {0:#08.4Lg}", -1234.); | |
250 | VERIFY( s == "-1.234,00 -1,23e+03 -01.234," ); | |
251 | ||
f48a5423 JW |
252 | s = std::format(cloc, "{:05L}", -1.0); // PR libstdc++/110968 |
253 | VERIFY( s == "-0001" ); | |
254 | ||
a0bc71e4 JW |
255 | // PR libstdc++/114863 grouping applied to nan and inf |
256 | double inf = std::numeric_limits<double>::infinity(); | |
257 | s = std::format(eloc, "{0:Le} {0:Lf} {0:Lg}", -inf); | |
258 | VERIFY( s == "-inf -inf -inf" ); | |
259 | double nan = std::numeric_limits<double>::quiet_NaN(); | |
260 | s = std::format(eloc, "{0:Le} {0:Lf} {0:Lg}", -nan); | |
261 | VERIFY( s == "-nan -nan -nan" ); | |
262 | ||
1d9454ab JW |
263 | // Restore |
264 | std::locale::global(cloc); | |
265 | } | |
266 | ||
267 | void | |
268 | test_width() | |
269 | { | |
270 | std::string s; | |
271 | ||
272 | s = std::format("{:4}", ""); | |
273 | VERIFY( s == " " ); | |
274 | s = std::format("{:{}}", "", 3); | |
275 | VERIFY( s == " " ); | |
628ba410 JW |
276 | s = std::format("{:{}}|{:{}}", 1, 2, 3, 4); |
277 | VERIFY( s == " 1| 3" ); | |
1d9454ab JW |
278 | s = std::format("{1:{0}}", 2, ""); |
279 | VERIFY( s == " " ); | |
280 | s = std::format("{:03}", 9); | |
281 | VERIFY( s == "009" ); | |
282 | ||
283 | s = std::format("DR {0:{1}}: allow width {1} from arg-id", 3721, 0); | |
284 | VERIFY( s == "DR 3721: allow width 0 from arg-id" ); | |
285 | ||
286 | try { | |
287 | s = std::format("Negative width is an error: {0:{1}}", 123, -1); | |
288 | VERIFY(false); | |
289 | } catch (const std::format_error&) { | |
290 | } | |
291 | ||
292 | try { | |
2a8ee259 JW |
293 | bool no = false, yes = true; |
294 | auto args = std::make_format_args(no, yes); | |
1d9454ab JW |
295 | s = std::vformat("DR 3720: restrict type of width arg-id {0:{1}}", args); |
296 | VERIFY(false); | |
297 | } catch (const std::format_error&) { | |
298 | } | |
299 | ||
300 | try { | |
2a8ee259 JW |
301 | char wat = '?', bang = '!'; |
302 | auto args = std::make_format_args(wat, bang); | |
1d9454ab JW |
303 | s = std::vformat("DR 3720: restrict type of width arg-id {0:{1}}", args); |
304 | VERIFY(false); | |
305 | } catch (const std::format_error&) { | |
306 | } | |
307 | } | |
308 | ||
52de6aa1 JW |
309 | void |
310 | test_char() | |
311 | { | |
312 | std::string s; | |
313 | ||
314 | s = std::format("{}", 'a'); | |
315 | VERIFY( s == "a" ); | |
316 | ||
317 | s = std::format("{:c} {:d} {:o}", 'b', '\x17', '\x3f'); | |
318 | VERIFY( s == "b 23 77" ); | |
319 | ||
320 | s = std::format("{:#d} {:#o}", '\x17', '\x3f'); | |
321 | VERIFY( s == "23 077" ); | |
322 | ||
323 | s = std::format("{:04d} {:04o}", '\x17', '\x3f'); | |
324 | VERIFY( s == "0023 0077" ); | |
325 | ||
326 | s = std::format("{:b} {:B} {:#b} {:#B}", '\xff', '\xa0', '\x17', '\x3f'); | |
74a0dab1 | 327 | VERIFY( s == "11111111 10100000 0b10111 0B111111" ); |
52de6aa1 JW |
328 | |
329 | s = std::format("{:x} {:#x} {:#X}", '\x12', '\x34', '\x45'); | |
330 | VERIFY( s == "12 0x34 0X45" ); | |
74a0dab1 JW |
331 | |
332 | // P2909R4 Fix formatting of code units as integers (Dude, where’s my char?) | |
333 | // char and wchar_t should be converted to unsigned when formatting them | |
334 | // with an integer presentation type. | |
335 | s = std::format("{0:b} {0:B} {0:d} {0:o} {0:x} {0:X}", '\xf0'); | |
336 | VERIFY( s == "11110000 11110000 240 360 f0 F0" ); | |
52de6aa1 JW |
337 | } |
338 | ||
1d9454ab JW |
339 | void |
340 | test_wchar() | |
341 | { | |
342 | using namespace std::literals; | |
343 | std::wstring s; | |
344 | ||
52de6aa1 JW |
345 | s = std::format(L"{}", L'a'); |
346 | VERIFY( s == L"a" ); | |
347 | ||
1d9454ab JW |
348 | s = std::format(L"{} {} {} {} {} {}", L'0', 1, 2LL, 3.4, L"five", L"six"s); |
349 | VERIFY( s == L"0 1 2 3.4 five six" ); | |
350 | ||
351 | std::locale loc; | |
352 | s = std::format(loc, L"{:L} {:.3s}{:Lc}", true, L"data"sv, '.'); | |
353 | VERIFY( s == L"true dat." ); | |
4a2b2625 JW |
354 | |
355 | s = std::format(L"{}", 0.0625); | |
356 | VERIFY( s == L"0.0625" ); | |
357 | s = std::format(L"{}", 0.25); | |
358 | VERIFY( s == L"0.25" ); | |
023a62b7 JW |
359 | s = std::format(L"{:+a} {:A}", 0x1.23p45, -0x1.abcdefp-15); |
360 | VERIFY( s == L"+1.23p+45 -1.ABCDEFP-15" ); | |
361 | ||
362 | double inf = std::numeric_limits<double>::infinity(); | |
363 | double nan = std::numeric_limits<double>::quiet_NaN(); | |
364 | s = std::format(L"{0} {0:F} {1} {1:E}", -inf, -nan); | |
365 | VERIFY( s == L"-inf -INF -nan -NAN" ); | |
366 | ||
367 | s = std::format(L"{0:#b} {0:#B} {0:#x} {0:#X}", 99); | |
368 | VERIFY( s == L"0b1100011 0B1100011 0x63 0X63" ); | |
74a0dab1 JW |
369 | |
370 | // P2909R4 Fix formatting of code units as integers (Dude, where’s my char?) | |
371 | s = std::format(L"{:d} {:d}", wchar_t(-1), char(-1)); | |
372 | VERIFY( s.find('-') == std::wstring::npos ); | |
1d9454ab JW |
373 | } |
374 | ||
375 | void | |
376 | test_minmax() | |
377 | { | |
c68c468e | 378 | auto check = []<typename T, typename U = std::make_unsigned_t<T>>(T, U = 0) { |
1d9454ab JW |
379 | const int digits = std::numeric_limits<T>::digits; |
380 | const std::string zeros(digits, '0'); | |
381 | const std::string ones(digits, '1'); | |
382 | auto s = std::format("{:b}" , std::numeric_limits<T>::min()); | |
383 | VERIFY( s == "-1" + zeros ); | |
384 | s = std::format("{:b}" , std::numeric_limits<T>::max()); | |
385 | VERIFY( s == ones ); | |
1d9454ab JW |
386 | s = std::format("{:0{}b}" , std::numeric_limits<U>::min(), digits + 1); |
387 | VERIFY( s == '0' + zeros ); | |
388 | s = std::format("{:b}" , std::numeric_limits<U>::max()); | |
389 | VERIFY( s == '1' + ones ); | |
390 | }; | |
db42a0a9 | 391 | check((signed char)(0)); // int8_t is char on Solaris, see PR 113450 |
1d9454ab JW |
392 | check(std::int16_t(0)); |
393 | check(std::int32_t(0)); | |
394 | check(std::int64_t(0)); | |
395 | #ifdef __SIZEOF_INT128__ | |
c68c468e JW |
396 | // std::make_unsigned_t<__int128> is invalid for strict -std=c++20 mode, |
397 | // so pass a second argument of the unsigned type. | |
398 | check(__int128(0), (unsigned __int128)(0)); | |
1d9454ab JW |
399 | #endif |
400 | } | |
401 | ||
402 | void | |
403 | test_p1652r1() // printf corner cases in std::format | |
404 | { | |
405 | std::string s; | |
406 | ||
407 | // Problem 1: "#o" specification should not print 0 as "00" | |
408 | s = std::format("{:#o}", 0); | |
409 | VERIFY( s == "0" ); | |
410 | ||
411 | // Problem 2: 'c' should be able to print 65 as "A" (ASCII) | |
412 | int c = 'A'; | |
413 | s = std::format("{:c}", c); | |
414 | VERIFY( s == "A" ); | |
415 | ||
416 | // Problem 3: "-000nan" is not a floating point value | |
417 | double nan = std::numeric_limits<double>::quiet_NaN(); | |
418 | try { | |
419 | s = std::vformat("{:0=6}", std::make_format_args(nan)); | |
420 | VERIFY( false ); | |
421 | } catch (const std::format_error&) { | |
422 | } | |
423 | ||
424 | s = std::format("{:06}", nan); | |
425 | VERIFY( s == " nan" ); | |
426 | ||
427 | // Problem 4: bool needs a type format specifier | |
428 | s = std::format("{:s}", true); | |
429 | VERIFY( s == "true" ); | |
430 | ||
431 | // Problem 5: double does not roundtrip float | |
432 | s = std::format("{}", 3.31f); | |
433 | VERIFY( s == "3.31" ); | |
434 | } | |
435 | ||
628ba410 JW |
436 | void |
437 | test_pointer() | |
438 | { | |
439 | void* p = nullptr; | |
440 | const void* pc = p; | |
441 | std::string s, str_int; | |
442 | ||
52de6aa1 JW |
443 | s = std::format("{}", p); |
444 | VERIFY( s == "0x0" ); | |
445 | ||
628ba410 JW |
446 | s = std::format("{} {} {}", p, pc, nullptr); |
447 | VERIFY( s == "0x0 0x0 0x0" ); | |
448 | s = std::format("{:p} {:p} {:p}", p, pc, nullptr); | |
449 | VERIFY( s == "0x0 0x0 0x0" ); | |
450 | s = std::format("{:4},{:5},{:6}", p, pc, nullptr); // width | |
451 | VERIFY( s == " 0x0, 0x0, 0x0" ); | |
452 | s = std::format("{:<4},{:>5},{:^7}", p, pc, nullptr); // align+width | |
453 | VERIFY( s == "0x0 , 0x0, 0x0 " ); | |
454 | s = std::format("{:o<4},{:o>5},{:o^7}", p, pc, nullptr); // fill+align+width | |
455 | VERIFY( s == "0x0o,oo0x0,oo0x0oo" ); | |
456 | ||
457 | pc = p = &s; | |
458 | str_int = std::format("{:#x}", reinterpret_cast<std::uintptr_t>(p)); | |
459 | s = std::format("{} {} {}", p, pc, nullptr); | |
460 | VERIFY( s == (str_int + ' ' + str_int + " 0x0") ); | |
461 | str_int = std::format("{:#20x}", reinterpret_cast<std::uintptr_t>(p)); | |
462 | s = std::format("{:20} {:20p}", p, pc); | |
463 | VERIFY( s == (str_int + ' ' + str_int) ); | |
464 | ||
72cd15b2 | 465 | #if __cpp_lib_format >= 202304L |
628ba410 JW |
466 | // P2510R3 Formatting pointers |
467 | s = std::format("{:06} {:07P} {:08p}", (void*)0, (const void*)0, nullptr); | |
468 | VERIFY( s == "0x0000 0X00000 0x000000" ); | |
469 | str_int = std::format("{:#016x}", reinterpret_cast<std::uintptr_t>(p)); | |
470 | s = std::format("{:016} {:016}", p, pc); | |
471 | VERIFY( s == (str_int + ' ' + str_int) ); | |
472 | str_int = std::format("{:#016X}", reinterpret_cast<std::uintptr_t>(p)); | |
473 | s = std::format("{:016P} {:016P}", p, pc); | |
474 | VERIFY( s == (str_int + ' ' + str_int) ); | |
475 | #endif | |
476 | } | |
477 | ||
52de6aa1 JW |
478 | void |
479 | test_bool() | |
480 | { | |
481 | std::string s; | |
482 | ||
483 | s = std::format("{}", true); | |
484 | VERIFY( s == "true" ); | |
485 | s = std::format("{:} {:s}", true, false); | |
486 | VERIFY( s == "true false" ); | |
487 | s = std::format("{:b} {:#b}", true, false); | |
488 | VERIFY( s == "1 0b0" ); | |
489 | s = std::format("{:B} {:#B}", false, true); | |
490 | VERIFY( s == "0 0B1" ); | |
491 | s = std::format("{:d} {:#d}", false, true); | |
492 | VERIFY( s == "0 1" ); | |
493 | s = std::format("{:o} {:#o} {:#o}", false, true, false); | |
494 | VERIFY( s == "0 01 0" ); | |
495 | s = std::format("{:x} {:#x} {:#X}", false, true, false); | |
496 | VERIFY( s == "0 0x1 0X0" ); | |
497 | } | |
498 | ||
37a4c5c2 JW |
499 | void |
500 | test_unicode() | |
501 | { | |
502 | // Similar to sC example in test_std_examples, but not from the standard. | |
503 | // Verify that the character "🤡" has estimated field width 2, | |
504 | // rather than estimated field width equal to strlen("🤡"), which would be 4. | |
505 | std::string sC = std::format("{:*<3}", "🤡"); | |
506 | VERIFY( sC == "🤡*" ); | |
507 | ||
508 | // Verify that "£" has estimated field width 1, not strlen("£") == 2. | |
509 | std::string sL = std::format("{:*<3}", "£"); | |
510 | VERIFY( sL == "£**" ); | |
511 | ||
512 | // Verify that precision is measured in field width units (column positions) | |
513 | // not bytes. The result should contain complete Unicode characters, not be | |
514 | // truncated in the middle of a multibyte UTF-8 sequence. The string "£" has | |
515 | // field width 1 despite being 2 bytes, and the string "🤡" has field width 2 | |
516 | // and so cannot be formatted into a replacement field using .1 precision. | |
517 | std::string sP = std::format("{:1.1} {:*<1.1}", "£", "🤡"); | |
518 | VERIFY( sP == "£ *" ); | |
519 | sP = std::format("{:*<2.1} {:*<2.1}", "£", "🤡"); | |
520 | VERIFY( sP == "£* **" ); | |
521 | ||
522 | // Verify field width handling for extended grapheme clusters, | |
523 | // and that a cluster gets output as a single item, not truncated. | |
524 | std::string sG = std::format("{:*>2.1}", "\u006f\u0302\u0323!"); | |
525 | VERIFY( sG == "*\u006f\u0302\u0323" ); | |
526 | ||
527 | // Examples from P1868R2 | |
528 | // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1868r2.html | |
529 | const char* inputs[][2] = { | |
530 | {"\x41", " \u0041"}, | |
531 | {"\xC3\x81", " \u00c1"}, | |
532 | {"\x41\xCC\x81", " \u0041\u0301"}, | |
533 | {"\xc4\xb2", " \u0132"}, | |
534 | {"\xce\x94", " \u0394"}, | |
535 | {"\xd0\xa9", " \u0429"}, | |
536 | {"\xd7\x90", " \u05D0"}, | |
537 | {"\xd8\xb4", " \u0634"}, | |
538 | {"\xe3\x80\x89", " \u3009"}, | |
539 | {"\xe7\x95\x8c", " \u754C"}, | |
540 | {"\xf0\x9f\xa6\x84", " \U0001F984"}, | |
541 | {"\xf0\x9f\x91\xa8\xe2\x80\x8d\xf0\x9f\x91\xa9\xe2\x80\x8d" | |
542 | "\xf0\x9f\x91\xa7\xe2\x80\x8d\xf0\x9f\x91\xa6", | |
543 | " \U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466" } | |
544 | }; | |
545 | for (auto& input : inputs) | |
546 | { | |
547 | std::string sA = std::format("{:>5}", input[0]); | |
548 | VERIFY( sA == input[1] ); | |
549 | } | |
550 | } | |
551 | ||
1d9454ab JW |
552 | int main() |
553 | { | |
554 | test_no_args(); | |
555 | test_unescaped(); | |
556 | test_std_examples(); | |
557 | test_alternate_forms(); | |
558 | test_locale(); | |
559 | test_width(); | |
52de6aa1 | 560 | test_char(); |
1d9454ab JW |
561 | test_wchar(); |
562 | test_minmax(); | |
563 | test_p1652r1(); | |
628ba410 | 564 | test_pointer(); |
52de6aa1 | 565 | test_bool(); |
37a4c5c2 | 566 | test_unicode(); |
1d9454ab | 567 | } |