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_RANGE_FORMAT_RANGE_FMTSTR_FORMAT_FUNCTIONS_TESTS_H
10 #define TEST_STD_UTILITIES_FORMAT_FORMAT_RANGE_FORMAT_RANGE_FMTSTR_FORMAT_FUNCTIONS_TESTS_H
11 
12 #include <array>
13 #include <format>
14 #include <list>
15 
16 #include "format.functions.common.h"
17 #include "make_string.h"
18 #include "platform_support.h" // locale name macros
19 #include "test_macros.h"
20 
21 //
22 // Types
23 //
24 
25 template <class Container>
26 class test_range_format_string {
27 public:
28   explicit test_range_format_string(Container str) : str_(std::move(str)) {}
29 
30   typename Container::const_iterator begin() const { return str_.begin(); }
31   typename Container::const_iterator end() const { return str_.end(); }
32 
33 private:
34   Container str_;
35 };
36 
37 template <class Container>
38 constexpr std::range_format std::format_kind<test_range_format_string<Container>> = std::range_format::string;
39 
40 template <class Container>
41 class test_range_format_debug_string {
42 public:
43   explicit test_range_format_debug_string(Container str) : str_(std::move(str)) {}
44 
45   typename Container::const_iterator begin() const { return str_.begin(); }
46   typename Container::const_iterator end() const { return str_.end(); }
47 
48 private:
49   Container str_;
50 };
51 
52 template <class Container>
53 constexpr std::range_format std::format_kind<test_range_format_debug_string<Container>> =
54     std::range_format::debug_string;
55 
56 //
57 // String
58 //
59 
60 template <class CharT, class TestFunction, class ExceptionTest>
61 void test_string(TestFunction check, ExceptionTest check_exception, auto&& input) {
62   check(SV("hello"), SV("{}"), input);
63   check(SV("hello^42"), SV("{}^42"), input);
64   check(SV("hello^42"), SV("{:}^42"), input);
65 
66   // *** align-fill & width ***
67   check(SV("hello     "), SV("{:10}"), input);
68   check(SV("hello*****"), SV("{:*<10}"), input);
69   check(SV("__hello___"), SV("{:_^10}"), input);
70   check(SV(":::::hello"), SV("{::>10}"), input);
71 
72   check(SV("hello     "), SV("{:{}}"), input, 10);
73   check(SV("hello*****"), SV("{:*<{}}"), input, 10);
74   check(SV("__hello___"), SV("{:_^{}}"), input, 10);
75   check(SV(":::::hello"), SV("{::>{}}"), input, 10);
76 
77   check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input);
78   check_exception("The fill option contains an invalid value", SV("{:{<}"), input);
79 
80   // *** sign ***
81   check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input);
82 
83   // *** alternate form ***
84   check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
85 
86   // *** zero-padding ***
87   check_exception("The width option should not have a leading zero", SV("{:0}"), input);
88 
89   // *** precision ***
90   check(SV("hel"), SV("{:.3}"), input);
91   check(SV("hel"), SV("{:.{}}"), input, 3);
92 
93   check(SV("hel  "), SV("{:5.3}"), input);
94   check(SV("hel  "), SV("{:{}.{}}"), input, 5, 3);
95 
96   // *** locale-specific form ***
97   check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
98 
99   // *** type ***
100   check(SV("hello"), SV("{:s}"), input);
101   check(SV("\"hello\""), SV("{:?}"), input);
102   for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s?"))
103     check_exception("The type option contains an invalid value for a string formatting argument", fmt, input);
104 }
105 
106 template <class CharT, class TestFunction, class ExceptionTest>
107 void test_string(TestFunction check, ExceptionTest check_exception) {
108   // libc++ uses different containers for contiguous and non-contiguous ranges.
109   std::basic_string<CharT> input = STR("hello");
110   test_string<CharT>(check, check_exception, test_range_format_string<std::basic_string<CharT>>{input});
111   test_string<CharT>(check, check_exception, test_range_format_string<std::basic_string_view<CharT>>{input});
112   test_string<CharT>(
113       check, check_exception, test_range_format_string<std::list<CharT>>{std::list<CharT>{input.begin(), input.end()}});
114 }
115 
116 //
117 // String range
118 //
119 
120 template <class CharT, class TestFunction, class ExceptionTest>
121 void test_range_string(TestFunction check, ExceptionTest check_exception, auto&& input) {
122   check(SV(R"([Hello, world])"), SV("{}"), input);
123   check(SV(R"([Hello, world]^42)"), SV("{}^42"), input);
124   check(SV(R"([Hello, world]^42)"), SV("{:}^42"), input);
125 
126   // ***** underlying has no format-spec
127 
128   // *** align-fill & width ***
129   check(SV(R"([Hello, world]     )"), SV("{:19}"), input);
130   check(SV(R"([Hello, world]*****)"), SV("{:*<19}"), input);
131   check(SV(R"(__[Hello, world]___)"), SV("{:_^19}"), input);
132   check(SV(R"(#####[Hello, world])"), SV("{:#>19}"), input);
133 
134   check(SV(R"([Hello, world]     )"), SV("{:{}}"), input, 19);
135   check(SV(R"([Hello, world]*****)"), SV("{:*<{}}"), input, 19);
136   check(SV(R"(__[Hello, world]___)"), SV("{:_^{}}"), input, 19);
137   check(SV(R"(#####[Hello, world])"), SV("{:#>{}}"), input, 19);
138 
139   check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input);
140   check_exception("The fill option contains an invalid value", SV("{:{<}"), input);
141 
142   // *** sign ***
143   check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input);
144 
145   // *** alternate form ***
146   check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
147 
148   // *** zero-padding ***
149   check_exception("The width option should not have a leading zero", SV("{:0}"), input);
150 
151   // *** precision ***
152   check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input);
153 
154   // *** locale-specific form ***
155   check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
156 
157   // *** n
158   check(SV(R"(_Hello, world_)"), SV("{:_^14n}"), input);
159 
160   // *** type ***
161   check_exception("Type m requires a pair or a tuple with two elements", SV("{:m}"), input);
162   check_exception("Type s requires character type as formatting argument", SV("{:s}"), input);
163   check_exception("Type ?s requires character type as formatting argument", SV("{:?s}"), input);
164 
165   for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s"))
166     check_exception("The format specifier should consume the input or end with a '}'", fmt, input);
167 
168   // ***** Only underlying has a format-spec
169   check(SV(R"([Hello   , world   ])"), SV("{::8}"), input);
170   check(SV(R"([Hello***, world***])"), SV("{::*<8}"), input);
171   check(SV(R"([_Hello__, _world__])"), SV("{::_^8}"), input);
172   check(SV(R"([:::Hello, :::world])"), SV("{:::>8}"), input);
173 
174   check(SV(R"([Hello   , world   ])"), SV("{::{}}"), input, 8);
175   check(SV(R"([Hello***, world***])"), SV("{::*<{}}"), input, 8);
176   check(SV(R"([_Hello__, _world__])"), SV("{::_^{}}"), input, 8);
177   check(SV(R"([:::Hello, :::world])"), SV("{:::>{}}"), input, 8);
178 
179   check_exception("The format string contains an invalid escape sequence", SV("{::}<}"), input);
180   check_exception("The fill option contains an invalid value", SV("{::{<}"), input);
181 
182   // *** sign ***
183   check_exception("The format specifier should consume the input or end with a '}'", SV("{::-}"), input);
184 
185   // *** alternate form ***
186   check_exception("The format specifier should consume the input or end with a '}'", SV("{::#}"), input);
187 
188   // *** zero-padding ***
189   check_exception("The width option should not have a leading zero", SV("{::05}"), input);
190 
191   // *** precision ***
192   check(SV(R"([Hel, wor])"), SV("{::.3}"), input);
193 
194   check(SV(R"([Hel, wor])"), SV("{::.{}}"), input, 3);
195 
196   check_exception("The precision option does not contain a value or an argument index", SV("{::.}"), input);
197 
198   // *** locale-specific form ***
199   check_exception("The format specifier should consume the input or end with a '}'", SV("{::L}"), input);
200 
201   // *** type ***
202   for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("s?"))
203     check_exception("The type option contains an invalid value for a string formatting argument", fmt, input);
204 
205   // ***** Both have a format-spec
206   check(SV(R"(^^[:::Hello, :::world]^^^)"), SV("{:^^25::>8}"), input);
207   check(SV(R"(^^[:::Hello, :::world]^^^)"), SV("{:^^{}::>8}"), input, 25);
208   check(SV(R"(^^[:::Hello, :::world]^^^)"), SV("{:^^{}::>{}}"), input, 25, 8);
209 
210   check(SV(R"(^^[:::Hello, :::world]^^^)"), SV("{:^^25::>8}"), input);
211   check(SV(R"(^^[:::Hello, :::world]^^^)"), SV("{:^^{}::>8}"), input, 25);
212   check(SV(R"(^^[:::Hello, :::world]^^^)"), SV("{:^^{}::>{}}"), input, 25, 8);
213 
214   check_exception(
215       "The argument index value is too large for the number of arguments supplied", SV("{:^^{}::>8}"), input);
216   check_exception(
217       "The argument index value is too large for the number of arguments supplied", SV("{:^^{}::>{}}"), input, 25);
218 }
219 
220 template <class CharT, class TestFunction, class ExceptionTest>
221 void test_range_string(TestFunction check, ExceptionTest check_exception) {
222   // libc++ uses different containers for contiguous and non-contiguous ranges.
223   std::array input{STR("Hello"), STR("world")};
224   test_range_string<CharT>(
225       check,
226       check_exception,
227       std::array{test_range_format_string<std::basic_string<CharT>>{input[0]},
228                  test_range_format_string<std::basic_string<CharT>>{input[1]}});
229   test_range_string<CharT>(
230       check,
231       check_exception,
232       std::array{test_range_format_string<std::basic_string_view<CharT>>{input[0]},
233                  test_range_format_string<std::basic_string_view<CharT>>{input[1]}});
234   test_range_string<CharT>(
235       check,
236       check_exception,
237       std::array{test_range_format_string<std::list<CharT>>{std::list<CharT>{input[0].begin(), input[0].end()}},
238                  test_range_format_string<std::list<CharT>>{std::list<CharT>{input[1].begin(), input[1].end()}}});
239   test_range_string<CharT>(
240       check,
241       check_exception,
242       std::list{test_range_format_string<std::list<CharT>>{std::list<CharT>{input[0].begin(), input[0].end()}},
243                 test_range_format_string<std::list<CharT>>{std::list<CharT>{input[1].begin(), input[1].end()}}});
244 }
245 
246 //
247 // Debug string
248 //
249 
250 template <class CharT, class TestFunction, class ExceptionTest>
251 void test_debug_string(TestFunction check, ExceptionTest check_exception, auto&& input) {
252   check(SV("\"hello\""), SV("{}"), input);
253   check(SV("\"hello\"^42"), SV("{}^42"), input);
254   check(SV("\"hello\"^42"), SV("{:}^42"), input);
255 
256   // *** align-fill & width ***
257   check(SV("\"hello\"     "), SV("{:12}"), input);
258   check(SV("\"hello\"*****"), SV("{:*<12}"), input);
259   check(SV("__\"hello\"___"), SV("{:_^12}"), input);
260   check(SV(":::::\"hello\""), SV("{::>12}"), input);
261 
262   check(SV("\"hello\"     "), SV("{:{}}"), input, 12);
263   check(SV("\"hello\"*****"), SV("{:*<{}}"), input, 12);
264   check(SV("__\"hello\"___"), SV("{:_^{}}"), input, 12);
265   check(SV(":::::\"hello\""), SV("{::>{}}"), input, 12);
266 
267   check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input);
268   check_exception("The fill option contains an invalid value", SV("{:{<}"), input);
269 
270   // *** sign ***
271   check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input);
272 
273   // *** alternate form ***
274   check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
275 
276   // *** zero-padding ***
277   check_exception("The width option should not have a leading zero", SV("{:0}"), input);
278 
279   // *** precision ***
280   check(SV("\"he"), SV("{:.3}"), input);
281   check(SV("\"he"), SV("{:.{}}"), input, 3);
282 
283   check(SV("\"he  "), SV("{:5.3}"), input);
284   check(SV("\"he  "), SV("{:{}.{}}"), input, 5, 3);
285 
286   // *** locale-specific form ***
287   check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
288 
289   // *** type ***
290   check(SV("\"hello\""), SV("{:s}"), input); // escape overrides the type option s
291   check(SV("\"hello\""), SV("{:?}"), input);
292   for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s?"))
293     check_exception("The type option contains an invalid value for a string formatting argument", fmt, input);
294 }
295 
296 template <class CharT, class TestFunction, class ExceptionTest>
297 void test_debug_string(TestFunction check, ExceptionTest check_exception) {
298   // libc++ uses different containers for contiguous and non-contiguous ranges.
299   std::basic_string<CharT> input = STR("hello");
300   test_debug_string<CharT>(check, check_exception, test_range_format_debug_string<std::basic_string<CharT>>{input});
301   test_debug_string<CharT>(
302       check, check_exception, test_range_format_debug_string<std::basic_string_view<CharT>>{input});
303   test_debug_string<CharT>(
304       check,
305       check_exception,
306       test_range_format_debug_string<std::list<CharT>>{std::list<CharT>{input.begin(), input.end()}});
307 }
308 
309 //
310 // Debug string range
311 //
312 
313 template <class CharT, class TestFunction, class ExceptionTest>
314 void test_range_debug_string(TestFunction check, ExceptionTest check_exception, auto&& input) {
315   // ***** underlying has no format-spec
316 
317   // *** align-fill & width ***
318   check(SV(R"(["Hello", "world"]     )"), SV("{:23}"), input);
319   check(SV(R"(["Hello", "world"]*****)"), SV("{:*<23}"), input);
320   check(SV(R"(__["Hello", "world"]___)"), SV("{:_^23}"), input);
321   check(SV(R"(#####["Hello", "world"])"), SV("{:#>23}"), input);
322 
323   check(SV(R"(["Hello", "world"]     )"), SV("{:{}}"), input, 23);
324   check(SV(R"(["Hello", "world"]*****)"), SV("{:*<{}}"), input, 23);
325   check(SV(R"(__["Hello", "world"]___)"), SV("{:_^{}}"), input, 23);
326   check(SV(R"(#####["Hello", "world"])"), SV("{:#>{}}"), input, 23);
327 
328   check_exception("The format string contains an invalid escape sequence", SV("{:}<}"), input);
329   check_exception("The fill option contains an invalid value", SV("{:{<}"), input);
330 
331   // *** sign ***
332   check_exception("The format specifier should consume the input or end with a '}'", SV("{:-}"), input);
333 
334   // *** alternate form ***
335   check_exception("The format specifier should consume the input or end with a '}'", SV("{:#}"), input);
336 
337   // *** zero-padding ***
338   check_exception("The width option should not have a leading zero", SV("{:0}"), input);
339 
340   // *** precision ***
341   check_exception("The format specifier should consume the input or end with a '}'", SV("{:.}"), input);
342 
343   // *** locale-specific form ***
344   check_exception("The format specifier should consume the input or end with a '}'", SV("{:L}"), input);
345 
346   // *** n
347   check(SV(R"(_"Hello", "world"_)"), SV("{:_^18n}"), input);
348 
349   // *** type ***
350   check_exception("Type m requires a pair or a tuple with two elements", SV("{:m}"), input);
351   check_exception("Type s requires character type as formatting argument", SV("{:s}"), input);
352   check_exception("Type ?s requires character type as formatting argument", SV("{:?s}"), input);
353 
354   for (std::basic_string_view<CharT> fmt : fmt_invalid_types<CharT>("s"))
355     check_exception("The format specifier should consume the input or end with a '}'", fmt, input);
356 
357   // ***** Only underlying has a format-spec
358   check(SV(R"(["Hello"   , "world"   ])"), SV("{::10}"), input);
359   check(SV(R"(["Hello"***, "world"***])"), SV("{::*<10}"), input);
360   check(SV(R"([_"Hello"__, _"world"__])"), SV("{::_^10}"), input);
361   check(SV(R"([:::"Hello", :::"world"])"), SV("{:::>10}"), input);
362 
363   check(SV(R"(["Hello"   , "world"   ])"), SV("{::{}}"), input, 10);
364   check(SV(R"(["Hello"***, "world"***])"), SV("{::*<{}}"), input, 10);
365   check(SV(R"([_"Hello"__, _"world"__])"), SV("{::_^{}}"), input, 10);
366   check(SV(R"([:::"Hello", :::"world"])"), SV("{:::>{}}"), input, 10);
367 
368   check_exception("The format string contains an invalid escape sequence", SV("{::}<}"), input);
369   check_exception("The fill option contains an invalid value", SV("{::{<}"), input);
370 
371   // *** sign ***
372   check_exception("The format specifier should consume the input or end with a '}'", SV("{::-}"), input);
373 
374   // *** alternate form ***
375   check_exception("The format specifier should consume the input or end with a '}'", SV("{::#}"), input);
376 
377   // *** zero-padding ***
378   check_exception("The width option should not have a leading zero", SV("{::05}"), input);
379 
380   // *** precision ***
381   check(SV(R"(["He, "wo])"), SV("{::.3}"), input);
382 
383   check(SV(R"(["He, "wo])"), SV("{::.{}}"), input, 3);
384 
385   check_exception("The precision option does not contain a value or an argument index", SV("{::.}"), input);
386 
387   // *** locale-specific form ***
388   check_exception("The format specifier should consume the input or end with a '}'", SV("{::L}"), input);
389 
390   // *** type ***
391   for (std::basic_string_view<CharT> fmt : fmt_invalid_nested_types<CharT>("s?"))
392     check_exception("The type option contains an invalid value for a string formatting argument", fmt, input);
393 
394   // ***** Both have a format-spec
395   check(SV(R"(^^[:::"Hello", :::"world"]^^^)"), SV("{:^^29::>10}"), input);
396   check(SV(R"(^^[:::"Hello", :::"world"]^^^)"), SV("{:^^{}::>10}"), input, 29);
397   check(SV(R"(^^[:::"Hello", :::"world"]^^^)"), SV("{:^^{}::>{}}"), input, 29, 10);
398 
399   check(SV(R"(^^[:::"Hello", :::"world"]^^^)"), SV("{:^^29::>10}"), input);
400   check(SV(R"(^^[:::"Hello", :::"world"]^^^)"), SV("{:^^{}::>10}"), input, 29);
401   check(SV(R"(^^[:::"Hello", :::"world"]^^^)"), SV("{:^^{}::>{}}"), input, 29, 10);
402 
403   check_exception(
404       "The argument index value is too large for the number of arguments supplied", SV("{:^^{}::>10}"), input);
405   check_exception(
406       "The argument index value is too large for the number of arguments supplied", SV("{:^^{}::>{}}"), input, 29);
407 }
408 
409 template <class CharT, class TestFunction, class ExceptionTest>
410 void test_range_debug_string(TestFunction check, ExceptionTest check_exception) {
411   // libc++ uses different containers for contiguous and non-contiguous ranges.
412   std::array input{STR("Hello"), STR("world")};
413   test_range_debug_string<CharT>(
414       check,
415       check_exception,
416       std::array{test_range_format_debug_string<std::basic_string<CharT>>{input[0]},
417                  test_range_format_debug_string<std::basic_string<CharT>>{input[1]}});
418   test_range_debug_string<CharT>(
419       check,
420       check_exception,
421       std::array{test_range_format_debug_string<std::basic_string_view<CharT>>{input[0]},
422                  test_range_format_debug_string<std::basic_string_view<CharT>>{input[1]}});
423   test_range_debug_string<CharT>(
424       check,
425       check_exception,
426       std::array{test_range_format_debug_string<std::list<CharT>>{std::list<CharT>{input[0].begin(), input[0].end()}},
427                  test_range_format_debug_string<std::list<CharT>>{std::list<CharT>{input[1].begin(), input[1].end()}}});
428   test_range_debug_string<CharT>(
429       check,
430       check_exception,
431       std::list{test_range_format_debug_string<std::list<CharT>>{std::list<CharT>{input[0].begin(), input[0].end()}},
432                 test_range_format_debug_string<std::list<CharT>>{std::list<CharT>{input[1].begin(), input[1].end()}}});
433 }
434 
435 //
436 // Driver
437 //
438 
439 template <class CharT, class TestFunction, class ExceptionTest>
440 void format_tests(TestFunction check, ExceptionTest check_exception) {
441   test_string<CharT>(check, check_exception);
442   test_range_string<CharT>(check, check_exception);
443 
444   test_debug_string<CharT>(check, check_exception);
445   test_range_debug_string<CharT>(check, check_exception);
446 }
447 
448 #endif //  TEST_STD_UTILITIES_FORMAT_FORMAT_RANGE_FORMAT_RANGE_FMTSTR_FORMAT_FUNCTIONS_TESTS_H
449