Googletest export

Print std::u8string, std::u16string, and std::u32string as string literals

Previously, these types were printed as "{ U+123, U+456, U+789 }". However,
printed output in that form is difficult to compare against any literals that
might be defined in code. Instead, just treat these types like std::string
and std::wstring, escaping non-ASCII characters with a hexadecimal escape
sequence.

The tests have also been updated to cover the new functionality: as a bonus,
the tests now also pass with the MSVC toolchain.

Internally, the code has been reorganized to primarily operate in terms of
char32_t, under the assumption that char32_t will always be at least as big
as wchar_t. While that assumption is currently true, perhaps it won't be in
the future...

PiperOrigin-RevId: 364033132
This commit is contained in:
Abseil Team 2021-03-20 01:24:27 -04:00 committed by Derek Mauro
parent 3ff1e8b98a
commit 1a8ecf1813
7 changed files with 396 additions and 183 deletions

View File

@ -43,6 +43,14 @@ config_setting(
constraint_values = ["@platforms//os:windows"], constraint_values = ["@platforms//os:windows"],
) )
config_setting(
name = "msvc_compiler",
flag_values = {
"@bazel_tools//tools/cpp:compiler": "msvc-cl",
},
visibility = [":__subpackages__"],
)
config_setting( config_setting(
name = "has_absl", name = "has_absl",
values = {"define": "absl=1"}, values = {"define": "absl=1"},

View File

@ -81,6 +81,8 @@ macro(config_compiler_and_linker)
# Suppress "unreachable code" warning # Suppress "unreachable code" warning
# http://stackoverflow.com/questions/3232669 explains the issue. # http://stackoverflow.com/questions/3232669 explains the issue.
set(cxx_base_flags "${cxx_base_flags} -wd4702") set(cxx_base_flags "${cxx_base_flags} -wd4702")
# Ensure MSVC treats source files as UTF-8 encoded.
set(cxx_base_flags "${cxx_base_flags} -utf-8")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(cxx_base_flags "-Wall -Wshadow -Werror -Wconversion") set(cxx_base_flags "-Wall -Wshadow -Werror -Wconversion")
set(cxx_exception_flags "-fexceptions") set(cxx_exception_flags "-fexceptions")

View File

@ -505,24 +505,21 @@ inline void PrintTo(unsigned char* s, ::std::ostream* os) {
PrintTo(ImplicitCast_<const void*>(s), os); PrintTo(ImplicitCast_<const void*>(s), os);
} }
#ifdef __cpp_char8_t #ifdef __cpp_char8_t
inline void PrintTo(const char8_t* s, ::std::ostream* os) { // Overloads for u8 strings.
PrintTo(ImplicitCast_<const void*>(s), os); void PrintTo(const char8_t* s, ::std::ostream* os);
}
inline void PrintTo(char8_t* s, ::std::ostream* os) { inline void PrintTo(char8_t* s, ::std::ostream* os) {
PrintTo(ImplicitCast_<const void*>(s), os); PrintTo(ImplicitCast_<const char8_t*>(s), os);
} }
#endif #endif
inline void PrintTo(const char16_t* s, ::std::ostream* os) { // Overloads for u16 strings.
PrintTo(ImplicitCast_<const void*>(s), os); void PrintTo(const char16_t* s, ::std::ostream* os);
}
inline void PrintTo(char16_t* s, ::std::ostream* os) { inline void PrintTo(char16_t* s, ::std::ostream* os) {
PrintTo(ImplicitCast_<const void*>(s), os); PrintTo(ImplicitCast_<const char16_t*>(s), os);
}
inline void PrintTo(const char32_t* s, ::std::ostream* os) {
PrintTo(ImplicitCast_<const void*>(s), os);
} }
// Overloads for u32 strings.
void PrintTo(const char32_t* s, ::std::ostream* os);
inline void PrintTo(char32_t* s, ::std::ostream* os) { inline void PrintTo(char32_t* s, ::std::ostream* os) {
PrintTo(ImplicitCast_<const void*>(s), os); PrintTo(ImplicitCast_<const char32_t*>(s), os);
} }
// MSVC can be configured to define wchar_t as a typedef of unsigned // MSVC can be configured to define wchar_t as a typedef of unsigned
@ -558,6 +555,26 @@ inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
PrintStringTo(s, os); PrintStringTo(s, os);
} }
// Overloads for ::std::u8string
#ifdef __cpp_char8_t
GTEST_API_ void PrintU8StringTo(const ::std::u8string& s, ::std::ostream* os);
inline void PrintTo(const ::std::u8string& s, ::std::ostream* os) {
PrintU8StringTo(s, os);
}
#endif
// Overloads for ::std::u16string
GTEST_API_ void PrintU16StringTo(const ::std::u16string& s, ::std::ostream* os);
inline void PrintTo(const ::std::u16string& s, ::std::ostream* os) {
PrintU16StringTo(s, os);
}
// Overloads for ::std::u32string
GTEST_API_ void PrintU32StringTo(const ::std::u32string& s, ::std::ostream* os);
inline void PrintTo(const ::std::u32string& s, ::std::ostream* os) {
PrintU32StringTo(s, os);
}
// Overloads for ::std::wstring. // Overloads for ::std::wstring.
#if GTEST_HAS_STD_WSTRING #if GTEST_HAS_STD_WSTRING
GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
@ -805,6 +822,20 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
GTEST_API_ void UniversalPrintArray( GTEST_API_ void UniversalPrintArray(
const char* begin, size_t len, ::std::ostream* os); const char* begin, size_t len, ::std::ostream* os);
#ifdef __cpp_char8_t
// This overload prints a (const) char8_t array compactly.
GTEST_API_ void UniversalPrintArray(const char8_t* begin, size_t len,
::std::ostream* os);
#endif
// This overload prints a (const) char16_t array compactly.
GTEST_API_ void UniversalPrintArray(const char16_t* begin, size_t len,
::std::ostream* os);
// This overload prints a (const) char32_t array compactly.
GTEST_API_ void UniversalPrintArray(const char32_t* begin, size_t len,
::std::ostream* os);
// This overload prints a (const) wchar_t array compactly. // This overload prints a (const) wchar_t array compactly.
GTEST_API_ void UniversalPrintArray( GTEST_API_ void UniversalPrintArray(
const wchar_t* begin, size_t len, ::std::ostream* os); const wchar_t* begin, size_t len, ::std::ostream* os);
@ -877,12 +908,55 @@ class UniversalTersePrinter<const char*> {
} }
}; };
template <> template <>
class UniversalTersePrinter<char*> { class UniversalTersePrinter<char*> : public UniversalTersePrinter<const char*> {
};
#ifdef __cpp_char8_t
template <>
class UniversalTersePrinter<const char8_t*> {
public: public:
static void Print(char* str, ::std::ostream* os) { static void Print(const char8_t* str, ::std::ostream* os) {
UniversalTersePrinter<const char*>::Print(str, os); if (str == nullptr) {
*os << "NULL";
} else {
UniversalPrint(::std::u8string(str), os);
}
} }
}; };
template <>
class UniversalTersePrinter<char8_t*>
: public UniversalTersePrinter<const char8_t*> {};
#endif
template <>
class UniversalTersePrinter<const char16_t*> {
public:
static void Print(const char16_t* str, ::std::ostream* os) {
if (str == nullptr) {
*os << "NULL";
} else {
UniversalPrint(::std::u16string(str), os);
}
}
};
template <>
class UniversalTersePrinter<char16_t*>
: public UniversalTersePrinter<const char16_t*> {};
template <>
class UniversalTersePrinter<const char32_t*> {
public:
static void Print(const char32_t* str, ::std::ostream* os) {
if (str == nullptr) {
*os << "NULL";
} else {
UniversalPrint(::std::u32string(str), os);
}
}
};
template <>
class UniversalTersePrinter<char32_t*>
: public UniversalTersePrinter<const char32_t*> {};
#if GTEST_HAS_STD_WSTRING #if GTEST_HAS_STD_WSTRING
template <> template <>

