1//===----------------------------------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef TEST_STD_UTILITIES_FORMAT_FORMAT_TUPLE_FORMAT_TESTS_H
10#define TEST_STD_UTILITIES_FORMAT_FORMAT_TUPLE_FORMAT_TESTS_H
11
12#include <concepts>
13#include <format>
14#include <tuple>
15
16#include "format.functions.common.h"
17
18enum class color { black, red, gold };
19
20template <class CharT>
21struct 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);
25 }
26};
27
28//
29// Generic tests for a tuple and pair with two elements.
30//
31template <class CharT, class TestFunction, class ExceptionTest, class TupleOrPair>
32void 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);
36
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);
42
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);
47
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);
50
51 // *** sign ***
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);
55
56 // *** alternate form ***
57 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
58
59 // *** zero-padding ***
60 check_exception("The width option should not have a leading zero", SV("{:0}"), input);
61
62 // *** precision ***
63 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input);
64
65 // *** locale-specific form ***
66 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
67
68 // *** type ***
69 check(SV("__42: 99___"), SV("{:_^11m}"), input);
70 check(SV("__42, 99___"), SV("{:_^11n}"), input);
71
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("}")},
75 input);
76 }
77}
78
79template <class CharT, class TestFunction, class ExceptionTest, class TupleOrPair>
80void 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);
84
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);
90
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);
95
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);
98
99 // *** sign ***
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);
103
104 // *** alternate form ***
105 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
106
107 // *** zero-padding ***
108 check_exception("The width option should not have a leading zero", SV("{:0}"), input);
109
110 // *** precision ***
111 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input);
112
113 // *** locale-specific form ***
114 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
115
116 // *** type ***
117 check(SV("__42: \"hello\"___"), SV("{:_^16m}"), input);
118 check(SV("__42, \"hello\"___"), SV("{:_^16n}"), input);
119
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("}")},
123 input);
124 }
125}
126
127template <class CharT, class TestFunction, class TupleOrPair>
128void 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>>);
131
132 check(SV(R"(('*', ""))"), SV("{}"), input);
133
134 // Char
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);
141
142 // String
143 std::get<0>(input) = CharT('*');
144 std::get<1>(input) = SV("hellö");
145 check(SV("('*', \"hellö\")"), SV("{}"), input);
146}
147
148//
149// pair tests
150//
151
152template <class CharT, class TestFunction, class ExceptionTest>
153void test_pair_int_int(TestFunction check, ExceptionTest check_exception) {
154 test_tuple_or_pair_int_int<CharT>(check, check_exception, std::make_pair(x: 42, y: 99));
155}
156
157template <class CharT, class TestFunction, class ExceptionTest>
158void 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")));
162}
163
164//
165// tuple tests
166//
167
168template <class CharT, class TestFunction, class ExceptionTest>
169void test_tuple_int(TestFunction check, ExceptionTest check_exception) {
170 auto input = std::make_tuple(args: 42);
171
172 check(SV("(42)"), SV("{}"), input);
173 check(SV("(42)^42"), SV("{}^42"), input);
174 check(SV("(42)^42"), SV("{:}^42"), input);
175
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);
181
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);
186
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);
189
190 // *** sign ***
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);
194
195 // *** alternate form ***
196 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
197
198 // *** zero-padding ***
199 check_exception("The width option should not have a leading zero", SV("{:0}"), input);
200
201 // *** precision ***
202 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input);
203
204 // *** locale-specific form ***
205 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
206
207 // *** type ***
208 check_exception("Type m requires a pair or a tuple with two elements", SV("{:m}"), input);
209 check(SV("__42___"), SV("{:_^7n}"), input);
210
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("}")},
214 input);
215 }
216}
217
218template <class CharT, class TestFunction, class ExceptionTest>
219void test_tuple_int_string_color(TestFunction check, ExceptionTest check_exception) {
220 const auto input = std::make_tuple(42, SV("hello"), color::red);
221
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);
225
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);
231
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);
236
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);
239
240 // *** sign ***
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);
244
245 // *** alternate form ***
246 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
247
248 // *** zero-padding ***
249 check_exception("The width option should not have a leading zero", SV("{:0}"), input);
250
251 // *** precision ***
252 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input);
253
254 // *** locale-specific form ***
255 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
256
257 // *** type ***
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);
260
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("}")},
264 input);
265 }
266}
267
268template <class CharT, class TestFunction, class ExceptionTest>
269void test_tuple_int_int(TestFunction check, ExceptionTest check_exception) {
270 test_tuple_or_pair_int_int<CharT>(check, check_exception, std::make_tuple(args: 42, args: 99));
271}
272
273template <class CharT, class TestFunction, class ExceptionTest>
274void 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")));
278}
279
280//
281// nested tests
282//
283
284template <class CharT, class TestFunction, class ExceptionTest, class Nested>
285void 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
294 // addressed this.
295
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);
299
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);
305
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);
310
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);
313
314 // *** sign ***
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);
318
319 // *** alternate form ***
320 check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
321
322 // *** zero-padding ***
323 check_exception("The width option should not have a leading zero", SV("{:0}"), input);
324
325 // *** precision ***
326 check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input);
327
328 // *** locale-specific form ***
329 check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
330
331 // *** type ***
332 check(SV("__42: (\"hello\", \"red\")___"), SV("{:_^25m}"), input);
333 check(SV("__42, (\"hello\", \"red\")___"), SV("{:_^25n}"), input);
334
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("}")},
338 input);
339 }
340}
341
342template <class CharT, class TestFunction, class ExceptionTest>
343void 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);
346
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);
351
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)));
356
357 test_escaping<CharT>(check, std::make_pair(CharT('*'), STR("")));
358 test_escaping<CharT>(check, std::make_tuple(CharT('*'), STR("")));
359
360 // Test const ref-qualified types.
361 // clang-format off
362 check(SV("(42)"), SV("{}"), std::tuple< int >{42});
363 check(SV("(42)"), SV("{}"), std::tuple<const int >{42});
364
365 int answer = 42;
366 check(SV("(42)"), SV("{}"), std::tuple< int& >{answer});
367 check(SV("(42)"), SV("{}"), std::tuple<const int& >{answer});
368
369 check(SV("(42)"), SV("{}"), std::tuple< int&&>{42});
370 check(SV("(42)"), SV("{}"), std::tuple<const int&&>{42});
371 // clang-format on
372}
373
374#endif // TEST_STD_UTILITIES_FORMAT_FORMAT_TUPLE_FORMAT_TESTS_H
375

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