mirror of
https://git.mirrors.martin98.com/https://github.com/google/googletest.git
synced 2025-06-04 11:25:34 +08:00
Print std::basic_string_view<Char> as a string literal
This is a followup to a previous change switching std::u8string, std::u16string, and std::u32string to print as string literals instead of an array of characters. Also update the PrintCharsAsStringTo<Char>() helper to handle cases where the pointer to the string data is null; unlike std::basic_string<Char>, std::basic_string_view<Char>'s data() is allowed to return nullptr. The new PrintTo overloads complicate the PrintTo(internal::StringView) overload, which needs to be disabled if internal::StringView is an alias for std::string_view to avoid multiple definitions with the same overload. Simply omitting the unconditional PrintTo(std::string_view) overload is a worse option though, as this results in std::string_view not printing nicely if internal::StringView is not an alias for std::string_view. PiperOrigin-RevId: 762020327 Change-Id: I92f5bdbacba89e97bbcc0fef3ca9261ea5a788d3
This commit is contained in:
parent
16d4f8eff6
commit
6aa03e6774
@ -111,6 +111,7 @@
|
||||
#include <ostream> // NOLINT
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
@ -248,8 +249,8 @@ struct StreamPrinter {
|
||||
// ADL (possibly involving implicit conversions).
|
||||
// (Use SFINAE via return type, because it seems GCC < 12 doesn't handle name
|
||||
// lookup properly when we do it in the template parameter list.)
|
||||
static auto PrintValue(const T& value,
|
||||
::std::ostream* os) -> decltype((void)(*os << value)) {
|
||||
static auto PrintValue(const T& value, ::std::ostream* os)
|
||||
-> decltype((void)(*os << value)) {
|
||||
// Call streaming operator found by ADL, possibly with implicit conversions
|
||||
// of the arguments.
|
||||
*os << value;
|
||||
@ -702,44 +703,63 @@ void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) {
|
||||
}
|
||||
}
|
||||
|
||||
// Overloads for ::std::string.
|
||||
GTEST_API_ void PrintStringTo(const ::std::string& s, ::std::ostream* os);
|
||||
// Overloads for ::std::string and ::std::string_view
|
||||
GTEST_API_ void PrintStringTo(::std::string_view s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
|
||||
PrintStringTo(s, os);
|
||||
}
|
||||
inline void PrintTo(::std::string_view s, ::std::ostream* os) {
|
||||
PrintStringTo(s, os);
|
||||
}
|
||||
|
||||
// Overloads for ::std::u8string
|
||||
// Overloads for ::std::u8string and ::std::u8string_view
|
||||
#ifdef __cpp_lib_char8_t
|
||||
GTEST_API_ void PrintU8StringTo(const ::std::u8string& s, ::std::ostream* os);
|
||||
GTEST_API_ void PrintU8StringTo(::std::u8string_view s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::u8string& s, ::std::ostream* os) {
|
||||
PrintU8StringTo(s, os);
|
||||
}
|
||||
inline void PrintTo(::std::u8string_view s, ::std::ostream* os) {
|
||||
PrintU8StringTo(s, os);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Overloads for ::std::u16string
|
||||
GTEST_API_ void PrintU16StringTo(const ::std::u16string& s, ::std::ostream* os);
|
||||
// Overloads for ::std::u16string and ::std::u16string_view
|
||||
GTEST_API_ void PrintU16StringTo(::std::u16string_view s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::u16string& s, ::std::ostream* os) {
|
||||
PrintU16StringTo(s, os);
|
||||
}
|
||||
inline void PrintTo(::std::u16string_view s, ::std::ostream* os) {
|
||||
PrintU16StringTo(s, os);
|
||||
}
|
||||
|
||||
// Overloads for ::std::u32string
|
||||
GTEST_API_ void PrintU32StringTo(const ::std::u32string& s, ::std::ostream* os);
|
||||
// Overloads for ::std::u32string and ::std::u32string_view
|
||||
GTEST_API_ void PrintU32StringTo(::std::u32string_view s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::u32string& s, ::std::ostream* os) {
|
||||
PrintU32StringTo(s, os);
|
||||
}
|
||||
inline void PrintTo(::std::u32string_view s, ::std::ostream* os) {
|
||||
PrintU32StringTo(s, os);
|
||||
}
|
||||
|
||||
// Overloads for ::std::wstring.
|
||||
// Overloads for ::std::wstring and ::std::wstring_view
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
GTEST_API_ void PrintWideStringTo(const ::std::wstring& s, ::std::ostream* os);
|
||||
GTEST_API_ void PrintWideStringTo(::std::wstring_view s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
|
||||
PrintWideStringTo(s, os);
|
||||
}
|
||||
inline void PrintTo(::std::wstring_view s, ::std::ostream* os) {
|
||||
PrintWideStringTo(s, os);
|
||||
}
|
||||
#endif // GTEST_HAS_STD_WSTRING
|
||||
|
||||
#if GTEST_INTERNAL_HAS_STRING_VIEW
|
||||
// Overload for internal::StringView.
|
||||
// Overload for internal::StringView. Needed for build configurations where
|
||||
// internal::StringView is an alias for absl::string_view, but absl::string_view
|
||||
// is a distinct type from std::string_view.
|
||||
template <int&... ExplicitArgumentBarrier, typename T = internal::StringView,
|
||||
std::enable_if_t<!std::is_same_v<T, ::std::string_view>, int> = 0>
|
||||
inline void PrintTo(internal::StringView sp, ::std::ostream* os) {
|
||||
PrintTo(::std::string(sp), os);
|
||||
PrintStringTo(sp, os);
|
||||
}
|
||||
#endif // GTEST_INTERNAL_HAS_STRING_VIEW
|
||||
|
||||
|
@ -50,7 +50,7 @@
|
||||
#include <iomanip>
|
||||
#include <ios>
|
||||
#include <ostream> // NOLINT
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
@ -333,14 +333,14 @@ void PrintTo(__int128_t v, ::std::ostream* os) {
|
||||
|
||||
// Prints the given array of characters to the ostream. CharType must be either
|
||||
// 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.
|
||||
// The array starts at begin (which may be nullptr) and contains len characters.
|
||||
// The array may include '\0' characters and may not be NUL-terminated.
|
||||
template <typename CharType>
|
||||
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
||||
GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
|
||||
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static CharFormat
|
||||
PrintCharsAsStringTo(const CharType* begin, size_t len, ostream* os) {
|
||||
const char* const quote_prefix = GetCharWidthPrefix(*begin);
|
||||
const char* const quote_prefix = GetCharWidthPrefix(CharType());
|
||||
*os << quote_prefix << "\"";
|
||||
bool is_previous_hex = false;
|
||||
CharFormat print_format = kAsIs;
|
||||
@ -522,7 +522,7 @@ void ConditionalPrintAsText(const char* str, size_t length, ostream* os) {
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void PrintStringTo(const ::std::string& s, ostream* os) {
|
||||
void PrintStringTo(::std::string_view s, ostream* os) {
|
||||
if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) {
|
||||
if (GTEST_FLAG_GET(print_utf8)) {
|
||||
ConditionalPrintAsText(s.data(), s.size(), os);
|
||||
@ -531,21 +531,21 @@ void PrintStringTo(const ::std::string& s, ostream* os) {
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_char8_t
|
||||
void PrintU8StringTo(const ::std::u8string& s, ostream* os) {
|
||||
void PrintU8StringTo(::std::u8string_view s, ostream* os) {
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
}
|
||||
#endif
|
||||
|
||||
void PrintU16StringTo(const ::std::u16string& s, ostream* os) {
|
||||
void PrintU16StringTo(::std::u16string_view s, ostream* os) {
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
}
|
||||
|
||||
void PrintU32StringTo(const ::std::u32string& s, ostream* os) {
|
||||
void PrintU32StringTo(::std::u32string_view s, ostream* os) {
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
}
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
|
||||
void PrintWideStringTo(::std::wstring_view s, ostream* os) {
|
||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||
}
|
||||
#endif // GTEST_HAS_STD_WSTRING
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
@ -65,7 +66,7 @@
|
||||
|
||||
#if GTEST_INTERNAL_HAS_STD_SPAN
|
||||
#include <span> // NOLINT
|
||||
#endif // GTEST_INTERNAL_HAS_STD_SPAN
|
||||
#endif // GTEST_INTERNAL_HAS_STD_SPAN
|
||||
|
||||
#if GTEST_INTERNAL_HAS_COMPARE_LIB
|
||||
#include <compare> // NOLINT
|
||||
@ -799,7 +800,7 @@ struct Foo {
|
||||
TEST(PrintPointerTest, MemberVariablePointer) {
|
||||
EXPECT_TRUE(HasPrefix(Print(&Foo::value),
|
||||
Print(sizeof(&Foo::value)) + "-byte object "));
|
||||
int Foo::*p = NULL; // NOLINT
|
||||
int Foo::* p = NULL; // NOLINT
|
||||
EXPECT_TRUE(HasPrefix(Print(p), Print(sizeof(p)) + "-byte object "));
|
||||
}
|
||||
|
||||
@ -926,7 +927,7 @@ TEST(PrintArrayTest, BigArray) {
|
||||
PrintArrayHelper(a));
|
||||
}
|
||||
|
||||
// Tests printing ::string and ::std::string.
|
||||
// Tests printing ::std::string and ::string_view.
|
||||
|
||||
// ::std::string.
|
||||
TEST(PrintStringTest, StringInStdNamespace) {
|
||||
@ -936,6 +937,13 @@ TEST(PrintStringTest, StringInStdNamespace) {
|
||||
Print(str));
|
||||
}
|
||||
|
||||
TEST(PrintStringTest, StringViewInStdNamespace) {
|
||||
const char s[] = "'\"?\\\a\b\f\n\0\r\t\v\x7F\xFF a";
|
||||
const ::std::string_view str(s, sizeof(s));
|
||||
EXPECT_EQ("\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"",
|
||||
Print(str));
|
||||
}
|
||||
|
||||
TEST(PrintStringTest, StringAmbiguousHex) {
|
||||
// "\x6BANANA" is ambiguous, it can be interpreted as starting with either of:
|
||||
// '\x6', '\x6B', or '\x6BA'.
|
||||
@ -953,7 +961,7 @@ TEST(PrintStringTest, StringAmbiguousHex) {
|
||||
EXPECT_EQ("\"!\\x5-!\"", Print(::std::string("!\x5-!")));
|
||||
}
|
||||
|
||||
// Tests printing ::std::wstring.
|
||||
// Tests printing ::std::wstring and ::std::wstring_view.
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
// ::std::wstring.
|
||||
TEST(PrintWideStringTest, StringInStdNamespace) {
|
||||
@ -965,6 +973,15 @@ TEST(PrintWideStringTest, StringInStdNamespace) {
|
||||
Print(str));
|
||||
}
|
||||
|
||||
TEST(PrintWideStringTest, StringViewInStdNamespace) {
|
||||
const wchar_t s[] = L"'\"?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a";
|
||||
const ::std::wstring_view str(s, sizeof(s) / sizeof(wchar_t));
|
||||
EXPECT_EQ(
|
||||
"L\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v"
|
||||
"\\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"
|
||||
@ -983,6 +1000,12 @@ TEST(PrintStringTest, U8String) {
|
||||
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
|
||||
EXPECT_EQ("u8\"Hello, \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"", Print(str));
|
||||
}
|
||||
|
||||
TEST(PrintStringTest, U8StringView) {
|
||||
std::u8string_view str = u8"Hello, 世界";
|
||||
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
|
||||
EXPECT_EQ("u8\"Hello, \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"", Print(str));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(PrintStringTest, U16String) {
|
||||
@ -991,12 +1014,24 @@ TEST(PrintStringTest, U16String) {
|
||||
EXPECT_EQ("u\"Hello, \\x4E16\\x754C\"", Print(str));
|
||||
}
|
||||
|
||||
TEST(PrintStringTest, U16StringView) {
|
||||
std::u16string_view str = u"Hello, 世界";
|
||||
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
|
||||
EXPECT_EQ("u\"Hello, \\x4E16\\x754C\"", Print(str));
|
||||
}
|
||||
|
||||
TEST(PrintStringTest, U32String) {
|
||||
std::u32string str = U"Hello, 🗺️";
|
||||
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type
|
||||
EXPECT_EQ("U\"Hello, \\x1F5FA\\xFE0F\"", Print(str));
|
||||
}
|
||||
|
||||
TEST(PrintStringTest, U32StringView) {
|
||||
std::u32string_view 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
|
||||
// to std::basic_ostream<Char, CharTraits> for any valid Char and
|
||||
// CharTraits types).
|
||||
@ -1456,7 +1491,7 @@ TEST(PrintReferenceTest, HandlesMemberFunctionPointer) {
|
||||
// Tests that the universal printer prints a member variable pointer
|
||||
// passed by reference.
|
||||
TEST(PrintReferenceTest, HandlesMemberVariablePointer) {
|
||||
int Foo::*p = &Foo::value; // NOLINT
|
||||
int Foo::* p = &Foo::value; // NOLINT
|
||||
EXPECT_TRUE(HasPrefix(PrintByRef(p), "@" + PrintPointer(&p) + " " +
|
||||
Print(sizeof(p)) + "-byte object "));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user