From a0f06a70e3da7afa88da9527c43951bca1f7cef2 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 29 Jul 2026 11:07:53 -0700 Subject: [PATCH] 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 --- googletest/include/gtest/gtest-printers.h | 47 +++++++++++++-------- googletest/test/googletest-printers-test.cc | 20 +++++++++ 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index a13815733..fc0913ff0 100644 --- a/googletest/include/gtest/gtest-printers.h +++ b/googletest/include/gtest/gtest-printers.h @@ -945,13 +945,13 @@ template class [[nodiscard]] UniversalPrinter> { public: static void Print(const std::optional& value, ::std::ostream* os) { - *os << '('; if (!value) { - *os << "nullopt"; + UniversalPrint(std::nullopt, os); } else { + *os << '('; UniversalPrint(*value, os); + *os << ')'; } - *os << ')'; } }; @@ -961,27 +961,38 @@ class [[nodiscard]] UniversalPrinter { static void Print(std::nullopt_t, ::std::ostream* os) { *os << "(nullopt)"; } }; +struct UniversalPrinterVisitor { + template + void operator()(const T& arg) const { + *os << "'" << GetTypeName() << "(index = " << index << ")' with value "; + UniversalPrint(arg, os); + } + ::std::ostream* os; + std::size_t index; +}; + // Printer for std::variant template class [[nodiscard]] UniversalPrinter> { public: static void Print(const std::variant& value, ::std::ostream* os) { - *os << '('; - std::visit(Visitor{os, value.index()}, value); - *os << ')'; - } - - private: - struct Visitor { - template - void operator()(const U& u) const { - *os << "'" << GetTypeName() << "(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 { + 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 0b11f8e4a..928aab10f 100644 --- a/googletest/test/googletest-printers-test.cc +++ b/googletest/test/googletest-printers-test.cc @@ -2030,6 +2030,26 @@ TEST(PrintOneofTest, Basic) { 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().at(0); + return *this; + } + }; + std::variant 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));