Test and fix writing wide strings.

This commit is contained in:
Victor Zverovich 2013-09-06 19:32:19 -07:00
parent 257b2106b3
commit 525de51320
2 changed files with 20 additions and 16 deletions

View File

@ -530,7 +530,9 @@ class BasicWriter {
template <typename T> template <typename T>
void FormatDouble(T value, const FormatSpec &spec, int precision); void FormatDouble(T value, const FormatSpec &spec, int precision);
CharPtr FormatString(const char *s, std::size_t size, const FormatSpec &spec); template <typename StringChar>
CharPtr FormatString(const StringChar *s,
std::size_t size, const FormatSpec &spec);
public: public:
/** /**
@ -833,8 +835,9 @@ void BasicWriter<Char>::FormatDouble(
} }
template <typename Char> template <typename Char>
template <typename StringChar>
typename BasicWriter<Char>::CharPtr BasicWriter<Char>::FormatString( typename BasicWriter<Char>::CharPtr BasicWriter<Char>::FormatString(
const char *s, std::size_t size, const FormatSpec &spec) { const StringChar *s, std::size_t size, const FormatSpec &spec) {
CharPtr out = CharPtr(); CharPtr out = CharPtr();
if (spec.width() > size) { if (spec.width() > size) {
out = GrowBuffer(spec.width()); out = GrowBuffer(spec.width());
@ -1000,7 +1003,7 @@ class BasicFormatter {
long double long_double_value; long double long_double_value;
const void *pointer_value; const void *pointer_value;
struct { struct {
const char *value; const Char *value;
std::size_t size; std::size_t size;
} string; } string;
struct { struct {
@ -1022,12 +1025,12 @@ class BasicFormatter {
: type(LONG_DOUBLE), long_double_value(value), formatter(0) {} : type(LONG_DOUBLE), long_double_value(value), formatter(0) {}
Arg(char value) : type(CHAR), int_value(value), formatter(0) {} Arg(char value) : type(CHAR), int_value(value), formatter(0) {}
Arg(const char *value) : type(STRING), formatter(0) { Arg(const Char *value) : type(STRING), formatter(0) {
string.value = value; string.value = value;
string.size = 0; string.size = 0;
} }
Arg(char *value) : type(STRING), formatter(0) { Arg(Char *value) : type(STRING), formatter(0) {
string.value = value; string.value = value;
string.size = 0; string.size = 0;
} }
@ -1604,13 +1607,13 @@ void BasicFormatter<Char>::DoFormat() {
case STRING: { case STRING: {
if (spec.type_ && spec.type_ != 's') if (spec.type_ && spec.type_ != 's')
internal::ReportUnknownType(spec.type_, "string"); internal::ReportUnknownType(spec.type_, "string");
const char *str = arg.string.value; const Char *str = arg.string.value;
std::size_t size = arg.string.size; std::size_t size = arg.string.size;
if (size == 0) { if (size == 0) {
if (!str) if (!str)
throw FormatError("string pointer is null"); throw FormatError("string pointer is null");
if (*str) if (*str)
size = std::strlen(str); size = std::char_traits<Char>::length(str);
} }
writer.FormatString(str, size, spec); writer.FormatString(str, size, spec);
break; break;

View File

@ -1030,6 +1030,8 @@ TEST(FormatterTest, CustomFormat) {
TEST(FormatterTest, WideFormatString) { TEST(FormatterTest, WideFormatString) {
EXPECT_EQ(L"42", str(Format(L"{}") << 42)); EXPECT_EQ(L"42", str(Format(L"{}") << 42));
EXPECT_EQ(L"4.2", str(Format(L"{}") << 4.2));
EXPECT_EQ(L"abc", str(Format(L"{}") << L"abc"));
} }
TEST(FormatterTest, FormatStringFromSpeedTest) { TEST(FormatterTest, FormatStringFromSpeedTest) {
@ -1104,7 +1106,7 @@ struct CountCalls {
} }
}; };
TEST(TempFormatterTest, Action) { TEST(FormatterTest, Action) {
int num_calls = 0; int num_calls = 0;
{ {
fmt::Formatter<CountCalls> af("test", CountCalls(num_calls)); fmt::Formatter<CountCalls> af("test", CountCalls(num_calls));
@ -1113,7 +1115,7 @@ TEST(TempFormatterTest, Action) {
EXPECT_EQ(1, num_calls); EXPECT_EQ(1, num_calls);
} }
TEST(TempFormatterTest, ActionNotCalledOnError) { TEST(FormatterTest, ActionNotCalledOnError) {
int num_calls = 0; int num_calls = 0;
{ {
typedef fmt::Formatter<CountCalls> TestFormatter; typedef fmt::Formatter<CountCalls> TestFormatter;
@ -1126,19 +1128,18 @@ TEST(TempFormatterTest, ActionNotCalledOnError) {
// require an accessible copy constructor when binding a temporary to // require an accessible copy constructor when binding a temporary to
// a const reference. // a const reference.
#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 7 #if __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
TEST(TempFormatterTest, ArgLifetime) { TEST(FormatterTest, ArgLifetime) {
// The following code is for testing purposes only. It is a definite abuse // The following code is for testing purposes only. It is a definite abuse
// of the API and shouldn't be used in real applications. // of the API and shouldn't be used in real applications.
const fmt::Formatter<> &af = fmt::Format("{0}"); const fmt::Formatter<> &af = fmt::Format("{0}");
const_cast<fmt::Formatter<>&>(af) << std::string("test"); const_cast<fmt::Formatter<>&>(af) << std::string("test");
// String object passed as an argument to TempFormatter has // String object passed as an argument to Formatter has been destroyed,
// been destroyed, but ArgInserter dtor hasn't been called yet. // but Formatter's dtor hasn't been called yet. That's OK since the Arg's
// But that's OK since the Arg's dtor takes care of this and // dtor takes care of this and calls Format.
// calls Format.
} }
#endif #endif
TEST(TempFormatterTest, ConvertToStringRef) { TEST(FormatterTest, ConvertToStringRef) {
EXPECT_STREQ("abc", StringRef(Format("a{0}c") << 'b').c_str()); EXPECT_STREQ("abc", StringRef(Format("a{0}c") << 'b').c_str());
EXPECT_EQ(3u, StringRef(Format("a{0}c") << 'b').size()); EXPECT_EQ(3u, StringRef(Format("a{0}c") << 'b').size());
} }
@ -1153,7 +1154,7 @@ fmt::Formatter<PrintError> ReportError(const char *format) {
return fmt::Formatter<PrintError>(format); return fmt::Formatter<PrintError>(format);
} }
TEST(TempFormatterTest, Examples) { TEST(FormatterTest, Examples) {
EXPECT_EQ("First, thou shalt count to three", EXPECT_EQ("First, thou shalt count to three",
str(Format("First, thou shalt count to {0}") << "three")); str(Format("First, thou shalt count to {0}") << "three"));
EXPECT_EQ("Bring me a shrubbery", EXPECT_EQ("Bring me a shrubbery",