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


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