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
6 //===----------------------------------------------------------------------===//
8 #ifndef TEST_STD_UTILITIES_FORMAT_FORMAT_TUPLE_FORMAT_TESTS_H
9 #define TEST_STD_UTILITIES_FORMAT_FORMAT_TUPLE_FORMAT_TESTS_H
15 #include "format.functions.common.h"
17 enum class color
{ black
, red
, gold
};
19 template <class CharT
>
20 struct std::formatter
<color
, CharT
> : std::formatter
<basic_string_view
<CharT
>, CharT
> {
21 static constexpr basic_string_view
<CharT
> color_names
[] = {SV("black"), SV("red"), SV("gold")};
22 auto format(color c
, auto& ctx
) const {
23 return formatter
<basic_string_view
<CharT
>, CharT
>::format(color_names
[static_cast<int>(c
)], ctx
);
28 // Generic tests for a tuple and pair with two elements.
30 template <class CharT
, class TestFunction
, class ExceptionTest
, class TupleOrPair
>
31 void test_tuple_or_pair_int_int(TestFunction check
, ExceptionTest check_exception
, TupleOrPair
&& input
) {
32 check(SV("(42, 99)"), SV("{}"), input
);
34 // *** align-fill & width ***
35 check(SV("(42, 99) "), SV("{:13}"), input
);
36 check(SV("(42, 99)*****"), SV("{:*<13}"), input
);
37 check(SV("__(42, 99)___"), SV("{:_^13}"), input
);
38 check(SV("#####(42, 99)"), SV("{:#>13}"), input
);
40 check(SV("(42, 99) "), SV("{:{}}"), input
, 13);
41 check(SV("(42, 99)*****"), SV("{:*<{}}"), input
, 13);
42 check(SV("__(42, 99)___"), SV("{:_^{}}"), input
, 13);
43 check(SV("#####(42, 99)"), SV("{:#>{}}"), input
, 13);
45 check_exception("The fill option contains an invalid value", SV("{:}<}"), input
);
46 check_exception("The fill option contains an invalid value", SV("{:{<}"), input
);
47 check_exception("The fill option contains an invalid value", SV("{::<}"), input
);
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
);
54 // *** alternate form ***
55 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input
);
57 // *** zero-padding ***
58 check_exception("The width option should not have a leading zero", SV("{:0}"), input
);
61 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input
);
63 // *** locale-specific form ***
64 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input
);
67 check(SV("__42: 99___"), SV("{:_^11m}"), input
);
68 check(SV("__42, 99___"), SV("{:_^11n}"), input
);
70 for (CharT c
: SV("aAbBcdeEfFgGopPsxX?")) {
71 check_exception("The format specifier should consume the input or end with a '}'",
72 std::basic_string_view
{STR("{:") + c
+ STR("}")},
77 template <class CharT
, class TestFunction
, class ExceptionTest
, class TupleOrPair
>
78 void test_tuple_or_pair_int_string(TestFunction check
, ExceptionTest check_exception
, TupleOrPair
&& input
) {
79 check(SV("(42, \"hello\")"), SV("{}"), input
);
81 // *** align-fill & width ***
82 check(SV("(42, \"hello\") "), SV("{:18}"), input
);
83 check(SV("(42, \"hello\")*****"), SV("{:*<18}"), input
);
84 check(SV("__(42, \"hello\")___"), SV("{:_^18}"), input
);
85 check(SV("#####(42, \"hello\")"), SV("{:#>18}"), input
);
87 check(SV("(42, \"hello\") "), SV("{:{}}"), input
, 18);
88 check(SV("(42, \"hello\")*****"), SV("{:*<{}}"), input
, 18);
89 check(SV("__(42, \"hello\")___"), SV("{:_^{}}"), input
, 18);
90 check(SV("#####(42, \"hello\")"), SV("{:#>{}}"), input
, 18);
92 check_exception("The fill option contains an invalid value", SV("{:}<}"), input
);
93 check_exception("The fill option contains an invalid value", SV("{:{<}"), input
);
94 check_exception("The fill option contains an invalid value", SV("{::<}"), input
);
97 check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input
);
98 check_exception("The format specifier should consume the input or end with a '}'", SV("{:+}"), input
);
99 check_exception("The format specifier should consume the input or end with a '}'", SV("{: }"), input
);
101 // *** alternate form ***
102 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input
);
104 // *** zero-padding ***
105 check_exception("The width option should not have a leading zero", SV("{:0}"), input
);
108 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input
);
110 // *** locale-specific form ***
111 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input
);
114 check(SV("__42: \"hello\"___"), SV("{:_^16m}"), input
);
115 check(SV("__42, \"hello\"___"), SV("{:_^16n}"), input
);
117 for (CharT c
: SV("aAbBcdeEfFgGopPsxX?")) {
118 check_exception("The format specifier should consume the input or end with a '}'",
119 std::basic_string_view
{STR("{:") + c
+ STR("}")},
124 template <class CharT
, class TestFunction
, class TupleOrPair
>
125 void test_escaping(TestFunction check
, TupleOrPair
&& input
) {
126 static_assert(std::same_as
<std::remove_cvref_t
<decltype(std::get
<0>(input
))>, CharT
>);
127 static_assert(std::same_as
<std::remove_cvref_t
<decltype(std::get
<1>(input
))>, std::basic_string
<CharT
>>);
129 check(SV(R
"(('*', ""))"), SV("{}"), input
);
132 std::get
<0>(input
) = CharT('\t');
133 check(SV(R
"(('\t', ""))"), SV("{}"), input
);
134 std::get
<0>(input
) = CharT('\n');
135 check(SV(R
"(('\n', ""))"), SV("{}"), input
);
136 std::get
<0>(input
) = CharT('\0');
137 check(SV(R
"(('\u{0}', ""))"), SV("{}"), input
);
140 std::get
<0>(input
) = CharT('*');
141 std::get
<1>(input
) = SV("hellö");
142 check(SV("('*', \"hellö\")"), SV("{}"), input
);
149 template <class CharT
, class TestFunction
, class ExceptionTest
>
150 void test_pair_int_int(TestFunction check
, ExceptionTest check_exception
) {
151 test_tuple_or_pair_int_int
<CharT
>(check
, check_exception
, std::make_pair(42, 99));
154 template <class CharT
, class TestFunction
, class ExceptionTest
>
155 void test_pair_int_string(TestFunction check
, ExceptionTest check_exception
) {
156 test_tuple_or_pair_int_string
<CharT
>(check
, check_exception
, std::make_pair(42, SV("hello")));
157 test_tuple_or_pair_int_string
<CharT
>(check
, check_exception
, std::make_pair(42, STR("hello")));
158 test_tuple_or_pair_int_string
<CharT
>(check
, check_exception
, std::make_pair(42, CSTR("hello")));
165 template <class CharT
, class TestFunction
, class ExceptionTest
>
166 void test_tuple_int(TestFunction check
, ExceptionTest check_exception
) {
167 auto input
= std::make_tuple(42);
169 check(SV("(42)"), SV("{}"), input
);
171 // *** align-fill & width ***
172 check(SV("(42) "), SV("{:9}"), input
);
173 check(SV("(42)*****"), SV("{:*<9}"), input
);
174 check(SV("__(42)___"), SV("{:_^9}"), input
);
175 check(SV("#####(42)"), SV("{:#>9}"), input
);
177 check(SV("(42) "), SV("{:{}}"), input
, 9);
178 check(SV("(42)*****"), SV("{:*<{}}"), input
, 9);
179 check(SV("__(42)___"), SV("{:_^{}}"), input
, 9);
180 check(SV("#####(42)"), SV("{:#>{}}"), input
, 9);
182 check_exception("The fill option contains an invalid value", SV("{:}<}"), input
);
183 check_exception("The fill option contains an invalid value", SV("{:{<}"), input
);
184 check_exception("The fill option contains an invalid value", SV("{::<}"), input
);
187 check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input
);
188 check_exception("The format specifier should consume the input or end with a '}'", SV("{:+}"), input
);
189 check_exception("The format specifier should consume the input or end with a '}'", SV("{: }"), input
);
191 // *** alternate form ***
192 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input
);
194 // *** zero-padding ***
195 check_exception("The width option should not have a leading zero", SV("{:0}"), input
);
198 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input
);
200 // *** locale-specific form ***
201 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input
);
204 check_exception("Type m requires a pair or a tuple with two elements", SV("{:m}"), input
);
205 check(SV("__42___"), SV("{:_^7n}"), input
);
207 for (CharT c
: SV("aAbBcdeEfFgGopPsxX?")) {
208 check_exception("The format specifier should consume the input or end with a '}'",
209 std::basic_string_view
{STR("{:") + c
+ STR("}")},
214 template <class CharT
, class TestFunction
, class ExceptionTest
>
215 void test_tuple_int_string_color(TestFunction check
, ExceptionTest check_exception
) {
216 const auto input
= std::make_tuple(42, SV("hello"), color::red
);
218 check(SV("(42, \"hello\", \"red\")"), SV("{}"), input
);
220 // *** align-fill & width ***
221 check(SV("(42, \"hello\", \"red\") "), SV("{:25}"), input
);
222 check(SV("(42, \"hello\", \"red\")*****"), SV("{:*<25}"), input
);
223 check(SV("__(42, \"hello\", \"red\")___"), SV("{:_^25}"), input
);
224 check(SV("#####(42, \"hello\", \"red\")"), SV("{:#>25}"), input
);
226 check(SV("(42, \"hello\", \"red\") "), SV("{:{}}"), input
, 25);
227 check(SV("(42, \"hello\", \"red\")*****"), SV("{:*<{}}"), input
, 25);
228 check(SV("__(42, \"hello\", \"red\")___"), SV("{:_^{}}"), input
, 25);
229 check(SV("#####(42, \"hello\", \"red\")"), SV("{:#>{}}"), input
, 25);
231 check_exception("The fill option contains an invalid value", SV("{:}<}"), input
);
232 check_exception("The fill option contains an invalid value", SV("{:{<}"), input
);
233 check_exception("The fill option contains an invalid value", SV("{::<}"), input
);
236 check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input
);
237 check_exception("The format specifier should consume the input or end with a '}'", SV("{:+}"), input
);
238 check_exception("The format specifier should consume the input or end with a '}'", SV("{: }"), input
);
240 // *** alternate form ***
241 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input
);
243 // *** zero-padding ***
244 check_exception("The width option should not have a leading zero", SV("{:0}"), input
);
247 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input
);
249 // *** locale-specific form ***
250 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input
);
253 check_exception("Type m requires a pair or a tuple with two elements", SV("{:m}"), input
);
254 check(SV("__42, \"hello\", \"red\"___"), SV("{:_^23n}"), input
);
256 for (CharT c
: SV("aAbBcdeEfFgGopPsxX?")) {
257 check_exception("The format specifier should consume the input or end with a '}'",
258 std::basic_string_view
{STR("{:") + c
+ STR("}")},
263 template <class CharT
, class TestFunction
, class ExceptionTest
>
264 void test_tuple_int_int(TestFunction check
, ExceptionTest check_exception
) {
265 test_tuple_or_pair_int_int
<CharT
>(check
, check_exception
, std::make_tuple(42, 99));
268 template <class CharT
, class TestFunction
, class ExceptionTest
>
269 void test_tuple_int_string(TestFunction check
, ExceptionTest check_exception
) {
270 test_tuple_or_pair_int_string
<CharT
>(check
, check_exception
, std::make_tuple(42, SV("hello")));
271 test_tuple_or_pair_int_string
<CharT
>(check
, check_exception
, std::make_tuple(42, STR("hello")));
272 test_tuple_or_pair_int_string
<CharT
>(check
, check_exception
, std::make_tuple(42, CSTR("hello")));
279 template <class CharT
, class TestFunction
, class ExceptionTest
, class Nested
>
280 void test_nested(TestFunction check
, ExceptionTest check_exception
, Nested
&& input
) {
281 // [format.formatter.spec]/2
282 // A debug-enabled specialization of formatter additionally provides a
283 // public, constexpr, non-static member function set_debug_format()
284 // which modifies the state of the formatter to be as if the type of the
285 // std-format-spec parsed by the last call to parse were ?.
286 // pair and tuple are not debug-enabled specializations to the
287 // set_debug_format is not propagated. The paper
288 // P2733 Fix handling of empty specifiers in std::format
291 check(SV("(42, (\"hello\", \"red\"))"), SV("{}"), input
);
293 // *** align-fill & width ***
294 check(SV("(42, (\"hello\", \"red\")) "), SV("{:27}"), input
);
295 check(SV("(42, (\"hello\", \"red\"))*****"), SV("{:*<27}"), input
);
296 check(SV("__(42, (\"hello\", \"red\"))___"), SV("{:_^27}"), input
);
297 check(SV("#####(42, (\"hello\", \"red\"))"), SV("{:#>27}"), input
);
299 check(SV("(42, (\"hello\", \"red\")) "), SV("{:{}}"), input
, 27);
300 check(SV("(42, (\"hello\", \"red\"))*****"), SV("{:*<{}}"), input
, 27);
301 check(SV("__(42, (\"hello\", \"red\"))___"), SV("{:_^{}}"), input
, 27);
302 check(SV("#####(42, (\"hello\", \"red\"))"), SV("{:#>{}}"), input
, 27);
304 check_exception("The fill option contains an invalid value", SV("{:}<}"), input
);
305 check_exception("The fill option contains an invalid value", SV("{:{<}"), input
);
306 check_exception("The fill option contains an invalid value", SV("{::<}"), input
);
309 check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input
);
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
);
313 // *** alternate form ***
314 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input
);
316 // *** zero-padding ***
317 check_exception("The width option should not have a leading zero", SV("{:0}"), input
);
320 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input
);
322 // *** locale-specific form ***
323 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input
);
326 check(SV("__42: (\"hello\", \"red\")___"), SV("{:_^25m}"), input
);
327 check(SV("__42, (\"hello\", \"red\")___"), SV("{:_^25n}"), input
);
329 for (CharT c
: SV("aAbBcdeEfFgGopPsxX?")) {
330 check_exception("The format specifier should consume the input or end with a '}'",
331 std::basic_string_view
{STR("{:") + c
+ STR("}")},
336 template <class CharT
, class TestFunction
, class ExceptionTest
>
337 void run_tests(TestFunction check
, ExceptionTest check_exception
) {
338 test_pair_int_int
<CharT
>(check
, check_exception
);
339 test_pair_int_string
<CharT
>(check
, check_exception
);
341 test_tuple_int
<CharT
>(check
, check_exception
);
342 test_tuple_int_int
<CharT
>(check
, check_exception
);
343 test_tuple_int_string
<CharT
>(check
, check_exception
);
344 test_tuple_int_string_color
<CharT
>(check
, check_exception
);
346 test_nested
<CharT
>(check
, check_exception
, std::make_pair(42, std::make_pair(SV("hello"), color::red
)));
347 test_nested
<CharT
>(check
, check_exception
, std::make_pair(42, std::make_tuple(SV("hello"), color::red
)));
348 test_nested
<CharT
>(check
, check_exception
, std::make_tuple(42, std::make_pair(SV("hello"), color::red
)));
349 test_nested
<CharT
>(check
, check_exception
, std::make_tuple(42, std::make_tuple(SV("hello"), color::red
)));
351 test_escaping
<CharT
>(check
, std::make_pair(CharT('*'), STR("")));
352 test_escaping
<CharT
>(check
, std::make_tuple(CharT('*'), STR("")));
354 // Test const ref-qualified types.
356 check(SV("(42)"), SV("{}"), std::tuple
< int >{42});
357 check(SV("(42)"), SV("{}"), std::tuple
<const int >{42});
360 check(SV("(42)"), SV("{}"), std::tuple
< int& >{answer
});
361 check(SV("(42)"), SV("{}"), std::tuple
<const int& >{answer
});
363 check(SV("(42)"), SV("{}"), std::tuple
< int&&>{42});
364 check(SV("(42)"), SV("{}"), std::tuple
<const int&&>{42});
368 #endif // TEST_STD_UTILITIES_FORMAT_FORMAT_TUPLE_FORMAT_TESTS_H