tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

parser_test.cc (14373B)


      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/internal/str_format/parser.h"
     16 
     17 #include <string.h>
     18 #include <algorithm>
     19 #include <initializer_list>
     20 #include <string>
     21 #include <utility>
     22 
     23 #include "gmock/gmock.h"
     24 #include "gtest/gtest.h"
     25 #include "absl/base/config.h"
     26 #include "absl/base/macros.h"
     27 #include "absl/strings/internal/str_format/constexpr_parser.h"
     28 #include "absl/strings/internal/str_format/extension.h"
     29 #include "absl/strings/string_view.h"
     30 
     31 namespace absl {
     32 ABSL_NAMESPACE_BEGIN
     33 namespace str_format_internal {
     34 
     35 namespace {
     36 
     37 using testing::Pair;
     38 
     39 TEST(LengthModTest, Names) {
     40  struct Expectation {
     41    int line;
     42    LengthMod mod;
     43    const char *name;
     44  };
     45  const Expectation kExpect[] = {
     46    {__LINE__, LengthMod::none, ""  },
     47    {__LINE__, LengthMod::h,    "h" },
     48    {__LINE__, LengthMod::hh,   "hh"},
     49    {__LINE__, LengthMod::l,    "l" },
     50    {__LINE__, LengthMod::ll,   "ll"},
     51    {__LINE__, LengthMod::L,    "L" },
     52    {__LINE__, LengthMod::j,    "j" },
     53    {__LINE__, LengthMod::z,    "z" },
     54    {__LINE__, LengthMod::t,    "t" },
     55    {__LINE__, LengthMod::q,    "q" },
     56  };
     57  EXPECT_EQ(ABSL_ARRAYSIZE(kExpect), 10);
     58  for (auto e : kExpect) {
     59    SCOPED_TRACE(e.line);
     60    EXPECT_EQ(e.name, LengthModToString(e.mod));
     61  }
     62 }
     63 
     64 TEST(ConversionCharTest, Names) {
     65  struct Expectation {
     66    FormatConversionChar id;
     67    char name;
     68  };
     69  // clang-format off
     70  const Expectation kExpect[] = {
     71 #define X(c) {FormatConversionCharInternal::c, #c[0]}
     72    X(c), X(s),                                      // text
     73    X(d), X(i), X(o), X(u), X(x), X(X),              // int
     74    X(f), X(F), X(e), X(E), X(g), X(G), X(a), X(A),  // float
     75    X(n), X(p),                                      // misc
     76 #undef X
     77    {FormatConversionCharInternal::kNone, '\0'},
     78  };
     79  // clang-format on
     80  for (auto e : kExpect) {
     81    SCOPED_TRACE(e.name);
     82    FormatConversionChar v = e.id;
     83    EXPECT_EQ(e.name, FormatConversionCharToChar(v));
     84  }
     85 }
     86 
     87 class ConsumeUnboundConversionTest : public ::testing::Test {
     88 public:
     89  std::pair<string_view, string_view> Consume(string_view src) {
     90    int next = 0;
     91    o = UnboundConversion();  // refresh
     92    const char* p = ConsumeUnboundConversion(
     93        src.data(), src.data() + src.size(), &o, &next);
     94    if (!p) return {{}, src};
     95    return {string_view(src.data(), p - src.data()),
     96            string_view(p, src.data() + src.size() - p)};
     97  }
     98 
     99  bool Run(const char *fmt, bool force_positional = false) {
    100    int next = force_positional ? -1 : 0;
    101    o = UnboundConversion();  // refresh
    102    return ConsumeUnboundConversion(fmt, fmt + strlen(fmt), &o, &next) ==
    103           fmt + strlen(fmt);
    104  }
    105  UnboundConversion o;
    106 };
    107 
    108 TEST_F(ConsumeUnboundConversionTest, ConsumeSpecification) {
    109  struct Expectation {
    110    int line;
    111    string_view src;
    112    string_view out;
    113    string_view src_post;
    114  };
    115  const Expectation kExpect[] = {
    116    {__LINE__, "",     "",     ""  },
    117    {__LINE__, "b",    "",     "b" },  // 'b' is invalid
    118    {__LINE__, "ba",   "",     "ba"},  // 'b' is invalid
    119    {__LINE__, "l",    "",     "l" },  // just length mod isn't okay
    120    {__LINE__, "d",    "d",    ""  },  // basic
    121    {__LINE__, "v",    "v",    ""  },  // basic
    122    {__LINE__, "d ",   "d",    " " },  // leave suffix
    123    {__LINE__, "dd",   "d",    "d" },  // don't be greedy
    124    {__LINE__, "d9",   "d",    "9" },  // leave non-space suffix
    125    {__LINE__, "dzz",  "d",    "zz"},  // length mod as suffix
    126    {__LINE__, "3v",   "",     "3v"},  // 'v' cannot have modifiers
    127    {__LINE__, "hv",   "",     "hv"},  // 'v' cannot have modifiers
    128    {__LINE__, "1$v",   "1$v",     ""},  // 'v' can have use posix syntax
    129    {__LINE__, "1$*2$d", "1$*2$d", ""  },  // arg indexing and * allowed.
    130    {__LINE__, "0-14.3hhd", "0-14.3hhd", ""},  // precision, width
    131    {__LINE__, " 0-+#14.3hhd", " 0-+#14.3hhd", ""},  // flags
    132  };
    133  for (const auto& e : kExpect) {
    134    SCOPED_TRACE(e.line);
    135    EXPECT_THAT(Consume(e.src), Pair(e.out, e.src_post));
    136  }
    137 }
    138 
    139 TEST_F(ConsumeUnboundConversionTest, BasicConversion) {
    140  EXPECT_FALSE(Run(""));
    141  EXPECT_FALSE(Run("z"));
    142 
    143  EXPECT_FALSE(Run("dd"));  // no excess allowed
    144 
    145  EXPECT_TRUE(Run("d"));
    146  EXPECT_EQ('d', FormatConversionCharToChar(o.conv));
    147  EXPECT_FALSE(o.width.is_from_arg());
    148  EXPECT_LT(o.width.value(), 0);
    149  EXPECT_FALSE(o.precision.is_from_arg());
    150  EXPECT_LT(o.precision.value(), 0);
    151  EXPECT_EQ(1, o.arg_position);
    152 }
    153 
    154 TEST_F(ConsumeUnboundConversionTest, ArgPosition) {
    155  EXPECT_TRUE(Run("d"));
    156  EXPECT_EQ(1, o.arg_position);
    157  EXPECT_TRUE(Run("3$d"));
    158  EXPECT_EQ(3, o.arg_position);
    159  EXPECT_TRUE(Run("1$d"));
    160  EXPECT_EQ(1, o.arg_position);
    161  EXPECT_TRUE(Run("1$d", true));
    162  EXPECT_EQ(1, o.arg_position);
    163  EXPECT_TRUE(Run("123$d"));
    164  EXPECT_EQ(123, o.arg_position);
    165  EXPECT_TRUE(Run("123$d", true));
    166  EXPECT_EQ(123, o.arg_position);
    167  EXPECT_TRUE(Run("10$d"));
    168  EXPECT_EQ(10, o.arg_position);
    169  EXPECT_TRUE(Run("10$d", true));
    170  EXPECT_EQ(10, o.arg_position);
    171 
    172  // Position can't be zero.
    173  EXPECT_FALSE(Run("0$d"));
    174  EXPECT_FALSE(Run("0$d", true));
    175  EXPECT_FALSE(Run("1$*0$d"));
    176  EXPECT_FALSE(Run("1$.*0$d"));
    177 
    178  // Position can't start with a zero digit at all. That is not a 'decimal'.
    179  EXPECT_FALSE(Run("01$p"));
    180  EXPECT_FALSE(Run("01$p", true));
    181  EXPECT_FALSE(Run("1$*01$p"));
    182  EXPECT_FALSE(Run("1$.*01$p"));
    183 }
    184 
    185 TEST_F(ConsumeUnboundConversionTest, WidthAndPrecision) {
    186  EXPECT_TRUE(Run("14d"));
    187  EXPECT_EQ('d', FormatConversionCharToChar(o.conv));
    188  EXPECT_FALSE(o.width.is_from_arg());
    189  EXPECT_EQ(14, o.width.value());
    190  EXPECT_FALSE(o.precision.is_from_arg());
    191  EXPECT_LT(o.precision.value(), 0);
    192 
    193  EXPECT_TRUE(Run("14.d"));
    194  EXPECT_FALSE(o.width.is_from_arg());
    195  EXPECT_FALSE(o.precision.is_from_arg());
    196  EXPECT_EQ(14, o.width.value());
    197  EXPECT_EQ(0, o.precision.value());
    198 
    199  EXPECT_TRUE(Run(".d"));
    200  EXPECT_FALSE(o.width.is_from_arg());
    201  EXPECT_LT(o.width.value(), 0);
    202  EXPECT_FALSE(o.precision.is_from_arg());
    203  EXPECT_EQ(0, o.precision.value());
    204 
    205  EXPECT_TRUE(Run(".5d"));
    206  EXPECT_FALSE(o.width.is_from_arg());
    207  EXPECT_LT(o.width.value(), 0);
    208  EXPECT_FALSE(o.precision.is_from_arg());
    209  EXPECT_EQ(5, o.precision.value());
    210 
    211  EXPECT_TRUE(Run(".0d"));
    212  EXPECT_FALSE(o.width.is_from_arg());
    213  EXPECT_LT(o.width.value(), 0);
    214  EXPECT_FALSE(o.precision.is_from_arg());
    215  EXPECT_EQ(0, o.precision.value());
    216 
    217  EXPECT_TRUE(Run("14.5d"));
    218  EXPECT_FALSE(o.width.is_from_arg());
    219  EXPECT_FALSE(o.precision.is_from_arg());
    220  EXPECT_EQ(14, o.width.value());
    221  EXPECT_EQ(5, o.precision.value());
    222 
    223  EXPECT_TRUE(Run("*.*d"));
    224  EXPECT_TRUE(o.width.is_from_arg());
    225  EXPECT_EQ(1, o.width.get_from_arg());
    226  EXPECT_TRUE(o.precision.is_from_arg());
    227  EXPECT_EQ(2, o.precision.get_from_arg());
    228  EXPECT_EQ(3, o.arg_position);
    229 
    230  EXPECT_TRUE(Run("*d"));
    231  EXPECT_TRUE(o.width.is_from_arg());
    232  EXPECT_EQ(1, o.width.get_from_arg());
    233  EXPECT_FALSE(o.precision.is_from_arg());
    234  EXPECT_LT(o.precision.value(), 0);
    235  EXPECT_EQ(2, o.arg_position);
    236 
    237  EXPECT_TRUE(Run(".*d"));
    238  EXPECT_FALSE(o.width.is_from_arg());
    239  EXPECT_LT(o.width.value(), 0);
    240  EXPECT_TRUE(o.precision.is_from_arg());
    241  EXPECT_EQ(1, o.precision.get_from_arg());
    242  EXPECT_EQ(2, o.arg_position);
    243 
    244  // mixed implicit and explicit: didn't specify arg position.
    245  EXPECT_FALSE(Run("*23$.*34$d"));
    246 
    247  EXPECT_TRUE(Run("12$*23$.*34$d"));
    248  EXPECT_EQ(12, o.arg_position);
    249  EXPECT_TRUE(o.width.is_from_arg());
    250  EXPECT_EQ(23, o.width.get_from_arg());
    251  EXPECT_TRUE(o.precision.is_from_arg());
    252  EXPECT_EQ(34, o.precision.get_from_arg());
    253 
    254  EXPECT_TRUE(Run("2$*5$.*9$d"));
    255  EXPECT_EQ(2, o.arg_position);
    256  EXPECT_TRUE(o.width.is_from_arg());
    257  EXPECT_EQ(5, o.width.get_from_arg());
    258  EXPECT_TRUE(o.precision.is_from_arg());
    259  EXPECT_EQ(9, o.precision.get_from_arg());
    260 
    261  EXPECT_FALSE(Run(".*0$d")) << "no arg 0";
    262 
    263  // Large values
    264  EXPECT_TRUE(Run("999999999.999999999d"));
    265  EXPECT_FALSE(o.width.is_from_arg());
    266  EXPECT_EQ(999999999, o.width.value());
    267  EXPECT_FALSE(o.precision.is_from_arg());
    268  EXPECT_EQ(999999999, o.precision.value());
    269 
    270  EXPECT_FALSE(Run("1000000000.999999999d"));
    271  EXPECT_FALSE(Run("999999999.1000000000d"));
    272  EXPECT_FALSE(Run("9999999999d"));
    273  EXPECT_FALSE(Run(".9999999999d"));
    274 }
    275 
    276 TEST_F(ConsumeUnboundConversionTest, Flags) {
    277  static const char kAllFlags[] = "-+ #0";
    278  static const int kNumFlags = ABSL_ARRAYSIZE(kAllFlags) - 1;
    279  for (int rev = 0; rev < 2; ++rev) {
    280    for (int i = 0; i < 1 << kNumFlags; ++i) {
    281      std::string fmt;
    282      for (int k = 0; k < kNumFlags; ++k)
    283        if ((i >> k) & 1) fmt += kAllFlags[k];
    284      // flag order shouldn't matter
    285      if (rev == 1) {
    286        std::reverse(fmt.begin(), fmt.end());
    287      }
    288      fmt += 'd';
    289      SCOPED_TRACE(fmt);
    290      EXPECT_TRUE(Run(fmt.c_str()));
    291      EXPECT_EQ(fmt.find('-') == std::string::npos,
    292                !FlagsContains(o.flags, Flags::kLeft));
    293      EXPECT_EQ(fmt.find('+') == std::string::npos,
    294                !FlagsContains(o.flags, Flags::kShowPos));
    295      EXPECT_EQ(fmt.find(' ') == std::string::npos,
    296                !FlagsContains(o.flags, Flags::kSignCol));
    297      EXPECT_EQ(fmt.find('#') == std::string::npos,
    298                !FlagsContains(o.flags, Flags::kAlt));
    299      EXPECT_EQ(fmt.find('0') == std::string::npos,
    300                !FlagsContains(o.flags, Flags::kZero));
    301    }
    302  }
    303 }
    304 
    305 TEST_F(ConsumeUnboundConversionTest, BasicFlag) {
    306  // Flag is on
    307  for (const char* fmt : {"d", "llx", "G", "1$X"}) {
    308    SCOPED_TRACE(fmt);
    309    EXPECT_TRUE(Run(fmt));
    310    EXPECT_EQ(o.flags, Flags::kBasic);
    311  }
    312 
    313  // Flag is off
    314  for (const char* fmt : {"3d", ".llx", "-G", "1$#X", "lc"}) {
    315    SCOPED_TRACE(fmt);
    316    EXPECT_TRUE(Run(fmt));
    317    EXPECT_NE(o.flags, Flags::kBasic);
    318  }
    319 }
    320 
    321 TEST_F(ConsumeUnboundConversionTest, LengthMod) {
    322  EXPECT_TRUE(Run("d"));
    323  EXPECT_EQ(LengthMod::none, o.length_mod);
    324  EXPECT_TRUE(Run("hd"));
    325  EXPECT_EQ(LengthMod::h, o.length_mod);
    326  EXPECT_TRUE(Run("hhd"));
    327  EXPECT_EQ(LengthMod::hh, o.length_mod);
    328  EXPECT_TRUE(Run("ld"));
    329  EXPECT_EQ(LengthMod::l, o.length_mod);
    330  EXPECT_TRUE(Run("lld"));
    331  EXPECT_EQ(LengthMod::ll, o.length_mod);
    332  EXPECT_TRUE(Run("Lf"));
    333  EXPECT_EQ(LengthMod::L, o.length_mod);
    334  EXPECT_TRUE(Run("qf"));
    335  EXPECT_EQ(LengthMod::q, o.length_mod);
    336  EXPECT_TRUE(Run("jd"));
    337  EXPECT_EQ(LengthMod::j, o.length_mod);
    338  EXPECT_TRUE(Run("zd"));
    339  EXPECT_EQ(LengthMod::z, o.length_mod);
    340  EXPECT_TRUE(Run("td"));
    341  EXPECT_EQ(LengthMod::t, o.length_mod);
    342 }
    343 
    344 struct SummarizeConsumer {
    345  std::string* out;
    346  explicit SummarizeConsumer(std::string* out) : out(out) {}
    347 
    348  bool Append(string_view s) {
    349    *out += "[" + std::string(s) + "]";
    350    return true;
    351  }
    352 
    353  bool ConvertOne(const UnboundConversion& conv, string_view s) {
    354    *out += "{";
    355    *out += std::string(s);
    356    *out += ":";
    357    *out += std::to_string(conv.arg_position) + "$";
    358    if (conv.width.is_from_arg()) {
    359      *out += std::to_string(conv.width.get_from_arg()) + "$*";
    360    }
    361    if (conv.precision.is_from_arg()) {
    362      *out += "." + std::to_string(conv.precision.get_from_arg()) + "$*";
    363    }
    364    *out += FormatConversionCharToChar(conv.conv);
    365    *out += "}";
    366    return true;
    367  }
    368 };
    369 
    370 std::string SummarizeParsedFormat(const ParsedFormatBase& pc) {
    371  std::string out;
    372  if (!pc.ProcessFormat(SummarizeConsumer(&out))) out += "!";
    373  return out;
    374 }
    375 
    376 class ParsedFormatTest : public testing::Test {};
    377 
    378 TEST_F(ParsedFormatTest, ValueSemantics) {
    379  ParsedFormatBase p1({}, true, {});  // empty format
    380  EXPECT_EQ("", SummarizeParsedFormat(p1));
    381 
    382  ParsedFormatBase p2 = p1;  // copy construct (empty)
    383  EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p2));
    384 
    385  p1 = ParsedFormatBase("hello%s", true,
    386                        {FormatConversionCharSetInternal::s});  // move assign
    387  EXPECT_EQ("[hello]{s:1$s}", SummarizeParsedFormat(p1));
    388 
    389  ParsedFormatBase p3 = p1;  // copy construct (nonempty)
    390  EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p3));
    391 
    392  using std::swap;
    393  swap(p1, p2);
    394  EXPECT_EQ("", SummarizeParsedFormat(p1));
    395  EXPECT_EQ("[hello]{s:1$s}", SummarizeParsedFormat(p2));
    396  swap(p1, p2);  // undo
    397 
    398  p2 = p1;  // copy assign
    399  EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p2));
    400 }
    401 
    402 struct ExpectParse {
    403  const char* in;
    404  std::initializer_list<FormatConversionCharSet> conv_set;
    405  const char* out;
    406 };
    407 
    408 TEST_F(ParsedFormatTest, Parsing) {
    409  // Parse should be equivalent to that obtained by ConversionParseIterator.
    410  // No need to retest the parsing edge cases here.
    411  const ExpectParse kExpect[] = {
    412      {"", {}, ""},
    413      {"ab", {}, "[ab]"},
    414      {"a%d", {FormatConversionCharSetInternal::d}, "[a]{d:1$d}"},
    415      {"a%+d", {FormatConversionCharSetInternal::d}, "[a]{+d:1$d}"},
    416      {"a% d", {FormatConversionCharSetInternal::d}, "[a]{ d:1$d}"},
    417      {"a%b %d", {}, "[a]!"},  // stop after error
    418  };
    419  for (const auto& e : kExpect) {
    420    SCOPED_TRACE(e.in);
    421    EXPECT_EQ(e.out,
    422              SummarizeParsedFormat(ParsedFormatBase(e.in, false, e.conv_set)));
    423  }
    424 }
    425 
    426 TEST_F(ParsedFormatTest, ParsingFlagOrder) {
    427  const ExpectParse kExpect[] = {
    428      {"a%+ 0d", {FormatConversionCharSetInternal::d}, "[a]{+ 0d:1$d}"},
    429      {"a%+0 d", {FormatConversionCharSetInternal::d}, "[a]{+0 d:1$d}"},
    430      {"a%0+ d", {FormatConversionCharSetInternal::d}, "[a]{0+ d:1$d}"},
    431      {"a% +0d", {FormatConversionCharSetInternal::d}, "[a]{ +0d:1$d}"},
    432      {"a%0 +d", {FormatConversionCharSetInternal::d}, "[a]{0 +d:1$d}"},
    433      {"a% 0+d", {FormatConversionCharSetInternal::d}, "[a]{ 0+d:1$d}"},
    434      {"a%+   0+d", {FormatConversionCharSetInternal::d}, "[a]{+   0+d:1$d}"},
    435  };
    436  for (const auto& e : kExpect) {
    437    SCOPED_TRACE(e.in);
    438    EXPECT_EQ(e.out,
    439              SummarizeParsedFormat(ParsedFormatBase(e.in, false, e.conv_set)));
    440  }
    441 }
    442 
    443 }  // namespace
    444 }  // namespace str_format_internal
    445 ABSL_NAMESPACE_END
    446 }  // namespace absl