• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <errno.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include <cctype>
5 #include <cmath>
6 #include <string>
7 
8 #include "gmock/gmock.h"
9 #include "gtest/gtest.h"
10 #include "absl/base/internal/raw_logging.h"
11 #include "absl/strings/internal/str_format/bind.h"
12 
13 namespace absl {
14 ABSL_NAMESPACE_BEGIN
15 namespace str_format_internal {
16 namespace {
17 
18 template <typename T, size_t N>
ArraySize(T (&)[N])19 size_t ArraySize(T (&)[N]) {
20   return N;
21 }
22 
LengthModFor(float)23 std::string LengthModFor(float) { return ""; }
LengthModFor(double)24 std::string LengthModFor(double) { return ""; }
LengthModFor(long double)25 std::string LengthModFor(long double) { return "L"; }
LengthModFor(char)26 std::string LengthModFor(char) { return "hh"; }
LengthModFor(signed char)27 std::string LengthModFor(signed char) { return "hh"; }
LengthModFor(unsigned char)28 std::string LengthModFor(unsigned char) { return "hh"; }
LengthModFor(short)29 std::string LengthModFor(short) { return "h"; }           // NOLINT
LengthModFor(unsigned short)30 std::string LengthModFor(unsigned short) { return "h"; }  // NOLINT
LengthModFor(int)31 std::string LengthModFor(int) { return ""; }
LengthModFor(unsigned)32 std::string LengthModFor(unsigned) { return ""; }
LengthModFor(long)33 std::string LengthModFor(long) { return "l"; }                 // NOLINT
LengthModFor(unsigned long)34 std::string LengthModFor(unsigned long) { return "l"; }        // NOLINT
LengthModFor(long long)35 std::string LengthModFor(long long) { return "ll"; }           // NOLINT
LengthModFor(unsigned long long)36 std::string LengthModFor(unsigned long long) { return "ll"; }  // NOLINT
37 
EscCharImpl(int v)38 std::string EscCharImpl(int v) {
39   if (std::isprint(static_cast<unsigned char>(v))) {
40     return std::string(1, static_cast<char>(v));
41   }
42   char buf[64];
43   int n = snprintf(buf, sizeof(buf), "\\%#.2x",
44                    static_cast<unsigned>(v & 0xff));
45   assert(n > 0 && n < sizeof(buf));
46   return std::string(buf, n);
47 }
48 
Esc(char v)49 std::string Esc(char v) { return EscCharImpl(v); }
Esc(signed char v)50 std::string Esc(signed char v) { return EscCharImpl(v); }
Esc(unsigned char v)51 std::string Esc(unsigned char v) { return EscCharImpl(v); }
52 
53 template <typename T>
Esc(const T & v)54 std::string Esc(const T &v) {
55   std::ostringstream oss;
56   oss << v;
57   return oss.str();
58 }
59 
StrAppend(std::string * dst,const char * format,va_list ap)60 void StrAppend(std::string *dst, const char *format, va_list ap) {
61   // First try with a small fixed size buffer
62   static const int kSpaceLength = 1024;
63   char space[kSpaceLength];
64 
65   // It's possible for methods that use a va_list to invalidate
66   // the data in it upon use.  The fix is to make a copy
67   // of the structure before using it and use that copy instead.
68   va_list backup_ap;
69   va_copy(backup_ap, ap);
70   int result = vsnprintf(space, kSpaceLength, format, backup_ap);
71   va_end(backup_ap);
72   if (result < kSpaceLength) {
73     if (result >= 0) {
74       // Normal case -- everything fit.
75       dst->append(space, result);
76       return;
77     }
78     if (result < 0) {
79       // Just an error.
80       return;
81     }
82   }
83 
84   // Increase the buffer size to the size requested by vsnprintf,
85   // plus one for the closing \0.
86   int length = result + 1;
87   char *buf = new char[length];
88 
89   // Restore the va_list before we use it again
90   va_copy(backup_ap, ap);
91   result = vsnprintf(buf, length, format, backup_ap);
92   va_end(backup_ap);
93 
94   if (result >= 0 && result < length) {
95     // It fit
96     dst->append(buf, result);
97   }
98   delete[] buf;
99 }
100 
StrPrint(const char * format,...)101 std::string StrPrint(const char *format, ...) {
102   va_list ap;
103   va_start(ap, format);
104   std::string result;
105   StrAppend(&result, format, ap);
106   va_end(ap);
107   return result;
108 }
109 
110 class FormatConvertTest : public ::testing::Test { };
111 
112 template <typename T>
TestStringConvert(const T & str)113 void TestStringConvert(const T& str) {
114   const FormatArgImpl args[] = {FormatArgImpl(str)};
115   struct Expectation {
116     const char *out;
117     const char *fmt;
118   };
119   const Expectation kExpect[] = {
120     {"hello",  "%1$s"      },
121     {"",       "%1$.s"     },
122     {"",       "%1$.0s"    },
123     {"h",      "%1$.1s"    },
124     {"he",     "%1$.2s"    },
125     {"hello",  "%1$.10s"   },
126     {" hello", "%1$6s"     },
127     {"   he",  "%1$5.2s"   },
128     {"he   ",  "%1$-5.2s"  },
129     {"hello ", "%1$-6.10s" },
130   };
131   for (const Expectation &e : kExpect) {
132     UntypedFormatSpecImpl format(e.fmt);
133     EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args)));
134   }
135 }
136 
TEST_F(FormatConvertTest,BasicString)137 TEST_F(FormatConvertTest, BasicString) {
138   TestStringConvert("hello");  // As char array.
139   TestStringConvert(static_cast<const char*>("hello"));
140   TestStringConvert(std::string("hello"));
141   TestStringConvert(string_view("hello"));
142 }
143 
TEST_F(FormatConvertTest,NullString)144 TEST_F(FormatConvertTest, NullString) {
145   const char* p = nullptr;
146   UntypedFormatSpecImpl format("%s");
147   EXPECT_EQ("", FormatPack(format, {FormatArgImpl(p)}));
148 }
149 
TEST_F(FormatConvertTest,StringPrecision)150 TEST_F(FormatConvertTest, StringPrecision) {
151   // We cap at the precision.
152   char c = 'a';
153   const char* p = &c;
154   UntypedFormatSpecImpl format("%.1s");
155   EXPECT_EQ("a", FormatPack(format, {FormatArgImpl(p)}));
156 
157   // We cap at the NUL-terminator.
158   p = "ABC";
159   UntypedFormatSpecImpl format2("%.10s");
160   EXPECT_EQ("ABC", FormatPack(format2, {FormatArgImpl(p)}));
161 }
162 
163 // Pointer formatting is implementation defined. This checks that the argument
164 // can be matched to `ptr`.
165 MATCHER_P(MatchesPointerString, ptr, "") {
166   if (ptr == nullptr && arg == "(nil)") {
167     return true;
168   }
169   void* parsed = nullptr;
170   if (sscanf(arg.c_str(), "%p", &parsed) != 1) {
171     ABSL_RAW_LOG(FATAL, "Could not parse %s", arg.c_str());
172   }
173   return ptr == parsed;
174 }
175 
TEST_F(FormatConvertTest,Pointer)176 TEST_F(FormatConvertTest, Pointer) {
177   static int x = 0;
178   const int *xp = &x;
179   char c = 'h';
180   char *mcp = &c;
181   const char *cp = "hi";
182   const char *cnil = nullptr;
183   const int *inil = nullptr;
184   using VoidF = void (*)();
185   VoidF fp = [] {}, fnil = nullptr;
186   volatile char vc;
187   volatile char *vcp = &vc;
188   volatile char *vcnil = nullptr;
189   const FormatArgImpl args_array[] = {
190       FormatArgImpl(xp),   FormatArgImpl(cp),  FormatArgImpl(inil),
191       FormatArgImpl(cnil), FormatArgImpl(mcp), FormatArgImpl(fp),
192       FormatArgImpl(fnil), FormatArgImpl(vcp), FormatArgImpl(vcnil),
193   };
194   auto args = absl::MakeConstSpan(args_array);
195 
196   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%p"), args),
197               MatchesPointerString(&x));
198   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%20p"), args),
199               MatchesPointerString(&x));
200   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.1p"), args),
201               MatchesPointerString(&x));
202   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.20p"), args),
203               MatchesPointerString(&x));
204   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%30.20p"), args),
205               MatchesPointerString(&x));
206 
207   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-p"), args),
208               MatchesPointerString(&x));
209   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-20p"), args),
210               MatchesPointerString(&x));
211   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-.1p"), args),
212               MatchesPointerString(&x));
213   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%.20p"), args),
214               MatchesPointerString(&x));
215   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%-30.20p"), args),
216               MatchesPointerString(&x));
217 
218   // const char*
219   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%2$p"), args),
220               MatchesPointerString(cp));
221   // null const int*
222   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%3$p"), args),
223               MatchesPointerString(nullptr));
224   // null const char*
225   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%4$p"), args),
226               MatchesPointerString(nullptr));
227   // nonconst char*
228   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%5$p"), args),
229               MatchesPointerString(mcp));
230 
231   // function pointers
232   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%6$p"), args),
233               MatchesPointerString(reinterpret_cast<const void*>(fp)));
234   EXPECT_THAT(
235       FormatPack(UntypedFormatSpecImpl("%8$p"), args),
236       MatchesPointerString(reinterpret_cast<volatile const void *>(vcp)));
237 
238   // null function pointers
239   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%7$p"), args),
240               MatchesPointerString(nullptr));
241   EXPECT_THAT(FormatPack(UntypedFormatSpecImpl("%9$p"), args),
242               MatchesPointerString(nullptr));
243 }
244 
245 struct Cardinal {
246   enum Pos { k1 = 1, k2 = 2, k3 = 3 };
247   enum Neg { kM1 = -1, kM2 = -2, kM3 = -3 };
248 };
249 
TEST_F(FormatConvertTest,Enum)250 TEST_F(FormatConvertTest, Enum) {
251   const Cardinal::Pos k3 = Cardinal::k3;
252   const Cardinal::Neg km3 = Cardinal::kM3;
253   const FormatArgImpl args[] = {FormatArgImpl(k3), FormatArgImpl(km3)};
254   UntypedFormatSpecImpl format("%1$d");
255   UntypedFormatSpecImpl format2("%2$d");
256   EXPECT_EQ("3", FormatPack(format, absl::MakeSpan(args)));
257   EXPECT_EQ("-3", FormatPack(format2, absl::MakeSpan(args)));
258 }
259 
260 template <typename T>
261 class TypedFormatConvertTest : public FormatConvertTest { };
262 
263 TYPED_TEST_SUITE_P(TypedFormatConvertTest);
264 
AllFlagCombinations()265 std::vector<std::string> AllFlagCombinations() {
266   const char kFlags[] = {'-', '#', '0', '+', ' '};
267   std::vector<std::string> result;
268   for (size_t fsi = 0; fsi < (1ull << ArraySize(kFlags)); ++fsi) {
269     std::string flag_set;
270     for (size_t fi = 0; fi < ArraySize(kFlags); ++fi)
271       if (fsi & (1ull << fi))
272         flag_set += kFlags[fi];
273     result.push_back(flag_set);
274   }
275   return result;
276 }
277 
TYPED_TEST_P(TypedFormatConvertTest,AllIntsWithFlags)278 TYPED_TEST_P(TypedFormatConvertTest, AllIntsWithFlags) {
279   typedef TypeParam T;
280   typedef typename std::make_unsigned<T>::type UnsignedT;
281   using remove_volatile_t = typename std::remove_volatile<T>::type;
282   const T kMin = std::numeric_limits<remove_volatile_t>::min();
283   const T kMax = std::numeric_limits<remove_volatile_t>::max();
284   const T kVals[] = {
285       remove_volatile_t(1),
286       remove_volatile_t(2),
287       remove_volatile_t(3),
288       remove_volatile_t(123),
289       remove_volatile_t(-1),
290       remove_volatile_t(-2),
291       remove_volatile_t(-3),
292       remove_volatile_t(-123),
293       remove_volatile_t(0),
294       kMax - remove_volatile_t(1),
295       kMax,
296       kMin + remove_volatile_t(1),
297       kMin,
298   };
299   const char kConvChars[] = {'d', 'i', 'u', 'o', 'x', 'X'};
300   const std::string kWid[] = {"", "4", "10"};
301   const std::string kPrec[] = {"", ".", ".0", ".4", ".10"};
302 
303   const std::vector<std::string> flag_sets = AllFlagCombinations();
304 
305   for (size_t vi = 0; vi < ArraySize(kVals); ++vi) {
306     const T val = kVals[vi];
307     SCOPED_TRACE(Esc(val));
308     const FormatArgImpl args[] = {FormatArgImpl(val)};
309     for (size_t ci = 0; ci < ArraySize(kConvChars); ++ci) {
310       const char conv_char = kConvChars[ci];
311       for (size_t fsi = 0; fsi < flag_sets.size(); ++fsi) {
312         const std::string &flag_set = flag_sets[fsi];
313         for (size_t wi = 0; wi < ArraySize(kWid); ++wi) {
314           const std::string &wid = kWid[wi];
315           for (size_t pi = 0; pi < ArraySize(kPrec); ++pi) {
316             const std::string &prec = kPrec[pi];
317 
318             const bool is_signed_conv = (conv_char == 'd' || conv_char == 'i');
319             const bool is_unsigned_to_signed =
320                 !std::is_signed<T>::value && is_signed_conv;
321             // Don't consider sign-related flags '+' and ' ' when doing
322             // unsigned to signed conversions.
323             if (is_unsigned_to_signed &&
324                 flag_set.find_first_of("+ ") != std::string::npos) {
325               continue;
326             }
327 
328             std::string new_fmt("%");
329             new_fmt += flag_set;
330             new_fmt += wid;
331             new_fmt += prec;
332             // old and new always agree up to here.
333             std::string old_fmt = new_fmt;
334             new_fmt += conv_char;
335             std::string old_result;
336             if (is_unsigned_to_signed) {
337               // don't expect agreement on unsigned formatted as signed,
338               // as printf can't do that conversion properly. For those
339               // cases, we do expect agreement with printf with a "%u"
340               // and the unsigned equivalent of 'val'.
341               UnsignedT uval = val;
342               old_fmt += LengthModFor(uval);
343               old_fmt += "u";
344               old_result = StrPrint(old_fmt.c_str(), uval);
345             } else {
346               old_fmt += LengthModFor(val);
347               old_fmt += conv_char;
348               old_result = StrPrint(old_fmt.c_str(), val);
349             }
350 
351             SCOPED_TRACE(std::string() + " old_fmt: \"" + old_fmt +
352                          "\"'"
353                          " new_fmt: \"" +
354                          new_fmt + "\"");
355             UntypedFormatSpecImpl format(new_fmt);
356             EXPECT_EQ(old_result, FormatPack(format, absl::MakeSpan(args)));
357           }
358         }
359       }
360     }
361   }
362 }
363 
TYPED_TEST_P(TypedFormatConvertTest,Char)364 TYPED_TEST_P(TypedFormatConvertTest, Char) {
365   typedef TypeParam T;
366   using remove_volatile_t = typename std::remove_volatile<T>::type;
367   static const T kMin = std::numeric_limits<remove_volatile_t>::min();
368   static const T kMax = std::numeric_limits<remove_volatile_t>::max();
369   T kVals[] = {
370     remove_volatile_t(1), remove_volatile_t(2), remove_volatile_t(10),
371     remove_volatile_t(-1), remove_volatile_t(-2), remove_volatile_t(-10),
372     remove_volatile_t(0),
373     kMin + remove_volatile_t(1), kMin,
374     kMax - remove_volatile_t(1), kMax
375   };
376   for (const T &c : kVals) {
377     const FormatArgImpl args[] = {FormatArgImpl(c)};
378     UntypedFormatSpecImpl format("%c");
379     EXPECT_EQ(StrPrint("%c", c), FormatPack(format, absl::MakeSpan(args)));
380   }
381 }
382 
383 REGISTER_TYPED_TEST_CASE_P(TypedFormatConvertTest, AllIntsWithFlags, Char);
384 
385 typedef ::testing::Types<
386     int, unsigned, volatile int,
387     short, unsigned short,
388     long, unsigned long,
389     long long, unsigned long long,
390     signed char, unsigned char, char>
391     AllIntTypes;
392 INSTANTIATE_TYPED_TEST_CASE_P(TypedFormatConvertTestWithAllIntTypes,
393                               TypedFormatConvertTest, AllIntTypes);
TEST_F(FormatConvertTest,VectorBool)394 TEST_F(FormatConvertTest, VectorBool) {
395   // Make sure vector<bool>'s values behave as bools.
396   std::vector<bool> v = {true, false};
397   const std::vector<bool> cv = {true, false};
398   EXPECT_EQ("1,0,1,0",
399             FormatPack(UntypedFormatSpecImpl("%d,%d,%d,%d"),
400                        absl::Span<const FormatArgImpl>(
401                            {FormatArgImpl(v[0]), FormatArgImpl(v[1]),
402                             FormatArgImpl(cv[0]), FormatArgImpl(cv[1])})));
403 }
404 
405 
TEST_F(FormatConvertTest,Int128)406 TEST_F(FormatConvertTest, Int128) {
407   absl::int128 positive = static_cast<absl::int128>(0x1234567890abcdef) * 1979;
408   absl::int128 negative = -positive;
409   absl::int128 max = absl::Int128Max(), min = absl::Int128Min();
410   const FormatArgImpl args[] = {FormatArgImpl(positive),
411                                 FormatArgImpl(negative), FormatArgImpl(max),
412                                 FormatArgImpl(min)};
413 
414   struct Case {
415     const char* format;
416     const char* expected;
417   } cases[] = {
418       {"%1$d", "2595989796776606496405"},
419       {"%1$30d", "        2595989796776606496405"},
420       {"%1$-30d", "2595989796776606496405        "},
421       {"%1$u", "2595989796776606496405"},
422       {"%1$x", "8cba9876066020f695"},
423       {"%2$d", "-2595989796776606496405"},
424       {"%2$30d", "       -2595989796776606496405"},
425       {"%2$-30d", "-2595989796776606496405       "},
426       {"%2$u", "340282366920938460867384810655161715051"},
427       {"%2$x", "ffffffffffffff73456789f99fdf096b"},
428       {"%3$d", "170141183460469231731687303715884105727"},
429       {"%3$u", "170141183460469231731687303715884105727"},
430       {"%3$x", "7fffffffffffffffffffffffffffffff"},
431       {"%4$d", "-170141183460469231731687303715884105728"},
432       {"%4$x", "80000000000000000000000000000000"},
433   };
434 
435   for (auto c : cases) {
436     UntypedFormatSpecImpl format(c.format);
437     EXPECT_EQ(c.expected, FormatPack(format, absl::MakeSpan(args)));
438   }
439 }
440 
TEST_F(FormatConvertTest,Uint128)441 TEST_F(FormatConvertTest, Uint128) {
442   absl::uint128 v = static_cast<absl::uint128>(0x1234567890abcdef) * 1979;
443   absl::uint128 max = absl::Uint128Max();
444   const FormatArgImpl args[] = {FormatArgImpl(v), FormatArgImpl(max)};
445 
446   struct Case {
447     const char* format;
448     const char* expected;
449   } cases[] = {
450       {"%1$d", "2595989796776606496405"},
451       {"%1$30d", "        2595989796776606496405"},
452       {"%1$-30d", "2595989796776606496405        "},
453       {"%1$u", "2595989796776606496405"},
454       {"%1$x", "8cba9876066020f695"},
455       {"%2$d", "340282366920938463463374607431768211455"},
456       {"%2$u", "340282366920938463463374607431768211455"},
457       {"%2$x", "ffffffffffffffffffffffffffffffff"},
458   };
459 
460   for (auto c : cases) {
461     UntypedFormatSpecImpl format(c.format);
462     EXPECT_EQ(c.expected, FormatPack(format, absl::MakeSpan(args)));
463   }
464 }
465 
TEST_F(FormatConvertTest,Float)466 TEST_F(FormatConvertTest, Float) {
467 #ifdef _MSC_VER
468   // MSVC has a different rounding policy than us so we can't test our
469   // implementation against the native one there.
470   return;
471 #endif  // _MSC_VER
472 
473   const char *const kFormats[] = {
474       "%",  "%.3",  "%8.5",   "%9",   "%.60", "%.30",   "%03",    "%+",
475       "% ", "%-10", "%#15.3", "%#.0", "%.0",  "%1$*2$", "%1$.*2$"};
476 
477   std::vector<double> doubles = {0.0,
478                                  -0.0,
479                                  .99999999999999,
480                                  99999999999999.,
481                                  std::numeric_limits<double>::max(),
482                                  -std::numeric_limits<double>::max(),
483                                  std::numeric_limits<double>::min(),
484                                  -std::numeric_limits<double>::min(),
485                                  std::numeric_limits<double>::lowest(),
486                                  -std::numeric_limits<double>::lowest(),
487                                  std::numeric_limits<double>::epsilon(),
488                                  std::numeric_limits<double>::epsilon() + 1,
489                                  std::numeric_limits<double>::infinity(),
490                                  -std::numeric_limits<double>::infinity()};
491 
492 #ifndef __APPLE__
493   // Apple formats NaN differently (+nan) vs. (nan)
494   doubles.push_back(std::nan(""));
495 #endif
496 
497   // Some regression tests.
498   doubles.push_back(0.99999999999999989);
499 
500   if (std::numeric_limits<double>::has_denorm != std::denorm_absent) {
501     doubles.push_back(std::numeric_limits<double>::denorm_min());
502     doubles.push_back(-std::numeric_limits<double>::denorm_min());
503   }
504 
505   for (double base :
506        {1., 12., 123., 1234., 12345., 123456., 1234567., 12345678., 123456789.,
507         1234567890., 12345678901., 123456789012., 1234567890123.}) {
508     for (int exp = -123; exp <= 123; ++exp) {
509       for (int sign : {1, -1}) {
510         doubles.push_back(sign * std::ldexp(base, exp));
511       }
512     }
513   }
514 
515   for (const char *fmt : kFormats) {
516     for (char f : {'f', 'F',  //
517                    'g', 'G',  //
518                    'a', 'A',  //
519                    'e', 'E'}) {
520       std::string fmt_str = std::string(fmt) + f;
521       for (double d : doubles) {
522         int i = -10;
523         FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)};
524         UntypedFormatSpecImpl format(fmt_str);
525         // We use ASSERT_EQ here because failures are usually correlated and a
526         // bug would print way too many failed expectations causing the test to
527         // time out.
528         ASSERT_EQ(StrPrint(fmt_str.c_str(), d, i),
529                   FormatPack(format, absl::MakeSpan(args)))
530             << fmt_str << " " << StrPrint("%.18g", d) << " "
531             << StrPrint("%.999f", d);
532       }
533     }
534   }
535 }
536 
TEST_F(FormatConvertTest,LongDouble)537 TEST_F(FormatConvertTest, LongDouble) {
538   const char *const kFormats[] = {"%",    "%.3", "%8.5", "%9",
539                                   "%.60", "%+",  "% ",   "%-10"};
540 
541   // This value is not representable in double, but it is in long double that
542   // uses the extended format.
543   // This is to verify that we are not truncating the value mistakenly through a
544   // double.
545   long double very_precise = 10000000000000000.25L;
546 
547   std::vector<long double> doubles = {
548       0.0,
549       -0.0,
550       very_precise,
551       1 / very_precise,
552       std::numeric_limits<long double>::max(),
553       -std::numeric_limits<long double>::max(),
554       std::numeric_limits<long double>::min(),
555       -std::numeric_limits<long double>::min(),
556       std::numeric_limits<long double>::infinity(),
557       -std::numeric_limits<long double>::infinity()};
558 
559   for (const char *fmt : kFormats) {
560     for (char f : {'f', 'F',  //
561                    'g', 'G',  //
562                    'a', 'A',  //
563                    'e', 'E'}) {
564       std::string fmt_str = std::string(fmt) + 'L' + f;
565       for (auto d : doubles) {
566         FormatArgImpl arg(d);
567         UntypedFormatSpecImpl format(fmt_str);
568         // We use ASSERT_EQ here because failures are usually correlated and a
569         // bug would print way too many failed expectations causing the test to
570         // time out.
571         ASSERT_EQ(StrPrint(fmt_str.c_str(), d),
572                   FormatPack(format, {&arg, 1}))
573             << fmt_str << " " << StrPrint("%.18Lg", d) << " "
574             << StrPrint("%.999Lf", d);
575       }
576     }
577   }
578 }
579 
TEST_F(FormatConvertTest,IntAsFloat)580 TEST_F(FormatConvertTest, IntAsFloat) {
581   const int kMin = std::numeric_limits<int>::min();
582   const int kMax = std::numeric_limits<int>::max();
583   const int ia[] = {
584     1, 2, 3, 123,
585     -1, -2, -3, -123,
586     0, kMax - 1, kMax, kMin + 1, kMin };
587   for (const int fx : ia) {
588     SCOPED_TRACE(fx);
589     const FormatArgImpl args[] = {FormatArgImpl(fx)};
590     struct Expectation {
591       int line;
592       std::string out;
593       const char *fmt;
594     };
595     const double dx = static_cast<double>(fx);
596     const Expectation kExpect[] = {
597       { __LINE__, StrPrint("%f", dx), "%f" },
598       { __LINE__, StrPrint("%12f", dx), "%12f" },
599       { __LINE__, StrPrint("%.12f", dx), "%.12f" },
600       { __LINE__, StrPrint("%12a", dx), "%12a" },
601       { __LINE__, StrPrint("%.12a", dx), "%.12a" },
602     };
603     for (const Expectation &e : kExpect) {
604       SCOPED_TRACE(e.line);
605       SCOPED_TRACE(e.fmt);
606       UntypedFormatSpecImpl format(e.fmt);
607       EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args)));
608     }
609   }
610 }
611 
612 template <typename T>
FormatFails(const char * test_format,T value)613 bool FormatFails(const char* test_format, T value) {
614   std::string format_string = std::string("<<") + test_format + ">>";
615   UntypedFormatSpecImpl format(format_string);
616 
617   int one = 1;
618   const FormatArgImpl args[] = {FormatArgImpl(value), FormatArgImpl(one)};
619   EXPECT_EQ(FormatPack(format, absl::MakeSpan(args)), "")
620       << "format=" << test_format << " value=" << value;
621   return FormatPack(format, absl::MakeSpan(args)).empty();
622 }
623 
TEST_F(FormatConvertTest,ExpectedFailures)624 TEST_F(FormatConvertTest, ExpectedFailures) {
625   // Int input
626   EXPECT_TRUE(FormatFails("%p", 1));
627   EXPECT_TRUE(FormatFails("%s", 1));
628   EXPECT_TRUE(FormatFails("%n", 1));
629 
630   // Double input
631   EXPECT_TRUE(FormatFails("%p", 1.));
632   EXPECT_TRUE(FormatFails("%s", 1.));
633   EXPECT_TRUE(FormatFails("%n", 1.));
634   EXPECT_TRUE(FormatFails("%c", 1.));
635   EXPECT_TRUE(FormatFails("%d", 1.));
636   EXPECT_TRUE(FormatFails("%x", 1.));
637   EXPECT_TRUE(FormatFails("%*d", 1.));
638 
639   // String input
640   EXPECT_TRUE(FormatFails("%n", ""));
641   EXPECT_TRUE(FormatFails("%c", ""));
642   EXPECT_TRUE(FormatFails("%d", ""));
643   EXPECT_TRUE(FormatFails("%x", ""));
644   EXPECT_TRUE(FormatFails("%f", ""));
645   EXPECT_TRUE(FormatFails("%*d", ""));
646 }
647 
648 }  // namespace
649 }  // namespace str_format_internal
650 ABSL_NAMESPACE_END
651 }  // namespace absl
652