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