• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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