From b5eb6ed9e27b7bf80a406e4a38ffe42db43889cc Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 2 Dec 2010 23:28:38 +0000 Subject: Makes gtest print string literals correctly when it contains \x escape sequences. Contributed by Yair Chuchem. --- include/gtest/internal/gtest-port.h | 3 +++ src/gtest-printers.cc | 41 ++++++++++++++++++++++++++----------- test/gtest-printers_test.cc | 24 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index f08f6df..900a41d 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -1462,6 +1462,9 @@ inline bool IsSpace(char ch) { inline bool IsUpper(char ch) { return isupper(static_cast(ch)) != 0; } +inline bool IsXDigit(char ch) { + return isxdigit(static_cast(ch)) != 0; +} inline char ToLower(char ch) { return static_cast(tolower(static_cast(ch))); diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index 147f8b2..c85d582 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -194,25 +194,25 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { return kSpecialEscape; } -// Prints a char as if it's part of a string literal, escaping it when -// necessary. -static void PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { switch (c) { case L'\'': *os << "'"; - break; + return kAsIs; case L'"': *os << "\\\""; - break; + return kSpecialEscape; default: - PrintAsCharLiteralTo(c, os); + return PrintAsCharLiteralTo(c, os); } } -// Prints a char as if it's part of a string literal, escaping it when -// necessary. -static void PrintAsNarrowStringLiteralTo(char c, ostream* os) { - PrintAsWideStringLiteralTo(static_cast(c), os); +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsNarrowStringLiteralTo(char c, ostream* os) { + return PrintAsWideStringLiteralTo(static_cast(c), os); } // Prints a wide or narrow character c and its code. '\0' is printed @@ -263,8 +263,16 @@ void PrintTo(wchar_t wc, ostream* os) { // and may not be null-terminated. static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { *os << "\""; + bool is_previous_hex = false; 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 << "\""; } @@ -280,8 +288,17 @@ void UniversalPrintArray(const char* begin, size_t len, ostream* os) { static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, ostream* os) { *os << "L\""; + bool is_previous_hex = false; 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(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 << "\""; } diff --git a/test/gtest-printers_test.cc b/test/gtest-printers_test.cc index 5eabd23..da1fbc2 100644 --- a/test/gtest-printers_test.cc +++ b/test/gtest-printers_test.cc @@ -658,6 +658,20 @@ TEST(PrintStringTest, StringInStdNamespace) { 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. #if GTEST_HAS_GLOBAL_WSTRING @@ -680,6 +694,16 @@ TEST(PrintWideStringTest, StringInStdNamespace) { "\\xD3\\x576\\x8D3\\xC74D a\\0\"", 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 // Tests printing types that support generic streaming (i.e. streaming -- cgit v0.12