Make GoogleTest handle std::monostate and valueless_by_exception() for std::variant similarly to how it handles std::nullopt Fixes: #2066 PiperOrigin-RevId: 955981465 Change-Id: I6b34dc2e634d4b727a50fb3e21e5d8e25c39a13b
diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index a138157..fc0913f 100644 --- a/googletest/include/gtest/gtest-printers.h +++ b/googletest/include/gtest/gtest-printers.h
@@ -945,13 +945,13 @@ class [[nodiscard]] UniversalPrinter<std::optional<T>> { public: static void Print(const std::optional<T>& value, ::std::ostream* os) { - *os << '('; if (!value) { - *os << "nullopt"; + UniversalPrint(std::nullopt, os); } else { + *os << '('; UniversalPrint(*value, os); + *os << ')'; } - *os << ')'; } }; @@ -961,27 +961,38 @@ static void Print(std::nullopt_t, ::std::ostream* os) { *os << "(nullopt)"; } }; +struct UniversalPrinterVisitor { + template <typename T> + void operator()(const T& arg) const { + *os << "'" << GetTypeName<T>() << "(index = " << index << ")' with value "; + UniversalPrint(arg, os); + } + ::std::ostream* os; + std::size_t index; +}; + // Printer for std::variant template <typename... T> class [[nodiscard]] UniversalPrinter<std::variant<T...>> { public: static void Print(const std::variant<T...>& value, ::std::ostream* os) { - *os << '('; - std::visit(Visitor{os, value.index()}, value); - *os << ')'; - } - - private: - struct Visitor { - template <typename U> - void operator()(const U& u) const { - *os << "'" << GetTypeName<U>() << "(index = " << index - << ")' with value "; - UniversalPrint(u, os); + if (value.valueless_by_exception()) { + *os << "(valueless)"; + } else { + *os << '('; + std::visit(UniversalPrinterVisitor{os, value.index()}, value); + *os << ')'; } - ::std::ostream* os; - std::size_t index; - }; + } +}; + +// Printer for std::monostate +template <> +class [[nodiscard]] UniversalPrinter<std::monostate> { + public: + static void Print(std::monostate, ::std::ostream* os) { + *os << "(monostate)"; + } }; // UniversalPrintArray(begin, len, os) prints an array of 'len'
diff --git a/googletest/test/googletest-printers-test.cc b/googletest/test/googletest-printers-test.cc index 0b11f8e..928aab1 100644 --- a/googletest/test/googletest-printers-test.cc +++ b/googletest/test/googletest-printers-test.cc
@@ -2030,6 +2030,26 @@ PrintToString(Type(NonPrintable{}))); } +TEST(PrintVariantTest, Monostate) { + EXPECT_EQ("(monostate)", PrintToString(std::monostate())); + +#if GTEST_HAS_EXCEPTIONS + struct ThrowOnMove { + ThrowOnMove() = default; + ThrowOnMove(ThrowOnMove&& other) { *this = std::move(other); } + ThrowOnMove& operator=(ThrowOnMove&&) { + (void)std::vector<bool>().at(0); + return *this; + } + }; + std::variant<std::monostate, ThrowOnMove> v = std::monostate(); + EXPECT_EQ("('std::monostate(index = 0)' with value (monostate))", + PrintToString(v)); + EXPECT_THROW(v = ThrowOnMove(), std::out_of_range); + EXPECT_EQ("(valueless)", PrintToString(v)); +#endif +} + #if GTEST_INTERNAL_HAS_COMPARE_LIB TEST(PrintOrderingTest, Basic) { EXPECT_EQ("(less)", PrintToString(std::strong_ordering::less));