From 33b44c4b35b5b24624c1203001e36df2dbab346b Mon Sep 17 00:00:00 2001 From: Krystian Kuzniarek Date: Sat, 7 Mar 2020 15:41:43 +0100 Subject: [PATCH 1/4] specialize UniversalPrinter<> for std::variant --- googletest/include/gtest/gtest-printers.h | 22 +++++++++---- .../include/gtest/internal/gtest-port.h | 32 +++++++++++++++++++ googletest/test/googletest-printers-test.cc | 13 +++++--- 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index 407d1f18..39c72c43 100644 --- a/googletest/include/gtest/gtest-printers.h +++ b/googletest/include/gtest/gtest-printers.h @@ -114,7 +114,6 @@ #if GTEST_HAS_ABSL #include "absl/strings/string_view.h" #include "absl/types/optional.h" -#include "absl/types/variant.h" #endif // GTEST_HAS_ABSL namespace testing { @@ -699,14 +698,22 @@ class UniversalPrinter<::absl::optional> { } }; -// Printer for absl::variant +#endif // GTEST_HAS_ABSL + +#if GTEST_INTERNAL_HAS_VARIANT + +// Printer for std::variant / absl::variant template -class UniversalPrinter<::absl::variant> { +class UniversalPrinter> { public: - static void Print(const ::absl::variant& value, ::std::ostream* os) { + static void Print(const Variant& value, ::std::ostream* os) { *os << '('; - absl::visit(Visitor{os}, value); +#if GTEST_HAS_ABSL + absl::visit(Visitor{os, value.index()}, value); +#else + std::visit(Visitor{os, value.index()}, value); +#endif // GTEST_HAS_ABSL *os << ')'; } @@ -714,14 +721,15 @@ class UniversalPrinter<::absl::variant> { struct Visitor { template void operator()(const U& u) const { - *os << "'" << GetTypeName() << "' with value "; + *os << "'" << GetTypeName() << "(" << index << ")' with value "; UniversalPrint(u, os); } ::std::ostream* os; + std::size_t index; }; }; -#endif // GTEST_HAS_ABSL +#endif // GTEST_INTERNAL_HAS_VARIANT // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h index 60ff4716..ea37fe13 100644 --- a/googletest/include/gtest/internal/gtest-port.h +++ b/googletest/include/gtest/internal/gtest-port.h @@ -202,6 +202,8 @@ // GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher or // Matcher // specializations. +// GTEST_INTERNAL_HAS_VARIANT - for enabling UniversalPrinter or +// UniversalPrinter specializations. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() @@ -2251,4 +2253,34 @@ using StringView = ::std::string_view; # endif // __has_include #endif // GTEST_HAS_ABSL +#if GTEST_HAS_ABSL +// Always use absl::variant for UniversalPrinter<> specializations if googletest +// is built with absl support. +# define GTEST_INTERNAL_HAS_VARIANT 1 +#include "absl/types/variant.h" +namespace testing { +namespace internal { +template +using Variant = ::absl::variant; +} // namespace internal +} // namespace testing +#else +# ifdef __has_include +# if __has_include() && __cplusplus >= 201703L +// Otherwise for C++17 and higher use std::variant for UniversalPrinter<> +// specializations. +# define GTEST_INTERNAL_HAS_VARIANT 1 +#include +namespace testing { +namespace internal { +template +using Variant = ::std::variant; +} // namespace internal +} // namespace testing +// The case where absl is configured NOT to alias std::variant is not +// supported. +# endif // __has_include() && __cplusplus >= 201703L +# endif // __has_include +#endif // GTEST_HAS_ABSL + #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ diff --git a/googletest/test/googletest-printers-test.cc b/googletest/test/googletest-printers-test.cc index ddf2c0e1..8a8ca51e 100644 --- a/googletest/test/googletest-printers-test.cc +++ b/googletest/test/googletest-printers-test.cc @@ -1542,21 +1542,24 @@ TEST(PrintOptionalTest, Basic) { EXPECT_EQ("(\"A\")", PrintToString(absl::optional{"A"})); } +#endif // GTEST_HAS_ABSL + +#if GTEST_INTERNAL_HAS_VARIANT struct NonPrintable { unsigned char contents = 17; }; TEST(PrintOneofTest, Basic) { - using Type = absl::variant; - EXPECT_EQ("('int' with value 7)", PrintToString(Type(7))); - EXPECT_EQ("('StreamableInGlobal' with value StreamableInGlobal)", + using Type = internal::Variant; + EXPECT_EQ("('int(0)' with value 7)", PrintToString(Type(7))); + EXPECT_EQ("('StreamableInGlobal(1)' with value StreamableInGlobal)", PrintToString(Type(StreamableInGlobal{}))); EXPECT_EQ( - "('testing::gtest_printers_test::NonPrintable' with value 1-byte object " + "('testing::gtest_printers_test::NonPrintable(2)' with value 1-byte object " "<11>)", PrintToString(Type(NonPrintable{}))); } -#endif // GTEST_HAS_ABSL +#endif // GTEST_INTERNAL_HAS_VARIANT namespace { class string_ref; From 95b0ea2cf5046465f448f01efa7c4b764a62a4bb Mon Sep 17 00:00:00 2001 From: Krystian Kuzniarek Date: Sat, 7 Mar 2020 15:48:20 +0100 Subject: [PATCH 2/4] specialize UniversalPrinter<> for std::optional --- googletest/include/gtest/gtest-printers.h | 11 +++---- .../include/gtest/internal/gtest-port.h | 32 +++++++++++++++++++ googletest/test/googletest-printers-test.cc | 12 +++---- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index 39c72c43..4260e4f7 100644 --- a/googletest/include/gtest/gtest-printers.h +++ b/googletest/include/gtest/gtest-printers.h @@ -113,7 +113,6 @@ #if GTEST_HAS_ABSL #include "absl/strings/string_view.h" -#include "absl/types/optional.h" #endif // GTEST_HAS_ABSL namespace testing { @@ -680,14 +679,14 @@ class UniversalPrinter { GTEST_DISABLE_MSC_WARNINGS_POP_() }; -#if GTEST_HAS_ABSL +#if GTEST_INTERNAL_HAS_OPTIONAL -// Printer for absl::optional +// Printer for std::optional / absl::optional template -class UniversalPrinter<::absl::optional> { +class UniversalPrinter> { public: - static void Print(const ::absl::optional& value, ::std::ostream* os) { + static void Print(const Optional& value, ::std::ostream* os) { *os << '('; if (!value) { *os << "nullopt"; @@ -698,7 +697,7 @@ class UniversalPrinter<::absl::optional> { } }; -#endif // GTEST_HAS_ABSL +#endif // GTEST_INTERNAL_HAS_OPTIONAL #if GTEST_INTERNAL_HAS_VARIANT diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h index ea37fe13..377c77fb 100644 --- a/googletest/include/gtest/internal/gtest-port.h +++ b/googletest/include/gtest/internal/gtest-port.h @@ -199,6 +199,8 @@ // suppressed (constant conditional). // GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 // is suppressed. +// GTEST_INTERNAL_HAS_OPTIONAL - for enabling UniversalPrinter or +// UniversalPrinter specializations. // GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher or // Matcher // specializations. @@ -2225,6 +2227,36 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val); #endif // !defined(GTEST_INTERNAL_DEPRECATED) +#if GTEST_HAS_ABSL +// Always use absl::optional for UniversalPrinter<> specializations if googletest +// is built with absl support. +# define GTEST_INTERNAL_HAS_OPTIONAL 1 +#include "absl/types/optional.h" +namespace testing { +namespace internal { +template +using Optional = ::absl::optional; +} // namespace internal +} // namespace testing +#else +# ifdef __has_include +# if __has_include() && __cplusplus >= 201703L +// Otherwise for C++17 and higher use std::optional for UniversalPrinter<> +// specializations. +# define GTEST_INTERNAL_HAS_OPTIONAL 1 +#include +namespace testing { +namespace internal { +template +using Optional = ::std::optional; +} // namespace internal +} // namespace testing +// The case where absl is configured NOT to alias std::optional is not +// supported. +# endif // __has_include() && __cplusplus >= 201703L +# endif // __has_include +#endif // GTEST_HAS_ABSL + #if GTEST_HAS_ABSL // Always use absl::string_view for Matcher<> specializations if googletest // is built with absl support. diff --git a/googletest/test/googletest-printers-test.cc b/googletest/test/googletest-printers-test.cc index 8a8ca51e..d71c1871 100644 --- a/googletest/test/googletest-printers-test.cc +++ b/googletest/test/googletest-printers-test.cc @@ -1531,18 +1531,16 @@ TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsTersely) { EXPECT_EQ("\"a\"", result[1]); } -#if GTEST_HAS_ABSL - +#if GTEST_INTERNAL_HAS_OPTIONAL TEST(PrintOptionalTest, Basic) { - absl::optional value; + internal::Optional value; EXPECT_EQ("(nullopt)", PrintToString(value)); value = {7}; EXPECT_EQ("(7)", PrintToString(value)); - EXPECT_EQ("(1.1)", PrintToString(absl::optional{1.1})); - EXPECT_EQ("(\"A\")", PrintToString(absl::optional{"A"})); + EXPECT_EQ("(1.1)", PrintToString(internal::Optional{1.1})); + EXPECT_EQ("(\"A\")", PrintToString(internal::Optional{"A"})); } - -#endif // GTEST_HAS_ABSL +#endif // GTEST_INTERNAL_HAS_OPTIONAL #if GTEST_INTERNAL_HAS_VARIANT struct NonPrintable { From 843267f0f1482b470fe14201edfda2c64b68232a Mon Sep 17 00:00:00 2001 From: Krystian Kuzniarek Date: Sat, 7 Mar 2020 17:03:50 +0100 Subject: [PATCH 3/4] specialize UniversalPrinter<> for std::any (without support for RTTI) --- BUILD.bazel | 1 + googletest/include/gtest/gtest-printers.h | 20 +++++++++++++ .../include/gtest/internal/gtest-port.h | 30 +++++++++++++++++++ googletest/test/googletest-printers-test.cc | 21 +++++++++++++ 4 files changed, 72 insertions(+) diff --git a/BUILD.bazel b/BUILD.bazel index 9b48aee5..7e227aa0 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -103,6 +103,7 @@ cc_library( "@com_google_absl//absl/debugging:stacktrace", "@com_google_absl//absl/debugging:symbolize", "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:any", "@com_google_absl//absl/types:optional", "@com_google_absl//absl/types:variant", ], diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index 4260e4f7..67c87f47 100644 --- a/googletest/include/gtest/gtest-printers.h +++ b/googletest/include/gtest/gtest-printers.h @@ -679,6 +679,26 @@ class UniversalPrinter { GTEST_DISABLE_MSC_WARNINGS_POP_() }; +#if GTEST_INTERNAL_HAS_ANY + +// Printer for std::any / absl::any + +template <> +class UniversalPrinter { + public: + static void Print(const Any& value, ::std::ostream* os) { + if (value.has_value()) + *os << "'any' type with value of type " << GetTypeName(); + else + *os << "'any' type with no value"; + } + + private: + static std::string GetTypeName() { return "the element type"; } +}; + +#endif // GTEST_INTERNAL_HAS_ANY + #if GTEST_INTERNAL_HAS_OPTIONAL // Printer for std::optional / absl::optional diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h index 377c77fb..75e00ccb 100644 --- a/googletest/include/gtest/internal/gtest-port.h +++ b/googletest/include/gtest/internal/gtest-port.h @@ -199,6 +199,8 @@ // suppressed (constant conditional). // GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 // is suppressed. +// GTEST_INTERNAL_HAS_ANY - for enabling UniversalPrinter or +// UniversalPrinter specializations. // GTEST_INTERNAL_HAS_OPTIONAL - for enabling UniversalPrinter or // UniversalPrinter specializations. // GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher or @@ -2227,6 +2229,34 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val); #endif // !defined(GTEST_INTERNAL_DEPRECATED) +#if GTEST_HAS_ABSL +// Always use absl::any for UniversalPrinter<> specializations if googletest +// is built with absl support. +# define GTEST_INTERNAL_HAS_ANY 1 +#include "absl/types/any.h" +namespace testing { +namespace internal { +using Any = ::absl::any; +} // namespace internal +} // namespace testing +#else +# ifdef __has_include +# if __has_include() && __cplusplus >= 201703L +// Otherwise for C++17 and higher use std::any for UniversalPrinter<> +// specializations. +# define GTEST_INTERNAL_HAS_ANY 1 +#include +namespace testing { +namespace internal { +using Any = ::std::any; +} // namespace internal +} // namespace testing +// The case where absl is configured NOT to alias std::any is not +// supported. +# endif // __has_include() && __cplusplus >= 201703L +# endif // __has_include +#endif // GTEST_HAS_ABSL + #if GTEST_HAS_ABSL // Always use absl::optional for UniversalPrinter<> specializations if googletest // is built with absl support. diff --git a/googletest/test/googletest-printers-test.cc b/googletest/test/googletest-printers-test.cc index d71c1871..33050352 100644 --- a/googletest/test/googletest-printers-test.cc +++ b/googletest/test/googletest-printers-test.cc @@ -1531,6 +1531,27 @@ TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsTersely) { EXPECT_EQ("\"a\"", result[1]); } +#if GTEST_INTERNAL_HAS_ANY +TEST(PrintAnyTest, Empty) { + internal::Any any; + EXPECT_EQ("'any' type with no value", PrintToString(any)); +} + +TEST(PrintAnyTest, NonEmpty) { + internal::Any any; + constexpr int val1 = 10; + const std::string val2 = "content"; + + any = val1; + EXPECT_EQ("'any' type with value of type the element type", + PrintToString(any)); + + any = val2; + EXPECT_EQ("'any' type with value of type the element type", + PrintToString(any)); +} +#endif // GTEST_INTERNAL_HAS_ANY + #if GTEST_INTERNAL_HAS_OPTIONAL TEST(PrintOptionalTest, Basic) { internal::Optional value; From eb3953f805d0ed9054dba78b8e842caba0b539c2 Mon Sep 17 00:00:00 2001 From: Krystian Kuzniarek Date: Sat, 7 Mar 2020 17:25:51 +0100 Subject: [PATCH 4/4] make UniversalPrinter support RTTI --- googletest/include/gtest/gtest-printers.h | 11 +++++- .../include/gtest/internal/gtest-type-util.h | 38 ++++++++++--------- googletest/test/googletest-printers-test.cc | 20 ++++++++-- 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index 67c87f47..718e6f13 100644 --- a/googletest/include/gtest/gtest-printers.h +++ b/googletest/include/gtest/gtest-printers.h @@ -688,13 +688,20 @@ class UniversalPrinter { public: static void Print(const Any& value, ::std::ostream* os) { if (value.has_value()) - *os << "'any' type with value of type " << GetTypeName(); + *os << "'any' type with value of type " << GetTypeName(value); else *os << "'any' type with no value"; } private: - static std::string GetTypeName() { return "the element type"; } + static std::string GetTypeName(const Any& value) { +#if GTEST_HAS_RTTI + return internal::GetTypeName(value.type()); +#else + static_cast(value); // possibly unused + return "the element type"; +#endif // GTEST_HAS_RTTI + } }; #endif // GTEST_INTERNAL_HAS_ANY diff --git a/googletest/include/gtest/internal/gtest-type-util.h b/googletest/include/gtest/internal/gtest-type-util.h index 082fdad1..c3326f2c 100644 --- a/googletest/include/gtest/internal/gtest-type-util.h +++ b/googletest/include/gtest/internal/gtest-type-util.h @@ -64,34 +64,38 @@ inline std::string CanonicalizeForStdLibVersioning(std::string s) { return s; } -// GetTypeName() returns a human-readable name of type T. -// NB: This function is also used in Google Mock, so don't move it inside of -// the typed-test-only section below. -template -std::string GetTypeName() { -# if GTEST_HAS_RTTI - - const char* const name = typeid(T).name(); -# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) +#if GTEST_HAS_RTTI +// GetTypeName(const std::type_info&) returns a human-readable name of type T. +inline std::string GetTypeName(const std::type_info& type) { + const char* const name = type.name(); +#if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. -# if GTEST_HAS_CXXABI_H_ +#if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; -# endif // GTEST_HAS_CXXABI_H_ +#endif // GTEST_HAS_CXXABI_H_ char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); return CanonicalizeForStdLibVersioning(name_str); -# else +#else return name; -# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC - -# else +#endif // GTEST_HAS_CXXABI_H_ || __HP_aCC +} +#endif // GTEST_HAS_RTTI +// GetTypeName() returns a human-readable name of type T if and only if +// RTTI is enabled, otherwise it returns a dummy type name. +// NB: This function is also used in Google Mock, so don't move it inside of +// the typed-test-only section below. +template +std::string GetTypeName() { +#if GTEST_HAS_RTTI + return GetTypeName(typeid(T)); +#else return ""; - -# endif // GTEST_HAS_RTTI +#endif // GTEST_HAS_RTTI } #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P diff --git a/googletest/test/googletest-printers-test.cc b/googletest/test/googletest-printers-test.cc index 33050352..1324dd6e 100644 --- a/googletest/test/googletest-printers-test.cc +++ b/googletest/test/googletest-printers-test.cc @@ -1532,22 +1532,34 @@ TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsTersely) { } #if GTEST_INTERNAL_HAS_ANY -TEST(PrintAnyTest, Empty) { +class PrintAnyTest : public ::testing::Test { + protected: + template + static std::string ExpectedTypeName() { +#if GTEST_HAS_RTTI + return internal::GetTypeName(); +#else + return "the element type"; +#endif // GTEST_HAS_RTTI + } +}; + +TEST_F(PrintAnyTest, Empty) { internal::Any any; EXPECT_EQ("'any' type with no value", PrintToString(any)); } -TEST(PrintAnyTest, NonEmpty) { +TEST_F(PrintAnyTest, NonEmpty) { internal::Any any; constexpr int val1 = 10; const std::string val2 = "content"; any = val1; - EXPECT_EQ("'any' type with value of type the element type", + EXPECT_EQ("'any' type with value of type " + ExpectedTypeName(), PrintToString(any)); any = val2; - EXPECT_EQ("'any' type with value of type the element type", + EXPECT_EQ("'any' type with value of type " + ExpectedTypeName(), PrintToString(any)); } #endif // GTEST_INTERNAL_HAS_ANY