Commit b5eb6ed9 by zhanyong.wan

Makes gtest print string literals correctly when it contains \x escape…

Makes gtest print string literals correctly when it contains \x escape sequences. Contributed by Yair Chuchem.
parent 42bf979c
...@@ -1462,6 +1462,9 @@ inline bool IsSpace(char ch) { ...@@ -1462,6 +1462,9 @@ inline bool IsSpace(char ch) {
inline bool IsUpper(char ch) { inline bool IsUpper(char ch) {
return isupper(static_cast<unsigned char>(ch)) != 0; return isupper(static_cast<unsigned char>(ch)) != 0;
} }
inline bool IsXDigit(char ch) {
return isxdigit(static_cast<unsigned char>(ch)) != 0;
}
inline char ToLower(char ch) { inline char ToLower(char ch) {
return static_cast<char>(tolower(static_cast<unsigned char>(ch))); return static_cast<char>(tolower(static_cast<unsigned char>(ch)));
......
...@@ -194,25 +194,25 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { ...@@ -194,25 +194,25 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
return kSpecialEscape; return kSpecialEscape;
} }
// Prints a char as if it's part of a string literal, escaping it when // Prints a char c as if it's part of a string literal, escaping it when
// necessary. // necessary; returns how c was formatted.
static void PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) {
switch (c) { switch (c) {
case L'\'': case L'\'':
*os << "'"; *os << "'";
break; return kAsIs;
case L'"': case L'"':
*os << "\\\""; *os << "\\\"";
break; return kSpecialEscape;
default: default:
PrintAsCharLiteralTo<wchar_t>(c, os); return PrintAsCharLiteralTo<wchar_t>(c, os);
} }
} }
// Prints a char as if it's part of a string literal, escaping it when // Prints a char c as if it's part of a string literal, escaping it when
// necessary. // necessary; returns how c was formatted.
static void PrintAsNarrowStringLiteralTo(char c, ostream* os) { static CharFormat PrintAsNarrowStringLiteralTo(char c, ostream* os) {
PrintAsWideStringLiteralTo(static_cast<unsigned char>(c), os); return PrintAsWideStringLiteralTo(static_cast<unsigned char>(c), os);
} }
// Prints a wide or narrow character c and its code. '\0' is printed // Prints a wide or narrow character c and its code. '\0' is printed
...@@ -263,8 +263,16 @@ void PrintTo(wchar_t wc, ostream* os) { ...@@ -263,8 +263,16 @@ void PrintTo(wchar_t wc, ostream* os) {
// and may not be null-terminated. // and may not be null-terminated.
static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) {
*os << "\""; *os << "\"";
bool is_previous_hex = false;
for (size_t index = 0; index < len; ++index) { for (size_t index = 0; index < len; ++index) {
PrintAsNarrowStringLiteralTo(begin[index], os); const char cur = begin[index];
if (is_previous_hex && IsXDigit(cur)) {
// Previous character is of '\x..' form and this character can be
// interpreted as another hexadecimal digit in its number. Break string to
// disambiguate.
*os << "\" \"";
}
is_previous_hex = PrintAsNarrowStringLiteralTo(cur, os) == kHexEscape;
} }
*os << "\""; *os << "\"";
} }
...@@ -280,8 +288,17 @@ void UniversalPrintArray(const char* begin, size_t len, ostream* os) { ...@@ -280,8 +288,17 @@ void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len,
ostream* os) { ostream* os) {
*os << "L\""; *os << "L\"";
bool is_previous_hex = false;
for (size_t index = 0; index < len; ++index) { for (size_t index = 0; index < len; ++index) {
PrintAsWideStringLiteralTo(begin[index], os); const wchar_t cur = begin[index];
if (is_previous_hex && 0 <= cur && cur < 128 &&
IsXDigit(static_cast<char>(cur))) {
// Previous character is of '\x..' form and this character can be
// interpreted as another hexadecimal digit in its number. Break string to
// disambiguate.
*os << "\" L\"";
}
is_previous_hex = PrintAsWideStringLiteralTo(cur, os) == kHexEscape;
} }
*os << "\""; *os << "\"";
} }
......
...@@ -658,6 +658,20 @@ TEST(PrintStringTest, StringInStdNamespace) { ...@@ -658,6 +658,20 @@ TEST(PrintStringTest, StringInStdNamespace) {
Print(str)); Print(str));
} }
TEST(PrintStringTest, StringAmbiguousHex) {
// "\x6BANANA" is ambiguous, it can be interpreted as starting with either of:
// '\x6', '\x6B', or '\x6BA'.
// a hex escaping sequence following by a decimal digit
EXPECT_EQ("\"0\\x12\" \"3\"", Print(::std::string("0\x12" "3")));
// a hex escaping sequence following by a hex digit (lower-case)
EXPECT_EQ("\"mm\\x6\" \"bananas\"", Print(::std::string("mm\x6" "bananas")));
// a hex escaping sequence following by a hex digit (upper-case)
EXPECT_EQ("\"NOM\\x6\" \"BANANA\"", Print(::std::string("NOM\x6" "BANANA")));
// a hex escaping sequence following by a non-xdigit
EXPECT_EQ("\"!\\x5-!\"", Print(::std::string("!\x5-!")));
}
// Tests printing ::wstring and ::std::wstring. // Tests printing ::wstring and ::std::wstring.
#if GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_GLOBAL_WSTRING
...@@ -680,6 +694,16 @@ TEST(PrintWideStringTest, StringInStdNamespace) { ...@@ -680,6 +694,16 @@ TEST(PrintWideStringTest, StringInStdNamespace) {
"\\xD3\\x576\\x8D3\\xC74D a\\0\"", "\\xD3\\x576\\x8D3\\xC74D a\\0\"",
Print(str)); Print(str));
} }
TEST(PrintWideStringTest, StringAmbiguousHex) {
// same for wide strings.
EXPECT_EQ("L\"0\\x12\" L\"3\"", Print(::std::wstring(L"0\x12" L"3")));
EXPECT_EQ("L\"mm\\x6\" L\"bananas\"",
Print(::std::wstring(L"mm\x6" L"bananas")));
EXPECT_EQ("L\"NOM\\x6\" L\"BANANA\"",
Print(::std::wstring(L"NOM\x6" L"BANANA")));
EXPECT_EQ("L\"!\\x5-!\"", Print(::std::wstring(L"!\x5-!")));
}
#endif // GTEST_HAS_STD_WSTRING #endif // GTEST_HAS_STD_WSTRING
// Tests printing types that support generic streaming (i.e. streaming // Tests printing types that support generic streaming (i.e. streaming
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment