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
00049 const Expectation kExpect[] = {
00050 #define X(c) {ConversionChar::c, #c[0]}
00051 X(c), X(C), X(s), X(S),
00052 X(d), X(i), X(o), X(u), X(x), X(X),
00053 X(f), X(F), X(e), X(E), X(g), X(G), X(a), X(A),
00054 X(n), X(p),
00055 #undef X
00056 {ConversionChar::none, '\0'},
00057 };
00058
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();
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();
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" },
00099 {__LINE__, "ba", "", "ba"},
00100 {__LINE__, "l", "", "l" },
00101 {__LINE__, "d", "d", "" },
00102 {__LINE__, "d ", "d", " " },
00103 {__LINE__, "dd", "d", "d" },
00104 {__LINE__, "d9", "d", "9" },
00105 {__LINE__, "dzz", "d", "zz"},
00106 {__LINE__, "1$*2$d", "1$*2$d", "" },
00107 {__LINE__, "0-14.3hhd", "0-14.3hhd", ""},
00108 {__LINE__, " 0-+#14.3hhd", " 0-+#14.3hhd", ""},
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"));
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
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
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
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
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
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
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
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, {});
00328 EXPECT_EQ("", SummarizeParsedFormat(p1));
00329
00330 ParsedFormatBase p2 = p1;
00331 EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p2));
00332
00333 p1 = ParsedFormatBase("hello%s", true, {Conv::s});
00334 EXPECT_EQ("[hello]{s:1$s}", SummarizeParsedFormat(p1));
00335
00336 ParsedFormatBase p3 = p1;
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);
00344
00345 p2 = p1;
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
00357
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]!"},
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 }
00391 }
00392 }