parser_test.cc
Go to the documentation of this file.
00001 #include "absl/strings/internal/str_format/parser.h"
00002 
00003 #include <string.h>
00004 
00005 #include "gmock/gmock.h"
00006 #include "gtest/gtest.h"
00007 #include "absl/base/macros.h"
00008 
00009 namespace absl {
00010 namespace str_format_internal {
00011 
00012 namespace {
00013 
00014 using testing::Pair;
00015 
00016 TEST(LengthModTest, Names) {
00017   struct Expectation {
00018     int line;
00019     LengthMod::Id id;
00020     const char *name;
00021   };
00022   const Expectation kExpect[] = {
00023     {__LINE__, LengthMod::none, ""  },
00024     {__LINE__, LengthMod::h,    "h" },
00025     {__LINE__, LengthMod::hh,   "hh"},
00026     {__LINE__, LengthMod::l,    "l" },
00027     {__LINE__, LengthMod::ll,   "ll"},
00028     {__LINE__, LengthMod::L,    "L" },
00029     {__LINE__, LengthMod::j,    "j" },
00030     {__LINE__, LengthMod::z,    "z" },
00031     {__LINE__, LengthMod::t,    "t" },
00032     {__LINE__, LengthMod::q,    "q" },
00033   };
00034   EXPECT_EQ(ABSL_ARRAYSIZE(kExpect), LengthMod::kNumValues);
00035   for (auto e : kExpect) {
00036     SCOPED_TRACE(e.line);
00037     LengthMod mod = LengthMod::FromId(e.id);
00038     EXPECT_EQ(e.id, mod.id());
00039     EXPECT_EQ(e.name, mod.name());
00040   }
00041 }
00042 
00043 TEST(ConversionCharTest, Names) {
00044   struct Expectation {
00045     ConversionChar::Id id;
00046     char name;
00047   };
00048   // clang-format off
00049   const Expectation kExpect[] = {
00050 #define X(c) {ConversionChar::c, #c[0]}
00051     X(c), X(C), X(s), X(S),                          // text
00052     X(d), X(i), X(o), X(u), X(x), X(X),              // int
00053     X(f), X(F), X(e), X(E), X(g), X(G), X(a), X(A),  // float
00054     X(n), X(p),                                      // misc
00055 #undef X
00056     {ConversionChar::none, '\0'},
00057   };
00058   // clang-format on
00059   EXPECT_EQ(ABSL_ARRAYSIZE(kExpect), ConversionChar::kNumValues);
00060   for (auto e : kExpect) {
00061     SCOPED_TRACE(e.name);
00062     ConversionChar v = ConversionChar::FromId(e.id);
00063     EXPECT_EQ(e.id, v.id());
00064     EXPECT_EQ(e.name, v.Char());
00065   }
00066 }
00067 
00068 class ConsumeUnboundConversionTest : public ::testing::Test {
00069  public:
00070   std::pair<string_view, string_view> Consume(string_view src) {
00071     int next = 0;
00072     o = UnboundConversion();  // refresh
00073     const char* p = ConsumeUnboundConversion(
00074         src.data(), src.data() + src.size(), &o, &next);
00075     if (!p) return {{}, src};
00076     return {string_view(src.data(), p - src.data()),
00077             string_view(p, src.data() + src.size() - p)};
00078   }
00079 
00080   bool Run(const char *fmt, bool force_positional = false) {
00081     int next = force_positional ? -1 : 0;
00082     o = UnboundConversion();  // refresh
00083     return ConsumeUnboundConversion(fmt, fmt + strlen(fmt), &o, &next) ==
00084            fmt + strlen(fmt);
00085   }
00086   UnboundConversion o;
00087 };
00088 
00089 TEST_F(ConsumeUnboundConversionTest, ConsumeSpecification) {
00090   struct Expectation {
00091     int line;
00092     string_view src;
00093     string_view out;
00094     string_view src_post;
00095   };
00096   const Expectation kExpect[] = {
00097     {__LINE__, "",     "",     ""  },
00098     {__LINE__, "b",    "",     "b" },  // 'b' is invalid
00099     {__LINE__, "ba",   "",     "ba"},  // 'b' is invalid
00100     {__LINE__, "l",    "",     "l" },  // just length mod isn't okay
00101     {__LINE__, "d",    "d",    ""  },  // basic
00102     {__LINE__, "d ",   "d",    " " },  // leave suffix
00103     {__LINE__, "dd",   "d",    "d" },  // don't be greedy
00104     {__LINE__, "d9",   "d",    "9" },  // leave non-space suffix
00105     {__LINE__, "dzz",  "d",    "zz"},  // length mod as suffix
00106     {__LINE__, "1$*2$d", "1$*2$d", ""  },  // arg indexing and * allowed.
00107     {__LINE__, "0-14.3hhd", "0-14.3hhd", ""},  // precision, width
00108     {__LINE__, " 0-+#14.3hhd", " 0-+#14.3hhd", ""},  // flags
00109   };
00110   for (const auto& e : kExpect) {
00111     SCOPED_TRACE(e.line);
00112     EXPECT_THAT(Consume(e.src), Pair(e.out, e.src_post));
00113   }
00114 }
00115 
00116 TEST_F(ConsumeUnboundConversionTest, BasicConversion) {
00117   EXPECT_FALSE(Run(""));
00118   EXPECT_FALSE(Run("z"));
00119 
00120   EXPECT_FALSE(Run("dd"));  // no excess allowed
00121 
00122   EXPECT_TRUE(Run("d"));
00123   EXPECT_EQ('d', o.conv.Char());
00124   EXPECT_FALSE(o.width.is_from_arg());
00125   EXPECT_LT(o.width.value(), 0);
00126   EXPECT_FALSE(o.precision.is_from_arg());
00127   EXPECT_LT(o.precision.value(), 0);
00128   EXPECT_EQ(1, o.arg_position);
00129   EXPECT_EQ(LengthMod::none, o.length_mod.id());
00130 }
00131 
00132 TEST_F(ConsumeUnboundConversionTest, ArgPosition) {
00133   EXPECT_TRUE(Run("d"));
00134   EXPECT_EQ(1, o.arg_position);
00135   EXPECT_TRUE(Run("3$d"));
00136   EXPECT_EQ(3, o.arg_position);
00137   EXPECT_TRUE(Run("1$d"));
00138   EXPECT_EQ(1, o.arg_position);
00139   EXPECT_TRUE(Run("1$d", true));
00140   EXPECT_EQ(1, o.arg_position);
00141   EXPECT_TRUE(Run("123$d"));
00142   EXPECT_EQ(123, o.arg_position);
00143   EXPECT_TRUE(Run("123$d", true));
00144   EXPECT_EQ(123, o.arg_position);
00145   EXPECT_TRUE(Run("10$d"));
00146   EXPECT_EQ(10, o.arg_position);
00147   EXPECT_TRUE(Run("10$d", true));
00148   EXPECT_EQ(10, o.arg_position);
00149 
00150   // Position can't be zero.
00151   EXPECT_FALSE(Run("0$d"));
00152   EXPECT_FALSE(Run("0$d", true));
00153   EXPECT_FALSE(Run("1$*0$d"));
00154   EXPECT_FALSE(Run("1$.*0$d"));
00155 
00156   // Position can't start with a zero digit at all. That is not a 'decimal'.
00157   EXPECT_FALSE(Run("01$p"));
00158   EXPECT_FALSE(Run("01$p", true));
00159   EXPECT_FALSE(Run("1$*01$p"));
00160   EXPECT_FALSE(Run("1$.*01$p"));
00161 }
00162 
00163 TEST_F(ConsumeUnboundConversionTest, WidthAndPrecision) {
00164   EXPECT_TRUE(Run("14d"));
00165   EXPECT_EQ('d', o.conv.Char());
00166   EXPECT_FALSE(o.width.is_from_arg());
00167   EXPECT_EQ(14, o.width.value());
00168   EXPECT_FALSE(o.precision.is_from_arg());
00169   EXPECT_LT(o.precision.value(), 0);
00170 
00171   EXPECT_TRUE(Run("14.d"));
00172   EXPECT_FALSE(o.width.is_from_arg());
00173   EXPECT_FALSE(o.precision.is_from_arg());
00174   EXPECT_EQ(14, o.width.value());
00175   EXPECT_EQ(0, o.precision.value());
00176 
00177   EXPECT_TRUE(Run(".d"));
00178   EXPECT_FALSE(o.width.is_from_arg());
00179   EXPECT_LT(o.width.value(), 0);
00180   EXPECT_FALSE(o.precision.is_from_arg());
00181   EXPECT_EQ(0, o.precision.value());
00182 
00183   EXPECT_TRUE(Run(".5d"));
00184   EXPECT_FALSE(o.width.is_from_arg());
00185   EXPECT_LT(o.width.value(), 0);
00186   EXPECT_FALSE(o.precision.is_from_arg());
00187   EXPECT_EQ(5, o.precision.value());
00188 
00189   EXPECT_TRUE(Run(".0d"));
00190   EXPECT_FALSE(o.width.is_from_arg());
00191   EXPECT_LT(o.width.value(), 0);
00192   EXPECT_FALSE(o.precision.is_from_arg());
00193   EXPECT_EQ(0, o.precision.value());
00194 
00195   EXPECT_TRUE(Run("14.5d"));
00196   EXPECT_FALSE(o.width.is_from_arg());
00197   EXPECT_FALSE(o.precision.is_from_arg());
00198   EXPECT_EQ(14, o.width.value());
00199   EXPECT_EQ(5, o.precision.value());
00200 
00201   EXPECT_TRUE(Run("*.*d"));
00202   EXPECT_TRUE(o.width.is_from_arg());
00203   EXPECT_EQ(1, o.width.get_from_arg());
00204   EXPECT_TRUE(o.precision.is_from_arg());
00205   EXPECT_EQ(2, o.precision.get_from_arg());
00206   EXPECT_EQ(3, o.arg_position);
00207 
00208   EXPECT_TRUE(Run("*d"));
00209   EXPECT_TRUE(o.width.is_from_arg());
00210   EXPECT_EQ(1, o.width.get_from_arg());
00211   EXPECT_FALSE(o.precision.is_from_arg());
00212   EXPECT_LT(o.precision.value(), 0);
00213   EXPECT_EQ(2, o.arg_position);
00214 
00215   EXPECT_TRUE(Run(".*d"));
00216   EXPECT_FALSE(o.width.is_from_arg());
00217   EXPECT_LT(o.width.value(), 0);
00218   EXPECT_TRUE(o.precision.is_from_arg());
00219   EXPECT_EQ(1, o.precision.get_from_arg());
00220   EXPECT_EQ(2, o.arg_position);
00221 
00222   // mixed implicit and explicit: didn't specify arg position.
00223   EXPECT_FALSE(Run("*23$.*34$d"));
00224 
00225   EXPECT_TRUE(Run("12$*23$.*34$d"));
00226   EXPECT_EQ(12, o.arg_position);
00227   EXPECT_TRUE(o.width.is_from_arg());
00228   EXPECT_EQ(23, o.width.get_from_arg());
00229   EXPECT_TRUE(o.precision.is_from_arg());
00230   EXPECT_EQ(34, o.precision.get_from_arg());
00231 
00232   EXPECT_TRUE(Run("2$*5$.*9$d"));
00233   EXPECT_EQ(2, o.arg_position);
00234   EXPECT_TRUE(o.width.is_from_arg());
00235   EXPECT_EQ(5, o.width.get_from_arg());
00236   EXPECT_TRUE(o.precision.is_from_arg());
00237   EXPECT_EQ(9, o.precision.get_from_arg());
00238 
00239   EXPECT_FALSE(Run(".*0$d")) << "no arg 0";
00240 
00241   // Large values
00242   EXPECT_TRUE(Run("999999999.999999999d"));
00243   EXPECT_FALSE(o.width.is_from_arg());
00244   EXPECT_EQ(999999999, o.width.value());
00245   EXPECT_FALSE(o.precision.is_from_arg());
00246   EXPECT_EQ(999999999, o.precision.value());
00247 
00248   EXPECT_FALSE(Run("1000000000.999999999d"));
00249   EXPECT_FALSE(Run("999999999.1000000000d"));
00250   EXPECT_FALSE(Run("9999999999d"));
00251   EXPECT_FALSE(Run(".9999999999d"));
00252 }
00253 
00254 TEST_F(ConsumeUnboundConversionTest, Flags) {
00255   static const char kAllFlags[] = "-+ #0";
00256   static const int kNumFlags = ABSL_ARRAYSIZE(kAllFlags) - 1;
00257   for (int rev = 0; rev < 2; ++rev) {
00258     for (int i = 0; i < 1 << kNumFlags; ++i) {
00259       std::string fmt;
00260       for (int k = 0; k < kNumFlags; ++k)
00261         if ((i >> k) & 1) fmt += kAllFlags[k];
00262       // flag order shouldn't matter
00263       if (rev == 1) { std::reverse(fmt.begin(), fmt.end()); }
00264       fmt += 'd';
00265       SCOPED_TRACE(fmt);
00266       EXPECT_TRUE(Run(fmt.c_str()));
00267       EXPECT_EQ(fmt.find('-') == std::string::npos, !o.flags.left);
00268       EXPECT_EQ(fmt.find('+') == std::string::npos, !o.flags.show_pos);
00269       EXPECT_EQ(fmt.find(' ') == std::string::npos, !o.flags.sign_col);
00270       EXPECT_EQ(fmt.find('#') == std::string::npos, !o.flags.alt);
00271       EXPECT_EQ(fmt.find('0') == std::string::npos, !o.flags.zero);
00272     }
00273   }
00274 }
00275 
00276 TEST_F(ConsumeUnboundConversionTest, BasicFlag) {
00277   // Flag is on
00278   for (const char* fmt : {"d", "llx", "G", "1$X"}) {
00279     SCOPED_TRACE(fmt);
00280     EXPECT_TRUE(Run(fmt));
00281     EXPECT_TRUE(o.flags.basic);
00282   }
00283 
00284   // Flag is off
00285   for (const char* fmt : {"3d", ".llx", "-G", "1$#X"}) {
00286     SCOPED_TRACE(fmt);
00287     EXPECT_TRUE(Run(fmt));
00288     EXPECT_FALSE(o.flags.basic);
00289   }
00290 }
00291 
00292 struct SummarizeConsumer {
00293   std::string* out;
00294   explicit SummarizeConsumer(std::string* out) : out(out) {}
00295 
00296   bool Append(string_view s) {
00297     *out += "[" + std::string(s) + "]";
00298     return true;
00299   }
00300 
00301   bool ConvertOne(const UnboundConversion& conv, string_view s) {
00302     *out += "{";
00303     *out += std::string(s);
00304     *out += ":";
00305     *out += std::to_string(conv.arg_position) + "$";
00306     if (conv.width.is_from_arg()) {
00307       *out += std::to_string(conv.width.get_from_arg()) + "$*";
00308     }
00309     if (conv.precision.is_from_arg()) {
00310       *out += "." + std::to_string(conv.precision.get_from_arg()) + "$*";
00311     }
00312     *out += conv.conv.Char();
00313     *out += "}";
00314     return true;
00315   }
00316 };
00317 
00318 std::string SummarizeParsedFormat(const ParsedFormatBase& pc) {
00319   std::string out;
00320   if (!pc.ProcessFormat(SummarizeConsumer(&out))) out += "!";
00321   return out;
00322 }
00323 
00324 class ParsedFormatTest : public testing::Test {};
00325 
00326 TEST_F(ParsedFormatTest, ValueSemantics) {
00327   ParsedFormatBase p1({}, true, {});  // empty format
00328   EXPECT_EQ("", SummarizeParsedFormat(p1));
00329 
00330   ParsedFormatBase p2 = p1;  // copy construct (empty)
00331   EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p2));
00332 
00333   p1 = ParsedFormatBase("hello%s", true, {Conv::s});  // move assign
00334   EXPECT_EQ("[hello]{s:1$s}", SummarizeParsedFormat(p1));
00335 
00336   ParsedFormatBase p3 = p1;  // copy construct (nonempty)
00337   EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p3));
00338 
00339   using std::swap;
00340   swap(p1, p2);
00341   EXPECT_EQ("", SummarizeParsedFormat(p1));
00342   EXPECT_EQ("[hello]{s:1$s}", SummarizeParsedFormat(p2));
00343   swap(p1, p2);  // undo
00344 
00345   p2 = p1;  // copy assign
00346   EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p2));
00347 }
00348 
00349 struct ExpectParse {
00350   const char* in;
00351   std::initializer_list<Conv> conv_set;
00352   const char* out;
00353 };
00354 
00355 TEST_F(ParsedFormatTest, Parsing) {
00356   // Parse should be equivalent to that obtained by ConversionParseIterator.
00357   // No need to retest the parsing edge cases here.
00358   const ExpectParse kExpect[] = {
00359       {"", {}, ""},
00360       {"ab", {}, "[ab]"},
00361       {"a%d", {Conv::d}, "[a]{d:1$d}"},
00362       {"a%+d", {Conv::d}, "[a]{+d:1$d}"},
00363       {"a% d", {Conv::d}, "[a]{ d:1$d}"},
00364       {"a%b %d", {}, "[a]!"},  // stop after error
00365   };
00366   for (const auto& e : kExpect) {
00367     SCOPED_TRACE(e.in);
00368     EXPECT_EQ(e.out,
00369               SummarizeParsedFormat(ParsedFormatBase(e.in, false, e.conv_set)));
00370   }
00371 }
00372 
00373 TEST_F(ParsedFormatTest, ParsingFlagOrder) {
00374   const ExpectParse kExpect[] = {
00375       {"a%+ 0d", {Conv::d}, "[a]{+ 0d:1$d}"},
00376       {"a%+0 d", {Conv::d}, "[a]{+0 d:1$d}"},
00377       {"a%0+ d", {Conv::d}, "[a]{0+ d:1$d}"},
00378       {"a% +0d", {Conv::d}, "[a]{ +0d:1$d}"},
00379       {"a%0 +d", {Conv::d}, "[a]{0 +d:1$d}"},
00380       {"a% 0+d", {Conv::d}, "[a]{ 0+d:1$d}"},
00381       {"a%+   0+d", {Conv::d}, "[a]{+   0+d:1$d}"},
00382   };
00383   for (const auto& e : kExpect) {
00384     SCOPED_TRACE(e.in);
00385     EXPECT_EQ(e.out,
00386               SummarizeParsedFormat(ParsedFormatBase(e.in, false, e.conv_set)));
00387   }
00388 }
00389 
00390 }  // namespace
00391 }  // namespace str_format_internal
00392 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:15