Make testing::Message support streamed AbslStringify values

This allows types that provide an AbslStringify definition to be streamed into GoogleTest macros.

PiperOrigin-RevId: 552914482
Change-Id: I5fb386980d4d24873f95f0a8ef83067a6a3c86ac
This commit is contained in:
Phoebe Liang 2023-08-01 14:01:00 -07:00 committed by Copybara-Service
parent 717d8ab5e0
commit e7fd109b53
2 changed files with 57 additions and 2 deletions

View File

@ -56,6 +56,13 @@
#include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-port.h"
#ifdef GTEST_HAS_ABSL
#include <type_traits>
#include "absl/strings/internal/has_absl_stringify.h"
#include "absl/strings/str_cat.h"
#endif // GTEST_HAS_ABSL
GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
/* class A needs to have dll-interface to be used by clients of class B */) /* class A needs to have dll-interface to be used by clients of class B */)
@ -111,8 +118,17 @@ class GTEST_API_ Message {
*ss_ << str; *ss_ << str;
} }
// Streams a non-pointer value to this object. // Streams a non-pointer value to this object. If building a version of
template <typename T> // GoogleTest with ABSL, this overload is only enabled if the value does not
// have an AbslStringify definition.
template <typename T
#ifdef GTEST_HAS_ABSL
,
typename std::enable_if<
!absl::strings_internal::HasAbslStringify<T>::value, // NOLINT
int>::type = 0
#endif // GTEST_HAS_ABSL
>
inline Message& operator<<(const T& val) { inline Message& operator<<(const T& val) {
// Some libraries overload << for STL containers. These // Some libraries overload << for STL containers. These
// overloads are defined in the global namespace instead of ::std. // overloads are defined in the global namespace instead of ::std.
@ -133,6 +149,22 @@ class GTEST_API_ Message {
return *this; return *this;
} }
#ifdef GTEST_HAS_ABSL
// Streams a non-pointer value with an AbslStringify definition to this
// object.
template <typename T,
typename std::enable_if<
absl::strings_internal::HasAbslStringify<T>::value, // NOLINT
int>::type = 0>
inline Message& operator<<(const T& val) {
// ::operator<< is needed here for a similar reason as with the non-Abseil
// version above
using ::operator<<;
*ss_ << absl::StrCat(val);
return *this;
}
#endif // GTEST_HAS_ABSL
// Streams a pointer value to this object. // Streams a pointer value to this object.
// //
// This function is an overload of the previous one. When you // This function is an overload of the previous one. When you

View File

@ -36,10 +36,26 @@
#include "gtest/gtest-message.h" #include "gtest/gtest-message.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#ifdef GTEST_HAS_ABSL
#include "absl/strings/str_format.h"
#endif // GTEST_HAS_ABSL
namespace { namespace {
using ::testing::Message; using ::testing::Message;
#ifdef GTEST_HAS_ABSL
struct AbslStringifiablePoint {
template <typename Sink>
friend void AbslStringify(Sink& sink, const AbslStringifiablePoint& p) {
absl::Format(&sink, "(%d, %d)", p.x, p.y);
}
int x;
int y;
};
#endif // GTEST_HAS_ABSL
// Tests the testing::Message class // Tests the testing::Message class
// Tests the default constructor. // Tests the default constructor.
@ -128,6 +144,13 @@ TEST(MessageTest, StreamsInt) {
EXPECT_EQ("123", (Message() << 123).GetString()); EXPECT_EQ("123", (Message() << 123).GetString());
} }
#ifdef GTEST_HAS_ABSL
// Tests streaming a type with an AbslStringify definition.
TEST(MessageTest, StreamsAbslStringify) {
EXPECT_EQ("(1, 2)", (Message() << AbslStringifiablePoint{1, 2}).GetString());
}
#endif // GTEST_HAS_ABSL
// Tests that basic IO manipulators (endl, ends, and flush) can be // Tests that basic IO manipulators (endl, ends, and flush) can be
// streamed to Message. // streamed to Message.
TEST(MessageTest, StreamsBasicIoManip) { TEST(MessageTest, StreamsBasicIoManip) {