]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/testsuite/std/format/functions/format.cc
libstc++: std::formattable concept should not be defined for C++20
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / std / format / functions / format.cc
CommitLineData
1d9454ab
JW
1// { dg-options "-std=gnu++20" }
2// { dg-do run { target c++20 } }
3
4#include <format>
5#include <string>
6#include <limits>
7#include <cstdint>
ce86d967 8#include <cstdio>
1d9454ab
JW
9#include <testsuite_hooks.h>
10
11void
12test_no_args()
13{
14 std::string s;
15 s = std::format("disco");
16 VERIFY( s == "disco" );
17
18 s = std::format("}} machine {{ funk }} specialists {{");
19 VERIFY( s == "} machine { funk } specialists {" );
20
21 s = std::format("128bpm }}");
22 VERIFY( s == "128bpm }" );
23}
24
25void
26test_unescaped()
27{
28#ifdef __cpp_exceptions
29 for (auto f : { "{", "}", "{{{", "{{}", "}{", "{{{{{" })
30 try {
31 (void) std::vformat(f, std::make_format_args());
32 VERIFY( false );
33 } catch (const std::format_error& e) {
34 std::string what = e.what();
35 VERIFY( what.find("unmatched") != what.npos );
36 }
37#endif
38}
39
40struct brit_punc : std::numpunct<char>
41{
42 std::string do_grouping() const override { return "\3\3"; }
43 char do_thousands_sep() const override { return ','; }
44 std::string do_truename() const override { return "yes mate"; }
45 std::string do_falsename() const override { return "nah bruv"; }
46};
47
48void
49test_std_examples()
50{
51 using namespace std;
52
53 string s = format("{0}-{{", 8); // value of s is "8-{"
54 VERIFY( s == "8-{" );
55
56 // align
57 {
58 char c = 120;
59 string s0 = format("{:6}", 42);
60 VERIFY(s0 == " 42");
61 string s1 = format("{:6}", 'x');
62 VERIFY(s1 == "x ");
63 string s2 = format("{:*<6}", 'x');
64 VERIFY(s2 == "x*****");
65 string s3 = format("{:*>6}", 'x');
66 VERIFY(s3 == "*****x");
67 string s4 = format("{:*^6}", 'x');
68 VERIFY(s4 == "**x***");
69 string s5 = format("{:6d}", c);
70 VERIFY(s5 == " 120");
71 string s6 = format("{:6}", true);
72 VERIFY(s6 == "true ");
73 }
74
75 // sign
76 {
77 double inf = numeric_limits<double>::infinity();
78 double nan = numeric_limits<double>::quiet_NaN();
79 string s0 = format("{0:},{0:+},{0:-},{0: }", 1);
80 VERIFY(s0 == "1,+1,1, 1");
81 string s1 = format("{0:},{0:+},{0:-},{0: }", -1);
82 VERIFY(s1 == "-1,-1,-1,-1");
83 string s2 = format("{0:},{0:+},{0:-},{0: }", inf);
84 VERIFY(s2 == "inf,+inf,inf, inf");
85 string s3 = format("{0:},{0:+},{0:-},{0: }", nan);
86 VERIFY(s3 == "nan,+nan,nan, nan");
87 }
88
89 // alternate form and zero fill
90 {
91 char c = 120;
92 string s1 = format("{:+06d}", c);
93 VERIFY(s1 == "+00120");
94 string s2 = format("{:#06x}", 0xa);
95 VERIFY(s2 == "0x000a");
96 string s3 = format("{:<06}", -42);
97 VERIFY(s3 == "-42 "); // 0 is ignored because of < alignment
98 }
99
100 // integer presentation types
101 {
102 // Change global locale so "{:L}" adds digit separators.
103 std::locale::global(std::locale({}, new brit_punc));
104
105 string s0 = format("{}", 42);
106 VERIFY(s0 == "42");
107 string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42);
108 VERIFY(s1 == "101010 42 52 2a");
109 string s2 = format("{0:#x} {0:#X}", 42);
110 VERIFY(s2 == "0x2a 0X2A");
111 string s3 = format("{:L}", 1234);
112 VERIFY(s3 == "1,234");
113
114 // Restore
115 std::locale::global(std::locale::classic());
116 }
117}
118
119void
120test_alternate_forms()
121{
122 std::string s;
123
124 s = std::format("{0:#b} {0:+#B} {0:#o} {0:#x} {0:+#X} {0: #d}", 42);
125 VERIFY( s == "0b101010 +0B101010 052 0x2a +0X2A 42" );
126 s = std::format("{0:#b} {0:+#B} {0:#o} {0:#x} {0:+#X} {0: #d}", 0);
127 VERIFY( s == "0b0 +0B0 0 0x0 +0X0 0" );
128
129 s = std::format("{0:+#012g} {0:+#014g} {0:+#014g}", 1234.0);
130 VERIFY( s == "+00001234.00 +0000001234.00 +0000001234.00" );
131 s = std::format("{0:+#0{1}g} {0:+#0{2}g} {0:+#0{2}g}", 1234.5, 12, 14);
132 VERIFY( s == "+00001234.50 +0000001234.50 +0000001234.50" );
133
134 s = std::format("{:#.2g}", -0.0);
135 VERIFY( s == "-0.0" );
136}
137
138struct euro_punc : std::numpunct<char>
139{
140 std::string do_grouping() const override { return "\3\3"; }
141 char do_thousands_sep() const override { return '.'; }
142 char do_decimal_point() const override { return ','; }
143};
144
145void
146test_locale()
147{
148 // The default C locale.
149 std::locale cloc = std::locale::classic();
150 // A custom locale using comma digit separators.
151 std::locale bloc(cloc, new brit_punc);
152 // A custom locale using period digit separators.
153 std::locale eloc(cloc, new euro_punc);
154
155 std::string s;
156
157 // Change the global locale:
158 std::locale::global(bloc);
159 // Format using the global locale:
160 s = std::format("{0:L} {0:Lx} {0:Lb}", 12345);
161 VERIFY( s == "12,345 3,039 11,000,000,111,001" );
162 s = std::format("{0:L} {0:.7Lg} {0:La}", 12345.6789);
163 VERIFY( s == "12,345.6789 12,345.68 1.81cd6e631f8a1p+13" );
164
165 s = std::format("{0:s} {0:L} {1:Ls} {0:Ld}", true, false);
166 VERIFY( s == "true yes mate nah bruv 1" );
167
168 // Format using a specific locale:
169 s = std::format(eloc, "{0:L} {0:Lx} {0:Lb}", 12345);
170 VERIFY( s == "12.345 3.039 11.000.000.111.001" );
171 s = std::format(eloc, "{0:L} {0:.7LG} {0:La}", 12345.6789);
172 VERIFY( s == "12.345,6789 12.345,68 1,81cd6e631f8a1p+13" );
173
174 s = std::format(eloc, "{0:#Lg} {0:+#.3Lg} {0:#08.4Lg}", -1234.);
175 VERIFY( s == "-1.234,00 -1,23e+03 -01.234," );
176
177 // Restore
178 std::locale::global(cloc);
179}
180
181void
182test_width()
183{
184 std::string s;
185
186 s = std::format("{:4}", "");
187 VERIFY( s == " " );
188 s = std::format("{:{}}", "", 3);
189 VERIFY( s == " " );
190 s = std::format("{1:{0}}", 2, "");
191 VERIFY( s == " " );
192 s = std::format("{:03}", 9);
193 VERIFY( s == "009" );
194
195 s = std::format("DR {0:{1}}: allow width {1} from arg-id", 3721, 0);
196 VERIFY( s == "DR 3721: allow width 0 from arg-id" );
197
198 try {
199 s = std::format("Negative width is an error: {0:{1}}", 123, -1);
200 VERIFY(false);
201 } catch (const std::format_error&) {
202 }
203
204 try {
205 auto args = std::make_format_args(false, true);
206 s = std::vformat("DR 3720: restrict type of width arg-id {0:{1}}", args);
207 VERIFY(false);
208 } catch (const std::format_error&) {
209 }
210
211 try {
212 auto args = std::make_format_args('?', '!');
213 s = std::vformat("DR 3720: restrict type of width arg-id {0:{1}}", args);
214 VERIFY(false);
215 } catch (const std::format_error&) {
216 }
217}
218
219void
220test_wchar()
221{
222 using namespace std::literals;
223 std::wstring s;
224
225 s = std::format(L"{} {} {} {} {} {}", L'0', 1, 2LL, 3.4, L"five", L"six"s);
226 VERIFY( s == L"0 1 2 3.4 five six" );
227
228 std::locale loc;
229 s = std::format(loc, L"{:L} {:.3s}{:Lc}", true, L"data"sv, '.');
230 VERIFY( s == L"true dat." );
231}
232
233void
234test_minmax()
235{
236 auto check = []<typename T>(T) {
237 const int digits = std::numeric_limits<T>::digits;
238 const std::string zeros(digits, '0');
239 const std::string ones(digits, '1');
240 auto s = std::format("{:b}" , std::numeric_limits<T>::min());
241 VERIFY( s == "-1" + zeros );
242 s = std::format("{:b}" , std::numeric_limits<T>::max());
243 VERIFY( s == ones );
244 using U = std::make_unsigned_t<T>;
245 s = std::format("{:0{}b}" , std::numeric_limits<U>::min(), digits + 1);
246 VERIFY( s == '0' + zeros );
247 s = std::format("{:b}" , std::numeric_limits<U>::max());
248 VERIFY( s == '1' + ones );
249 };
250 check(std::int8_t(0));
251 check(std::int16_t(0));
252 check(std::int32_t(0));
253 check(std::int64_t(0));
254#ifdef __SIZEOF_INT128__
255 check(__int128(0));
256#endif
257}
258
259void
260test_p1652r1() // printf corner cases in std::format
261{
262 std::string s;
263
264 // Problem 1: "#o" specification should not print 0 as "00"
265 s = std::format("{:#o}", 0);
266 VERIFY( s == "0" );
267
268 // Problem 2: 'c' should be able to print 65 as "A" (ASCII)
269 int c = 'A';
270 s = std::format("{:c}", c);
271 VERIFY( s == "A" );
272
273 // Problem 3: "-000nan" is not a floating point value
274 double nan = std::numeric_limits<double>::quiet_NaN();
275 try {
276 s = std::vformat("{:0=6}", std::make_format_args(nan));
277 VERIFY( false );
278 } catch (const std::format_error&) {
279 }
280
281 s = std::format("{:06}", nan);
282 VERIFY( s == " nan" );
283
284 // Problem 4: bool needs a type format specifier
285 s = std::format("{:s}", true);
286 VERIFY( s == "true" );
287
288 // Problem 5: double does not roundtrip float
289 s = std::format("{}", 3.31f);
290 VERIFY( s == "3.31" );
291}
292
ce86d967
JW
293template<typename T>
294bool format_float()
295{
296 auto s = std::format("{:#} != {:<+7.3f}", (T)-0.0, (T)0.5);
297 return s == "-0. != +0.500 ";
298}
299
a5d4f38f
JW
300#if __cplusplus > 202002L
301template<typename T>
302concept formattable = std::formattable<T, char>;
303#else
304template<typename T>
305concept formattable = requires (T t, char* p) { std::to_chars(p, p, t); };
306#endif
307
1d9454ab
JW
308void
309test_float128()
310{
311#ifdef __SIZEOF_FLOAT128__
a5d4f38f 312 if constexpr (formattable<__float128>)
ce86d967
JW
313 VERIFY( format_float<__float128>() );
314 else
315 std::puts("Cannot format __float128 on this target");
316#endif
317#if __FLT128_DIG__
a5d4f38f 318 if constexpr (formattable<_Float128>)
ce86d967
JW
319 VERIFY( format_float<_Float128>() );
320 else
321 std::puts("Cannot format _Float128 on this target");
1d9454ab
JW
322#endif
323}
324
325int main()
326{
327 test_no_args();
328 test_unescaped();
329 test_std_examples();
330 test_alternate_forms();
331 test_locale();
332 test_width();
333 test_wchar();
334 test_minmax();
335 test_p1652r1();
336 test_float128();
337}