blob: cfd81bb34be3715e3352ffa7d7fdce485c3bcef2 [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001
2#include <cstdarg>
3#include <cstdint>
4#include <cstdio>
5#include <string>
6
7#include "gmock/gmock.h"
8#include "gtest/gtest.h"
9#include "absl/strings/str_format.h"
10#include "absl/strings/string_view.h"
11
12namespace absl {
13namespace {
14using str_format_internal::FormatArgImpl;
15
16using FormatEntryPointTest = ::testing::Test;
17
18TEST_F(FormatEntryPointTest, Format) {
19 std::string sink;
20 EXPECT_TRUE(Format(&sink, "A format %d", 123));
21 EXPECT_EQ("A format 123", sink);
22 sink.clear();
23
24 ParsedFormat<'d'> pc("A format %d");
25 EXPECT_TRUE(Format(&sink, pc, 123));
26 EXPECT_EQ("A format 123", sink);
27}
28TEST_F(FormatEntryPointTest, UntypedFormat) {
29 constexpr const char* formats[] = {
30 "",
31 "a",
32 "%80d",
33#if !defined(_MSC_VER) && !defined(__ANDROID__) && !defined(__native_client__)
34 // MSVC, NaCL and Android don't support positional syntax.
35 "complicated multipart %% %1$d format %1$0999d",
36#endif // _MSC_VER
37 };
38 for (const char* fmt : formats) {
39 std::string actual;
40 int i = 123;
41 FormatArgImpl arg_123(i);
42 absl::Span<const FormatArgImpl> args(&arg_123, 1);
43 UntypedFormatSpec format(fmt);
44
45 EXPECT_TRUE(FormatUntyped(&actual, format, args));
46 char buf[4096]{};
47 snprintf(buf, sizeof(buf), fmt, 123);
48 EXPECT_EQ(
49 str_format_internal::FormatPack(
50 str_format_internal::UntypedFormatSpecImpl::Extract(format), args),
51 buf);
52 EXPECT_EQ(actual, buf);
53 }
54 // The internal version works with a preparsed format.
55 ParsedFormat<'d'> pc("A format %d");
56 int i = 345;
57 FormatArg arg(i);
58 std::string out;
59 EXPECT_TRUE(str_format_internal::FormatUntyped(
60 &out, str_format_internal::UntypedFormatSpecImpl(&pc), {&arg, 1}));
61 EXPECT_EQ("A format 345", out);
62}
63
64TEST_F(FormatEntryPointTest, StringFormat) {
65 EXPECT_EQ("123", StrFormat("%d", 123));
66 constexpr absl::string_view view("=%d=", 4);
67 EXPECT_EQ("=123=", StrFormat(view, 123));
68}
69
70TEST_F(FormatEntryPointTest, AppendFormat) {
71 std::string s;
72 std::string& r = StrAppendFormat(&s, "%d", 123);
73 EXPECT_EQ(&s, &r); // should be same object
74 EXPECT_EQ("123", r);
75}
76
77TEST_F(FormatEntryPointTest, AppendFormatFail) {
78 std::string s = "orig";
79
80 UntypedFormatSpec format(" more %d");
81 FormatArgImpl arg("not an int");
82
83 EXPECT_EQ("orig",
84 str_format_internal::AppendPack(
85 &s, str_format_internal::UntypedFormatSpecImpl::Extract(format),
86 {&arg, 1}));
87}
88
89
90TEST_F(FormatEntryPointTest, ManyArgs) {
91 EXPECT_EQ("24", StrFormat("%24$d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
92 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24));
93 EXPECT_EQ("60", StrFormat("%60$d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
94 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
95 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
96 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
97 53, 54, 55, 56, 57, 58, 59, 60));
98}
99
100TEST_F(FormatEntryPointTest, Preparsed) {
101 ParsedFormat<'d'> pc("%d");
102 EXPECT_EQ("123", StrFormat(pc, 123));
103 // rvalue ok?
104 EXPECT_EQ("123", StrFormat(ParsedFormat<'d'>("%d"), 123));
105 constexpr absl::string_view view("=%d=", 4);
106 EXPECT_EQ("=123=", StrFormat(ParsedFormat<'d'>(view), 123));
107}
108
109TEST_F(FormatEntryPointTest, FormatCountCapture) {
110 int n = 0;
111 EXPECT_EQ("", StrFormat("%n", FormatCountCapture(&n)));
112 EXPECT_EQ(0, n);
113 EXPECT_EQ("123", StrFormat("%d%n", 123, FormatCountCapture(&n)));
114 EXPECT_EQ(3, n);
115}
116
117TEST_F(FormatEntryPointTest, FormatCountCaptureWrongType) {
118 // Should reject int*.
119 int n = 0;
120 UntypedFormatSpec format("%d%n");
121 int i = 123, *ip = &n;
122 FormatArgImpl args[2] = {FormatArgImpl(i), FormatArgImpl(ip)};
123
124 EXPECT_EQ("", str_format_internal::FormatPack(
125 str_format_internal::UntypedFormatSpecImpl::Extract(format),
126 absl::MakeSpan(args)));
127}
128
129TEST_F(FormatEntryPointTest, FormatCountCaptureMultiple) {
130 int n1 = 0;
131 int n2 = 0;
132 EXPECT_EQ(" 1 2",
133 StrFormat("%5d%n%10d%n", 1, FormatCountCapture(&n1), 2,
134 FormatCountCapture(&n2)));
135 EXPECT_EQ(5, n1);
136 EXPECT_EQ(15, n2);
137}
138
139TEST_F(FormatEntryPointTest, FormatCountCaptureExample) {
140 int n;
141 std::string s;
142 StrAppendFormat(&s, "%s: %n%s\n", "(1,1)", FormatCountCapture(&n), "(1,2)");
143 StrAppendFormat(&s, "%*s%s\n", n, "", "(2,2)");
144 EXPECT_EQ(7, n);
145 EXPECT_EQ(
146 "(1,1): (1,2)\n"
147 " (2,2)\n",
148 s);
149}
150
151TEST_F(FormatEntryPointTest, Stream) {
152 const std::string formats[] = {
153 "",
154 "a",
155 "%80d",
156 "%d %u %c %s %f %g",
157#if !defined(_MSC_VER) && !defined(__ANDROID__) && !defined(__native_client__)
158 // MSVC, NaCL and Android don't support positional syntax.
159 "complicated multipart %% %1$d format %1$080d",
160#endif // _MSC_VER
161 };
162 std::string buf(4096, '\0');
163 for (const auto& fmt : formats) {
164 const auto parsed =
165 ParsedFormat<'d', 'u', 'c', 's', 'f', 'g'>::NewAllowIgnored(fmt);
166 std::ostringstream oss;
167 oss << StreamFormat(*parsed, 123, 3, 49, "multistreaming!!!", 1.01, 1.01);
168 int fmt_result = snprintf(&*buf.begin(), buf.size(), fmt.c_str(), //
169 123, 3, 49, "multistreaming!!!", 1.01, 1.01);
170 ASSERT_TRUE(oss) << fmt;
171 ASSERT_TRUE(fmt_result >= 0 && static_cast<size_t>(fmt_result) < buf.size())
172 << fmt_result;
173 EXPECT_EQ(buf.c_str(), oss.str());
174 }
175}
176
177TEST_F(FormatEntryPointTest, StreamOk) {
178 std::ostringstream oss;
179 oss << StreamFormat("hello %d", 123);
180 EXPECT_EQ("hello 123", oss.str());
181 EXPECT_TRUE(oss.good());
182}
183
184TEST_F(FormatEntryPointTest, StreamFail) {
185 std::ostringstream oss;
186 UntypedFormatSpec format("hello %d");
187 FormatArgImpl arg("non-numeric");
188 oss << str_format_internal::Streamable(
189 str_format_internal::UntypedFormatSpecImpl::Extract(format), {&arg, 1});
190 EXPECT_EQ("hello ", oss.str()); // partial write
191 EXPECT_TRUE(oss.fail());
192}
193
194std::string WithSnprintf(const char* fmt, ...) {
195 std::string buf;
196 buf.resize(128);
197 va_list va;
198 va_start(va, fmt);
199 int r = vsnprintf(&*buf.begin(), buf.size(), fmt, va);
200 va_end(va);
201 EXPECT_GE(r, 0);
202 EXPECT_LT(r, buf.size());
203 buf.resize(r);
204 return buf;
205}
206
207TEST_F(FormatEntryPointTest, FloatPrecisionArg) {
208 // Test that positional parameters for width and precision
209 // are indexed to precede the value.
210 // Also sanity check the same formats against snprintf.
211 EXPECT_EQ("0.1", StrFormat("%.1f", 0.1));
212 EXPECT_EQ("0.1", WithSnprintf("%.1f", 0.1));
213 EXPECT_EQ(" 0.1", StrFormat("%*.1f", 5, 0.1));
214 EXPECT_EQ(" 0.1", WithSnprintf("%*.1f", 5, 0.1));
215 EXPECT_EQ("0.1", StrFormat("%.*f", 1, 0.1));
216 EXPECT_EQ("0.1", WithSnprintf("%.*f", 1, 0.1));
217 EXPECT_EQ(" 0.1", StrFormat("%*.*f", 5, 1, 0.1));
218 EXPECT_EQ(" 0.1", WithSnprintf("%*.*f", 5, 1, 0.1));
219}
220namespace streamed_test {
221struct X {};
222std::ostream& operator<<(std::ostream& os, const X&) {
223 return os << "X";
224}
225} // streamed_test
226
227TEST_F(FormatEntryPointTest, FormatStreamed) {
228 EXPECT_EQ("123", StrFormat("%s", FormatStreamed(123)));
229 EXPECT_EQ(" 123", StrFormat("%5s", FormatStreamed(123)));
230 EXPECT_EQ("123 ", StrFormat("%-5s", FormatStreamed(123)));
231 EXPECT_EQ("X", StrFormat("%s", FormatStreamed(streamed_test::X())));
232 EXPECT_EQ("123", StrFormat("%s", FormatStreamed(StreamFormat("%d", 123))));
233}
234
235// Helper class that creates a temporary file and exposes a FILE* to it.
236// It will close the file on destruction.
237class TempFile {
238 public:
239 TempFile() : file_(std::tmpfile()) {}
240 ~TempFile() { std::fclose(file_); }
241
242 std::FILE* file() const { return file_; }
243
244 // Read the file into a std::string.
245 std::string ReadFile() {
246 std::fseek(file_, 0, SEEK_END);
247 int size = std::ftell(file_);
248 EXPECT_GT(size, 0);
249 std::rewind(file_);
250 std::string str(2 * size, ' ');
251 int read_bytes = std::fread(&str[0], 1, str.size(), file_);
252 EXPECT_EQ(read_bytes, size);
253 str.resize(read_bytes);
254 EXPECT_TRUE(std::feof(file_));
255 return str;
256 }
257
258 private:
259 std::FILE* file_;
260};
261
262TEST_F(FormatEntryPointTest, FPrintF) {
263 TempFile tmp;
264 int result =
265 FPrintF(tmp.file(), "STRING: %s NUMBER: %010d", std::string("ABC"), -19);
266 EXPECT_EQ(result, 30);
267 EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019");
268}
269
270TEST_F(FormatEntryPointTest, FPrintFError) {
271 errno = 0;
272 int result = FPrintF(stdin, "ABC");
273 EXPECT_LT(result, 0);
274 EXPECT_EQ(errno, EBADF);
275}
276
277#ifdef __GLIBC__
278TEST_F(FormatEntryPointTest, FprintfTooLarge) {
279 std::FILE* f = std::fopen("/dev/null", "w");
280 int width = 2000000000;
281 errno = 0;
282 int result = FPrintF(f, "%*d %*d", width, 0, width, 0);
283 EXPECT_LT(result, 0);
284 EXPECT_EQ(errno, EFBIG);
285 std::fclose(f);
286}
287
288TEST_F(FormatEntryPointTest, PrintF) {
289 int stdout_tmp = dup(STDOUT_FILENO);
290
291 TempFile tmp;
292 std::fflush(stdout);
293 dup2(fileno(tmp.file()), STDOUT_FILENO);
294
295 int result = PrintF("STRING: %s NUMBER: %010d", std::string("ABC"), -19);
296
297 std::fflush(stdout);
298 dup2(stdout_tmp, STDOUT_FILENO);
299 close(stdout_tmp);
300
301 EXPECT_EQ(result, 30);
302 EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019");
303}
304#endif // __GLIBC__
305
306TEST_F(FormatEntryPointTest, SNPrintF) {
307 char buffer[16];
308 int result =
309 SNPrintF(buffer, sizeof(buffer), "STRING: %s", std::string("ABC"));
310 EXPECT_EQ(result, 11);
311 EXPECT_EQ(std::string(buffer), "STRING: ABC");
312
313 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 123456);
314 EXPECT_EQ(result, 14);
315 EXPECT_EQ(std::string(buffer), "NUMBER: 123456");
316
317 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 1234567);
318 EXPECT_EQ(result, 15);
319 EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
320
321 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 12345678);
322 EXPECT_EQ(result, 16);
323 EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
324
325 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 123456789);
326 EXPECT_EQ(result, 17);
327 EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
328
329 result = SNPrintF(nullptr, 0, "Just checking the %s of the output.", "size");
330 EXPECT_EQ(result, 37);
331}
332
333TEST(StrFormat, BehavesAsDocumented) {
334 std::string s = absl::StrFormat("%s, %d!", "Hello", 123);
335 EXPECT_EQ("Hello, 123!", s);
336 // The format of a replacement is
337 // '%'[position][flags][width['.'precision]][length_modifier][format]
338 EXPECT_EQ(absl::StrFormat("%1$+3.2Lf", 1.1), "+1.10");
339 // Text conversion:
340 // "c" - Character. Eg: 'a' -> "A", 20 -> " "
341 EXPECT_EQ(StrFormat("%c", 'a'), "a");
342 EXPECT_EQ(StrFormat("%c", 0x20), " ");
343 // Formats char and integral types: int, long, uint64_t, etc.
344 EXPECT_EQ(StrFormat("%c", int{'a'}), "a");
345 EXPECT_EQ(StrFormat("%c", long{'a'}), "a"); // NOLINT
346 EXPECT_EQ(StrFormat("%c", uint64_t{'a'}), "a");
347 // "s" - std::string Eg: "C" -> "C", std::string("C++") -> "C++"
348 // Formats std::string, char*, string_view, and Cord.
349 EXPECT_EQ(StrFormat("%s", "C"), "C");
350 EXPECT_EQ(StrFormat("%s", std::string("C++")), "C++");
351 EXPECT_EQ(StrFormat("%s", string_view("view")), "view");
352 // Integral Conversion
353 // These format integral types: char, int, long, uint64_t, etc.
354 EXPECT_EQ(StrFormat("%d", char{10}), "10");
355 EXPECT_EQ(StrFormat("%d", int{10}), "10");
356 EXPECT_EQ(StrFormat("%d", long{10}), "10"); // NOLINT
357 EXPECT_EQ(StrFormat("%d", uint64_t{10}), "10");
358 // d,i - signed decimal Eg: -10 -> "-10"
359 EXPECT_EQ(StrFormat("%d", -10), "-10");
360 EXPECT_EQ(StrFormat("%i", -10), "-10");
361 // o - octal Eg: 10 -> "12"
362 EXPECT_EQ(StrFormat("%o", 10), "12");
363 // u - unsigned decimal Eg: 10 -> "10"
364 EXPECT_EQ(StrFormat("%u", 10), "10");
365 // x/X - lower,upper case hex Eg: 10 -> "a"/"A"
366 EXPECT_EQ(StrFormat("%x", 10), "a");
367 EXPECT_EQ(StrFormat("%X", 10), "A");
368 // Floating-point, with upper/lower-case output.
369 // These format floating points types: float, double, long double, etc.
370 EXPECT_EQ(StrFormat("%.1f", float{1}), "1.0");
371 EXPECT_EQ(StrFormat("%.1f", double{1}), "1.0");
372 const long double long_double = 1.0;
373 EXPECT_EQ(StrFormat("%.1f", long_double), "1.0");
374 // These also format integral types: char, int, long, uint64_t, etc.:
375 EXPECT_EQ(StrFormat("%.1f", char{1}), "1.0");
376 EXPECT_EQ(StrFormat("%.1f", int{1}), "1.0");
377 EXPECT_EQ(StrFormat("%.1f", long{1}), "1.0"); // NOLINT
378 EXPECT_EQ(StrFormat("%.1f", uint64_t{1}), "1.0");
379 // f/F - decimal. Eg: 123456789 -> "123456789.000000"
380 EXPECT_EQ(StrFormat("%f", 123456789), "123456789.000000");
381 EXPECT_EQ(StrFormat("%F", 123456789), "123456789.000000");
382 // e/E - exponentiated Eg: .01 -> "1.00000e-2"/"1.00000E-2"
383 EXPECT_EQ(StrFormat("%e", .01), "1.000000e-02");
384 EXPECT_EQ(StrFormat("%E", .01), "1.000000E-02");
385 // g/G - exponentiate to fit Eg: .01 -> "0.01", 1e10 ->"1e+10"/"1E+10"
386 EXPECT_EQ(StrFormat("%g", .01), "0.01");
387 EXPECT_EQ(StrFormat("%g", 1e10), "1e+10");
388 EXPECT_EQ(StrFormat("%G", 1e10), "1E+10");
389 // a/A - lower,upper case hex Eg: -3.0 -> "-0x1.8p+1"/"-0X1.8P+1"
390
391// On Android platform <=21, there is a regression in hexfloat formatting.
392#if !defined(__ANDROID_API__) || __ANDROID_API__ > 21
393 EXPECT_EQ(StrFormat("%.1a", -3.0), "-0x1.8p+1"); // .1 to fix MSVC output
394 EXPECT_EQ(StrFormat("%.1A", -3.0), "-0X1.8P+1"); // .1 to fix MSVC output
395#endif
396
397 // Other conversion
398 int64_t value = 0x7ffdeb4;
399 auto ptr_value = static_cast<uintptr_t>(value);
400 const int& something = *reinterpret_cast<const int*>(ptr_value);
401 EXPECT_EQ(StrFormat("%p", &something), StrFormat("0x%x", ptr_value));
402
403 // Output widths are supported, with optional flags.
404 EXPECT_EQ(StrFormat("%3d", 1), " 1");
405 EXPECT_EQ(StrFormat("%3d", 123456), "123456");
406 EXPECT_EQ(StrFormat("%06.2f", 1.234), "001.23");
407 EXPECT_EQ(StrFormat("%+d", 1), "+1");
408 EXPECT_EQ(StrFormat("% d", 1), " 1");
409 EXPECT_EQ(StrFormat("%-4d", -1), "-1 ");
410 EXPECT_EQ(StrFormat("%#o", 10), "012");
411 EXPECT_EQ(StrFormat("%#x", 15), "0xf");
412 EXPECT_EQ(StrFormat("%04d", 8), "0008");
413 // Posix positional substitution.
414 EXPECT_EQ(absl::StrFormat("%2$s, %3$s, %1$s!", "vici", "veni", "vidi"),
415 "veni, vidi, vici!");
416 // Length modifiers are ignored.
417 EXPECT_EQ(StrFormat("%hhd", int{1}), "1");
418 EXPECT_EQ(StrFormat("%hd", int{1}), "1");
419 EXPECT_EQ(StrFormat("%ld", int{1}), "1");
420 EXPECT_EQ(StrFormat("%lld", int{1}), "1");
421 EXPECT_EQ(StrFormat("%Ld", int{1}), "1");
422 EXPECT_EQ(StrFormat("%jd", int{1}), "1");
423 EXPECT_EQ(StrFormat("%zd", int{1}), "1");
424 EXPECT_EQ(StrFormat("%td", int{1}), "1");
425 EXPECT_EQ(StrFormat("%qd", int{1}), "1");
426}
427
428using str_format_internal::ExtendedParsedFormat;
429using str_format_internal::ParsedFormatBase;
430
431struct SummarizeConsumer {
432 std::string* out;
433 explicit SummarizeConsumer(std::string* out) : out(out) {}
434
435 bool Append(string_view s) {
436 *out += "[" + std::string(s) + "]";
437 return true;
438 }
439
440 bool ConvertOne(const str_format_internal::UnboundConversion& conv,
441 string_view s) {
442 *out += "{";
443 *out += std::string(s);
444 *out += ":";
445 *out += std::to_string(conv.arg_position) + "$";
446 if (conv.width.is_from_arg()) {
447 *out += std::to_string(conv.width.get_from_arg()) + "$*";
448 }
449 if (conv.precision.is_from_arg()) {
450 *out += "." + std::to_string(conv.precision.get_from_arg()) + "$*";
451 }
452 *out += conv.conv.Char();
453 *out += "}";
454 return true;
455 }
456};
457
458std::string SummarizeParsedFormat(const ParsedFormatBase& pc) {
459 std::string out;
460 if (!pc.ProcessFormat(SummarizeConsumer(&out))) out += "!";
461 return out;
462}
463
464using ParsedFormatTest = ::testing::Test;
465
466TEST_F(ParsedFormatTest, SimpleChecked) {
467 EXPECT_EQ("[ABC]{d:1$d}[DEF]",
468 SummarizeParsedFormat(ParsedFormat<'d'>("ABC%dDEF")));
469 EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}",
470 SummarizeParsedFormat(ParsedFormat<'s', 'd', 'f'>("%sFFF%dZZZ%f")));
471 EXPECT_EQ("{s:1$s}[ ]{.*d:3$.2$*d}",
472 SummarizeParsedFormat(ParsedFormat<'s', '*', 'd'>("%s %.*d")));
473}
474
475TEST_F(ParsedFormatTest, SimpleUncheckedCorrect) {
476 auto f = ParsedFormat<'d'>::New("ABC%dDEF");
477 ASSERT_TRUE(f);
478 EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
479
480 std::string format = "%sFFF%dZZZ%f";
481 auto f2 = ParsedFormat<'s', 'd', 'f'>::New(format);
482
483 ASSERT_TRUE(f2);
484 EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
485
486 f2 = ParsedFormat<'s', 'd', 'f'>::New("%s %d %f");
487
488 ASSERT_TRUE(f2);
489 EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
490
491 auto star = ParsedFormat<'*', 'd'>::New("%*d");
492 ASSERT_TRUE(star);
493 EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
494
495 auto dollar = ParsedFormat<'d', 's'>::New("%2$s %1$d");
496 ASSERT_TRUE(dollar);
497 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
498 // with reuse
499 dollar = ParsedFormat<'d', 's'>::New("%2$s %1$d %1$d");
500 ASSERT_TRUE(dollar);
501 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
502 SummarizeParsedFormat(*dollar));
503}
504
505TEST_F(ParsedFormatTest, SimpleUncheckedIgnoredArgs) {
506 EXPECT_FALSE((ParsedFormat<'d', 's'>::New("ABC")));
507 EXPECT_FALSE((ParsedFormat<'d', 's'>::New("%dABC")));
508 EXPECT_FALSE((ParsedFormat<'d', 's'>::New("ABC%2$s")));
509 auto f = ParsedFormat<'d', 's'>::NewAllowIgnored("ABC");
510 ASSERT_TRUE(f);
511 EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
512 f = ParsedFormat<'d', 's'>::NewAllowIgnored("%dABC");
513 ASSERT_TRUE(f);
514 EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
515 f = ParsedFormat<'d', 's'>::NewAllowIgnored("ABC%2$s");
516 ASSERT_TRUE(f);
517 EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
518}
519
520TEST_F(ParsedFormatTest, SimpleUncheckedUnsupported) {
521 EXPECT_FALSE(ParsedFormat<'d'>::New("%1$d %1$x"));
522 EXPECT_FALSE(ParsedFormat<'x'>::New("%1$d %1$x"));
523}
524
525TEST_F(ParsedFormatTest, SimpleUncheckedIncorrect) {
526 EXPECT_FALSE(ParsedFormat<'d'>::New(""));
527
528 EXPECT_FALSE(ParsedFormat<'d'>::New("ABC%dDEF%d"));
529
530 std::string format = "%sFFF%dZZZ%f";
531 EXPECT_FALSE((ParsedFormat<'s', 'd', 'g'>::New(format)));
532}
533
534using str_format_internal::Conv;
535
536TEST_F(ParsedFormatTest, UncheckedCorrect) {
537 auto f = ExtendedParsedFormat<Conv::d>::New("ABC%dDEF");
538 ASSERT_TRUE(f);
539 EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
540
541 std::string format = "%sFFF%dZZZ%f";
542 auto f2 =
543 ExtendedParsedFormat<Conv::string, Conv::d, Conv::floating>::New(format);
544
545 ASSERT_TRUE(f2);
546 EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
547
548 f2 = ExtendedParsedFormat<Conv::string, Conv::d, Conv::floating>::New(
549 "%s %d %f");
550
551 ASSERT_TRUE(f2);
552 EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
553
554 auto star = ExtendedParsedFormat<Conv::star, Conv::d>::New("%*d");
555 ASSERT_TRUE(star);
556 EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
557
558 auto dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d");
559 ASSERT_TRUE(dollar);
560 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
561 // with reuse
562 dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d %1$d");
563 ASSERT_TRUE(dollar);
564 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
565 SummarizeParsedFormat(*dollar));
566}
567
568TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) {
569 EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC")));
570 EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("%dABC")));
571 EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC%2$s")));
572 auto f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC");
573 ASSERT_TRUE(f);
574 EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
575 f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("%dABC");
576 ASSERT_TRUE(f);
577 EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
578 f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC%2$s");
579 ASSERT_TRUE(f);
580 EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
581}
582
583TEST_F(ParsedFormatTest, UncheckedMultipleTypes) {
584 auto dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d %1$x");
585 EXPECT_TRUE(dx);
586 EXPECT_EQ("{1$d:1$d}[ ]{1$x:1$x}", SummarizeParsedFormat(*dx));
587
588 dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d");
589 EXPECT_TRUE(dx);
590 EXPECT_EQ("{1$d:1$d}", SummarizeParsedFormat(*dx));
591}
592
593TEST_F(ParsedFormatTest, UncheckedIncorrect) {
594 EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New(""));
595
596 EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New("ABC%dDEF%d"));
597
598 std::string format = "%sFFF%dZZZ%f";
599 EXPECT_FALSE((ExtendedParsedFormat<Conv::s, Conv::d, Conv::g>::New(format)));
600}
601
602TEST_F(ParsedFormatTest, RegressionMixPositional) {
603 EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::o>::New("%1$d %o")));
604}
605
606using FormatWrapperTest = ::testing::Test;
607
608// Plain wrapper for StrFormat.
609template <typename... Args>
610std::string WrappedFormat(const absl::FormatSpec<Args...>& format,
611 const Args&... args) {
612 return StrFormat(format, args...);
613}
614
615TEST_F(FormatWrapperTest, ConstexprStringFormat) {
616 EXPECT_EQ(WrappedFormat("%s there", "hello"), "hello there");
617}
618
619TEST_F(FormatWrapperTest, ParsedFormat) {
620 ParsedFormat<'s'> format("%s there");
621 EXPECT_EQ(WrappedFormat(format, "hello"), "hello there");
622}
623
624} // namespace
625} // namespace absl
626
627// Some codegen thunks that we can use to easily dump the generated assembly for
628// different StrFormat calls.
629
630std::string CodegenAbslStrFormatInt(int i) { // NOLINT
631 return absl::StrFormat("%d", i);
632}
633
634std::string CodegenAbslStrFormatIntStringInt64(int i, const std::string& s,
635 int64_t i64) { // NOLINT
636 return absl::StrFormat("%d %s %d", i, s, i64);
637}
638
639void CodegenAbslStrAppendFormatInt(std::string* out, int i) { // NOLINT
640 absl::StrAppendFormat(out, "%d", i);
641}
642
643void CodegenAbslStrAppendFormatIntStringInt64(std::string* out, int i,
644 const std::string& s,
645 int64_t i64) { // NOLINT
646 absl::StrAppendFormat(out, "%d %s %d", i, s, i64);
647}