Merge pull request #2837 from inazarenko:duck_type_protos

PiperOrigin-RevId: 336087297
This commit is contained in:
Derek Mauro 2020-10-14 18:25:04 -04:00
commit 4abb012c70
3 changed files with 91 additions and 20 deletions

View File

@ -235,8 +235,9 @@ struct ProtobufPrinter {
// DebugString() for better readability.
static const size_t kProtobufOneLinerMaxLength = 50;
template <typename T, typename = typename std::enable_if<
internal::IsAProtocolMessage<T>::value>::type>
template <typename T,
typename = typename std::enable_if<
internal::HasDebugStringAndShortDebugString<T>::value>::type>
static void PrintValue(const T& value, ::std::ostream* os) {
std::string pretty_str = value.ShortDebugString();
if (pretty_str.length() > kProtobufOneLinerMaxLength) {

View File

@ -892,11 +892,34 @@ class GTEST_API_ Random {
#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \
typename std::remove_const<typename std::remove_reference<T>::type>::type
// IsAProtocolMessage<T>::value is a compile-time bool constant that's
// true if and only if T is type proto2::MessageLite or a subclass of it.
// HasDebugStringAndShortDebugString<T>::value is a compile-time bool constant
// that's true if and only if T has methods DebugString() and ShortDebugString()
// that return std::string.
template <typename T>
struct IsAProtocolMessage
: public std::is_convertible<const T*, const ::proto2::MessageLite*> {};
class HasDebugStringAndShortDebugString {
private:
template <typename C>
static constexpr auto CheckDebugString(C*) -> typename std::is_same<
std::string, decltype(std::declval<const C>().DebugString())>::type;
template <typename>
static constexpr std::false_type CheckDebugString(...);
template <typename C>
static constexpr auto CheckShortDebugString(C*) -> typename std::is_same<
std::string, decltype(std::declval<const C>().ShortDebugString())>::type;
template <typename>
static constexpr std::false_type CheckShortDebugString(...);
using HasDebugStringType = decltype(CheckDebugString<T>(nullptr));
using HasShortDebugStringType = decltype(CheckShortDebugString<T>(nullptr));
public:
static constexpr bool value =
HasDebugStringType::value && HasShortDebugStringType::value;
};
template <typename T>
constexpr bool HasDebugStringAndShortDebugString<T>::value;
// When the compiler sees expression IsContainerTest<C>(0), if C is an
// STL-style container class, the first overload of IsContainerTest

View File

@ -254,8 +254,8 @@ using testing::internal::GetTimeInMillis;
using testing::internal::GetTypeId;
using testing::internal::GetUnitTestImpl;
using testing::internal::GTestFlagSaver;
using testing::internal::HasDebugStringAndShortDebugString;
using testing::internal::Int32FromEnvOrDie;
using testing::internal::IsAProtocolMessage;
using testing::internal::IsContainer;
using testing::internal::IsContainerTest;
using testing::internal::IsNotContainer;
@ -7185,24 +7185,71 @@ GTEST_TEST(AlternativeNameTest, Works) { // GTEST_TEST is the same as TEST.
class ConversionHelperBase {};
class ConversionHelperDerived : public ConversionHelperBase {};
// Tests that IsAProtocolMessage<T>::value is a compile-time constant.
TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) {
GTEST_COMPILE_ASSERT_(IsAProtocolMessage<::proto2::MessageLite>::value,
struct HasDebugStringMethods {
std::string DebugString() const { return ""; }
std::string ShortDebugString() const { return ""; }
};
struct InheritsDebugStringMethods : public HasDebugStringMethods {};
struct WrongTypeDebugStringMethod {
std::string DebugString() const { return ""; }
int ShortDebugString() const { return 1; }
};
struct NotConstDebugStringMethod {
std::string DebugString() { return ""; }
std::string ShortDebugString() const { return ""; }
};
struct MissingDebugStringMethod {
std::string DebugString() { return ""; }
};
struct IncompleteType;
// Tests that HasDebugStringAndShortDebugString<T>::value is a compile-time
// constant.
TEST(HasDebugStringAndShortDebugStringTest, ValueIsCompileTimeConstant) {
GTEST_COMPILE_ASSERT_(
HasDebugStringAndShortDebugString<HasDebugStringMethods>::value,
const_true);
GTEST_COMPILE_ASSERT_(
HasDebugStringAndShortDebugString<InheritsDebugStringMethods>::value,
const_true);
GTEST_COMPILE_ASSERT_(HasDebugStringAndShortDebugString<
const InheritsDebugStringMethods>::value,
const_true);
GTEST_COMPILE_ASSERT_(!IsAProtocolMessage<int>::value, const_false);
GTEST_COMPILE_ASSERT_(
!HasDebugStringAndShortDebugString<WrongTypeDebugStringMethod>::value,
const_false);
GTEST_COMPILE_ASSERT_(
!HasDebugStringAndShortDebugString<NotConstDebugStringMethod>::value,
const_false);
GTEST_COMPILE_ASSERT_(
!HasDebugStringAndShortDebugString<MissingDebugStringMethod>::value,
const_false);
GTEST_COMPILE_ASSERT_(
!HasDebugStringAndShortDebugString<IncompleteType>::value, const_false);
GTEST_COMPILE_ASSERT_(!HasDebugStringAndShortDebugString<int>::value,
const_false);
}
// Tests that IsAProtocolMessage<T>::value is true when T is
// proto2::Message or a sub-class of it.
TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) {
EXPECT_TRUE(IsAProtocolMessage<::proto2::MessageLite>::value);
// Tests that HasDebugStringAndShortDebugString<T>::value is true when T has
// needed methods.
TEST(HasDebugStringAndShortDebugStringTest,
ValueIsTrueWhenTypeHasDebugStringAndShortDebugString) {
EXPECT_TRUE(
HasDebugStringAndShortDebugString<InheritsDebugStringMethods>::value);
}
// Tests that IsAProtocolMessage<T>::value is false when T is neither
// ::proto2::Message nor a sub-class of it.
TEST(IsAProtocolMessageTest, ValueIsFalseWhenTypeIsNotAProtocolMessage) {
EXPECT_FALSE(IsAProtocolMessage<int>::value);
EXPECT_FALSE(IsAProtocolMessage<const ConversionHelperBase>::value);
// Tests that HasDebugStringAndShortDebugString<T>::value is false when T
// doesn't have needed methods.
TEST(HasDebugStringAndShortDebugStringTest,
ValueIsFalseWhenTypeIsNotAProtocolMessage) {
EXPECT_FALSE(HasDebugStringAndShortDebugString<int>::value);
EXPECT_FALSE(
HasDebugStringAndShortDebugString<const ConversionHelperBase>::value);
}
// Tests GTEST_REMOVE_REFERENCE_AND_CONST_.