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"],
)
config_setting(
name = "msvc_compiler",
flag_values = {
"@bazel_tools//tools/cpp:compiler": "msvc-cl",
},
visibility = [":__subpackages__"],
)
config_setting(
name = "has_absl",
values = {"define": "absl=1"},

View File

@ -81,6 +81,8 @@ macro(config_compiler_and_linker)
# Suppress "unreachable code" warning
# http://stackoverflow.com/questions/3232669 explains the issue.
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")
set(cxx_base_flags "-Wall -Wshadow -Werror -Wconversion")
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);
}
#ifdef __cpp_char8_t
inline void PrintTo(const char8_t* s, ::std::ostream* os) {
PrintTo(ImplicitCast_<const void*>(s), os);
}
// Overloads for u8 strings.
void PrintTo(const 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
inline void PrintTo(const char16_t* s, ::std::ostream* os) {
PrintTo(ImplicitCast_<const void*>(s), os);
}
// Overloads for u16 strings.
void PrintTo(const char16_t* s, ::std::ostream* os);
inline void PrintTo(char16_t* s, ::std::ostream* os) {
PrintTo(ImplicitCast_<const void*>(s), os);
}
inline void PrintTo(const char32_t* s, ::std::ostream* os) {
PrintTo(ImplicitCast_<const void*>(s), os);
PrintTo(ImplicitCast_<const char16_t*>(s), os);
}
// Overloads for u32 strings.
void PrintTo(const 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
@ -558,6 +555,26 @@ inline void PrintTo(const ::std::string& s, ::std::ostream* 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.
#if GTEST_HAS_STD_WSTRING
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(
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.
GTEST_API_ void UniversalPrintArray(
const wchar_t* begin, size_t len, ::std::ostream* os);
@ -877,12 +908,55 @@ class UniversalTersePrinter<const char*> {
}
};
template <>
class UniversalTersePrinter<char*> {
class UniversalTersePrinter<char*> : public UniversalTersePrinter<const char*> {
};
#ifdef __cpp_char8_t
template <>
class UniversalTersePrinter<const char8_t*> {
public:
static void Print(char* str, ::std::ostream* os) {
UniversalTersePrinter<const char*>::Print(str, os);
static void Print(const char8_t* str, ::std::ostream* 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
template <>

View File

@ -1936,6 +1936,19 @@ inline bool IsUpper(char ch) {
inline bool IsXDigit(char ch) {
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) {
const unsigned char low_byte = static_cast<unsigned char>(ch);
return ch == low_byte && isxdigit(low_byte) != 0;

View File

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

View File

@ -83,6 +83,10 @@ cc_test(
copts = select({
"//:windows": ["-DGTEST_USE_OWN_TR1_TUPLE=0"],
"//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 = [
"googletest",

View File

@ -493,6 +493,92 @@ TEST(PrintCStringTest, EscapesProperly) {
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
// of unsigned short. Defining an overload for const wchar_t* in that case
// would cause pointers to unsigned shorts be printed as wide strings,
@ -564,56 +650,6 @@ TEST(PrintCharPointerTest, ConstUnsignedChar) {
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.
// bool*.
@ -753,64 +789,70 @@ TEST(PrintArrayTest, CharArrayWithNoTerminatingNul) {
EXPECT_EQ("\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a));
}
// const char array with terminating NUL.
TEST(PrintArrayTest, ConstCharArrayWithTerminatingNul) {
// char array with terminating NUL.
TEST(PrintArrayTest, CharArrayWithTerminatingNul) {
const char a[] = "\0Hi";
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) {
// 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'};
EXPECT_EQ("L\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a));
}
// wchar_t array with terminating NUL.
TEST(PrintArrayTest, WConstCharArrayWithTerminatingNul) {
TEST(PrintArrayTest, WCharArrayWithTerminatingNul) {
const wchar_t a[] = L"\0Hi";
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.
TEST(PrintArrayTest, ObjectArray) {
std::string a[3] = {"Hi", "Hello", "Ni hao"};
@ -872,41 +914,22 @@ TEST(PrintWideStringTest, StringAmbiguousHex) {
#ifdef __cpp_char8_t
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(
"{ 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));
EXPECT_EQ("u8\"Hello, \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"", Print(str));
}
#endif
#ifdef _MSC_VER
// TODO(b/173029407): Figure out why this doesn't work under MSVC.
TEST(PrintStringTest, DISABLED_U16String) {
#else
TEST(PrintStringTest, U16String) {
#endif
std::u16string str = u"Hello, 世界";
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
EXPECT_EQ(
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+4E16, "
"U+754C }",
Print(str));
EXPECT_EQ("u\"Hello, \\x4E16\\x754C\"", 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) {
#endif
std::u32string str = U"Hello, 世界";
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
EXPECT_EQ(
"{ U+0048, U+0065, U+006C, U+006C, U+006F, U+002C, U+0020, U+4E16, "
"U+754C }",
Print(str));
std::u32string str = U"Hello, 🗺️";
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type
EXPECT_EQ("U\"Hello, \\x1F5FA\\xFE0F\"", Print(str));
}
// Tests printing types that support generic streaming (i.e. streaming