specialize UniversalPrinter<> for std::variant

This commit is contained in:
Krystian Kuzniarek 2020-03-07 15:41:43 +01:00
parent e588eb1ff9
commit 33b44c4b35
3 changed files with 55 additions and 12 deletions

View File

@ -114,7 +114,6 @@
#if GTEST_HAS_ABSL #if GTEST_HAS_ABSL
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include "absl/types/variant.h"
#endif // GTEST_HAS_ABSL #endif // GTEST_HAS_ABSL
namespace testing { namespace testing {
@ -699,14 +698,22 @@ class UniversalPrinter<::absl::optional<T>> {
} }
}; };
// Printer for absl::variant #endif // GTEST_HAS_ABSL
#if GTEST_INTERNAL_HAS_VARIANT
// Printer for std::variant / absl::variant
template <typename... T> template <typename... T>
class UniversalPrinter<::absl::variant<T...>> { class UniversalPrinter<Variant<T...>> {
public: public:
static void Print(const ::absl::variant<T...>& value, ::std::ostream* os) { static void Print(const Variant<T...>& value, ::std::ostream* os) {
*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 << ')'; *os << ')';
} }
@ -714,14 +721,15 @@ class UniversalPrinter<::absl::variant<T...>> {
struct Visitor { struct Visitor {
template <typename U> template <typename U>
void operator()(const U& u) const { void operator()(const U& u) const {
*os << "'" << GetTypeName<U>() << "' with value "; *os << "'" << GetTypeName<U>() << "(" << index << ")' with value ";
UniversalPrint(u, os); UniversalPrint(u, os);
} }
::std::ostream* 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' // UniversalPrintArray(begin, len, os) prints an array of 'len'
// elements, starting at address 'begin'. // elements, starting at address 'begin'.

View File

@ -202,6 +202,8 @@
// GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher<std::string_view> or // GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher<std::string_view> or
// Matcher<absl::string_view> // Matcher<absl::string_view>
// specializations. // specializations.
// GTEST_INTERNAL_HAS_VARIANT - for enabling UniversalPrinter<std::variant> or
// UniversalPrinter<absl::variant> specializations.
// //
// Synchronization: // Synchronization:
// Mutex, MutexLock, ThreadLocal, GetThreadCount() // Mutex, MutexLock, ThreadLocal, GetThreadCount()
@ -2251,4 +2253,34 @@ using StringView = ::std::string_view;
# endif // __has_include # endif // __has_include
#endif // GTEST_HAS_ABSL #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 <typename... T>
using Variant = ::absl::variant<T...>;
} // namespace internal
} // namespace testing
#else
# ifdef __has_include
# if __has_include(<variant>) && __cplusplus >= 201703L
// Otherwise for C++17 and higher use std::variant for UniversalPrinter<>
// specializations.
# define GTEST_INTERNAL_HAS_VARIANT 1
#include <variant>
namespace testing {
namespace internal {
template <typename... T>
using Variant = ::std::variant<T...>;
} // namespace internal
} // namespace testing
// The case where absl is configured NOT to alias std::variant is not
// supported.
# endif // __has_include(<variant>) && __cplusplus >= 201703L
# endif // __has_include
#endif // GTEST_HAS_ABSL
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_

View File

@ -1542,21 +1542,24 @@ TEST(PrintOptionalTest, Basic) {
EXPECT_EQ("(\"A\")", PrintToString(absl::optional<std::string>{"A"})); EXPECT_EQ("(\"A\")", PrintToString(absl::optional<std::string>{"A"}));
} }
#endif // GTEST_HAS_ABSL
#if GTEST_INTERNAL_HAS_VARIANT
struct NonPrintable { struct NonPrintable {
unsigned char contents = 17; unsigned char contents = 17;
}; };
TEST(PrintOneofTest, Basic) { TEST(PrintOneofTest, Basic) {
using Type = absl::variant<int, StreamableInGlobal, NonPrintable>; using Type = internal::Variant<int, StreamableInGlobal, NonPrintable>;
EXPECT_EQ("('int' with value 7)", PrintToString(Type(7))); EXPECT_EQ("('int(0)' with value 7)", PrintToString(Type(7)));
EXPECT_EQ("('StreamableInGlobal' with value StreamableInGlobal)", EXPECT_EQ("('StreamableInGlobal(1)' with value StreamableInGlobal)",
PrintToString(Type(StreamableInGlobal{}))); PrintToString(Type(StreamableInGlobal{})));
EXPECT_EQ( EXPECT_EQ(
"('testing::gtest_printers_test::NonPrintable' with value 1-byte object " "('testing::gtest_printers_test::NonPrintable(2)' with value 1-byte object "
"<11>)", "<11>)",
PrintToString(Type(NonPrintable{}))); PrintToString(Type(NonPrintable{})));
} }
#endif // GTEST_HAS_ABSL #endif // GTEST_INTERNAL_HAS_VARIANT
namespace { namespace {
class string_ref; class string_ref;