1 // Copyright 2020 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/strings/str_format.h"
16
17 #include <cstdarg>
18 #include <cstdint>
19 #include <cstdio>
20 #include <string>
21
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/strings/cord.h"
25 #include "absl/strings/str_cat.h"
26 #include "absl/strings/string_view.h"
27
28 namespace absl {
29 ABSL_NAMESPACE_BEGIN
30 namespace {
31 using str_format_internal::FormatArgImpl;
32
33 using FormatEntryPointTest = ::testing::Test;
34
TEST_F(FormatEntryPointTest,Format)35 TEST_F(FormatEntryPointTest, Format) {
36 std::string sink;
37 EXPECT_TRUE(Format(&sink, "A format %d", 123));
38 EXPECT_EQ("A format 123", sink);
39 sink.clear();
40
41 ParsedFormat<'d'> pc("A format %d");
42 EXPECT_TRUE(Format(&sink, pc, 123));
43 EXPECT_EQ("A format 123", sink);
44 }
TEST_F(FormatEntryPointTest,UntypedFormat)45 TEST_F(FormatEntryPointTest, UntypedFormat) {
46 constexpr const char* formats[] = {
47 "",
48 "a",
49 "%80d",
50 #if !defined(_MSC_VER) && !defined(__ANDROID__) && !defined(__native_client__)
51 // MSVC, NaCL and Android don't support positional syntax.
52 "complicated multipart %% %1$d format %1$0999d",
53 #endif // _MSC_VER
54 };
55 for (const char* fmt : formats) {
56 std::string actual;
57 int i = 123;
58 FormatArgImpl arg_123(i);
59 absl::Span<const FormatArgImpl> args(&arg_123, 1);
60 UntypedFormatSpec format(fmt);
61
62 EXPECT_TRUE(FormatUntyped(&actual, format, args));
63 char buf[4096]{};
64 snprintf(buf, sizeof(buf), fmt, 123);
65 EXPECT_EQ(
66 str_format_internal::FormatPack(
67 str_format_internal::UntypedFormatSpecImpl::Extract(format), args),
68 buf);
69 EXPECT_EQ(actual, buf);
70 }
71 // The internal version works with a preparsed format.
72 ParsedFormat<'d'> pc("A format %d");
73 int i = 345;
74 FormatArg arg(i);
75 std::string out;
76 EXPECT_TRUE(str_format_internal::FormatUntyped(
77 &out, str_format_internal::UntypedFormatSpecImpl(&pc), {&arg, 1}));
78 EXPECT_EQ("A format 345", out);
79 }
80
TEST_F(FormatEntryPointTest,StringFormat)81 TEST_F(FormatEntryPointTest, StringFormat) {
82 EXPECT_EQ("123", StrFormat("%d", 123));
83 constexpr absl::string_view view("=%d=", 4);
84 EXPECT_EQ("=123=", StrFormat(view, 123));
85 }
86
TEST_F(FormatEntryPointTest,AppendFormat)87 TEST_F(FormatEntryPointTest, AppendFormat) {
88 std::string s;
89 std::string& r = StrAppendFormat(&s, "%d", 123);
90 EXPECT_EQ(&s, &r); // should be same object
91 EXPECT_EQ("123", r);
92 }
93
TEST_F(FormatEntryPointTest,AppendFormatFail)94 TEST_F(FormatEntryPointTest, AppendFormatFail) {
95 std::string s = "orig";
96
97 UntypedFormatSpec format(" more %d");
98 FormatArgImpl arg("not an int");
99
100 EXPECT_EQ("orig",
101 str_format_internal::AppendPack(
102 &s, str_format_internal::UntypedFormatSpecImpl::Extract(format),
103 {&arg, 1}));
104 }
105
106
TEST_F(FormatEntryPointTest,ManyArgs)107 TEST_F(FormatEntryPointTest, ManyArgs) {
108 EXPECT_EQ("24", StrFormat("%24$d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
109 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24));
110 EXPECT_EQ("60", StrFormat("%60$d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
111 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
112 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
113 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
114 53, 54, 55, 56, 57, 58, 59, 60));
115 }
116
TEST_F(FormatEntryPointTest,Preparsed)117 TEST_F(FormatEntryPointTest, Preparsed) {
118 ParsedFormat<'d'> pc("%d");
119 EXPECT_EQ("123", StrFormat(pc, 123));
120 // rvalue ok?
121 EXPECT_EQ("123", StrFormat(ParsedFormat<'d'>("%d"), 123));
122 constexpr absl::string_view view("=%d=", 4);
123 EXPECT_EQ("=123=", StrFormat(ParsedFormat<'d'>(view), 123));
124 }
125
TEST_F(FormatEntryPointTest,FormatCountCapture)126 TEST_F(FormatEntryPointTest, FormatCountCapture) {
127 int n = 0;
128 EXPECT_EQ("", StrFormat("%n", FormatCountCapture(&n)));
129 EXPECT_EQ(0, n);
130 EXPECT_EQ("123", StrFormat("%d%n", 123, FormatCountCapture(&n)));
131 EXPECT_EQ(3, n);
132 }
133
TEST_F(FormatEntryPointTest,FormatCountCaptureWrongType)134 TEST_F(FormatEntryPointTest, FormatCountCaptureWrongType) {
135 // Should reject int*.
136 int n = 0;
137 UntypedFormatSpec format("%d%n");
138 int i = 123, *ip = &n;
139 FormatArgImpl args[2] = {FormatArgImpl(i), FormatArgImpl(ip)};
140
141 EXPECT_EQ("", str_format_internal::FormatPack(
142 str_format_internal::UntypedFormatSpecImpl::Extract(format),
143 absl::MakeSpan(args)));
144 }
145
TEST_F(FormatEntryPointTest,FormatCountCaptureMultiple)146 TEST_F(FormatEntryPointTest, FormatCountCaptureMultiple) {
147 int n1 = 0;
148 int n2 = 0;
149 EXPECT_EQ(" 1 2",
150 StrFormat("%5d%n%10d%n", 1, FormatCountCapture(&n1), 2,
151 FormatCountCapture(&n2)));
152 EXPECT_EQ(5, n1);
153 EXPECT_EQ(15, n2);
154 }
155
TEST_F(FormatEntryPointTest,FormatCountCaptureExample)156 TEST_F(FormatEntryPointTest, FormatCountCaptureExample) {
157 int n;
158 std::string s;
159 StrAppendFormat(&s, "%s: %n%s\n", "(1,1)", FormatCountCapture(&n), "(1,2)");
160 StrAppendFormat(&s, "%*s%s\n", n, "", "(2,2)");
161 EXPECT_EQ(7, n);
162 EXPECT_EQ(
163 "(1,1): (1,2)\n"
164 " (2,2)\n",
165 s);
166 }
167
TEST_F(FormatEntryPointTest,Stream)168 TEST_F(FormatEntryPointTest, Stream) {
169 const std::string formats[] = {
170 "",
171 "a",
172 "%80d",
173 "%d %u %c %s %f %g",
174 #if !defined(_MSC_VER) && !defined(__ANDROID__) && !defined(__native_client__)
175 // MSVC, NaCL and Android don't support positional syntax.
176 "complicated multipart %% %1$d format %1$080d",
177 #endif // _MSC_VER
178 };
179 std::string buf(4096, '\0');
180 for (const auto& fmt : formats) {
181 const auto parsed =
182 ParsedFormat<'d', 'u', 'c', 's', 'f', 'g'>::NewAllowIgnored(fmt);
183 std::ostringstream oss;
184 oss << StreamFormat(*parsed, 123, 3, 49, "multistreaming!!!", 1.01, 1.01);
185 int fmt_result = snprintf(&*buf.begin(), buf.size(), fmt.c_str(), //
186 123, 3, 49, "multistreaming!!!", 1.01, 1.01);
187 ASSERT_TRUE(oss) << fmt;
188 ASSERT_TRUE(fmt_result >= 0 && static_cast<size_t>(fmt_result) < buf.size())
189 << fmt_result;
190 EXPECT_EQ(buf.c_str(), oss.str());
191 }
192 }
193
TEST_F(FormatEntryPointTest,StreamOk)194 TEST_F(FormatEntryPointTest, StreamOk) {
195 std::ostringstream oss;
196 oss << StreamFormat("hello %d", 123);
197 EXPECT_EQ("hello 123", oss.str());
198 EXPECT_TRUE(oss.good());
199 }
200
TEST_F(FormatEntryPointTest,StreamFail)201 TEST_F(FormatEntryPointTest, StreamFail) {
202 std::ostringstream oss;
203 UntypedFormatSpec format("hello %d");
204 FormatArgImpl arg("non-numeric");
205 oss << str_format_internal::Streamable(
206 str_format_internal::UntypedFormatSpecImpl::Extract(format), {&arg, 1});
207 EXPECT_EQ("hello ", oss.str()); // partial write
208 EXPECT_TRUE(oss.fail());
209 }
210
WithSnprintf(const char * fmt,...)211 std::string WithSnprintf(const char* fmt, ...) {
212 std::string buf;
213 buf.resize(128);
214 va_list va;
215 va_start(va, fmt);
216 int r = vsnprintf(&*buf.begin(), buf.size(), fmt, va);
217 va_end(va);
218 EXPECT_GE(r, 0);
219 EXPECT_LT(r, buf.size());
220 buf.resize(r);
221 return buf;
222 }
223
TEST_F(FormatEntryPointTest,FloatPrecisionArg)224 TEST_F(FormatEntryPointTest, FloatPrecisionArg) {
225 // Test that positional parameters for width and precision
226 // are indexed to precede the value.
227 // Also sanity check the same formats against snprintf.
228 EXPECT_EQ("0.1", StrFormat("%.1f", 0.1));
229 EXPECT_EQ("0.1", WithSnprintf("%.1f", 0.1));
230 EXPECT_EQ(" 0.1", StrFormat("%*.1f", 5, 0.1));
231 EXPECT_EQ(" 0.1", WithSnprintf("%*.1f", 5, 0.1));
232 EXPECT_EQ("0.1", StrFormat("%.*f", 1, 0.1));
233 EXPECT_EQ("0.1", WithSnprintf("%.*f", 1, 0.1));
234 EXPECT_EQ(" 0.1", StrFormat("%*.*f", 5, 1, 0.1));
235 EXPECT_EQ(" 0.1", WithSnprintf("%*.*f", 5, 1, 0.1));
236 }
237 namespace streamed_test {
238 struct X {};
operator <<(std::ostream & os,const X &)239 std::ostream& operator<<(std::ostream& os, const X&) {
240 return os << "X";
241 }
242 } // streamed_test
243
TEST_F(FormatEntryPointTest,FormatStreamed)244 TEST_F(FormatEntryPointTest, FormatStreamed) {
245 EXPECT_EQ("123", StrFormat("%s", FormatStreamed(123)));
246 EXPECT_EQ(" 123", StrFormat("%5s", FormatStreamed(123)));
247 EXPECT_EQ("123 ", StrFormat("%-5s", FormatStreamed(123)));
248 EXPECT_EQ("X", StrFormat("%s", FormatStreamed(streamed_test::X())));
249 EXPECT_EQ("123", StrFormat("%s", FormatStreamed(StreamFormat("%d", 123))));
250 }
251
252 // Helper class that creates a temporary file and exposes a FILE* to it.
253 // It will close the file on destruction.
254 class TempFile {
255 public:
TempFile()256 TempFile() : file_(std::tmpfile()) {}
~TempFile()257 ~TempFile() { std::fclose(file_); }
258
file() const259 std::FILE* file() const { return file_; }
260
261 // Read the file into a string.
ReadFile()262 std::string ReadFile() {
263 std::fseek(file_, 0, SEEK_END);
264 int size = std::ftell(file_);
265 EXPECT_GT(size, 0);
266 std::rewind(file_);
267 std::string str(2 * size, ' ');
268 int read_bytes = std::fread(&str[0], 1, str.size(), file_);
269 EXPECT_EQ(read_bytes, size);
270 str.resize(read_bytes);
271 EXPECT_TRUE(std::feof(file_));
272 return str;
273 }
274
275 private:
276 std::FILE* file_;
277 };
278
TEST_F(FormatEntryPointTest,FPrintF)279 TEST_F(FormatEntryPointTest, FPrintF) {
280 TempFile tmp;
281 int result =
282 FPrintF(tmp.file(), "STRING: %s NUMBER: %010d", std::string("ABC"), -19);
283 EXPECT_EQ(result, 30);
284 EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019");
285 }
286
TEST_F(FormatEntryPointTest,FPrintFError)287 TEST_F(FormatEntryPointTest, FPrintFError) {
288 errno = 0;
289 int result = FPrintF(stdin, "ABC");
290 EXPECT_LT(result, 0);
291 EXPECT_EQ(errno, EBADF);
292 }
293
294 #ifdef __GLIBC__
TEST_F(FormatEntryPointTest,FprintfTooLarge)295 TEST_F(FormatEntryPointTest, FprintfTooLarge) {
296 std::FILE* f = std::fopen("/dev/null", "w");
297 int width = 2000000000;
298 errno = 0;
299 int result = FPrintF(f, "%*d %*d", width, 0, width, 0);
300 EXPECT_LT(result, 0);
301 EXPECT_EQ(errno, EFBIG);
302 std::fclose(f);
303 }
304
TEST_F(FormatEntryPointTest,PrintF)305 TEST_F(FormatEntryPointTest, PrintF) {
306 int stdout_tmp = dup(STDOUT_FILENO);
307
308 TempFile tmp;
309 std::fflush(stdout);
310 dup2(fileno(tmp.file()), STDOUT_FILENO);
311
312 int result = PrintF("STRING: %s NUMBER: %010d", std::string("ABC"), -19);
313
314 std::fflush(stdout);
315 dup2(stdout_tmp, STDOUT_FILENO);
316 close(stdout_tmp);
317
318 EXPECT_EQ(result, 30);
319 EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019");
320 }
321 #endif // __GLIBC__
322
TEST_F(FormatEntryPointTest,SNPrintF)323 TEST_F(FormatEntryPointTest, SNPrintF) {
324 char buffer[16];
325 int result =
326 SNPrintF(buffer, sizeof(buffer), "STRING: %s", std::string("ABC"));
327 EXPECT_EQ(result, 11);
328 EXPECT_EQ(std::string(buffer), "STRING: ABC");
329
330 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 123456);
331 EXPECT_EQ(result, 14);
332 EXPECT_EQ(std::string(buffer), "NUMBER: 123456");
333
334 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 1234567);
335 EXPECT_EQ(result, 15);
336 EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
337
338 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 12345678);
339 EXPECT_EQ(result, 16);
340 EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
341
342 result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 123456789);
343 EXPECT_EQ(result, 17);
344 EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
345
346 result = SNPrintF(nullptr, 0, "Just checking the %s of the output.", "size");
347 EXPECT_EQ(result, 37);
348 }
349
TEST(StrFormat,BehavesAsDocumented)350 TEST(StrFormat, BehavesAsDocumented) {
351 std::string s = absl::StrFormat("%s, %d!", "Hello", 123);
352 EXPECT_EQ("Hello, 123!", s);
353 // The format of a replacement is
354 // '%'[position][flags][width['.'precision]][length_modifier][format]
355 EXPECT_EQ(absl::StrFormat("%1$+3.2Lf", 1.1), "+1.10");
356 // Text conversion:
357 // "c" - Character. Eg: 'a' -> "A", 20 -> " "
358 EXPECT_EQ(StrFormat("%c", 'a'), "a");
359 EXPECT_EQ(StrFormat("%c", 0x20), " ");
360 // Formats char and integral types: int, long, uint64_t, etc.
361 EXPECT_EQ(StrFormat("%c", int{'a'}), "a");
362 EXPECT_EQ(StrFormat("%c", long{'a'}), "a"); // NOLINT
363 EXPECT_EQ(StrFormat("%c", uint64_t{'a'}), "a");
364 // "s" - string Eg: "C" -> "C", std::string("C++") -> "C++"
365 // Formats std::string, char*, string_view, and Cord.
366 EXPECT_EQ(StrFormat("%s", "C"), "C");
367 EXPECT_EQ(StrFormat("%s", std::string("C++")), "C++");
368 EXPECT_EQ(StrFormat("%s", string_view("view")), "view");
369 EXPECT_EQ(StrFormat("%s", absl::Cord("cord")), "cord");
370 // Integral Conversion
371 // These format integral types: char, int, long, uint64_t, etc.
372 EXPECT_EQ(StrFormat("%d", char{10}), "10");
373 EXPECT_EQ(StrFormat("%d", int{10}), "10");
374 EXPECT_EQ(StrFormat("%d", long{10}), "10"); // NOLINT
375 EXPECT_EQ(StrFormat("%d", uint64_t{10}), "10");
376 // d,i - signed decimal Eg: -10 -> "-10"
377 EXPECT_EQ(StrFormat("%d", -10), "-10");
378 EXPECT_EQ(StrFormat("%i", -10), "-10");
379 // o - octal Eg: 10 -> "12"
380 EXPECT_EQ(StrFormat("%o", 10), "12");
381 // u - unsigned decimal Eg: 10 -> "10"
382 EXPECT_EQ(StrFormat("%u", 10), "10");
383 // x/X - lower,upper case hex Eg: 10 -> "a"/"A"
384 EXPECT_EQ(StrFormat("%x", 10), "a");
385 EXPECT_EQ(StrFormat("%X", 10), "A");
386 // Floating-point, with upper/lower-case output.
387 // These format floating points types: float, double, long double, etc.
388 EXPECT_EQ(StrFormat("%.1f", float{1}), "1.0");
389 EXPECT_EQ(StrFormat("%.1f", double{1}), "1.0");
390 const long double long_double = 1.0;
391 EXPECT_EQ(StrFormat("%.1f", long_double), "1.0");
392 // These also format integral types: char, int, long, uint64_t, etc.:
393 EXPECT_EQ(StrFormat("%.1f", char{1}), "1.0");
394 EXPECT_EQ(StrFormat("%.1f", int{1}), "1.0");
395 EXPECT_EQ(StrFormat("%.1f", long{1}), "1.0"); // NOLINT
396 EXPECT_EQ(StrFormat("%.1f", uint64_t{1}), "1.0");
397 // f/F - decimal. Eg: 123456789 -> "123456789.000000"
398 EXPECT_EQ(StrFormat("%f", 123456789), "123456789.000000");
399 EXPECT_EQ(StrFormat("%F", 123456789), "123456789.000000");
400 // e/E - exponentiated Eg: .01 -> "1.00000e-2"/"1.00000E-2"
401 EXPECT_EQ(StrFormat("%e", .01), "1.000000e-02");
402 EXPECT_EQ(StrFormat("%E", .01), "1.000000E-02");
403 // g/G - exponentiate to fit Eg: .01 -> "0.01", 1e10 ->"1e+10"/"1E+10"
404 EXPECT_EQ(StrFormat("%g", .01), "0.01");
405 EXPECT_EQ(StrFormat("%g", 1e10), "1e+10");
406 EXPECT_EQ(StrFormat("%G", 1e10), "1E+10");
407 // a/A - lower,upper case hex Eg: -3.0 -> "-0x1.8p+1"/"-0X1.8P+1"
408
409 // On Android platform <=21, there is a regression in hexfloat formatting.
410 #if !defined(__ANDROID_API__) || __ANDROID_API__ > 21
411 EXPECT_EQ(StrFormat("%.1a", -3.0), "-0x1.8p+1"); // .1 to fix MSVC output
412 EXPECT_EQ(StrFormat("%.1A", -3.0), "-0X1.8P+1"); // .1 to fix MSVC output
413 #endif
414
415 // Other conversion
416 int64_t value = 0x7ffdeb4;
417 auto ptr_value = static_cast<uintptr_t>(value);
418 const int& something = *reinterpret_cast<const int*>(ptr_value);
419 EXPECT_EQ(StrFormat("%p", &something), StrFormat("0x%x", ptr_value));
420
421 // Output widths are supported, with optional flags.
422 EXPECT_EQ(StrFormat("%3d", 1), " 1");
423 EXPECT_EQ(StrFormat("%3d", 123456), "123456");
424 EXPECT_EQ(StrFormat("%06.2f", 1.234), "001.23");
425 EXPECT_EQ(StrFormat("%+d", 1), "+1");
426 EXPECT_EQ(StrFormat("% d", 1), " 1");
427 EXPECT_EQ(StrFormat("%-4d", -1), "-1 ");
428 EXPECT_EQ(StrFormat("%#o", 10), "012");
429 EXPECT_EQ(StrFormat("%#x", 15), "0xf");
430 EXPECT_EQ(StrFormat("%04d", 8), "0008");
431 // Posix positional substitution.
432 EXPECT_EQ(absl::StrFormat("%2$s, %3$s, %1$s!", "vici", "veni", "vidi"),
433 "veni, vidi, vici!");
434 // Length modifiers are ignored.
435 EXPECT_EQ(StrFormat("%hhd", int{1}), "1");
436 EXPECT_EQ(StrFormat("%hd", int{1}), "1");
437 EXPECT_EQ(StrFormat("%ld", int{1}), "1");
438 EXPECT_EQ(StrFormat("%lld", int{1}), "1");
439 EXPECT_EQ(StrFormat("%Ld", int{1}), "1");
440 EXPECT_EQ(StrFormat("%jd", int{1}), "1");
441 EXPECT_EQ(StrFormat("%zd", int{1}), "1");
442 EXPECT_EQ(StrFormat("%td", int{1}), "1");
443 EXPECT_EQ(StrFormat("%qd", int{1}), "1");
444 }
445
446 using str_format_internal::ExtendedParsedFormat;
447 using str_format_internal::ParsedFormatBase;
448
449 struct SummarizeConsumer {
450 std::string* out;
SummarizeConsumerabsl::__anon036ce1f40111::SummarizeConsumer451 explicit SummarizeConsumer(std::string* out) : out(out) {}
452
Appendabsl::__anon036ce1f40111::SummarizeConsumer453 bool Append(string_view s) {
454 *out += "[" + std::string(s) + "]";
455 return true;
456 }
457
ConvertOneabsl::__anon036ce1f40111::SummarizeConsumer458 bool ConvertOne(const str_format_internal::UnboundConversion& conv,
459 string_view s) {
460 *out += "{";
461 *out += std::string(s);
462 *out += ":";
463 *out += std::to_string(conv.arg_position) + "$";
464 if (conv.width.is_from_arg()) {
465 *out += std::to_string(conv.width.get_from_arg()) + "$*";
466 }
467 if (conv.precision.is_from_arg()) {
468 *out += "." + std::to_string(conv.precision.get_from_arg()) + "$*";
469 }
470 *out += str_format_internal::FormatConversionCharToChar(conv.conv);
471 *out += "}";
472 return true;
473 }
474 };
475
SummarizeParsedFormat(const ParsedFormatBase & pc)476 std::string SummarizeParsedFormat(const ParsedFormatBase& pc) {
477 std::string out;
478 if (!pc.ProcessFormat(SummarizeConsumer(&out))) out += "!";
479 return out;
480 }
481
482 using ParsedFormatTest = ::testing::Test;
483
TEST_F(ParsedFormatTest,SimpleChecked)484 TEST_F(ParsedFormatTest, SimpleChecked) {
485 EXPECT_EQ("[ABC]{d:1$d}[DEF]",
486 SummarizeParsedFormat(ParsedFormat<'d'>("ABC%dDEF")));
487 EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}",
488 SummarizeParsedFormat(ParsedFormat<'s', 'd', 'f'>("%sFFF%dZZZ%f")));
489 EXPECT_EQ("{s:1$s}[ ]{.*d:3$.2$*d}",
490 SummarizeParsedFormat(ParsedFormat<'s', '*', 'd'>("%s %.*d")));
491 }
492
TEST_F(ParsedFormatTest,SimpleUncheckedCorrect)493 TEST_F(ParsedFormatTest, SimpleUncheckedCorrect) {
494 auto f = ParsedFormat<'d'>::New("ABC%dDEF");
495 ASSERT_TRUE(f);
496 EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
497
498 std::string format = "%sFFF%dZZZ%f";
499 auto f2 = ParsedFormat<'s', 'd', 'f'>::New(format);
500
501 ASSERT_TRUE(f2);
502 EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
503
504 f2 = ParsedFormat<'s', 'd', 'f'>::New("%s %d %f");
505
506 ASSERT_TRUE(f2);
507 EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
508
509 auto star = ParsedFormat<'*', 'd'>::New("%*d");
510 ASSERT_TRUE(star);
511 EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
512
513 auto dollar = ParsedFormat<'d', 's'>::New("%2$s %1$d");
514 ASSERT_TRUE(dollar);
515 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
516 // with reuse
517 dollar = ParsedFormat<'d', 's'>::New("%2$s %1$d %1$d");
518 ASSERT_TRUE(dollar);
519 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
520 SummarizeParsedFormat(*dollar));
521 }
522
TEST_F(ParsedFormatTest,SimpleUncheckedIgnoredArgs)523 TEST_F(ParsedFormatTest, SimpleUncheckedIgnoredArgs) {
524 EXPECT_FALSE((ParsedFormat<'d', 's'>::New("ABC")));
525 EXPECT_FALSE((ParsedFormat<'d', 's'>::New("%dABC")));
526 EXPECT_FALSE((ParsedFormat<'d', 's'>::New("ABC%2$s")));
527 auto f = ParsedFormat<'d', 's'>::NewAllowIgnored("ABC");
528 ASSERT_TRUE(f);
529 EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
530 f = ParsedFormat<'d', 's'>::NewAllowIgnored("%dABC");
531 ASSERT_TRUE(f);
532 EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
533 f = ParsedFormat<'d', 's'>::NewAllowIgnored("ABC%2$s");
534 ASSERT_TRUE(f);
535 EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
536 }
537
TEST_F(ParsedFormatTest,SimpleUncheckedUnsupported)538 TEST_F(ParsedFormatTest, SimpleUncheckedUnsupported) {
539 EXPECT_FALSE(ParsedFormat<'d'>::New("%1$d %1$x"));
540 EXPECT_FALSE(ParsedFormat<'x'>::New("%1$d %1$x"));
541 }
542
TEST_F(ParsedFormatTest,SimpleUncheckedIncorrect)543 TEST_F(ParsedFormatTest, SimpleUncheckedIncorrect) {
544 EXPECT_FALSE(ParsedFormat<'d'>::New(""));
545
546 EXPECT_FALSE(ParsedFormat<'d'>::New("ABC%dDEF%d"));
547
548 std::string format = "%sFFF%dZZZ%f";
549 EXPECT_FALSE((ParsedFormat<'s', 'd', 'g'>::New(format)));
550 }
551
552 #if defined(__cpp_nontype_template_parameter_auto)
553
554 template <auto T>
555 std::true_type IsValidParsedFormatArgTest(ParsedFormat<T>*);
556
557 template <auto T>
558 std::false_type IsValidParsedFormatArgTest(...);
559
560 template <auto T>
561 using IsValidParsedFormatArg = decltype(IsValidParsedFormatArgTest<T>(nullptr));
562
TEST_F(ParsedFormatTest,OnlyValidTypesAllowed)563 TEST_F(ParsedFormatTest, OnlyValidTypesAllowed) {
564 ASSERT_TRUE(IsValidParsedFormatArg<'c'>::value);
565
566 ASSERT_TRUE(IsValidParsedFormatArg<FormatConversionCharSet::d>::value);
567
568 ASSERT_TRUE(IsValidParsedFormatArg<absl::FormatConversionCharSet::d |
569 absl::FormatConversionCharSet::x>::value);
570 ASSERT_TRUE(
571 IsValidParsedFormatArg<absl::FormatConversionCharSet::kIntegral>::value);
572
573 // This is an easy mistake to make, however, this will reduce to an integer
574 // which has no meaning, so we need to ensure it doesn't compile.
575 ASSERT_FALSE(IsValidParsedFormatArg<'x' | 'd'>::value);
576
577 // For now, we disallow construction based on ConversionChar (rather than
578 // CharSet)
579 ASSERT_FALSE(IsValidParsedFormatArg<absl::FormatConversionChar::d>::value);
580 }
581
TEST_F(ParsedFormatTest,ExtendedTyping)582 TEST_F(ParsedFormatTest, ExtendedTyping) {
583 EXPECT_FALSE(ParsedFormat<FormatConversionCharSet::d>::New(""));
584 ASSERT_TRUE(ParsedFormat<absl::FormatConversionCharSet::d>::New("%d"));
585 auto v1 = ParsedFormat<'d', absl::FormatConversionCharSet::s>::New("%d%s");
586 ASSERT_TRUE(v1);
587 auto v2 = ParsedFormat<absl::FormatConversionCharSet::d, 's'>::New("%d%s");
588 ASSERT_TRUE(v2);
589 auto v3 = ParsedFormat<absl::FormatConversionCharSet::d |
590 absl::FormatConversionCharSet::s,
591 's'>::New("%d%s");
592 ASSERT_TRUE(v3);
593 auto v4 = ParsedFormat<absl::FormatConversionCharSet::d |
594 absl::FormatConversionCharSet::s,
595 's'>::New("%s%s");
596 ASSERT_TRUE(v4);
597 }
598 #endif
599
TEST_F(ParsedFormatTest,UncheckedCorrect)600 TEST_F(ParsedFormatTest, UncheckedCorrect) {
601 auto f =
602 ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New("ABC%dDEF");
603 ASSERT_TRUE(f);
604 EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
605
606 std::string format = "%sFFF%dZZZ%f";
607 auto f2 = ExtendedParsedFormat<
608 absl::FormatConversionCharSet::kString, absl::FormatConversionCharSet::d,
609 absl::FormatConversionCharSet::kFloating>::New(format);
610
611 ASSERT_TRUE(f2);
612 EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
613
614 f2 = ExtendedParsedFormat<
615 absl::FormatConversionCharSet::kString, absl::FormatConversionCharSet::d,
616 absl::FormatConversionCharSet::kFloating>::New("%s %d %f");
617
618 ASSERT_TRUE(f2);
619 EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
620
621 auto star =
622 ExtendedParsedFormat<absl::FormatConversionCharSet::kStar,
623 absl::FormatConversionCharSet::d>::New("%*d");
624 ASSERT_TRUE(star);
625 EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star));
626
627 auto dollar =
628 ExtendedParsedFormat<absl::FormatConversionCharSet::d,
629 absl::FormatConversionCharSet::s>::New("%2$s %1$d");
630 ASSERT_TRUE(dollar);
631 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar));
632 // with reuse
633 dollar = ExtendedParsedFormat<
634 absl::FormatConversionCharSet::d,
635 absl::FormatConversionCharSet::s>::New("%2$s %1$d %1$d");
636 ASSERT_TRUE(dollar);
637 EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}",
638 SummarizeParsedFormat(*dollar));
639 }
640
TEST_F(ParsedFormatTest,UncheckedIgnoredArgs)641 TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) {
642 EXPECT_FALSE(
643 (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
644 absl::FormatConversionCharSet::s>::New("ABC")));
645 EXPECT_FALSE(
646 (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
647 absl::FormatConversionCharSet::s>::New("%dABC")));
648 EXPECT_FALSE(
649 (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
650 absl::FormatConversionCharSet::s>::New("ABC%2$s")));
651 auto f = ExtendedParsedFormat<
652 absl::FormatConversionCharSet::d,
653 absl::FormatConversionCharSet::s>::NewAllowIgnored("ABC");
654 ASSERT_TRUE(f);
655 EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
656 f = ExtendedParsedFormat<
657 absl::FormatConversionCharSet::d,
658 absl::FormatConversionCharSet::s>::NewAllowIgnored("%dABC");
659 ASSERT_TRUE(f);
660 EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f));
661 f = ExtendedParsedFormat<
662 absl::FormatConversionCharSet::d,
663 absl::FormatConversionCharSet::s>::NewAllowIgnored("ABC%2$s");
664 ASSERT_TRUE(f);
665 EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
666 }
667
TEST_F(ParsedFormatTest,UncheckedMultipleTypes)668 TEST_F(ParsedFormatTest, UncheckedMultipleTypes) {
669 auto dx =
670 ExtendedParsedFormat<absl::FormatConversionCharSet::d |
671 absl::FormatConversionCharSet::x>::New("%1$d %1$x");
672 EXPECT_TRUE(dx);
673 EXPECT_EQ("{1$d:1$d}[ ]{1$x:1$x}", SummarizeParsedFormat(*dx));
674
675 dx = ExtendedParsedFormat<absl::FormatConversionCharSet::d |
676 absl::FormatConversionCharSet::x>::New("%1$d");
677 EXPECT_TRUE(dx);
678 EXPECT_EQ("{1$d:1$d}", SummarizeParsedFormat(*dx));
679 }
680
TEST_F(ParsedFormatTest,UncheckedIncorrect)681 TEST_F(ParsedFormatTest, UncheckedIncorrect) {
682 EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New(""));
683
684 EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New(
685 "ABC%dDEF%d"));
686
687 std::string format = "%sFFF%dZZZ%f";
688 EXPECT_FALSE(
689 (ExtendedParsedFormat<absl::FormatConversionCharSet::s,
690 absl::FormatConversionCharSet::d,
691 absl::FormatConversionCharSet::g>::New(format)));
692 }
693
TEST_F(ParsedFormatTest,RegressionMixPositional)694 TEST_F(ParsedFormatTest, RegressionMixPositional) {
695 EXPECT_FALSE(
696 (ExtendedParsedFormat<absl::FormatConversionCharSet::d,
697 absl::FormatConversionCharSet::o>::New("%1$d %o")));
698 }
699
700 using FormatWrapperTest = ::testing::Test;
701
702 // Plain wrapper for StrFormat.
703 template <typename... Args>
WrappedFormat(const absl::FormatSpec<Args...> & format,const Args &...args)704 std::string WrappedFormat(const absl::FormatSpec<Args...>& format,
705 const Args&... args) {
706 return StrFormat(format, args...);
707 }
708
TEST_F(FormatWrapperTest,ConstexprStringFormat)709 TEST_F(FormatWrapperTest, ConstexprStringFormat) {
710 EXPECT_EQ(WrappedFormat("%s there", "hello"), "hello there");
711 }
712
TEST_F(FormatWrapperTest,ParsedFormat)713 TEST_F(FormatWrapperTest, ParsedFormat) {
714 ParsedFormat<'s'> format("%s there");
715 EXPECT_EQ(WrappedFormat(format, "hello"), "hello there");
716 }
717
718 } // namespace
719 ABSL_NAMESPACE_END
720 } // namespace absl
721
722 using FormatExtensionTest = ::testing::Test;
723
724 struct Point {
725 friend absl::FormatConvertResult<absl::FormatConversionCharSet::kString |
726 absl::FormatConversionCharSet::kIntegral>
AbslFormatConvert(const Point & p,const absl::FormatConversionSpec & spec,absl::FormatSink * s)727 AbslFormatConvert(const Point& p, const absl::FormatConversionSpec& spec,
728 absl::FormatSink* s) {
729 if (spec.conversion_char() == absl::FormatConversionChar::s) {
730 s->Append(absl::StrCat("x=", p.x, " y=", p.y));
731 } else {
732 s->Append(absl::StrCat(p.x, ",", p.y));
733 }
734 return {true};
735 }
736
737 int x = 10;
738 int y = 20;
739 };
740
TEST_F(FormatExtensionTest,AbslFormatConvertExample)741 TEST_F(FormatExtensionTest, AbslFormatConvertExample) {
742 Point p;
743 EXPECT_EQ(absl::StrFormat("a %s z", p), "a x=10 y=20 z");
744 EXPECT_EQ(absl::StrFormat("a %d z", p), "a 10,20 z");
745
746 // Typed formatting will fail to compile an invalid format.
747 // StrFormat("%f", p); // Does not compile.
748 std::string actual;
749 absl::UntypedFormatSpec f1("%f");
750 // FormatUntyped will return false for bad character.
751 EXPECT_FALSE(absl::FormatUntyped(&actual, f1, {absl::FormatArg(p)}));
752 }
753
754 // Some codegen thunks that we can use to easily dump the generated assembly for
755 // different StrFormat calls.
756
CodegenAbslStrFormatInt(int i)757 std::string CodegenAbslStrFormatInt(int i) { // NOLINT
758 return absl::StrFormat("%d", i);
759 }
760
CodegenAbslStrFormatIntStringInt64(int i,const std::string & s,int64_t i64)761 std::string CodegenAbslStrFormatIntStringInt64(int i, const std::string& s,
762 int64_t i64) { // NOLINT
763 return absl::StrFormat("%d %s %d", i, s, i64);
764 }
765
CodegenAbslStrAppendFormatInt(std::string * out,int i)766 void CodegenAbslStrAppendFormatInt(std::string* out, int i) { // NOLINT
767 absl::StrAppendFormat(out, "%d", i);
768 }
769
CodegenAbslStrAppendFormatIntStringInt64(std::string * out,int i,const std::string & s,int64_t i64)770 void CodegenAbslStrAppendFormatIntStringInt64(std::string* out, int i,
771 const std::string& s,
772 int64_t i64) { // NOLINT
773 absl::StrAppendFormat(out, "%d %s %d", i, s, i64);
774 }
775