xref: /llvm-project/libcxx/test/std/utilities/format/format.functions/fill.unicode.pass.cpp (revision 5db033e204b27a36ab1ffeca912f995bf1a751d4)
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
9 // UNSUPPORTED: libcpp-has-no-incomplete-format
10 // TODO FMT Evaluate gcc-12 status
11 
12 // This version runs the test when the platform has Unicode support.
13 // UNSUPPORTED: libcpp-has-no-unicode
14 
15 // XFAIL: availability-fp_to_chars-missing
16 
17 // <format>
18 
19 // The paper
20 //   P2572R1 std::format fill character allowances
21 // adds support for Unicode Scalar Values as fill character.
22 
23 #include <format>
24 
25 #include "assert_macros.h"
26 #include "concat_macros.h"
27 #include "format.functions.common.h"
28 #include "make_string.h"
29 #include "string_literal.h"
30 #include "test_format_string.h"
31 #include "test_macros.h"
32 
33 #define SV(S) MAKE_STRING_VIEW(CharT, S)
34 
35 auto check = []<class CharT, class... Args>(
36                  std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) {
37   std::basic_string<CharT> out = std::format(fmt, std::forward<Args>(args)...);
38   TEST_REQUIRE(out == expected,
39                TEST_WRITE_CONCATENATED(
40                    "\nFormat string   ", fmt.get(), "\nExpected output ", expected, "\nActual output   ", out, '\n'));
41 };
42 
43 auto check_exception =
44     []<class CharT, class... Args>(
45         [[maybe_unused]] std::string_view what,
46         [[maybe_unused]] std::basic_string_view<CharT> fmt,
47         [[maybe_unused]] Args&&... args) {
48       TEST_VALIDATE_EXCEPTION(
49           std::format_error,
50           [&]([[maybe_unused]] const std::format_error& e) {
51             TEST_LIBCPP_REQUIRE(
52                 e.what() == what,
53                 TEST_WRITE_CONCATENATED(
54                     "\nFormat string   ", fmt, "\nExpected exception ", what, "\nActual exception   ", e.what(), '\n'));
55           },
56           TEST_IGNORE_NODISCARD std::vformat(fmt, std::make_format_args<context_t<CharT>>(args...)));
57     };
58 
59 template <class CharT>
60 void test() {
61   // 1, 2, 3, 4 code unit UTF-8 transitions
62   check(SV("\u000042\u0000"), SV("{:\u0000^4}"), 42);
63   check(SV("\u007f42\u007f"), SV("{:\u007f^4}"), 42);
64   check(SV("\u008042\u0080"), SV("{:\u0080^4}"), 42);
65   check(SV("\u07ff42\u07ff"), SV("{:\u07ff^4}"), 42);
66   check(SV("\u080042\u0800"), SV("{:\u0800^4}"), 42);
67   check(SV("\uffff42\uffff"), SV("{:\uffff^4}"), 42);
68   check(SV("\U0010000042\U00100000"), SV("{:\U00100000^4}"), 42);
69   check(SV("\U0010ffff42\U0010ffff"), SV("{:\U0010ffff^4}"), 42);
70 
71   // Examples of P2572R1
72   check(SV("����x������"), SV("{:��^6}"), SV("x"));
73   check(SV("������"), SV("{:*^6}"), SV("������"));
74   check(SV("12345678"), SV("{:*>6}"), SV("12345678"));
75 
76   // Invalid Unicode Scalar Values
77   if constexpr (std::same_as<CharT, char>) {
78     check_exception("The format-spec contains malformed Unicode characters", SV("{:\xed\xa0\x80^}"), 42); // U+D800
79     check_exception("The format-spec contains malformed Unicode characters", SV("{:\xed\xa0\xbf^}"), 42); // U+DBFF
80     check_exception("The format-spec contains malformed Unicode characters", SV("{:\xed\xbf\x80^}"), 42); // U+DC00
81     check_exception("The format-spec contains malformed Unicode characters", SV("{:\xed\xbf\xbf^}"), 42); // U+DFFF
82 
83     check_exception(
84         "The format-spec contains malformed Unicode characters", SV("{:\xf4\x90\x80\x80^}"), 42); // U+110000
85     check_exception(
86         "The format-spec contains malformed Unicode characters", SV("{:\xf4\x90\xbf\xbf^}"), 42); // U+11FFFF
87 
88     check_exception("The format-spec contains malformed Unicode characters",
89                     SV("{:\x80^}"),
90                     42); // Trailing code unit with no leading one.
91     check_exception(
92         "The format-spec contains malformed Unicode characters", SV("{:\xc0^}"), 42); // Missing trailing code unit.
93     check_exception(
94         "The format-spec contains malformed Unicode characters", SV("{:\xe0\x80^}"), 42); // Missing trailing code unit.
95     check_exception("The format-spec contains malformed Unicode characters",
96                     SV("{:\xf0\x80^}"),
97                     42); // Missing two trailing code units.
98     check_exception("The format-spec contains malformed Unicode characters",
99                     SV("{:\xf0\x80\x80^}"),
100                     42); // Missing trailing code unit.
101 
102 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
103   } else {
104 #  ifdef TEST_SHORT_WCHAR
105     check_exception("The format-spec contains malformed Unicode characters", std::wstring_view{L"{:\xd800^}"}, 42);
106     check_exception("The format-spec contains malformed Unicode characters", std::wstring_view{L"{:\xdbff^}"}, 42);
107     check_exception("The format-spec contains malformed Unicode characters", std::wstring_view{L"{:\xdc00^}"}, 42);
108     check_exception("The format-spec contains malformed Unicode characters", std::wstring_view{L"{:\xddff^}"}, 42);
109 
110     check_exception("The format-spec contains malformed Unicode characters",
111                     std::wstring_view{L"{:\xdc00\xd800^}"},
112                     42); // Reverted surrogates.
113 
114 #  else  // TEST_SHORT_WCHAR
115     check_exception("The fill character contains an invalid value", std::wstring_view{L"{:\xd800^}"}, 42);
116     check_exception("The fill character contains an invalid value", std::wstring_view{L"{:\xdbff^}"}, 42);
117     check_exception("The fill character contains an invalid value", std::wstring_view{L"{:\xdc00^}"}, 42);
118     check_exception("The fill character contains an invalid value", std::wstring_view{L"{:\xddff^}"}, 42);
119 
120     check_exception(
121         "The format-spec should consume the input or end with a '}'", std::wstring_view{L"{:\xdc00\xd800^}"}, 42);
122 
123     check_exception("The fill character contains an invalid value", std::wstring_view{L"{:\x00110000^}"}, 42);
124     check_exception("The fill character contains an invalid value", std::wstring_view{L"{:\x0011ffff^}"}, 42);
125 #  endif // TEST_SHORT_WCHAR
126 #endif   // TEST_HAS_NO_WIDE_CHARACTERS
127   }
128 }
129 
130 int main(int, char**) {
131   test<char>();
132 
133 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
134   test<wchar_t>();
135 #endif
136 
137   return 0;
138 }
139