View File

@ -1936,6 +1936,19 @@ inline bool IsUpper(char ch) {
inline bool IsXDigit(char ch) { inline bool IsXDigit(char ch) {
return isxdigit(static_cast<unsigned char>(ch)) != 0; return isxdigit(static_cast<unsigned char>(ch)) != 0;
} }
#ifdef __cpp_char8_t
inline bool IsXDigit(char8_t ch) {
return isxdigit(static_cast<unsigned char>(ch)) != 0;
}
#endif
inline bool IsXDigit(char16_t ch) {
const unsigned char low_byte = static_cast<unsigned char>(ch);
return ch == low_byte && isxdigit(low_byte) != 0;
}
inline bool IsXDigit(char32_t ch) {
const unsigned char low_byte = static_cast<unsigned char>(ch);
return ch == low_byte && isxdigit(low_byte) != 0;
}
inline bool IsXDigit(wchar_t ch) { inline bool IsXDigit(wchar_t ch) {
const unsigned char low_byte = static_cast<unsigned char>(ch); const unsigned char low_byte = static_cast<unsigned char>(ch);
return ch == low_byte && isxdigit(low_byte) != 0; return ch == low_byte && isxdigit(low_byte) != 0;

View File

@ -42,12 +42,16 @@
// defines Foo. // defines Foo.
#include "gtest/gtest-printers.h" #include "gtest/gtest-printers.h"
#include <stdio.h> #include <stdio.h>
#include <cctype> #include <cctype>
#include <cstdint> #include <cstdint>
#include <cwchar> #include <cwchar>
#include <ostream> // NOLINT #include <ostream> // NOLINT
#include <string> #include <string>
#include <type_traits>
#include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-port.h"
#include "src/gtest-internal-inl.h" #include "src/gtest-internal-inl.h"
@ -103,6 +107,16 @@ void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
*os << ">"; *os << ">";
} }
// Helpers for widening a character to char32_t. Since the standard does not
// specify if char / wchar_t is signed or unsigned, it is important to first
// convert it to the unsigned type of the same width before widening it to
// char32_t.
template <typename CharType>
char32_t ToChar32(CharType in) {
return static_cast<char32_t>(
static_cast<typename std::make_unsigned<CharType>::type>(in));
}
} // namespace } // namespace
namespace internal { namespace internal {
@ -131,18 +145,15 @@ enum CharFormat {
// Returns true if c is a printable ASCII character. We test the // Returns true if c is a printable ASCII character. We test the
// value of c directly instead of calling isprint(), which is buggy on // value of c directly instead of calling isprint(), which is buggy on
// Windows Mobile. // Windows Mobile.
inline bool IsPrintableAscii(wchar_t c) { inline bool IsPrintableAscii(char32_t c) { return 0x20 <= c && c <= 0x7E; }
return 0x20 <= c && c <= 0x7E;
}
// Prints a wide or narrow char c as a character literal without the // Prints c (of type char, char8_t, char16_t, char32_t, or wchar_t) as a
// quotes, escaping it when necessary; returns how c was formatted. // character literal without the quotes, escaping it when necessary; returns how
// The template argument UnsignedChar is the unsigned version of Char, // c was formatted.
// which is the type of c. template <typename Char>
template <typename UnsignedChar, typename Char>
static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
wchar_t w_c = static_cast<wchar_t>(c); const char32_t u_c = ToChar32(c);
switch (w_c) { switch (u_c) {
case L'\0': case L'\0':
*os << "\\0"; *os << "\\0";
break; break;
@ -174,13 +185,12 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
*os << "\\v"; *os << "\\v";
break; break;
default: default:
if (IsPrintableAscii(w_c)) { if (IsPrintableAscii(u_c)) {
*os << static_cast<char>(c); *os << static_cast<char>(c);
return kAsIs; return kAsIs;
} else { } else {
ostream::fmtflags flags = os->flags(); ostream::fmtflags flags = os->flags();
*os << "\\x" << std::hex << std::uppercase *os << "\\x" << std::hex << std::uppercase << static_cast<int>(u_c);
<< static_cast<int>(static_cast<UnsignedChar>(c));
os->flags(flags); os->flags(flags);
return kHexEscape; return kHexEscape;
} }
@ -188,9 +198,9 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
return kSpecialEscape; return kSpecialEscape;
} }
// Prints a wchar_t c as if it's part of a string literal, escaping it when // Prints a char32_t c as if it's part of a string literal, escaping it when
// necessary; returns how c was formatted. // necessary; returns how c was formatted.
static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { static CharFormat PrintAsStringLiteralTo(char32_t c, ostream* os) {
switch (c) { switch (c) {
case L'\'': case L'\'':
*os << "'"; *os << "'";
@ -199,26 +209,68 @@ static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
*os << "\\\""; *os << "\\\"";
return kSpecialEscape; return kSpecialEscape;
default: default:
return PrintAsCharLiteralTo<wchar_t>(c, os); return PrintAsCharLiteralTo(c, os);
} }
} }
static const char* GetCharWidthPrefix(char) {
return "";
}
static const char* GetCharWidthPrefix(signed char) {
return "";
}
static const char* GetCharWidthPrefix(unsigned char) {
return "";
}
#ifdef __cpp_char8_t
static const char* GetCharWidthPrefix(char8_t) {
return "u8";
}
#endif
static const char* GetCharWidthPrefix(char16_t) {
return "u";
}
static const char* GetCharWidthPrefix(char32_t) {
return "U";
}
static const char* GetCharWidthPrefix(wchar_t) {
return "L";
}
// Prints a char c 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; returns how c was formatted. // necessary; returns how c was formatted.
static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
return PrintAsStringLiteralTo( return PrintAsStringLiteralTo(ToChar32(c), os);
static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
} }
// Prints a wide or narrow character c and its code. '\0' is printed #ifdef __cpp_char8_t
// as "'\\0'", other unprintable characters are also properly escaped static CharFormat PrintAsStringLiteralTo(char8_t c, ostream* os) {
// using the standard C++ escape sequence. The template argument return PrintAsStringLiteralTo(ToChar32(c), os);
// UnsignedChar is the unsigned version of Char, which is the type of c. }
template <typename UnsignedChar, typename Char> #endif
static CharFormat PrintAsStringLiteralTo(char16_t c, ostream* os) {
return PrintAsStringLiteralTo(ToChar32(c), os);
}
static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
return PrintAsStringLiteralTo(ToChar32(c), os);
}
// Prints a character c (of type char, char8_t, char16_t, char32_t, or wchar_t)
// and its code. '\0' is printed as "'\\0'", other unprintable characters are
// also properly escaped using the standard C++ escape sequence.
template <typename Char>
void PrintCharAndCodeTo(Char c, ostream* os) { void PrintCharAndCodeTo(Char c, ostream* os) {
// First, print c as a literal in the most readable form we can find. // First, print c as a literal in the most readable form we can find.
*os << ((sizeof(c) > 1) ? "L'" : "'"); *os << GetCharWidthPrefix(c) << "'";
const CharFormat format = PrintAsCharLiteralTo<UnsignedChar>(c, os); const CharFormat format = PrintAsCharLiteralTo(c, os);
*os << "'"; *os << "'";
// To aid user debugging, we also print c's code in decimal, unless // To aid user debugging, we also print c's code in decimal, unless
@ -239,26 +291,21 @@ void PrintCharAndCodeTo(Char c, ostream* os) {
*os << ")"; *os << ")";
} }
void PrintTo(unsigned char c, ::std::ostream* os) { void PrintTo(unsigned char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); }
PrintCharAndCodeTo<unsigned char>(c, os); void PrintTo(signed char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); }
}
void PrintTo(signed char c, ::std::ostream* os) {
PrintCharAndCodeTo<unsigned char>(c, os);
}
// Prints a wchar_t as a symbol if it is printable or as its internal // Prints a wchar_t as a symbol if it is printable or as its internal
// code otherwise and also as its code. L'\0' is printed as "L'\\0'". // code otherwise and also as its code. L'\0' is printed as "L'\\0'".
void PrintTo(wchar_t wc, ostream* os) { void PrintTo(wchar_t wc, ostream* os) { PrintCharAndCodeTo(wc, os); }
PrintCharAndCodeTo<wchar_t>(wc, os);
}
// TODO(dcheng): Consider making this delegate to PrintCharAndCodeTo() as well.
void PrintTo(char32_t c, ::std::ostream* os) { void PrintTo(char32_t c, ::std::ostream* os) {
*os << std::hex << "U+" << std::uppercase << std::setfill('0') << std::setw(4) *os << std::hex << "U+" << std::uppercase << std::setfill('0') << std::setw(4)
<< static_cast<uint32_t>(c); << static_cast<uint32_t>(c);
} }
// Prints the given array of characters to the ostream. CharType must be either // Prints the given array of characters to the ostream. CharType must be either
// char or wchar_t. // char, char8_t, char16_t, char32_t, or wchar_t.
// The array starts at begin, the length is len, it may include '\0' characters // The array starts at begin, the length is len, it may include '\0' characters
// and may not be NUL-terminated. // and may not be NUL-terminated.
template <typename CharType> template <typename CharType>
@ -268,8 +315,8 @@ GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
static CharFormat PrintCharsAsStringTo( static CharFormat PrintCharsAsStringTo(
const CharType* begin, size_t len, ostream* os) { const CharType* begin, size_t len, ostream* os) {
const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; const char* const quote_prefix = GetCharWidthPrefix(*begin);
*os << kQuoteBegin; *os << quote_prefix << "\"";
bool is_previous_hex = false; bool is_previous_hex = false;
CharFormat print_format = kAsIs; CharFormat print_format = kAsIs;
for (size_t index = 0; index < len; ++index) { for (size_t index = 0; index < len; ++index) {
@ -278,7 +325,7 @@ static CharFormat PrintCharsAsStringTo(
// Previous character is of '\x..' form and this character can be // Previous character is of '\x..' form and this character can be
// interpreted as another hexadecimal digit in its number. Break string to // interpreted as another hexadecimal digit in its number. Break string to
// disambiguate. // disambiguate.
*os << "\" " << kQuoteBegin; *os << "\" " << quote_prefix << "\"";
} }
is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
// Remember if any characters required hex escaping. // Remember if any characters required hex escaping.
@ -324,22 +371,57 @@ void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
UniversalPrintCharArray(begin, len, os); UniversalPrintCharArray(begin, len, os);
} }
#ifdef __cpp_char8_t
// Prints a (const) char8_t array of 'len' elements, starting at address
// 'begin'.
void UniversalPrintArray(const char8_t* begin, size_t len, ostream* os) {
UniversalPrintCharArray(begin, len, os);
}
#endif
// Prints a (const) char16_t array of 'len' elements, starting at address
// 'begin'.
void UniversalPrintArray(const char16_t* begin, size_t len, ostream* os) {
UniversalPrintCharArray(begin, len, os);
}
// Prints a (const) char32_t array of 'len' elements, starting at address
// 'begin'.
void UniversalPrintArray(const char32_t* begin, size_t len, ostream* os) {
UniversalPrintCharArray(begin, len, os);
}
// Prints a (const) wchar_t array of 'len' elements, starting at address // Prints a (const) wchar_t array of 'len' elements, starting at address
// 'begin'. // 'begin'.
void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
UniversalPrintCharArray(begin, len, os); UniversalPrintCharArray(begin, len, os);
} }
// Prints the given C string to the ostream. namespace {
void PrintTo(const char* s, ostream* os) {
// Prints a null-terminated C-style string to the ostream.
template <typename Char>
void PrintCStringTo(const Char* s, ostream* os) {
if (s == nullptr) { if (s == nullptr) {
*os << "NULL"; *os << "NULL";
} else { } else {
*os << ImplicitCast_<const void*>(s) << " pointing to "; *os << ImplicitCast_<const void*>(s) << " pointing to ";
PrintCharsAsStringTo(s, strlen(s), os); PrintCharsAsStringTo(s, std::char_traits<Char>::length(s), os);
} }
} }
} // anonymous namespace
void PrintTo(const char* s, ostream* os) { PrintCStringTo(s, os); }
#ifdef __cpp_char8_t
void PrintTo(const char8_t* s, ostream* os) { PrintCStringTo(s, os); }
#endif
void PrintTo(const char16_t* s, ostream* os) { PrintCStringTo(s, os); }
void PrintTo(const char32_t* s, ostream* os) { PrintCStringTo(s, os); }
// MSVC compiler can be configured to define whar_t as a typedef // MSVC compiler can be configured to define whar_t as a typedef
// of unsigned short. Defining an overload for const wchar_t* in that case // of unsigned short. Defining an overload for const wchar_t* in that case
// would cause pointers to unsigned shorts be printed as wide strings, // would cause pointers to unsigned shorts be printed as wide strings,
@ -348,14 +430,7 @@ void PrintTo(const char* s, ostream* os) {
// wchar_t is implemented as a native type. // wchar_t is implemented as a native type.
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
// Prints the given wide C string to the ostream. // Prints the given wide C string to the ostream.
void PrintTo(const wchar_t* s, ostream* os) { void PrintTo(const wchar_t* s, ostream* os) { PrintCStringTo(s, os); }
if (s == nullptr) {
*os << "NULL";
} else {
*os << ImplicitCast_<const void*>(s) << " pointing to ";
PrintCharsAsStringTo(s, wcslen(s), os);
}
}
#endif // wchar_t is native #endif // wchar_t is native
namespace { namespace {
@ -433,6 +508,20 @@ void PrintStringTo(const ::std::string& s, ostream* os) {
} }
} }
#ifdef __cpp_char8_t
void PrintU8StringTo(const ::std::u8string& s, ostream* os) {
PrintCharsAsStringTo(s.data(), s.size(), os);
}
#endif
void PrintU16StringTo(const ::std::u16string& s, ostream* os) {
PrintCharsAsStringTo(s.data(), s.size(), os);
}
void PrintU32StringTo(const ::std::u32string& s, ostream* os) {
PrintCharsAsStringTo(s.data(), s.size(), os);
}
#if GTEST_HAS_STD_WSTRING #if GTEST_HAS_STD_WSTRING
void PrintWideStringTo(const ::std::wstring& s, ostream* os) { void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
PrintCharsAsStringTo(s.data(), s.size(), os); PrintCharsAsStringTo(s.data(), s.size(), os);

View File

@ -83,6 +83,10 @@ cc_test(
copts = select({ copts = select({
"//:windows": ["-DGTEST_USE_OWN_TR1_TUPLE=0"], "//:windows": ["-DGTEST_USE_OWN_TR1_TUPLE=0"],
"//conditions:default": ["-DGTEST_USE_OWN_TR1_TUPLE=1"], "//conditions:default": ["-DGTEST_USE_OWN_TR1_TUPLE=1"],
}) + select({
# Ensure MSVC treats source files as UTF-8 encoded.
"//:msvc_compiler": ["-utf-8"],
"//conditions:default": [],
}), }),
includes = [ includes = [
"googletest", "googletest",

View File

@ -493,6 +493,92 @@ TEST(PrintCStringTest, EscapesProperly) {
Print(p)); Print(p));
} }
#ifdef __cpp_char8_t
// const char8_t*.
TEST(PrintU8StringTest, Const) {
const char8_t* p = u8"";
EXPECT_EQ(PrintPointer(p) + " pointing to u8\"\\xE7\\x95\\x8C\"", Print(p));
}
// char8_t*.
TEST(PrintU8StringTest, NonConst) {
char8_t p[] = u8"";
EXPECT_EQ(PrintPointer(p) + " pointing to u8\"\\xE4\\xB8\\x96\"",
Print(static_cast<char8_t*>(p)));
}
// NULL u8 string.
TEST(PrintU8StringTest, Null) {
const char8_t* p = nullptr;
EXPECT_EQ("NULL", Print(p));
}
// Tests that u8 strings are escaped properly.
TEST(PrintU8StringTest, EscapesProperly) {
const char8_t* p = u8"'\"?\\\a\b\f\n\r\t\v\x7F\xFF hello 世界";
EXPECT_EQ(PrintPointer(p) +
" pointing to u8\"'\\\"?\\\\\\a\\b\\f\\n\\r\\t\\v\\x7F\\xFF "
"hello \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"",
Print(p));
}
#endif
// const char16_t*.
TEST(PrintU16StringTest, Const) {
const char16_t* p = u"";
EXPECT_EQ(PrintPointer(p) + " pointing to u\"\\x754C\"", Print(p));
}
// char16_t*.
TEST(PrintU16StringTest, NonConst) {
char16_t p[] = u"";
EXPECT_EQ(PrintPointer(p) + " pointing to u\"\\x4E16\"",
Print(static_cast<char16_t*>(p)));
}
// NULL u16 string.
TEST(PrintU16StringTest, Null) {
const char16_t* p = nullptr;
EXPECT_EQ("NULL", Print(p));
}
// Tests that u16 strings are escaped properly.
TEST(PrintU16StringTest, EscapesProperly) {
const char16_t* p = u"'\"?\\\a\b\f\n\r\t\v\x7F\xFF hello 世界";
EXPECT_EQ(PrintPointer(p) +
" pointing to u\"'\\\"?\\\\\\a\\b\\f\\n\\r\\t\\v\\x7F\\xFF "
"hello \\x4E16\\x754C\"",
Print(p));
}
// const char32_t*.
TEST(PrintU32StringTest, Const) {
const char32_t* p = U"🗺️";
EXPECT_EQ(PrintPointer(p) + " pointing to U\"\\x1F5FA\\xFE0F\"", Print(p));
}
// char32_t*.
TEST(PrintU32StringTest, NonConst) {
char32_t p[] = U"🌌";
EXPECT_EQ(PrintPointer(p) + " pointing to U\"\\x1F30C\"",
Print(static_cast<char32_t*>(p)));
}
// NULL u32 string.
TEST(PrintU32StringTest, Null) {
const char32_t* p = nullptr;
EXPECT_EQ("NULL", Print(p));
}
// Tests that u32 strings are escaped properly.
TEST(PrintU32StringTest, EscapesProperly) {
const char32_t* p = U"'\"?\\\a\b\f\n\r\t\v\x7F\xFF hello 🗺️";
EXPECT_EQ(PrintPointer(p) +
" pointing to U\"'\\\"?\\\\\\a\\b\\f\\n\\r\\t\\v\\x7F\\xFF "
"hello \\x1F5FA\\xFE0F\"",
Print(p));
}
// MSVC compiler can be configured to define whar_t as a typedef // MSVC compiler can be configured to define whar_t as a typedef
// of unsigned short. Defining an overload for const wchar_t* in that case // of unsigned short. Defining an overload for const wchar_t* in that case
// would cause pointers to unsigned shorts be printed as wide strings, // would cause pointers to unsigned shorts be printed as wide strings,
@ -564,56 +650,6 @@ TEST(PrintCharPointerTest, ConstUnsignedChar) {
EXPECT_EQ("NULL", Print(p)); EXPECT_EQ("NULL", Print(p));
} }
#ifdef __cpp_char8_t
// char8_t*
TEST(PrintCharPointerTest, Char8) {
char8_t* p = reinterpret_cast<char8_t*>(0x1234);
EXPECT_EQ(PrintPointer(p), Print(p));
p = nullptr;
EXPECT_EQ("NULL", Print(p));
}
// const char8_t*
TEST(PrintCharPointerTest, ConstChar8) {
const char8_t* p = reinterpret_cast<const char8_t*>(0x1234);
EXPECT_EQ(PrintPointer(p), Print(p));
p = nullptr;
EXPECT_EQ("NULL", Print(p));
}
#endif
// char16_t*
TEST(PrintCharPointerTest, Char16) {
char16_t* p = reinterpret_cast<char16_t*>(0x1234);
EXPECT_EQ(PrintPointer(p), Print(p));
p = nullptr;
EXPECT_EQ("NULL", Print(p));
}
// const char16_t*
TEST(PrintCharPointerTest, ConstChar16) {
const char16_t* p = reinterpret_cast<const char16_t*>(0x1234);
EXPECT_EQ(PrintPointer(p), Print(p));
p = nullptr;
EXPECT_EQ("NULL", Print(p));
}
// char32_t*
TEST(PrintCharPointerTest, Char32) {
char32_t* p = reinterpret_cast<char32_t*>(0x1234);
EXPECT_EQ(PrintPointer(p), Print(p));
p = nullptr;
EXPECT_EQ("NULL", Print(p));
}
// const char32_t*
TEST(PrintCharPointerTest, ConstChar32) {
const char32_t* p = reinterpret_cast<const char32_t*>(0x1234);
EXPECT_EQ(PrintPointer(p), Print(p));
p = nullptr;
EXPECT_EQ("NULL", Print(p));
}
// Tests printing pointers to simple, built-in types. // Tests printing pointers to simple, built-in types.
// bool*. // bool*.
@ -753,13 +789,58 @@ TEST(PrintArrayTest, CharArrayWithNoTerminatingNul) {
EXPECT_EQ("\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a)); EXPECT_EQ("\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a));
} }
// const char array with terminating NUL. // char array with terminating NUL.
TEST(PrintArrayTest, ConstCharArrayWithTerminatingNul) { TEST(PrintArrayTest, CharArrayWithTerminatingNul) {
const char a[] = "\0Hi"; const char a[] = "\0Hi";
EXPECT_EQ("\"\\0Hi\"", PrintArrayHelper(a)); EXPECT_EQ("\"\\0Hi\"", PrintArrayHelper(a));
} }
// const wchar_t array without terminating NUL. #ifdef __cpp_char8_t
// char_t array without terminating NUL.
TEST(PrintArrayTest, Char8ArrayWithNoTerminatingNul) {
// Array a contains '\0' in the middle and doesn't end with '\0'.
const char8_t a[] = {u8'H', u8'\0', u8'i'};
EXPECT_EQ("u8\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a));
}
// char8_t array with terminating NUL.
TEST(PrintArrayTest, Char8ArrayWithTerminatingNul) {
const char8_t a[] = u8"\0世界";
EXPECT_EQ(
"u8\"\\0\\xE4\\xB8\\x96\\xE7\\x95\\x8C\"",
PrintArrayHelper(a));
}
#endif
// const char16_t array without terminating NUL.
TEST(PrintArrayTest, Char16ArrayWithNoTerminatingNul) {
// Array a contains '\0' in the middle and doesn't end with '\0'.
const char16_t a[] = {u'', u'\0', u'', u'', u'', u''};
EXPECT_EQ("u\"\\x3053\\0\\x3093\\x306B\\x3061\\x306F\" (no terminating NUL)",
PrintArrayHelper(a));
}
// char16_t array with terminating NUL.
TEST(PrintArrayTest, Char16ArrayWithTerminatingNul) {
const char16_t a[] = u"\0こんにちは";
EXPECT_EQ("u\"\\0\\x3053\\x3093\\x306B\\x3061\\x306F\"", PrintArrayHelper(a));
}
// char32_t array without terminating NUL.
TEST(PrintArrayTest, Char32ArrayWithNoTerminatingNul) {
// Array a contains '\0' in the middle and doesn't end with '\0'.
const char32_t a[] = {U'👋', U'\0', U'🌌'};
EXPECT_EQ("U\"\\x1F44B\\0\\x1F30C\" (no terminating NUL)",
PrintArrayHelper(a));
}
// char32_t array with terminating NUL.
TEST(PrintArrayTest, Char32ArrayWithTerminatingNul) {
const char32_t a[] = U"\0👋🌌";
EXPECT_EQ("U\"\\0\\x1F44B\\x1F30C\"", PrintArrayHelper(a));
}
// wchar_t array without terminating NUL.
TEST(PrintArrayTest, WCharArrayWithNoTerminatingNul) { TEST(PrintArrayTest, WCharArrayWithNoTerminatingNul) {
// Array a contains '\0' in the middle and doesn't end with '\0'. // Array a contains '\0' in the middle and doesn't end with '\0'.
const wchar_t a[] = {L'H', L'\0', L'i'}; const wchar_t a[] = {L'H', L'\0', L'i'};
@ -767,50 +848,11 @@ TEST(PrintArrayTest, WCharArrayWithNoTerminatingNul) {
} }
// wchar_t array with terminating NUL. // wchar_t array with terminating NUL.
TEST(PrintArrayTest, WConstCharArrayWithTerminatingNul) { TEST(PrintArrayTest, WCharArrayWithTerminatingNul) {
const wchar_t a[] = L"\0Hi"; const wchar_t a[] = L"\0Hi";
EXPECT_EQ("L\"\\0Hi\"", PrintArrayHelper(a)); EXPECT_EQ("L\"\\0Hi\"", PrintArrayHelper(a));
} }
#ifdef __cpp_char8_t
// char8_t array.
TEST(PrintArrayTest, Char8Array) {
const char8_t a[] = u8"Hello, world!";
EXPECT_EQ(
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+0077, "
"U+006F, U+0072, U+006C, U+0064, U+0021, U+0000 }",
PrintArrayHelper(a));
}
#endif
// char16_t array.
#ifdef _MSC_VER
// TODO(b/173029407): Figure out why this doesn't work under MSVC.
TEST(PrintArrayTest, DISABLED_Char16Array) {
#else
TEST(PrintArrayTest, Char16Array) {
#endif
const char16_t a[] = u"Hello, 世界";
EXPECT_EQ(
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+4E16, "
"U+754C, U+0000 }",
PrintArrayHelper(a));
}
// char32_t array.
#ifdef _MSC_VER
// TODO(b/173029407): Figure out why this doesn't work under MSVC.
TEST(PrintArrayTest, DISABLED_Char32Array) {
#else
TEST(PrintArrayTest, Char32Array) {
#endif
const char32_t a[] = U"Hello, 世界";
EXPECT_EQ(
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+4E16, "
"U+754C, U+0000 }",
PrintArrayHelper(a));
}
// Array of objects. // Array of objects.
TEST(PrintArrayTest, ObjectArray) { TEST(PrintArrayTest, ObjectArray) {
std::string a[3] = {"Hi", "Hello", "Ni hao"}; std::string a[3] = {"Hi", "Hello", "Ni hao"};
@ -872,41 +914,22 @@ TEST(PrintWideStringTest, StringAmbiguousHex) {
#ifdef __cpp_char8_t #ifdef __cpp_char8_t
TEST(PrintStringTest, U8String) { TEST(PrintStringTest, U8String) {
std::u8string str = u8"Hello, world!"; std::u8string str = u8"Hello, 世界";
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type. EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
EXPECT_EQ( EXPECT_EQ("u8\"Hello, \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"", Print(str));
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+0077, "
"U+006F, U+0072, U+006C, U+0064, U+0021 }",
Print(str));
} }
#endif #endif
#ifdef _MSC_VER
// TODO(b/173029407): Figure out why this doesn't work under MSVC.
TEST(PrintStringTest, DISABLED_U16String) {
#else
TEST(PrintStringTest, U16String) { TEST(PrintStringTest, U16String) {
#endif
std::u16string str = u"Hello, 世界"; std::u16string str = u"Hello, 世界";
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type. EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
EXPECT_EQ( EXPECT_EQ("u\"Hello, \\x4E16\\x754C\"", Print(str));
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+4E16, "
"U+754C }",
Print(str));
} }
#ifdef _MSC_VER
// TODO(b/173029407): Figure out why this doesn't work under MSVC.
TEST(PrintStringTest, DISABLED_U32String) {
#else
TEST(PrintStringTest, U32String) { TEST(PrintStringTest, U32String) {
#endif std::u32string str = U"Hello, 🗺️";
std::u32string str = U"Hello, 世界"; EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type. EXPECT_EQ("U\"Hello, \\x1F5FA\\xFE0F\"", Print(str));
EXPECT_EQ(
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+4E16, "
"U+754C }",
Print(str));
} }
// Tests printing types that support generic streaming (i.e. streaming // Tests printing types that support generic streaming (i.e. streaming