1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef TEST_STD_UTILITIES_FORMAT_FORMAT_TUPLE_FORMAT_TESTS_H
10 #define TEST_STD_UTILITIES_FORMAT_FORMAT_TUPLE_FORMAT_TESTS_H
16 #include "format.functions.common.h"
18 enum class color
{ black
, red
, gold
};
20 template <class CharT
>
21 struct std::formatter
<color
, CharT
> : std::formatter
<basic_string_view
<CharT
>, CharT
> {
22 static constexpr basic_string_view
<CharT
> color_names
[] = {SV("black"), SV("red"), SV("gold")};
23 auto format(color c
, auto& ctx
) const {
24 return formatter
<basic_string_view
<CharT
>, CharT
>::format(color_names
[static_cast<int>(c
)], ctx
);
29 // Generic tests for a tuple and pair with two elements.
31 template <class CharT
, class TestFunction
, class ExceptionTest
, class TupleOrPair
>
32 void test_tuple_or_pair_int_int(TestFunction check
, ExceptionTest check_exception
, TupleOrPair
&& input
) {
33 check(SV("(42, 99)"), SV("{}"), input
);
34 check(SV("(42, 99)^42"), SV("{}^42"), input
);
35 check(SV("(42, 99)^42"), SV("{:}^42"), input
);
37 // *** align-fill & width ***
38 check(SV("(42, 99) "), SV("{:13}"), input
);
39 check(SV("(42, 99)*****"), SV("{:*<13}"), input
);
40 check(SV("__(42, 99)___"), SV("{:_^13}"), input
);
41 check(SV("#####(42, 99)"), SV("{:#>13}"), input
);
43 check(SV("(42, 99) "), SV("{:{}}"), input
, 13);
44 check(SV("(42, 99)*****"), SV("{:*<{}}"), input
, 13);
45 check(SV("__(42, 99)___"), SV("{:_^{}}"), input
, 13);
46 check(SV("#####(42, 99)"), SV("{:#>{}}"), input
, 13);
48 check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input
);
49 check_exception("The fill option contains an invalid value", SV("{:{<}"), input
);
52 check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input
);
53 check_exception("The format specifier should consume the input or end with a '}'", SV("{:+}"), input
);
54 check_exception("The format specifier should consume the input or end with a '}'", SV("{: }"), input
);
56 // *** alternate form ***
57 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input
);
59 // *** zero-padding ***
60 check_exception("The width option should not have a leading zero", SV("{:0}"), input
);
63 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input
);
65 // *** locale-specific form ***
66 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input
);
69 check(SV("__42: 99___"), SV("{:_^11m}"), input
);
70 check(SV("__42, 99___"), SV("{:_^11n}"), input
);
72 for (CharT c
: SV("aAbBcdeEfFgGopPsxX?")) {
73 check_exception("The format specifier should consume the input or end with a '}'",
74 std::basic_string_view
{STR("{:") + c
+ STR("}")},
79 template <class CharT
, class TestFunction
, class ExceptionTest
, class TupleOrPair
>
80 void test_tuple_or_pair_int_string(TestFunction check
, ExceptionTest check_exception
, TupleOrPair
&& input
) {
81 check(SV("(42, \"hello\")"), SV("{}"), input
);
82 check(SV("(42, \"hello\")^42"), SV("{}^42"), input
);
83 check(SV("(42, \"hello\")^42"), SV("{:}^42"), input
);
85 // *** align-fill & width ***
86 check(SV("(42, \"hello\") "), SV("{:18}"), input
);
87 check(SV("(42, \"hello\")*****"), SV("{:*<18}"), input
);
88 check(SV("__(42, \"hello\")___"), SV("{:_^18}"), input
);
89 check(SV("#####(42, \"hello\")"), SV("{:#>18}"), input
);
91 check(SV("(42, \"hello\") "), SV("{:{}}"), input
, 18);
92 check(SV("(42, \"hello\")*****"), SV("{:*<{}}"), input
, 18);
93 check(SV("__(42, \"hello\")___"), SV("{:_^{}}"), input
, 18);
94 check(SV("#####(42, \"hello\")"), SV("{:#>{}}"), input
, 18);
96 check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input
);
97 check_exception("The fill option contains an invalid value", SV("{:{<}"), input
);
100 check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input
);
101 check_exception("The format specifier should consume the input or end with a '}'", SV("{:+}"), input
);
102 check_exception("The format specifier should consume the input or end with a '}'", SV("{: }"), input
);
104 // *** alternate form ***
105 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input
);
107 // *** zero-padding ***
108 check_exception("The width option should not have a leading zero", SV("{:0}"), input
);
111 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input
);
113 // *** locale-specific form ***
114 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input
);
117 check(SV("__42: \"hello\"___"), SV("{:_^16m}"), input
);
118 check(SV("__42, \"hello\"___"), SV("{:_^16n}"), input
);
120 for (CharT c
: SV("aAbBcdeEfFgGopPsxX?")) {
121 check_exception("The format specifier should consume the input or end with a '}'",
122 std::basic_string_view
{STR("{:") + c
+ STR("}")},
127 template <class CharT
, class TestFunction
, class TupleOrPair
>
128 void test_escaping(TestFunction check
, TupleOrPair
&& input
) {
129 static_assert(std::same_as
<std::remove_cvref_t
<decltype(std::get
<0>(input
))>, CharT
>);
130 static_assert(std::same_as
<std::remove_cvref_t
<decltype(std::get
<1>(input
))>, std::basic_string
<CharT
>>);
132 check(SV(R
"(('*', ""))"), SV("{}"), input
);
135 std::get
<0>(input
) = CharT('\t');
136 check(SV(R
"(('\t', ""))"), SV("{}"), input
);
137 std::get
<0>(input
) = CharT('\n');
138 check(SV(R
"(('\n', ""))"), SV("{}"), input
);
139 std::get
<0>(input
) = CharT('\0');
140 check(SV(R
"(('\u{0}', ""))"), SV("{}"), input
);
143 std::get
<0>(input
) = CharT('*');
144 std::get
<1>(input
) = SV("hellö");
145 check(SV("('*', \"hellö\")"), SV("{}"), input
);
152 template <class CharT
, class TestFunction
, class ExceptionTest
>
153 void test_pair_int_int(TestFunction check
, ExceptionTest check_exception
) {
154 test_tuple_or_pair_int_int
<CharT
>(check
, check_exception
, std::make_pair(42, 99));
157 template <class CharT
, class TestFunction
, class ExceptionTest
>
158 void test_pair_int_string(TestFunction check
, ExceptionTest check_exception
) {
159 test_tuple_or_pair_int_string
<CharT
>(check
, check_exception
, std::make_pair(42, SV("hello")));
160 test_tuple_or_pair_int_string
<CharT
>(check
, check_exception
, std::make_pair(42, STR("hello")));
161 test_tuple_or_pair_int_string
<CharT
>(check
, check_exception
, std::make_pair(42, CSTR("hello")));
168 template <class CharT
, class TestFunction
, class ExceptionTest
>
169 void test_tuple_int(TestFunction check
, ExceptionTest check_exception
) {
170 auto input
= std::make_tuple(42);
172 check(SV("(42)"), SV("{}"), input
);
173 check(SV("(42)^42"), SV("{}^42"), input
);
174 check(SV("(42)^42"), SV("{:}^42"), input
);
176 // *** align-fill & width ***
177 check(SV("(42) "), SV("{:9}"), input
);
178 check(SV("(42)*****"), SV("{:*<9}"), input
);
179 check(SV("__(42)___"), SV("{:_^9}"), input
);
180 check(SV("#####(42)"), SV("{:#>9}"), input
);
182 check(SV("(42) "), SV("{:{}}"), input
, 9);
183 check(SV("(42)*****"), SV("{:*<{}}"), input
, 9);
184 check(SV("__(42)___"), SV("{:_^{}}"), input
, 9);
185 check(SV("#####(42)"), SV("{:#>{}}"), input
, 9);
187 check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input
);
188 check_exception("The fill option contains an invalid value", SV("{:{<}"), input
);
191 check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input
);
192 check_exception("The format specifier should consume the input or end with a '}'", SV("{:+}"), input
);
193 check_exception("The format specifier should consume the input or end with a '}'", SV("{: }"), input
);
195 // *** alternate form ***
196 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input
);
198 // *** zero-padding ***
199 check_exception("The width option should not have a leading zero", SV("{:0}"), input
);
202 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input
);
204 // *** locale-specific form ***
205 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input
);
208 check_exception("Type m requires a pair or a tuple with two elements", SV("{:m}"), input
);
209 check(SV("__42___"), SV("{:_^7n}"), input
);
211 for (CharT c
: SV("aAbBcdeEfFgGopPsxX?")) {
212 check_exception("The format specifier should consume the input or end with a '}'",
213 std::basic_string_view
{STR("{:") + c
+ STR("}")},
218 template <class CharT
, class TestFunction
, class ExceptionTest
>
219 void test_tuple_int_string_color(TestFunction check
, ExceptionTest check_exception
) {
220 const auto input
= std::make_tuple(42, SV("hello"), color::red
);
222 check(SV("(42, \"hello\", \"red\")"), SV("{}"), input
);
223 check(SV("(42, \"hello\", \"red\")^42"), SV("{}^42"), input
);
224 check(SV("(42, \"hello\", \"red\")^42"), SV("{:}^42"), input
);
226 // *** align-fill & width ***
227 check(SV("(42, \"hello\", \"red\") "), SV("{:25}"), input
);
228 check(SV("(42, \"hello\", \"red\")*****"), SV("{:*<25}"), input
);
229 check(SV("__(42, \"hello\", \"red\")___"), SV("{:_^25}"), input
);
230 check(SV("#####(42, \"hello\", \"red\")"), SV("{:#>25}"), input
);
232 check(SV("(42, \"hello\", \"red\") "), SV("{:{}}"), input
, 25);
233 check(SV("(42, \"hello\", \"red\")*****"), SV("{:*<{}}"), input
, 25);
234 check(SV("__(42, \"hello\", \"red\")___"), SV("{:_^{}}"), input
, 25);
235 check(SV("#####(42, \"hello\", \"red\")"), SV("{:#>{}}"), input
, 25);
237 check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input
);
238 check_exception("The fill option contains an invalid value", SV("{:{<}"), input
);
241 check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input
);
242 check_exception("The format specifier should consume the input or end with a '}'", SV("{:+}"), input
);
243 check_exception("The format specifier should consume the input or end with a '}'", SV("{: }"), input
);
245 // *** alternate form ***
246 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input
);
248 // *** zero-padding ***
249 check_exception("The width option should not have a leading zero", SV("{:0}"), input
);
252 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input
);
254 // *** locale-specific form ***
255 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input
);
258 check_exception("Type m requires a pair or a tuple with two elements", SV("{:m}"), input
);
259 check(SV("__42, \"hello\", \"red\"___"), SV("{:_^23n}"), input
);
261 for (CharT c
: SV("aAbBcdeEfFgGopPsxX?")) {
262 check_exception("The format specifier should consume the input or end with a '}'",
263 std::basic_string_view
{STR("{:") + c
+ STR("}")},
268 template <class CharT
, class TestFunction
, class ExceptionTest
>
269 void test_tuple_int_int(TestFunction check
, ExceptionTest check_exception
) {
270 test_tuple_or_pair_int_int
<CharT
>(check
, check_exception
, std::make_tuple(42, 99));
273 template <class CharT
, class TestFunction
, class ExceptionTest
>
274 void test_tuple_int_string(TestFunction check
, ExceptionTest check_exception
) {
275 test_tuple_or_pair_int_string
<CharT
>(check
, check_exception
, std::make_tuple(42, SV("hello")));
276 test_tuple_or_pair_int_string
<CharT
>(check
, check_exception
, std::make_tuple(42, STR("hello")));
277 test_tuple_or_pair_int_string
<CharT
>(check
, check_exception
, std::make_tuple(42, CSTR("hello")));
284 template <class CharT
, class TestFunction
, class ExceptionTest
, class Nested
>
285 void test_nested(TestFunction check
, ExceptionTest check_exception
, Nested
&& input
) {
286 // [format.formatter.spec]/2
287 // A debug-enabled specialization of formatter additionally provides a
288 // public, constexpr, non-static member function set_debug_format()
289 // which modifies the state of the formatter to be as if the type of the
290 // std-format-spec parsed by the last call to parse were ?.
291 // pair and tuple are not debug-enabled specializations to the
292 // set_debug_format is not propagated. The paper
293 // P2733 Fix handling of empty specifiers in std::format
296 check(SV("(42, (\"hello\", \"red\"))"), SV("{}"), input
);
297 check(SV("(42, (\"hello\", \"red\"))^42"), SV("{}^42"), input
);
298 check(SV("(42, (\"hello\", \"red\"))^42"), SV("{:}^42"), input
);
300 // *** align-fill & width ***
301 check(SV("(42, (\"hello\", \"red\")) "), SV("{:27}"), input
);
302 check(SV("(42, (\"hello\", \"red\"))*****"), SV("{:*<27}"), input
);
303 check(SV("__(42, (\"hello\", \"red\"))___"), SV("{:_^27}"), input
);
304 check(SV("#####(42, (\"hello\", \"red\"))"), SV("{:#>27}"), input
);
306 check(SV("(42, (\"hello\", \"red\")) "), SV("{:{}}"), input
, 27);
307 check(SV("(42, (\"hello\", \"red\"))*****"), SV("{:*<{}}"), input
, 27);
308 check(SV("__(42, (\"hello\", \"red\"))___"), SV("{:_^{}}"), input
, 27);
309 check(SV("#####(42, (\"hello\", \"red\"))"), SV("{:#>{}}"), input
, 27);
311 check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input
);
312 check_exception("The fill option contains an invalid value", SV("{:{<}"), input
);
315 check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input
);
316 check_exception("The format specifier should consume the input or end with a '}'", SV("{:+}"), input
);
317 check_exception("The format specifier should consume the input or end with a '}'", SV("{: }"), input
);
319 // *** alternate form ***
320 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input
);
322 // *** zero-padding ***
323 check_exception("The width option should not have a leading zero", SV("{:0}"), input
);
326 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input
);
328 // *** locale-specific form ***
329 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input
);
332 check(SV("__42: (\"hello\", \"red\")___"), SV("{:_^25m}"), input
);
333 check(SV("__42, (\"hello\", \"red\")___"), SV("{:_^25n}"), input
);
335 for (CharT c
: SV("aAbBcdeEfFgGopPsxX?")) {
336 check_exception("The format specifier should consume the input or end with a '}'",
337 std::basic_string_view
{STR("{:") + c
+ STR("}")},
342 template <class CharT
, class TestFunction
, class ExceptionTest
>
343 void run_tests(TestFunction check
, ExceptionTest check_exception
) {
344 test_pair_int_int
<CharT
>(check
, check_exception
);
345 test_pair_int_string
<CharT
>(check
, check_exception
);
347 test_tuple_int
<CharT
>(check
, check_exception
);
348 test_tuple_int_int
<CharT
>(check
, check_exception
);
349 test_tuple_int_string
<CharT
>(check
, check_exception
);
350 test_tuple_int_string_color
<CharT
>(check
, check_exception
);
352 test_nested
<CharT
>(check
, check_exception
, std::make_pair(42, std::make_pair(SV("hello"), color::red
)));
353 test_nested
<CharT
>(check
, check_exception
, std::make_pair(42, std::make_tuple(SV("hello"), color::red
)));
354 test_nested
<CharT
>(check
, check_exception
, std::make_tuple(42, std::make_pair(SV("hello"), color::red
)));
355 test_nested
<CharT
>(check
, check_exception
, std::make_tuple(42, std::make_tuple(SV("hello"), color::red
)));
357 test_escaping
<CharT
>(check
, std::make_pair(CharT('*'), STR("")));
358 test_escaping
<CharT
>(check
, std::make_tuple(CharT('*'), STR("")));
360 // Test const ref-qualified types.
362 check(SV("(42)"), SV("{}"), std::tuple
< int >{42});
363 check(SV("(42)"), SV("{}"), std::tuple
<const int >{42});
366 check(SV("(42)"), SV("{}"), std::tuple
< int& >{answer
});
367 check(SV("(42)"), SV("{}"), std::tuple
<const int& >{answer
});
369 check(SV("(42)"), SV("{}"), std::tuple
< int&&>{42});
370 check(SV("(42)"), SV("{}"), std::tuple
<const int&&>{42});
374 #endif // TEST_STD_UTILITIES_FORMAT_FORMAT_TUPLE_FORMAT_TESTS_H