xref: /llvm-project/libcxx/test/std/utilities/format/format.functions/escaped_output.unicode.pass.cpp (revision 9c8f3409494feac1ffc5082a9b32db56d208a9e5)
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 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
9 // UNSUPPORTED: libcpp-has-no-incomplete-format
10 
11 // This version runs the test when the platform has Unicode support.
12 // UNSUPPORTED: libcpp-has-no-unicode
13 
14 // TODO FMT Investigate Windows and AIX issues.
15 // UNSUPPORTED: msvc, target={{.+}}-windows-gnu
16 // UNSUPPORTED: LIBCXX-AIX-FIXME
17 
18 // <format>
19 
20 // This test the debug string type for the formatter specializations for char
21 // and string types. This tests Unicode strings.
22 
23 #include <format>
24 
25 #include <cassert>
26 #include <concepts>
27 #include <iterator>
28 #include <list>
29 #include <vector>
30 
31 #include "test_macros.h"
32 #include "make_string.h"
33 #include "test_format_string.h"
34 #include "assert_macros.h"
35 
36 #ifndef TEST_HAS_NO_LOCALIZATION
37 #  include <iostream>
38 #endif
39 
40 #define SV(S) MAKE_STRING_VIEW(CharT, S)
41 
42 auto test_format = []<class CharT, class... Args>(
43                        std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) {
44   {
45     std::basic_string<CharT> out = std::format(fmt, std::forward<Args>(args)...);
46     TEST_REQUIRE(out == expected,
47                  test_concat_message(
48                      "\nFormat string   ", fmt.get(), "\nExpected output ", expected, "\nActual output   ", out, '\n'));
49   }
50 #ifndef TEST_HAS_NO_LOCALIZATION
51   {
52     std::basic_string<CharT> out = std::format(std::locale(), fmt, std::forward<Args>(args)...);
53     assert(out == expected);
54   }
55 #endif // TEST_HAS_NO_LOCALIZATION
56 };
57 
58 auto test_format_to =
59     []<class CharT, class... Args>(
60         std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) {
61       {
62         std::basic_string<CharT> out(expected.size(), CharT(' '));
63         auto it = std::format_to(out.begin(), fmt, std::forward<Args>(args)...);
64         assert(it == out.end());
65         assert(out == expected);
66       }
67 #ifndef TEST_HAS_NO_LOCALIZATION
68       {
69         std::basic_string<CharT> out(expected.size(), CharT(' '));
70         auto it = std::format_to(out.begin(), std::locale(), fmt, std::forward<Args>(args)...);
71         assert(it == out.end());
72         assert(out == expected);
73       }
74 #endif // TEST_HAS_NO_LOCALIZATION
75       {
76         std::list<CharT> out;
77         std::format_to(std::back_inserter(out), fmt, std::forward<Args>(args)...);
78         assert(std::equal(out.begin(), out.end(), expected.begin(), expected.end()));
79       }
80       {
81         std::vector<CharT> out;
82         std::format_to(std::back_inserter(out), fmt, std::forward<Args>(args)...);
83         assert(std::equal(out.begin(), out.end(), expected.begin(), expected.end()));
84       }
85       {
86         assert(expected.size() < 4096 && "Update the size of the buffer.");
87         CharT out[4096];
88         CharT* it = std::format_to(out, fmt, std::forward<Args>(args)...);
89         assert(std::distance(out, it) == int(expected.size()));
90         // Convert to std::string since output contains '\0' for boolean tests.
91         assert(std::basic_string<CharT>(out, it) == expected);
92       }
93     };
94 
95 auto test_formatted_size =
96     []<class CharT, class... Args>(
97         std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) {
98       {
99         size_t size = std::formatted_size(fmt, std::forward<Args>(args)...);
100         assert(size == expected.size());
101       }
102 #ifndef TEST_HAS_NO_LOCALIZATION
103       {
104         size_t size = std::formatted_size(std::locale(), fmt, std::forward<Args>(args)...);
105         assert(size == expected.size());
106       }
107 #endif // TEST_HAS_NO_LOCALIZATION
108     };
109 
110 auto test_format_to_n =
111     []<class CharT, class... Args>(
112         std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) {
113       {
114         size_t n = expected.size();
115         std::basic_string<CharT> out(n, CharT(' '));
116         std::format_to_n_result result = std::format_to_n(out.begin(), n, fmt, std::forward<Args>(args)...);
117         assert(result.size == static_cast<ptrdiff_t>(expected.size()));
118         assert(result.out == out.end());
119         assert(out == expected);
120       }
121 #ifndef TEST_HAS_NO_LOCALIZATION
122       {
123         size_t n = expected.size();
124         std::basic_string<CharT> out(n, CharT(' '));
125         std::format_to_n_result result =
126             std::format_to_n(out.begin(), n, std::locale(), fmt, std::forward<Args>(args)...);
127         assert(result.size == static_cast<ptrdiff_t>(expected.size()));
128         assert(result.out == out.end());
129         assert(out == expected);
130       }
131 #endif // TEST_HAS_NO_LOCALIZATION
132       {
133         ptrdiff_t n = 0;
134         std::basic_string<CharT> out;
135         std::format_to_n_result result = std::format_to_n(out.begin(), n, fmt, std::forward<Args>(args)...);
136         assert(result.size == static_cast<ptrdiff_t>(expected.size()));
137         assert(result.out == out.end());
138         assert(out.empty());
139       }
140       {
141         ptrdiff_t n = expected.size() / 2;
142         std::basic_string<CharT> out(n, CharT(' '));
143         std::format_to_n_result result = std::format_to_n(out.begin(), n, fmt, std::forward<Args>(args)...);
144         assert(result.size == static_cast<ptrdiff_t>(expected.size()));
145         assert(result.out == out.end());
146         assert(out == expected.substr(0, n));
147       }
148     };
149 
150 template <class CharT>
151 void test_char() {
152   // *** P2286 examples ***
153   test_format(SV("['\\'', '\"']"), SV("[{:?}, {:?}]"), CharT('\''), CharT('"'));
154 
155   // *** Specical cases ***
156   test_format(SV("'\\t'"), SV("{:?}"), CharT('\t'));
157   test_format(SV("'\\n'"), SV("{:?}"), CharT('\n'));
158   test_format(SV("'\\r'"), SV("{:?}"), CharT('\r'));
159   test_format(SV("'\\\\'"), SV("{:?}"), CharT('\\'));
160 
161   test_format(SV("'\\\''"), SV("{:?}"), CharT('\''));
162   test_format(SV("'\"'"), SV("{:?}"), CharT('"')); // only special for string
163 
164   test_format(SV("' '"), SV("{:?}"), CharT(' '));
165 
166   // *** Printable ***
167   test_format(SV("'a'"), SV("{:?}"), CharT('a'));
168   test_format(SV("'b'"), SV("{:?}"), CharT('b'));
169   test_format(SV("'c'"), SV("{:?}"), CharT('c'));
170 
171   // *** Non-printable ***
172 
173   // Control
174   test_format(SV("'\\u{0}'"), SV("{:?}"), CharT('\0'));
175   test_format(SV("'\\u{1f}'"), SV("{:?}"), CharT('\x1f'));
176 
177   // Ill-formed
178   if constexpr (sizeof(CharT) == 1)
179     test_format(SV("'\\x{80}'"), SV("{:?}"), CharT('\x80'));
180 
181 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
182   if constexpr (sizeof(CharT) > 1) {
183     using V = std::basic_string_view<CharT>;
184 
185     // Unicode fitting in a 16-bit wchar_t
186 
187     // *** Non-printable ***
188 
189     // Space_Separator
190     test_format(V{L"'\\u{a0}'"}, L"{:?}", L'\xa0');     // NO-BREAK SPACE
191     test_format(V{L"'\\u{3000}'"}, L"{:?}", L'\x3000'); // IDEOGRAPHIC SPACE
192 
193     // Line_Separator
194     test_format(V{L"'\\u{2028}'"}, L"{:?}", L'\x2028'); // LINE SEPARATOR
195 
196     // Paragraph_Separator
197     test_format(V{L"'\\u{2029}'"}, L"{:?}", L'\x2029'); // PARAGRAPH SEPARATOR
198 
199     // Format
200     test_format(V{L"'\\u{ad}'"}, L"{:?}", L'\xad');     // SOFT HYPHEN
201     test_format(V{L"'\\u{600}'"}, L"{:?}", L'\x600');   // ARABIC NUMBER SIGN
202     test_format(V{L"'\\u{feff}'"}, L"{:?}", L'\xfeff'); // ZERO WIDTH NO-BREAK SPACE
203 
204     if constexpr (sizeof(CharT) == 2) {
205       // Incomplete surrogate pair in UTF-16
206       test_format(V{L"'\\x{d800}'"}, L"{:?}", L'\xd800'); // <surrogate-D800>
207       test_format(V{L"'\\x{dfff}'"}, L"{:?}", L'\xdfff'); // <surrogate-DFFF>
208     } else {
209       test_format(V{L"'\\u{d800}'"}, L"{:?}", L'\xd800'); // <surrogate-D800>
210       test_format(V{L"'\\u{dfff}'"}, L"{:?}", L'\xdfff'); // <surrogate-DFFF>
211     }
212 
213     // Private_Use
214     test_format(V{L"'\\u{e000}'"}, L"{:?}", L'\xe000'); // <private-use-E000>
215     test_format(V{L"'\\u{f8ff}'"}, L"{:?}", L'\xf8ff'); // <private-use-F8FF>
216 
217     // Unassigned
218     test_format(V{L"'\\u{378}'"}, L"{:?}", L'\x378');   // <reserved-0378>
219     test_format(V{L"'\\u{1774}'"}, L"{:?}", L'\x1774'); // <reserved-1774>
220     test_format(V{L"'\\u{ffff}'"}, L"{:?}", L'\xffff'); // <noncharacter-FFFF>
221 
222     // Grapheme Extended
223     test_format(V{L"'\\u{300}'"}, L"{:?}", L'\x300');   // COMBINING GRAVE ACCENT
224     test_format(V{L"'\\u{fe20}'"}, L"{:?}", L'\xfe20'); // VARIATION SELECTOR-1
225   }
226 #  ifndef TEST_SHORT_WCHAR
227   if constexpr (sizeof(CharT) > 2) {
228     static_assert(sizeof(CharT) == 4, "add support for unexpected size");
229     // Unicode fitting in a 32-bit wchar_t
230 
231     constexpr wchar_t x  = 0x1ffff;
232     constexpr uint32_t y = 0x1ffff;
233     static_assert(x == y);
234 
235     using V = std::basic_string_view<CharT>;
236 
237     // *** Non-printable ***
238     // Format
239     test_format(V{L"'\\u{110bd}'"}, L"{:?}", L'\x110bd'); // KAITHI NUMBER SIGN
240     test_format(V{L"'\\u{e007f}'"}, L"{:?}", L'\xe007f'); // CANCEL TAG
241 
242     // Private_Use
243     test_format(V{L"'\\u{f0000}'"}, L"{:?}", L'\xf0000'); // <private-use-F0000>
244     test_format(V{L"'\\u{ffffd}'"}, L"{:?}", L'\xffffd'); // <private-use-FFFFD>
245 
246     test_format(V{L"'\\u{100000}'"}, L"{:?}", L'\x100000'); // <private-use-100000>
247     test_format(V{L"'\\u{10fffd}'"}, L"{:?}", L'\x10fffd'); // <private-use-10FFFD>
248 
249     // Unassigned
250     test_format(V{L"'\\u{1000c}'"}, L"{:?}", L'\x1000c');   // <reserved-1000c>
251     test_format(V{L"'\\u{fffff}'"}, L"{:?}", L'\xfffff');   // <noncharacter-FFFFF>
252     test_format(V{L"'\\u{10fffe}'"}, L"{:?}", L'\x10fffe'); // <noncharacter-10FFFE>
253 
254     // Grapheme Extended
255     test_format(V{L"'\\u{101fd}'"}, L"{:?}", L'\x101fd'); // COMBINING OLD PERMIC LETTER AN
256     test_format(V{L"'\\u{e0100}'"}, L"{:?}", L'\xe0100'); // VARIATION SELECTOR-17
257 
258     // Ill-formed
259     test_format(V{L"'\\x{110000}'"}, L"{:?}", L'\x110000');
260     test_format(V{L"'\\x{ffffffff}'"}, L"{:?}", L'\xffffffff');
261   }
262 #  endif // TEST_SHORT_WCHAR
263 #endif   // TEST_HAS_NO_WIDE_CHARACTERS
264 }
265 
266 template <class CharT>
267 void test_string() {
268   // *** P2286 examples ***
269   test_format(SV("[h\tllo]"), SV("[{}]"), SV("h\tllo"));
270   test_format(SV(R"(["h\tllo"])"), SV("[{:?}]"), SV("h\tllo"));
271   test_format(SV(R"(["Спасибо, Виктор ♥!"])"), SV("[{:?}]"), SV("Спасибо, Виктор ♥!"));
272 
273   test_format(SV(R"(["\u{0} \n \t \u{2} \u{1b}"])"), SV("[{:?}]"), SV("\0 \n \t \x02 \x1b"));
274 
275   if constexpr (sizeof(CharT) == 1) {
276     // Ill-formend UTF-8
277     test_format(SV(R"(["\x{c3}"])"), SV("[{:?}]"), "\xc3");
278     test_format(SV(R"(["\x{c3}("])"), SV("[{:?}]"), "\xc3\x28");
279   } else {
280     // Valid UTF-16 and UTF-32
281     test_format(SV("[\"\u00c3\"]"), SV("[{:?}]"), L"\xc3"); // LATIN CAPITAL LETTER A WITH TILDE
282     test_format(SV("[\"\u00c3(\"]"), SV("[{:?}]"), L"\xc3\x28");
283   }
284 
285   test_format(SV(R"(["����\u{200d}♂\u{fe0f}"])"), SV("[{:?}]"), SV("����‍♂️"));
286 
287   // *** Specical cases ***
288   test_format(SV(R"("\t\n\r\\'\" ")"), SV("{:?}"), SV("\t\n\r\\'\" "));
289 
290   // *** Printable ***
291   test_format(SV(R"("abcdefg")"), SV("{:?}"), SV("abcdefg"));
292 
293   // *** Non-printable ***
294 
295   // Control
296   test_format(SV(R"("\u{0}\u{1f}")"), SV("{:?}"), SV("\0\x1f"));
297 
298   // Ill-formed
299   if constexpr (sizeof(CharT) == 1)
300     test_format(SV(R"("\x{80}")"), SV("{:?}"), SV("\x80"));
301 
302 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
303   if constexpr (sizeof(CharT) > 1) {
304     using V = std::basic_string_view<CharT>;
305 
306     // Unicode fitting in a 16-bit wchar_t
307 
308     // *** Non-printable ***
309 
310     // Space_Separator
311     test_format(V{LR"("\u{a0}\u{3000}")"}, L"{:?}", L"\xa0\x3000");
312 
313     // Line_Separator
314     test_format(V{LR"("\u{2028}")"}, L"{:?}", L"\x2028"); // LINE SEPARATOR
315 
316     // Paragraph_Separator
317     test_format(V{LR"("\u{2029}")"}, L"{:?}", L"\x2029"); // PARAGRAPH SEPARATOR
318 
319     // Format
320     test_format(V{LR"("\u{ad}\u{600}\u{feff}")"}, L"{:?}", L"\xad\x600\xfeff");
321 
322     if constexpr (sizeof(CharT) == 2)
323       // Incomplete surrogate pair in UTF-16
324       test_format(V{LR"("\x{d800}")"}, L"{:?}", L"\xd800");
325     else
326       test_format(V{LR"("\u{d800}")"}, L"{:?}", L"\xd800");
327 
328     // Private_Use
329     test_format(V{LR"("\u{e000}\u{f8ff}")"}, L"{:?}", L"\xe000\xf8ff");
330 
331     // Unassigned
332     test_format(V{LR"("\u{378}\u{1774}\u{ffff}")"}, L"{:?}", L"\x378\x1774\xffff");
333 
334     // Grapheme Extended
335     test_format(V{LR"("\u{300}\u{fe20}")"}, L"{:?}", L"\x300\xfe20");
336   }
337 #  ifndef TEST_SHORT_WCHAR
338   if constexpr (sizeof(CharT) > 2) {
339     static_assert(sizeof(CharT) == 4, "add support for unexpected size");
340     // Unicode fitting in a 32-bit wchar_t
341 
342     constexpr wchar_t x  = 0x1ffff;
343     constexpr uint32_t y = 0x1ffff;
344     static_assert(x == y);
345 
346     using V = std::basic_string_view<CharT>;
347 
348     // *** Non-printable ***
349     // Format
350     test_format(V{LR"("\u{110bd}\u{e007f}")"}, L"{:?}", L"\x110bd\xe007f");
351 
352     // Private_Use
353     test_format(V{LR"("\u{f0000}\u{ffffd}\u{100000}\u{10fffd}")"}, L"{:?}", L"\xf0000\xffffd\x100000\x10fffd");
354 
355     // Unassigned
356     test_format(V{LR"("\u{1000c}\u{fffff}\u{10fffe}")"}, L"{:?}", L"\x1000c\xfffff\x10fffe");
357 
358     // Grapheme Extended
359     test_format(V{LR"("\u{101fd}\u{e0100}")"}, L"{:?}", L"\x101fd\xe0100");
360 
361     // Ill-formed
362     test_format(V{LR"("\x{110000}\x{ffffffff}")"}, L"{:?}", L"\x110000\xffffffff");
363   }
364 #  endif // TEST_SHORT_WCHAR
365 #endif   // TEST_HAS_NO_WIDE_CHARACTERS
366 }
367 
368 template <class CharT, class TestFunction>
369 void test_format_functions(TestFunction check) {
370   // *** align-fill & width ***
371   check(SV(R"(***"hellö")"), SV("{:*>10?}"), SV("hellö")); // ö is LATIN SMALL LETTER O WITH DIAERESIS
372   check(SV(R"(*"hellö"**)"), SV("{:*^10?}"), SV("hellö"));
373   check(SV(R"("hellö"***)"), SV("{:*<10?}"), SV("hellö"));
374 
375   check(SV(R"("hello\u{308}")"), SV("{:*>10?}"), SV("hello\u0308"));
376   check(SV(R"(***"hello\u{308}")"), SV("{:*>17?}"), SV("hello\u0308"));
377   check(SV(R"(*"hello\u{308}"**)"), SV("{:*^17?}"), SV("hello\u0308"));
378   check(SV(R"("hello\u{308}"***)"), SV("{:*<17?}"), SV("hello\u0308"));
379 
380   check(SV(R"("hello ����\u{200d}♂\u{fe0f}")"), SV("{:*>10?}"), SV("hello ����‍♂️"));
381   check(SV(R"(***"hello ����\u{200d}♂\u{fe0f}")"), SV("{:*>30?}"), SV("hello ����‍♂️"));
382   check(SV(R"(*"hello ����\u{200d}♂\u{fe0f}"**)"), SV("{:*^30?}"), SV("hello ����‍♂️"));
383   check(SV(R"("hello ����\u{200d}♂\u{fe0f}"***)"), SV("{:*<30?}"), SV("hello ����‍♂️"));
384 
385   // *** width ***
386   check(SV(R"("hellö"   )"), SV("{:10?}"), SV("hellö"));
387   check(SV(R"("hello\u{308}"   )"), SV("{:17?}"), SV("hello\u0308"));
388   check(SV(R"("hello ����\u{200d}♂\u{fe0f}"   )"), SV("{:30?}"), SV("hello ����‍♂️"));
389 
390   // *** precision ***
391   check(SV(R"("hell)"), SV("{:.5?}"), SV("hellö"));
392   check(SV(R"("hellö)"), SV("{:.6?}"), SV("hellö"));
393   check(SV(R"("hellö")"), SV("{:.7?}"), SV("hellö"));
394 
395   check(SV(R"("hello )"), SV("{:.7?}"), SV("hello ����‍♂️"));
396   check(SV(R"("hello )"), SV("{:.8?}"), SV("hello ����‍♂️")); // shrug is two columns
397   check(SV(R"("hello ����)"), SV("{:.9?}"), SV("hello ����‍♂️"));
398   check(SV(R"("hello ����\)"), SV("{:.10?}"), SV("hello ����‍♂️"));
399   check(SV(R"("hello ����\u{200d})"), SV("{:.17?}"), SV("hello ����‍♂️"));
400   check(SV(R"("hello ����\u{200d}♂)"), SV("{:.18?}"), SV("hello ����‍♂️"));
401   check(SV(R"("hello ����\u{200d}♂\)"), SV("{:.19?}"), SV("hello ����‍♂️"));
402   check(SV(R"("hello ����\u{200d}♂\u{fe0f}")"), SV("{:.28?}"), SV("hello ����‍♂️"));
403 
404   // *** width & precision ***
405   check(SV(R"("hell#########################)"), SV("{:#<30.5?}"), SV("hellö"));
406   check(SV(R"("hellö########################)"), SV("{:#<30.6?}"), SV("hellö"));
407   check(SV(R"("hellö"#######################)"), SV("{:#<30.7?}"), SV("hellö"));
408 
409   check(SV(R"("hello #######################)"), SV("{:#<30.7?}"), SV("hello ����‍♂️"));
410   check(SV(R"("hello #######################)"), SV("{:#<30.8?}"), SV("hello ����‍♂️"));
411   check(SV(R"("hello ����#####################)"), SV("{:#<30.9?}"), SV("hello ����‍♂️"));
412   check(SV(R"("hello ����\####################)"), SV("{:#<30.10?}"), SV("hello ����‍♂️"));
413   check(SV(R"("hello ����\u{200d}#############)"), SV("{:#<30.17?}"), SV("hello ����‍♂️"));
414   check(SV(R"("hello ����\u{200d}♂############)"), SV("{:#<30.18?}"), SV("hello ����‍♂️"));
415   check(SV(R"("hello ����\u{200d}♂\###########)"), SV("{:#<30.19?}"), SV("hello ����‍♂️"));
416   check(SV(R"("hello ����\u{200d}♂\u{fe0f}"###)"), SV("{:#<30.28?}"), SV("hello ����‍♂️"));
417 }
418 
419 template <class CharT>
420 void test() {
421   test_char<CharT>();
422   test_string<CharT>();
423 
424   test_format_functions<CharT>(test_format);
425   test_format_functions<CharT>(test_format_to);
426   test_format_functions<CharT>(test_formatted_size);
427   test_format_functions<CharT>(test_format_to_n);
428 }
429 
430 static void test_ill_formed_utf8() {
431   using namespace std::literals;
432 
433   // Too few code units
434   test_format(R"("\x{df}")"sv, "{:?}", "\xdf");
435   test_format(R"("\x{ef}")"sv, "{:?}", "\xef");
436   test_format(R"("\x{ef}\x{bf}")"sv, "{:?}", "\xef\xbf");
437   test_format(R"("\x{f7}")"sv, "{:?}", "\xf7");
438   test_format(R"("\x{f7}\x{bf}")"sv, "{:?}", "\xf7\xbf");
439   test_format(R"("\x{f7}\x{bf}\x{bf}")"sv, "{:?}", "\xf7\xbf\xbf");
440 
441   // Invalid continuation byte
442   test_format(R"("\x{df}a")"sv,
443               "{:?}",
444               "\xdf"
445               "a");
446   test_format(R"("\x{ef}a")"sv,
447               "{:?}",
448               "\xef"
449               "a");
450   test_format(R"("\x{ef}\x{bf}a")"sv,
451               "{:?}",
452               "\xef\xbf"
453               "a");
454   test_format(R"("\x{f7}a")"sv,
455               "{:?}",
456               "\xf7"
457               "a");
458   test_format(R"("\x{f7}\x{bf}a")"sv,
459               "{:?}",
460               "\xf7\xbf"
461               "a");
462   test_format(R"("\x{f7}\x{bf}\x{bf}a")"sv,
463               "{:?}",
464               "\xf7\xbf\xbf"
465               "a");
466 
467   // Code unit out of range
468   test_format(R"("\u{10ffff}")"sv, "{:?}", "\xf4\x8f\xbf\xbf");               // last valid code point
469   test_format(R"("\x{f4}\x{90}\x{80}\x{80}")"sv, "{:?}", "\xf4\x90\x80\x80"); // first invalid code point
470   test_format(R"("\x{f5}\x{b1}\x{b2}\x{b3}")"sv, "{:?}", "\xf5\xb1\xb2\xb3");
471   test_format(R"("\x{f7}\x{bf}\x{bf}\x{bf}")"sv, "{:?}", "\xf7\xbf\xbf\xbf"); // largest encoded code point
472 }
473 
474 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
475 #  ifdef _LIBCPP_SHORT_WCHAR
476 static void test_ill_formed_utf16() {
477   using namespace std::literals;
478 
479   // Too few code units
480   test_format(LR"("\x{d800}")"sv, L"{:?}", L"\xd800");
481   test_format(LR"("\x{dbff}")"sv, L"{:?}", L"\xdbff");
482 
483   // Start with low surrogate pair
484   test_format(LR"("\x{dc00}a")"sv,
485               L"{:?}",
486               L"\xdc00"
487               "a");
488   test_format(LR"("\x{dfff}a")"sv,
489               L"{:?}",
490               L"\xdfff"
491               "a");
492 
493   // Only high surrogate pair
494   test_format(LR"("\x{d800}a")"sv,
495               L"{:?}",
496               L"\xd800"
497               "a");
498   test_format(LR"("\x{dbff}a")"sv,
499               L"{:?}",
500               L"\xdbff"
501               "a");
502 }
503 #  else // _LIBCPP_SHORT_WCHAR
504 static void test_ill_formed_utf32() {
505   using namespace std::literals;
506 
507   test_format(LR"("\u{10ffff}")"sv, L"{:?}", L"\x10ffff");     // last valid code point
508   test_format(LR"("\x{110000}")"sv, L"{:?}", L"\x110000");     // first invalid code point
509   test_format(LR"("\x{ffffffff}")"sv, L"{:?}", L"\xffffffff"); // largest encoded code point
510 }
511 
512 #  endif // _LIBCPP_SHORT_WCHAR
513 #endif   // TEST_HAS_NO_WIDE_CHARACTERS
514 
515 int main(int, char**) {
516   test<char>();
517 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
518   test<wchar_t>();
519 #endif
520 
521   test_ill_formed_utf8();
522 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
523 #  ifdef _LIBCPP_SHORT_WCHAR
524   test_ill_formed_utf16();
525   assert(false);
526 #  else  // _LIBCPP_SHORT_WCHAR
527   test_ill_formed_utf32();
528 #  endif // _LIBCPP_SHORT_WCHAR
529 #endif   // TEST_HAS_NO_WIDE_CHARACTERS
530 
531   return 0;
532 }
533