summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2022-09-15 14:29:39 -0700
committerGravatar Copybara-Service <copybara-worker@google.com>2022-09-15 14:30:34 -0700
commitab2e2c4f6062999afaf960759dfccb77f350c702 (patch)
treea09ca81723521190744e2ec917a9f697cd08254b
parentd423ac0ef052bd7b6fc53fd1a026a44e1713d993 (diff)
Adds support for "%v" in absl::StrFormat and related functions for numeric types, including integer and floating point values. Users may now specify %v and have the format specifier deduced. Integer values will print according to %d specifications, unsigned values will use %u, and floating point values will use %g. Note that %v does not work for `char` due to ambiguity regarding the intended output. Please continue to use %c for `char`.
PiperOrigin-RevId: 474658166 Change-Id: Iecae39263e368b27232db440535f2bf7da8d863c
-rw-r--r--absl/strings/internal/str_format/arg.cc49
-rw-r--r--absl/strings/internal/str_format/arg.h26
-rw-r--r--absl/strings/internal/str_format/checker_test.cc4
-rw-r--r--absl/strings/internal/str_format/extension.h2
-rw-r--r--absl/strings/internal/str_format/extension_test.cc11
-rw-r--r--absl/strings/str_format_test.cc237
6 files changed, 250 insertions, 79 deletions
diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc
index 007e8e83..b0e06bfb 100644
--- a/absl/strings/internal/str_format/arg.cc
+++ b/absl/strings/internal/str_format/arg.cc
@@ -278,12 +278,33 @@ bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
return true;
}
+template <typename T,
+ typename std::enable_if<(std::is_integral<T>::value &&
+ std::is_signed<T>::value) ||
+ std::is_same<T, int128>::value,
+ int>::type = 0>
+constexpr auto ConvertV(T) {
+ return FormatConversionCharInternal::d;
+}
+
+template <typename T,
+ typename std::enable_if<(std::is_integral<T>::value &&
+ std::is_unsigned<T>::value) ||
+ std::is_same<T, uint128>::value,
+ int>::type = 0>
+constexpr auto ConvertV(T) {
+ return FormatConversionCharInternal::u;
+}
+
template <typename T>
-bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
- FormatSinkImpl *sink) {
+bool ConvertIntArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
using U = typename MakeUnsigned<T>::type;
IntDigits as_digits;
+ if (conv.conversion_char() == FormatConversionCharInternal::v) {
+ conv.set_conversion_char(ConvertV(T{}));
+ }
+
// This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
// it to complain about a switch/case type mismatch, even though both are
// FormatConverionChar. Likely this is because at this point
@@ -334,8 +355,11 @@ bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
}
template <typename T>
-bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv,
- FormatSinkImpl *sink) {
+bool ConvertFloatArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
+ if (conv.conversion_char() == FormatConversionCharInternal::v) {
+ conv.set_conversion_char(FormatConversionCharInternal::g);
+ }
+
return FormatConversionCharIsFloat(conv.conversion_char()) &&
ConvertFloatImpl(v, conv, sink);
}
@@ -413,19 +437,18 @@ FloatingConvertResult FormatConvertImpl(long double v,
}
// ==================== Chars ====================
-IntegralConvertResult FormatConvertImpl(char v,
- const FormatConversionSpecImpl conv,
- FormatSinkImpl *sink) {
+CharConvertResult FormatConvertImpl(char v, const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
-IntegralConvertResult FormatConvertImpl(signed char v,
- const FormatConversionSpecImpl conv,
- FormatSinkImpl *sink) {
+CharConvertResult FormatConvertImpl(signed char v,
+ const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
-IntegralConvertResult FormatConvertImpl(unsigned char v,
- const FormatConversionSpecImpl conv,
- FormatSinkImpl *sink) {
+CharConvertResult FormatConvertImpl(unsigned char v,
+ const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h
index a56ca301..3c2bb3e6 100644
--- a/absl/strings/internal/str_format/arg.h
+++ b/absl/strings/internal/str_format/arg.h
@@ -176,9 +176,15 @@ StringConvertResult FormatConvertImpl(const AbslCord& value,
using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
FormatConversionCharSetInternal::c,
FormatConversionCharSetInternal::kNumeric,
+ FormatConversionCharSetInternal::kStar,
+ FormatConversionCharSetInternal::v)>;
+using FloatingConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
+ FormatConversionCharSetInternal::kFloating,
+ FormatConversionCharSetInternal::v)>;
+using CharConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
+ FormatConversionCharSetInternal::c,
+ FormatConversionCharSetInternal::kNumeric,
FormatConversionCharSetInternal::kStar)>;
-using FloatingConvertResult =
- ArgConvertResult<FormatConversionCharSetInternal::kFloating>;
// Floats.
FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
@@ -190,14 +196,14 @@ FloatingConvertResult FormatConvertImpl(long double v,
FormatSinkImpl* sink);
// Chars.
-IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
- FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(signed char v,
- FormatConversionSpecImpl conv,
- FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(unsigned char v,
- FormatConversionSpecImpl conv,
- FormatSinkImpl* sink);
+CharConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
+CharConvertResult FormatConvertImpl(signed char v,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
+CharConvertResult FormatConvertImpl(unsigned char v,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
// Ints.
IntegralConvertResult FormatConvertImpl(short v, // NOLINT
diff --git a/absl/strings/internal/str_format/checker_test.cc b/absl/strings/internal/str_format/checker_test.cc
index b186e7d8..680517f7 100644
--- a/absl/strings/internal/str_format/checker_test.cc
+++ b/absl/strings/internal/str_format/checker_test.cc
@@ -45,10 +45,10 @@ TEST(StrFormatChecker, ArgumentToConv) {
EXPECT_EQ(ConvToString(conv), "sp");
conv = ArgumentToConv<double>();
- EXPECT_EQ(ConvToString(conv), "fFeEgGaA");
+ EXPECT_EQ(ConvToString(conv), "fFeEgGaAv");
conv = ArgumentToConv<int>();
- EXPECT_EQ(ConvToString(conv), "cdiouxXfFeEgGaA*");
+ EXPECT_EQ(ConvToString(conv), "cdiouxXfFeEgGaAv*");
conv = ArgumentToConv<std::string*>();
EXPECT_EQ(ConvToString(conv), "p");
diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h
index f8d98bf7..603bd49d 100644
--- a/absl/strings/internal/str_format/extension.h
+++ b/absl/strings/internal/str_format/extension.h
@@ -292,6 +292,8 @@ class FormatConversionSpecImpl {
return conv_;
}
+ void set_conversion_char(FormatConversionChar c) { conv_ = c; }
+
// Returns the specified width. If width is unspecfied, it returns a negative
// value.
int width() const { return width_; }
diff --git a/absl/strings/internal/str_format/extension_test.cc b/absl/strings/internal/str_format/extension_test.cc
index 1c93fdb1..694c1264 100644
--- a/absl/strings/internal/str_format/extension_test.cc
+++ b/absl/strings/internal/str_format/extension_test.cc
@@ -19,6 +19,7 @@
#include <random>
#include <string>
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
@@ -95,4 +96,14 @@ TEST(FormatExtensionTest, VerifyEnumEquality) {
#undef X_VAL
}
+TEST(FormatExtensionTest, SetConversionChar) {
+ absl::str_format_internal::FormatConversionSpecImpl spec;
+ EXPECT_EQ(spec.conversion_char(),
+ absl::str_format_internal::FormatConversionCharInternal::kNone);
+ spec.set_conversion_char(
+ absl::str_format_internal::FormatConversionCharInternal::d);
+ EXPECT_EQ(spec.conversion_char(),
+ absl::str_format_internal::FormatConversionCharInternal::d);
+}
+
} // namespace
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc
index 4ac6aa27..9ef69837 100644
--- a/absl/strings/str_format_test.cc
+++ b/absl/strings/str_format_test.cc
@@ -42,6 +42,18 @@ TEST_F(FormatEntryPointTest, Format) {
EXPECT_TRUE(Format(&sink, pc, 123));
EXPECT_EQ("A format 123", sink);
}
+
+TEST_F(FormatEntryPointTest, FormatWithV) {
+ std::string sink;
+ EXPECT_TRUE(Format(&sink, "A format %v", 123));
+ EXPECT_EQ("A format 123", sink);
+ sink.clear();
+
+ ParsedFormat<'v'> pc("A format %v");
+ EXPECT_TRUE(Format(&sink, pc, 123));
+ EXPECT_EQ("A format 123", sink);
+}
+
TEST_F(FormatEntryPointTest, UntypedFormat) {
constexpr const char* formats[] = {
"",
@@ -87,6 +99,9 @@ TEST_F(FormatEntryPointTest, StringFormat) {
TEST_F(FormatEntryPointTest, StringFormatV) {
std::string hello = "hello";
EXPECT_EQ("hello", StrFormat("%v", hello));
+ EXPECT_EQ("123", StrFormat("%v", 123));
+ constexpr absl::string_view view("=%v=", 4);
+ EXPECT_EQ("=123=", StrFormat(view, 123));
}
TEST_F(FormatEntryPointTest, AppendFormat) {
@@ -96,6 +111,13 @@ TEST_F(FormatEntryPointTest, AppendFormat) {
EXPECT_EQ("123", r);
}
+TEST_F(FormatEntryPointTest, AppendFormatWithV) {
+ std::string s;
+ std::string& r = StrAppendFormat(&s, "%v", 123);
+ EXPECT_EQ(&s, &r); // should be same object
+ EXPECT_EQ("123", r);
+}
+
TEST_F(FormatEntryPointTest, AppendFormatFail) {
std::string s = "orig";
@@ -108,6 +130,17 @@ TEST_F(FormatEntryPointTest, AppendFormatFail) {
{&arg, 1}));
}
+TEST_F(FormatEntryPointTest, AppendFormatFailWithV) {
+ std::string s = "orig";
+
+ UntypedFormatSpec format(" more %v");
+ FormatArgImpl arg("not an int");
+
+ EXPECT_EQ("orig",
+ str_format_internal::AppendPack(
+ &s, str_format_internal::UntypedFormatSpecImpl::Extract(format),
+ {&arg, 1}));
+}
TEST_F(FormatEntryPointTest, ManyArgs) {
EXPECT_EQ("24", StrFormat("%24$d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
@@ -128,6 +161,15 @@ TEST_F(FormatEntryPointTest, Preparsed) {
EXPECT_EQ("=123=", StrFormat(ParsedFormat<'d'>(view), 123));
}
+TEST_F(FormatEntryPointTest, PreparsedWithV) {
+ ParsedFormat<'v'> pc("%v");
+ EXPECT_EQ("123", StrFormat(pc, 123));
+ // rvalue ok?
+ EXPECT_EQ("123", StrFormat(ParsedFormat<'v'>("%v"), 123));
+ constexpr absl::string_view view("=%v=", 4);
+ EXPECT_EQ("=123=", StrFormat(ParsedFormat<'v'>(view), 123));
+}
+
TEST_F(FormatEntryPointTest, FormatCountCapture) {
int n = 0;
EXPECT_EQ("", StrFormat("%n", FormatCountCapture(&n)));
@@ -136,6 +178,14 @@ TEST_F(FormatEntryPointTest, FormatCountCapture) {
EXPECT_EQ(3, n);
}
+TEST_F(FormatEntryPointTest, FormatCountCaptureWithV) {
+ int n = 0;
+ EXPECT_EQ("", StrFormat("%n", FormatCountCapture(&n)));
+ EXPECT_EQ(0, n);
+ EXPECT_EQ("123", StrFormat("%v%n", 123, FormatCountCapture(&n)));
+ EXPECT_EQ(3, n);
+}
+
TEST_F(FormatEntryPointTest, FormatCountCaptureWrongType) {
// Should reject int*.
int n = 0;
@@ -148,6 +198,18 @@ TEST_F(FormatEntryPointTest, FormatCountCaptureWrongType) {
absl::MakeSpan(args)));
}
+TEST_F(FormatEntryPointTest, FormatCountCaptureWrongTypeWithV) {
+ // Should reject int*.
+ int n = 0;
+ UntypedFormatSpec format("%v%n");
+ int i = 123, *ip = &n;
+ FormatArgImpl args[2] = {FormatArgImpl(i), FormatArgImpl(ip)};
+
+ EXPECT_EQ("", str_format_internal::FormatPack(
+ str_format_internal::UntypedFormatSpecImpl::Extract(format),
+ absl::MakeSpan(args)));
+}
+
TEST_F(FormatEntryPointTest, FormatCountCaptureMultiple) {
int n1 = 0;
int n2 = 0;
@@ -212,23 +274,33 @@ TEST_F(FormatEntryPointTest, Stream) {
}
TEST_F(FormatEntryPointTest, StreamWithV) {
- const std::string format = "%d %u %c %v %f %g";
+ const std::string formats[] = {
+ "",
+ "a",
+ "%v %u %c %v %f %v",
+ };
- const std::string format_for_buf = "%d %u %c %s %f %g";
+ const std::string formats_for_buf[] = {
+ "",
+ "a",
+ "%d %u %c %s %f %g",
+ };
std::string buf(4096, '\0');
- const auto parsed =
- ParsedFormat<'d', 'u', 'c', 'v', 'f', 'g'>::NewAllowIgnored(format);
- std::ostringstream oss;
- oss << StreamFormat(*parsed, 123, 3, 49,
- absl::string_view("multistreaming!!!"), 1.01, 1.01);
- int fmt_result =
- snprintf(&*buf.begin(), buf.size(), format_for_buf.c_str(), //
- 123, 3, 49, "multistreaming!!!", 1.01, 1.01);
- ASSERT_TRUE(oss) << format;
- ASSERT_TRUE(fmt_result >= 0 && static_cast<size_t>(fmt_result) < buf.size())
- << fmt_result;
- EXPECT_EQ(buf.c_str(), oss.str());
+ for (auto i = 0; i < ABSL_ARRAYSIZE(formats); ++i) {
+ const auto parsed =
+ ParsedFormat<'v', 'u', 'c', 'v', 'f', 'v'>::NewAllowIgnored(formats[i]);
+ std::ostringstream oss;
+ oss << StreamFormat(*parsed, 123, 3, 49,
+ absl::string_view("multistreaming!!!"), 1.01, 1.01);
+ int fmt_result =
+ snprintf(&*buf.begin(), buf.size(), formats_for_buf[i].c_str(), //
+ 123, 3, 49, "multistreaming!!!", 1.01, 1.01);
+ ASSERT_TRUE(oss) << formats[i];
+ ASSERT_TRUE(fmt_result >= 0 && static_cast<size_t>(fmt_result) < buf.size())
+ << fmt_result;
+ EXPECT_EQ(buf.c_str(), oss.str());
+ }
}
TEST_F(FormatEntryPointTest, StreamOk) {
@@ -238,6 +310,13 @@ TEST_F(FormatEntryPointTest, StreamOk) {
EXPECT_TRUE(oss.good());
}
+TEST_F(FormatEntryPointTest, StreamOkWithV) {
+ std::ostringstream oss;
+ oss << StreamFormat("hello %v", 123);
+ EXPECT_EQ("hello 123", oss.str());
+ EXPECT_TRUE(oss.good());
+}
+
TEST_F(FormatEntryPointTest, StreamFail) {
std::ostringstream oss;
UntypedFormatSpec format("hello %d");
@@ -248,6 +327,16 @@ TEST_F(FormatEntryPointTest, StreamFail) {
EXPECT_TRUE(oss.fail());
}
+TEST_F(FormatEntryPointTest, StreamFailWithV) {
+ std::ostringstream oss;
+ UntypedFormatSpec format("hello %v");
+ FormatArgImpl arg("non-numeric");
+ oss << str_format_internal::Streamable(
+ str_format_internal::UntypedFormatSpecImpl::Extract(format), {&arg, 1});
+ EXPECT_EQ("hello ", oss.str()); // partial write
+ EXPECT_TRUE(oss.fail());
+}
+
std::string WithSnprintf(const char* fmt, ...) {
std::string buf;
buf.resize(128);
@@ -425,19 +514,19 @@ TEST_F(FormatEntryPointTest, SNPrintFWithV) {
EXPECT_EQ(result, 11);
EXPECT_EQ(std::string(buffer), "STRING: ABC");
- result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 123456);
+ result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %v", 123456);
EXPECT_EQ(result, 14);
EXPECT_EQ(std::string(buffer), "NUMBER: 123456");
- result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 1234567);
+ result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %v", 1234567);
EXPECT_EQ(result, 15);
EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
- result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 12345678);
+ result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %v", 12345678);
EXPECT_EQ(result, 16);
EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
- result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 123456789);
+ result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %v", 123456789);
EXPECT_EQ(result, 17);
EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
@@ -451,7 +540,7 @@ TEST(StrFormat, BehavesAsDocumented) {
std::string s = absl::StrFormat("%s, %d!", "Hello", 123);
EXPECT_EQ("Hello, 123!", s);
std::string hello = "Hello";
- std::string s2 = absl::StrFormat("%v, %d!", hello, 123);
+ std::string s2 = absl::StrFormat("%v, %v!", hello, 123);
EXPECT_EQ("Hello, 123!", s2);
// The format of a replacement is
// '%'[position][flags][width['.'precision]][length_modifier][format]
@@ -480,13 +569,18 @@ TEST(StrFormat, BehavesAsDocumented) {
EXPECT_EQ(StrFormat("%d", int{10}), "10");
EXPECT_EQ(StrFormat("%d", long{10}), "10"); // NOLINT
EXPECT_EQ(StrFormat("%d", uint64_t{10}), "10");
+ EXPECT_EQ(StrFormat("%v", int{10}), "10");
+ EXPECT_EQ(StrFormat("%v", long{10}), "10"); // NOLINT
+ EXPECT_EQ(StrFormat("%v", uint64_t{10}), "10");
// d,i - signed decimal Eg: -10 -> "-10"
EXPECT_EQ(StrFormat("%d", -10), "-10");
EXPECT_EQ(StrFormat("%i", -10), "-10");
+ EXPECT_EQ(StrFormat("%v", -10), "-10");
// o - octal Eg: 10 -> "12"
EXPECT_EQ(StrFormat("%o", 10), "12");
// u - unsigned decimal Eg: 10 -> "10"
EXPECT_EQ(StrFormat("%u", 10), "10");
+ EXPECT_EQ(StrFormat("%v", 10), "10");
// x/X - lower,upper case hex Eg: 10 -> "a"/"A"
EXPECT_EQ(StrFormat("%x", 10), "a");
EXPECT_EQ(StrFormat("%X", 10), "A");
@@ -511,6 +605,8 @@ TEST(StrFormat, BehavesAsDocumented) {
EXPECT_EQ(StrFormat("%g", .01), "0.01");
EXPECT_EQ(StrFormat("%g", 1e10), "1e+10");
EXPECT_EQ(StrFormat("%G", 1e10), "1E+10");
+ EXPECT_EQ(StrFormat("%v", .01), "0.01");
+ EXPECT_EQ(StrFormat("%v", 1e10), "1e+10");
// a/A - lower,upper case hex Eg: -3.0 -> "-0x1.8p+1"/"-0X1.8P+1"
// On Android platform <=21, there is a regression in hexfloat formatting.
@@ -598,10 +694,10 @@ TEST_F(ParsedFormatTest, SimpleChecked) {
}
TEST_F(ParsedFormatTest, SimpleCheckedWithV) {
- EXPECT_EQ("[ABC]{d:1$d}[DEF]",
- SummarizeParsedFormat(ParsedFormat<'d'>("ABC%dDEF")));
- EXPECT_EQ("{v:1$v}[FFF]{d:2$d}[ZZZ]{f:3$f}",
- SummarizeParsedFormat(ParsedFormat<'v', 'd', 'f'>("%vFFF%dZZZ%f")));
+ EXPECT_EQ("[ABC]{v:1$v}[DEF]",
+ SummarizeParsedFormat(ParsedFormat<'v'>("ABC%vDEF")));
+ EXPECT_EQ("{v:1$v}[FFF]{v:2$v}[ZZZ]{f:3$f}",
+ SummarizeParsedFormat(ParsedFormat<'v', 'v', 'f'>("%vFFF%vZZZ%f")));
EXPECT_EQ("{v:1$v}[ ]{.*d:3$.2$*d}",
SummarizeParsedFormat(ParsedFormat<'v', '*', 'd'>("%v %.*d")));
}
@@ -637,20 +733,20 @@ TEST_F(ParsedFormatTest, SimpleUncheckedCorrect) {
}
TEST_F(ParsedFormatTest, SimpleUncheckedCorrectWithV) {
- auto f = ParsedFormat<'d'>::New("ABC%dDEF");
+ auto f = ParsedFormat<'v'>::New("ABC%vDEF");
ASSERT_TRUE(f);
- EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
+ EXPECT_EQ("[ABC]{v:1$v}[DEF]", SummarizeParsedFormat(*f));
- std::string format = "%vFFF%dZZZ%f";
- auto f2 = ParsedFormat<'v', 'd', 'f'>::New(format);
+ std::string format = "%vFFF%vZZZ%f";
+ auto f2 = ParsedFormat<'v', 'v', 'f'>::New(format);
ASSERT_TRUE(f2);
- EXPECT_EQ("{v:1$v}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
+ EXPECT_EQ("{v:1$v}[FFF]{v:2$v}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
- f2 = ParsedFormat<'v', 'd', 'f'>::New("%v %d %f");
+ f2 = ParsedFormat<'v', 'v', 'f'>::New("%v %v %f");
ASSERT_TRUE(f2);
- EXPECT_EQ("{v:1$v}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
+ EXPECT_EQ("{v:1$v}[ ]{v:2$v}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
}
TEST_F(ParsedFormatTest, SimpleUncheckedIgnoredArgs) {
@@ -668,6 +764,18 @@ TEST_F(ParsedFormatTest, SimpleUncheckedIgnoredArgs) {
EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
}
+TEST_F(ParsedFormatTest, SimpleUncheckedIgnoredArgsWithV) {
+ EXPECT_FALSE((ParsedFormat<'v', 'v'>::New("ABC")));
+ EXPECT_FALSE((ParsedFormat<'v', 'v'>::New("%vABC")));
+ EXPECT_FALSE((ParsedFormat<'v', 's'>::New("ABC%2$s")));
+ auto f = ParsedFormat<'v', 'v'>::NewAllowIgnored("ABC");
+ ASSERT_TRUE(f);
+ EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
+ f = ParsedFormat<'v', 'v'>::NewAllowIgnored("%vABC");
+ ASSERT_TRUE(f);
+ EXPECT_EQ("{v:1$v}[ABC]", SummarizeParsedFormat(*f));
+}
+
TEST_F(ParsedFormatTest, SimpleUncheckedUnsupported) {
EXPECT_FALSE(ParsedFormat<'d'>::New("%1$d %1$x"));
EXPECT_FALSE(ParsedFormat<'x'>::New("%1$d %1$x"));
@@ -683,12 +791,12 @@ TEST_F(ParsedFormatTest, SimpleUncheckedIncorrect) {
}
TEST_F(ParsedFormatTest, SimpleUncheckedIncorrectWithV) {
- EXPECT_FALSE(ParsedFormat<'d'>::New(""));
+ EXPECT_FALSE(ParsedFormat<'v'>::New(""));
- EXPECT_FALSE(ParsedFormat<'d'>::New("ABC%dDEF%d"));
+ EXPECT_FALSE(ParsedFormat<'v'>::New("ABC%vDEF%v"));
- std::string format = "%vFFF%dZZZ%f";
- EXPECT_FALSE((ParsedFormat<'v', 'd', 'g'>::New(format)));
+ std::string format = "%vFFF%vZZZ%f";
+ EXPECT_FALSE((ParsedFormat<'v', 'v', 'g'>::New(format)));
}
#if defined(__cpp_nontype_template_parameter_auto)
@@ -739,17 +847,17 @@ TEST_F(ParsedFormatTest, ExtendedTyping) {
}
TEST_F(ParsedFormatTest, ExtendedTypingWithV) {
- EXPECT_FALSE(ParsedFormat<FormatConversionCharSet::d>::New(""));
- ASSERT_TRUE(ParsedFormat<absl::FormatConversionCharSet::d>::New("%d"));
- auto v1 = ParsedFormat<'d', absl::FormatConversionCharSet::v>::New("%d%v");
+ EXPECT_FALSE(ParsedFormat<FormatConversionCharSet::v>::New(""));
+ ASSERT_TRUE(ParsedFormat<absl::FormatConversionCharSet::v>::New("%v"));
+ auto v1 = ParsedFormat<'v', absl::FormatConversionCharSet::v>::New("%v%v");
ASSERT_TRUE(v1);
- auto v2 = ParsedFormat<absl::FormatConversionCharSet::d, 'v'>::New("%d%v");
+ auto v2 = ParsedFormat<absl::FormatConversionCharSet::v, 'v'>::New("%v%v");
ASSERT_TRUE(v2);
- auto v3 = ParsedFormat<absl::FormatConversionCharSet::d |
+ auto v3 = ParsedFormat<absl::FormatConversionCharSet::v |
absl::FormatConversionCharSet::v,
- 'v'>::New("%d%v");
+ 'v'>::New("%v%v");
ASSERT_TRUE(v3);
- auto v4 = ParsedFormat<absl::FormatConversionCharSet::d |
+ auto v4 = ParsedFormat<absl::FormatConversionCharSet::v |
absl::FormatConversionCharSet::v,
'v'>::New("%v%v");
ASSERT_TRUE(v4);
@@ -799,24 +907,24 @@ TEST_F(ParsedFormatTest, UncheckedCorrect) {
TEST_F(ParsedFormatTest, UncheckedCorrectWithV) {
auto f =
- ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New("ABC%dDEF");
+ ExtendedParsedFormat<absl::FormatConversionCharSet::v>::New("ABC%vDEF");
ASSERT_TRUE(f);
- EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f));
+ EXPECT_EQ("[ABC]{v:1$v}[DEF]", SummarizeParsedFormat(*f));
- std::string format = "%vFFF%dZZZ%f";
+ std::string format = "%vFFF%vZZZ%f";
auto f2 = ExtendedParsedFormat<
- absl::FormatConversionCharSet::v, absl::FormatConversionCharSet::d,
+ absl::FormatConversionCharSet::v, absl::FormatConversionCharSet::v,
absl::FormatConversionCharSet::kFloating>::New(format);
ASSERT_TRUE(f2);
- EXPECT_EQ("{v:1$v}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
+ EXPECT_EQ("{v:1$v}[FFF]{v:2$v}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2));
f2 = ExtendedParsedFormat<
- absl::FormatConversionCharSet::v, absl::FormatConversionCharSet::d,
- absl::FormatConversionCharSet::kFloating>::New("%v %d %f");
+ absl::FormatConversionCharSet::v, absl::FormatConversionCharSet::v,
+ absl::FormatConversionCharSet::kFloating>::New("%v %v %f");
ASSERT_TRUE(f2);
- EXPECT_EQ("{v:1$v}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
+ EXPECT_EQ("{v:1$v}[ ]{v:2$v}[ ]{f:3$f}", SummarizeParsedFormat(*f2));
}
TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) {
@@ -846,6 +954,28 @@ TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) {
EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f));
}
+TEST_F(ParsedFormatTest, UncheckedIgnoredArgsWithV) {
+ EXPECT_FALSE(
+ (ExtendedParsedFormat<absl::FormatConversionCharSet::v,
+ absl::FormatConversionCharSet::v>::New("ABC")));
+ EXPECT_FALSE(
+ (ExtendedParsedFormat<absl::FormatConversionCharSet::v,
+ absl::FormatConversionCharSet::v>::New("%vABC")));
+ EXPECT_FALSE((ExtendedParsedFormat<absl::FormatConversionCharSet::v,
+ absl::FormatConversionCharSet::s>::
+ New("ABC%2$s")));
+ auto f = ExtendedParsedFormat<
+ absl::FormatConversionCharSet::v,
+ absl::FormatConversionCharSet::v>::NewAllowIgnored("ABC");
+ ASSERT_TRUE(f);
+ EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f));
+ f = ExtendedParsedFormat<
+ absl::FormatConversionCharSet::v,
+ absl::FormatConversionCharSet::v>::NewAllowIgnored("%vABC");
+ ASSERT_TRUE(f);
+ EXPECT_EQ("{v:1$v}[ABC]", SummarizeParsedFormat(*f));
+}
+
TEST_F(ParsedFormatTest, UncheckedMultipleTypes) {
auto dx =
ExtendedParsedFormat<absl::FormatConversionCharSet::d |
@@ -873,15 +1003,14 @@ TEST_F(ParsedFormatTest, UncheckedIncorrect) {
}
TEST_F(ParsedFormatTest, UncheckedIncorrectWithV) {
- EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New(""));
+ EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::v>::New(""));
- EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::d>::New(
- "ABC%dDEF%d"));
+ EXPECT_FALSE(ExtendedParsedFormat<absl::FormatConversionCharSet::v>::New(
+ "ABC%vDEF%v"));
- std::string format = "%vFFF%dZZZ%f";
+ std::string format = "%vFFF%vZZZ%f";
EXPECT_FALSE(
(ExtendedParsedFormat<absl::FormatConversionCharSet::v,
- absl::FormatConversionCharSet::d,
absl::FormatConversionCharSet::g>::New(format)));
}