mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-26 04:00:05 +00:00
Test pointer, c string and character formatting.
This commit is contained in:
parent
d73306bdce
commit
d599e3b262
29
format.cc
29
format.cc
@ -28,6 +28,16 @@ void ReportError(const char *s, const std::string &message) {
|
||||
throw fmt::FormatError(*s ? message : std::string("unmatched '{' in format"));
|
||||
}
|
||||
|
||||
void ReportUnknownType(char code, const char *type) {
|
||||
if (std::isprint(code)) {
|
||||
throw fmt::FormatError(
|
||||
str(fmt::Format("unknown format code '{0}' for {1}") << code << type));
|
||||
}
|
||||
throw fmt::FormatError(
|
||||
str(fmt::Format("unknown format code '\\x{0:02x}' for {1}")
|
||||
<< static_cast<unsigned>(code) << type));
|
||||
}
|
||||
|
||||
// Parses an unsigned integer advancing s to the end of the parsed input.
|
||||
// This function assumes that the first character of s is a digit.
|
||||
unsigned ParseUInt(const char *&s) {
|
||||
@ -141,8 +151,8 @@ void fmt::Formatter::FormatInt(T value, unsigned flags, int width, char type) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw FormatError(
|
||||
str(fmt::Format("unknown format code '{0}' for integer") << type));
|
||||
ReportUnknownType(type, "integer");
|
||||
break;
|
||||
}
|
||||
if (sign) {
|
||||
if ((flags & ZERO_FLAG) != 0)
|
||||
@ -163,8 +173,8 @@ void fmt::Formatter::FormatDouble(
|
||||
case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
|
||||
break;
|
||||
default:
|
||||
throw FormatError(
|
||||
str(fmt::Format("unknown format code '{0}' for double") << type));
|
||||
ReportUnknownType(type, "double");
|
||||
break;
|
||||
}
|
||||
|
||||
// Build format string.
|
||||
@ -306,13 +316,16 @@ void fmt::Formatter::Format() {
|
||||
FormatDouble(arg.long_double_value, flags, width, precision, type);
|
||||
break;
|
||||
case CHAR:
|
||||
// TODO: check if type is 'c' or none
|
||||
if (type && type != 'c')
|
||||
ReportUnknownType(type, "char");
|
||||
buffer_.reserve(std::max(width, 1));
|
||||
buffer_.push_back(arg.int_value);
|
||||
if (width > 1)
|
||||
buffer_.resize(buffer_.size() + width - 1, ' ');
|
||||
break;
|
||||
case STRING: {
|
||||
if (type && type != 's')
|
||||
ReportUnknownType(type, "string");
|
||||
const char *str = arg.string_value;
|
||||
size_t size = arg.size;
|
||||
if (size == 0 && *str)
|
||||
@ -324,12 +337,14 @@ void fmt::Formatter::Format() {
|
||||
break;
|
||||
}
|
||||
case POINTER:
|
||||
// TODO: don't allow type specifiers other than 'p'
|
||||
if (type && type != 'p')
|
||||
ReportUnknownType(type, "pointer");
|
||||
FormatInt(reinterpret_cast<uintptr_t>(
|
||||
arg.pointer_value), HEX_PREFIX_FLAG, width, 'x');
|
||||
break;
|
||||
case CUSTOM:
|
||||
// TODO: check if type is 's' or none
|
||||
if (type)
|
||||
ReportUnknownType(type, "object");
|
||||
(this->*arg.format)(arg.custom_value, width);
|
||||
break;
|
||||
default:
|
||||
|
@ -42,7 +42,7 @@ using fmt::FormatError;
|
||||
} else if (actual_message != message) {\
|
||||
gtest_msg.value = \
|
||||
"Expected: " #statement " throws an exception of type " \
|
||||
#expected_exception " with message \"" message "\"."; \
|
||||
#expected_exception "."; \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
|
||||
} \
|
||||
} else \
|
||||
@ -258,19 +258,27 @@ TEST(FormatterTest, Precision) {
|
||||
FormatError, "precision specifier requires floating-point argument");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void CheckUnknownTypes(
|
||||
const T &value, const char *types, const char *type_name) {
|
||||
char format[256], message[256];
|
||||
const char *special = ".0123456789}";
|
||||
for (int c = CHAR_MIN; c <= CHAR_MAX; ++c) {
|
||||
if (std::strchr(types, c) || std::strchr(special, c) || !c) continue;
|
||||
sprintf(format, "{0:1%c}", c, type_name);
|
||||
if (std::isprint(c))
|
||||
sprintf(message, "unknown format code '%c' for %s", c, type_name);
|
||||
else
|
||||
sprintf(message, "unknown format code '\\x%02x' for %s", c, type_name);
|
||||
EXPECT_THROW_MSG(Format(format) << value, FormatError, message)
|
||||
<< format << " " << message;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatInt) {
|
||||
EXPECT_THROW_MSG(Format("{0:v") << 42,
|
||||
FormatError, "unmatched '{' in format");
|
||||
EXPECT_THROW_MSG(Format("{0:v}") << 42,
|
||||
FormatError, "unknown format code 'v' for integer");
|
||||
EXPECT_THROW_MSG(Format("{0:c}") << 42,
|
||||
FormatError, "unknown format code 'c' for integer");
|
||||
EXPECT_THROW_MSG(Format("{0:e}") << 42,
|
||||
FormatError, "unknown format code 'e' for integer");
|
||||
EXPECT_THROW_MSG(Format("{0:f}") << 42,
|
||||
FormatError, "unknown format code 'f' for integer");
|
||||
EXPECT_THROW_MSG(Format("{0:g}") << 42,
|
||||
FormatError, "unknown format code 'g' for integer");
|
||||
CheckUnknownTypes(42, "doxX", "integer");
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatDec) {
|
||||
@ -342,14 +350,7 @@ TEST(FormatterTest, FormatOct) {
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatDouble) {
|
||||
EXPECT_THROW_MSG(Format("{0:c}") << 1.2,
|
||||
FormatError, "unknown format code 'c' for double");
|
||||
EXPECT_THROW_MSG(Format("{0:d}") << 1.2,
|
||||
FormatError, "unknown format code 'd' for double");
|
||||
EXPECT_THROW_MSG(Format("{0:o}") << 1.2,
|
||||
FormatError, "unknown format code 'o' for double");
|
||||
EXPECT_THROW_MSG(Format("{0:x}") << 1.2,
|
||||
FormatError, "unknown format code 'x' for double");
|
||||
CheckUnknownTypes(1.2, "eEfFgG", "double");
|
||||
EXPECT_EQ("0", str(Format("{0:}") << 0.0));
|
||||
EXPECT_EQ("0.000000", str(Format("{0:f}") << 0.0));
|
||||
EXPECT_EQ("392.65", str(Format("{0:}") << 392.65));
|
||||
@ -376,17 +377,28 @@ TEST(FormatterTest, FormatLongDouble) {
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatChar) {
|
||||
EXPECT_EQ("a*b", str(Format("{0}{1}{2}") << 'a' << '*' << 'b'));
|
||||
CheckUnknownTypes('a', "c", "char");
|
||||
EXPECT_EQ("a", str(Format("{0}") << 'a'));
|
||||
EXPECT_EQ("z", str(Format("{0:c}") << 'z'));
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatCString) {
|
||||
CheckUnknownTypes("test", "s", "string");
|
||||
EXPECT_EQ("test", str(Format("{0}") << "test"));
|
||||
EXPECT_EQ("test", str(Format("{0:s}") << "test"));
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatPointer) {
|
||||
CheckUnknownTypes(reinterpret_cast<void*>(0x1234), "p", "pointer");
|
||||
EXPECT_EQ("0x0", str(Format("{0}") << reinterpret_cast<void*>(0)));
|
||||
EXPECT_EQ("0x1234", str(Format("{0}") << reinterpret_cast<void*>(0x1234)));
|
||||
EXPECT_EQ("0x1234", str(Format("{0:p}") << reinterpret_cast<void*>(0x1234)));
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatString) {
|
||||
EXPECT_EQ("test", str(Format("{0}") << std::string("test")));
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatPointer) {
|
||||
EXPECT_EQ("0x0", str(Format("{0}") << reinterpret_cast<void*>(0)));
|
||||
}
|
||||
|
||||
class Date {
|
||||
int year_, month_, day_;
|
||||
public:
|
||||
@ -398,10 +410,12 @@ class Date {
|
||||
}
|
||||
};
|
||||
|
||||
TEST(FormatterTest, FormatCustomArg) {
|
||||
TEST(FormatterTest, FormatCustom) {
|
||||
EXPECT_EQ("a string", str(Format("{0}") << TestString("a string")));
|
||||
std::string s = str(fmt::Format("The date is {0}") << Date(2012, 12, 9));
|
||||
EXPECT_EQ("The date is 2012-12-9", s);
|
||||
Date date(2012, 12, 9);
|
||||
CheckUnknownTypes(date, "", "object");
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatStringFromSpeedTest) {
|
||||
|
Loading…
Reference in New Issue
Block a user