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#ifndef TEST_STD_UTILITIES_FORMAT_FORMAT_TUPLE_FORMAT_TESTS_H
9#define TEST_STD_UTILITIES_FORMAT_FORMAT_TUPLE_FORMAT_TESTS_H
10
11#include <concepts>
12#include <format>
13#include <tuple>
14
15#include "format.functions.common.h"
16
17enum class color { black, red, gold };
18
19template <class CharT>
20struct 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);
24 }
25};
26
27//
28// Generic tests for a tuple and pair with two elements.
29//
30template <class CharT, class TestFunction, class ExceptionTest, class TupleOrPair>
31void test_tuple_or_pair_int_int(TestFunction check, ExceptionTest check_exception, TupleOrPair&& input) {
32 check(SV("(42, 99)"), SV("{}"), input);
33 check(SV("(42, 99)^42"), SV("{}^42"), input);
34 check(SV("(42, 99)^42"), SV("{:}^42"), input);
35
36 // *** align-fill & width ***
37 check(SV("(42, 99) "), SV("{:13}"), input);
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
42 check(SV("(42, 99) "), SV("{:{}}"), input, 13);
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
47 check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input);
48 check_exception("The fill option contains an invalid value", SV("{:{<}"), input);
49
50 // *** sign ***
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);
53 check_exception("The format specifier should consume the input or end with a '}'", SV("{: }"), input);
54
55 // *** alternate form ***
56 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
57
58 // *** zero-padding ***
59 check_exception("The width option should not have a leading zero", SV("{:0}"), input);
60
61 // *** precision ***
62 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input);
63
64 // *** locale-specific form ***
65 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
66
67 // *** type ***
68 check(SV("__42: 99___"), SV("{:_^11m}"), input);
69 check(SV("__42, 99___"), SV("{:_^11n}"), input);
70
71 for (CharT c : SV("aAbBcdeEfFgGopPsxX?")) {
72 check_exception("The format specifier should consume the input or end with a '}'",
73 std::basic_string_view{STR("{:") + c + STR("}")},
74 input);
75 }
76}
77
78template <class CharT, class TestFunction, class ExceptionTest, class TupleOrPair>
79void test_tuple_or_pair_int_string(TestFunction check, ExceptionTest check_exception, TupleOrPair&& input) {
80 check(SV("(42, \"hello\")"), SV("{}"), input);
81 check(SV("(42, \"hello\")^42"), SV("{}^42"), input);
82 check(SV("(42, \"hello\")^42"), SV("{:}^42"), input);
83
84 // *** align-fill & width ***
85 check(SV("(42, \"hello\") "), SV("{:18}"), input);
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
90 check(SV("(42, \"hello\") "), SV("{:{}}"), input, 18);
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
95 check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input);
96 check_exception("The fill option contains an invalid value", SV("{:{<}"), input);
97
98 // *** sign ***
99 check_exception("The format specifier should consume the input or end with a '}'", 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
103 // *** alternate form ***
104 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
105
106 // *** zero-padding ***
107 check_exception("The width option should not have a leading zero", SV("{:0}"), input);
108
109 // *** precision ***
110 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input);
111
112 // *** locale-specific form ***
113 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
114
115 // *** type ***
116 check(SV("__42: \"hello\"___"), SV("{:_^16m}"), input);
117 check(SV("__42, \"hello\"___"), SV("{:_^16n}"), input);
118
119 for (CharT c : SV("aAbBcdeEfFgGopPsxX?")) {
120 check_exception("The format specifier should consume the input or end with a '}'",
121 std::basic_string_view{STR("{:") + c + STR("}")},
122 input);
123 }
124}
125
126template <class CharT, class TestFunction, class TupleOrPair>
127void test_escaping(TestFunction check, TupleOrPair&& input) {
128 static_assert(std::same_as<std::remove_cvref_t<decltype(std::get<0>(input))>, CharT>);
129 static_assert(std::same_as<std::remove_cvref_t<decltype(std::get<1>(input))>, std::basic_string<CharT>>);
130
131 check(SV(R"(('*', ""))"), SV("{}"), input);
132
133 // Char
134 std::get<0>(input) = CharT('\t');
135 check(SV(R"(('\t', ""))"), SV("{}"), input);
136 std::get<0>(input) = CharT('\n');
137 check(SV(R"(('\n', ""))"), SV("{}"), input);
138 std::get<0>(input) = CharT('\0');
139 check(SV(R"(('\u{0}', ""))"), SV("{}"), input);
140
141 // String
142 std::get<0>(input) = CharT('*');
143 std::get<1>(input) = SV("hellö");
144 check(SV("('*', \"hellö\")"), SV("{}"), input);
145}
146
147//
148// pair tests
149//
150
151template <class CharT, class TestFunction, class ExceptionTest>
152void test_pair_int_int(TestFunction check, ExceptionTest check_exception) {
153 test_tuple_or_pair_int_int<CharT>(check, check_exception, std::make_pair(x: 42, y: 99));
154}
155
156template <class CharT, class TestFunction, class ExceptionTest>
157void test_pair_int_string(TestFunction check, ExceptionTest check_exception) {
158 test_tuple_or_pair_int_string<CharT>(check, check_exception, std::make_pair(42, SV("hello")));
159 test_tuple_or_pair_int_string<CharT>(check, check_exception, std::make_pair(42, STR("hello")));
160 test_tuple_or_pair_int_string<CharT>(check, check_exception, std::make_pair(42, CSTR("hello")));
161}
162
163//
164// tuple tests
165//
166
167template <class CharT, class TestFunction, class ExceptionTest>
168void test_tuple_int(TestFunction check, ExceptionTest check_exception) {
169 auto input = std::make_tuple(args: 42);
170
171 check(SV("(42)"), SV("{}"), input);
172 check(SV("(42)^42"), SV("{}^42"), input);
173 check(SV("(42)^42"), SV("{:}^42"), input);
174
175 // *** align-fill & width ***
176 check(SV("(42) "), SV("{:9}"), input);
177 check(SV("(42)*****"), SV("{:*<9}"), input);
178 check(SV("__(42)___"), SV("{:_^9}"), input);
179 check(SV("#####(42)"), SV("{:#>9}"), input);
180
181 check(SV("(42) "), SV("{:{}}"), input, 9);
182 check(SV("(42)*****"), SV("{:*<{}}"), input, 9);
183 check(SV("__(42)___"), SV("{:_^{}}"), input, 9);
184 check(SV("#####(42)"), SV("{:#>{}}"), input, 9);
185
186 check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input);
187 check_exception("The fill option contains an invalid value", SV("{:{<}"), input);
188
189 // *** sign ***
190 check_exception("The format specifier should consume the input or end with a '}'", 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
194 // *** alternate form ***
195 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
196
197 // *** zero-padding ***
198 check_exception("The width option should not have a leading zero", SV("{:0}"), input);
199
200 // *** precision ***
201 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input);
202
203 // *** locale-specific form ***
204 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
205
206 // *** type ***
207 check_exception("Type m requires a pair or a tuple with two elements", SV("{:m}"), input);
208 check(SV("__42___"), SV("{:_^7n}"), input);
209
210 for (CharT c : SV("aAbBcdeEfFgGopPsxX?")) {
211 check_exception("The format specifier should consume the input or end with a '}'",
212 std::basic_string_view{STR("{:") + c + STR("}")},
213 input);
214 }
215}
216
217template <class CharT, class TestFunction, class ExceptionTest>
218void test_tuple_int_string_color(TestFunction check, ExceptionTest check_exception) {
219 const auto input = std::make_tuple(42, SV("hello"), color::red);
220
221 check(SV("(42, \"hello\", \"red\")"), SV("{}"), input);
222 check(SV("(42, \"hello\", \"red\")^42"), SV("{}^42"), input);
223 check(SV("(42, \"hello\", \"red\")^42"), SV("{:}^42"), input);
224
225 // *** align-fill & width ***
226 check(SV("(42, \"hello\", \"red\") "), SV("{:25}"), input);
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
231 check(SV("(42, \"hello\", \"red\") "), SV("{:{}}"), input, 25);
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
236 check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input);
237 check_exception("The fill option contains an invalid value", SV("{:{<}"), input);
238
239 // *** sign ***
240 check_exception("The format specifier should consume the input or end with a '}'", 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
244 // *** alternate form ***
245 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
246
247 // *** zero-padding ***
248 check_exception("The width option should not have a leading zero", SV("{:0}"), input);
249
250 // *** precision ***
251 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input);
252
253 // *** locale-specific form ***
254 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
255
256 // *** type ***
257 check_exception("Type m requires a pair or a tuple with two elements", SV("{:m}"), input);
258 check(SV("__42, \"hello\", \"red\"___"), SV("{:_^23n}"), input);
259
260 for (CharT c : SV("aAbBcdeEfFgGopPsxX?")) {
261 check_exception("The format specifier should consume the input or end with a '}'",
262 std::basic_string_view{STR("{:") + c + STR("}")},
263 input);
264 }
265}
266
267template <class CharT, class TestFunction, class ExceptionTest>
268void test_tuple_int_int(TestFunction check, ExceptionTest check_exception) {
269 test_tuple_or_pair_int_int<CharT>(check, check_exception, std::make_tuple(args: 42, args: 99));
270}
271
272template <class CharT, class TestFunction, class ExceptionTest>
273void test_tuple_int_string(TestFunction check, ExceptionTest check_exception) {
274 test_tuple_or_pair_int_string<CharT>(check, check_exception, std::make_tuple(42, SV("hello")));
275 test_tuple_or_pair_int_string<CharT>(check, check_exception, std::make_tuple(42, STR("hello")));
276 test_tuple_or_pair_int_string<CharT>(check, check_exception, std::make_tuple(42, CSTR("hello")));
277}
278
279//
280// nested tests
281//
282
283template <class CharT, class TestFunction, class ExceptionTest, class Nested>
284void test_nested(TestFunction check, ExceptionTest check_exception, Nested&& input) {
285 // [format.formatter.spec]/2
286 // A debug-enabled specialization of formatter additionally provides a
287 // public, constexpr, non-static member function set_debug_format()
288 // which modifies the state of the formatter to be as if the type of the
289 // std-format-spec parsed by the last call to parse were ?.
290 // pair and tuple are not debug-enabled specializations to the
291 // set_debug_format is not propagated. The paper
292 // P2733 Fix handling of empty specifiers in std::format
293 // addressed this.
294
295 check(SV("(42, (\"hello\", \"red\"))"), SV("{}"), input);
296 check(SV("(42, (\"hello\", \"red\"))^42"), SV("{}^42"), input);
297 check(SV("(42, (\"hello\", \"red\"))^42"), SV("{:}^42"), input);
298
299 // *** align-fill & width ***
300 check(SV("(42, (\"hello\", \"red\")) "), SV("{:27}"), input);
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
305 check(SV("(42, (\"hello\", \"red\")) "), SV("{:{}}"), input, 27);
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
310 check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input);
311 check_exception("The fill option contains an invalid value", SV("{:{<}"), input);
312
313 // *** sign ***
314 check_exception("The format specifier should consume the input or end with a '}'", 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
318 // *** alternate form ***
319 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
320
321 // *** zero-padding ***
322 check_exception("The width option should not have a leading zero", SV("{:0}"), input);
323
324 // *** precision ***
325 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input);
326
327 // *** locale-specific form ***
328 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
329
330 // *** type ***
331 check(SV("__42: (\"hello\", \"red\")___"), SV("{:_^25m}"), input);
332 check(SV("__42, (\"hello\", \"red\")___"), SV("{:_^25n}"), input);
333
334 for (CharT c : SV("aAbBcdeEfFgGopPsxX?")) {
335 check_exception("The format specifier should consume the input or end with a '}'",
336 std::basic_string_view{STR("{:") + c + STR("}")},
337 input);
338 }
339}
340
341template <class CharT, class TestFunction, class ExceptionTest>
342void run_tests(TestFunction check, ExceptionTest check_exception) {
343 test_pair_int_int<CharT>(check, check_exception);
344 test_pair_int_string<CharT>(check, check_exception);
345
346 test_tuple_int<CharT>(check, check_exception);
347 test_tuple_int_int<CharT>(check, check_exception);
348 test_tuple_int_string<CharT>(check, check_exception);
349 test_tuple_int_string_color<CharT>(check, check_exception);
350
351 test_nested<CharT>(check, check_exception, std::make_pair(42, std::make_pair(SV("hello"), color::red)));
352 test_nested<CharT>(check, check_exception, std::make_pair(42, std::make_tuple(SV("hello"), color::red)));
353 test_nested<CharT>(check, check_exception, std::make_tuple(42, std::make_pair(SV("hello"), color::red)));
354 test_nested<CharT>(check, check_exception, std::make_tuple(42, std::make_tuple(SV("hello"), color::red)));
355
356 test_escaping<CharT>(check, std::make_pair(CharT('*'), STR("")));
357 test_escaping<CharT>(check, std::make_tuple(CharT('*'), STR("")));
358
359 // Test const ref-qualified types.
360 // clang-format off
361 check(SV("(42)"), SV("{}"), std::tuple< int >{42});
362 check(SV("(42)"), SV("{}"), std::tuple<const int >{42});
363
364 int answer = 42;
365 check(SV("(42)"), SV("{}"), std::tuple< int& >{answer});
366 check(SV("(42)"), SV("{}"), std::tuple<const int& >{answer});
367
368 check(SV("(42)"), SV("{}"), std::tuple< int&&>{42});
369 check(SV("(42)"), SV("{}"), std::tuple<const int&&>{42});
370 // clang-format on
371}
372
373#endif // TEST_STD_UTILITIES_FORMAT_FORMAT_TUPLE_FORMAT_TESTS_H
374

source code of libcxx/test/std/utilities/format/format.tuple/format.functions.tests.h