Test pointer, c string and character formatting.

This commit is contained in:
Victor Zverovich 2012-12-10 13:30:06 -08:00
parent d73306bdce
commit d599e3b262
2 changed files with 61 additions and 32 deletions

View File

@ -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:

View File

@ -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) {