mirror of
https://github.com/google/googletest.git
synced 2026-07-21 14:43:35 +00:00
Specialize testing::WhenDynamicCastTo for protobuf messages.
Protobuf messages have a custom dynamic_cast, for when RTTI is not available on the messages. PiperOrigin-RevId: 933270097 Change-Id: Iaeb50bce3fe1b746306a7507ab1985b111c03416
This commit is contained in:
committed by
Copybara-Service
parent
44f22083d7
commit
0b1e895ba4
@@ -275,6 +275,7 @@
|
||||
#include "gmock/internal/gmock-internal-utils.h"
|
||||
#include "gmock/internal/gmock-pp.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
|
||||
// MSVC warning C5046 is new as of VS2017 version 15.8.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1915
|
||||
@@ -2059,6 +2060,15 @@ class [[nodiscard]] PointerMatcher {
|
||||
};
|
||||
|
||||
#if GTEST_HAS_RTTI
|
||||
// A type trait to essentially determine if `DynamicCastMessage` is available,
|
||||
// since older versions of protobuf don't have this function.
|
||||
template <typename T, typename = void>
|
||||
static constexpr bool kHasDynamicCastMessage = false;
|
||||
template <typename T>
|
||||
static constexpr bool kHasDynamicCastMessage<
|
||||
T, std::void_t<decltype(proto2::DynamicCastMessage<T>(
|
||||
std::declval<const proto2::MessageLite*>()))>> = true;
|
||||
|
||||
// Implements the WhenDynamicCastTo<T>(m) matcher that matches a pointer or
|
||||
// reference that matches inner_matcher when dynamic_cast<T> is applied.
|
||||
// The result of dynamic_cast<To> is forwarded to the inner matcher.
|
||||
@@ -2086,6 +2096,27 @@ class [[nodiscard]] WhenDynamicCastToMatcherBase {
|
||||
|
||||
static std::string GetToName() { return GetTypeName<To>(); }
|
||||
|
||||
template <typename From>
|
||||
static auto DoDynamicCast(From& from) {
|
||||
using ToType =
|
||||
std::remove_const_t<std::remove_reference_t<std::remove_pointer_t<To>>>;
|
||||
|
||||
if constexpr (std::is_base_of_v<proto2::MessageLite, ToType> &&
|
||||
kHasDynamicCastMessage<ToType>) {
|
||||
if constexpr (std::is_pointer_v<From>) {
|
||||
return proto2::DynamicCastMessage<ToType>(from);
|
||||
} else {
|
||||
// We don't want an std::bad_cast here, so do the cast with pointers.
|
||||
return proto2::DynamicCastMessage<ToType>(&from);
|
||||
}
|
||||
} else if constexpr (std::is_pointer_v<To>) {
|
||||
return dynamic_cast<To>(from);
|
||||
} else {
|
||||
// We don't want an std::bad_cast here, so do the cast with pointers.
|
||||
return dynamic_cast<std::remove_reference_t<To>*>(&from);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static void GetCastTypeDescription(::std::ostream* os) {
|
||||
*os << "when dynamic_cast to " << GetToName() << ", ";
|
||||
@@ -2103,7 +2134,7 @@ class [[nodiscard]] WhenDynamicCastToMatcher
|
||||
|
||||
template <typename From>
|
||||
bool MatchAndExplain(From from, MatchResultListener* listener) const {
|
||||
To to = dynamic_cast<To>(from);
|
||||
To to = this->DoDynamicCast(from);
|
||||
return MatchPrintAndExplain(to, this->matcher_, listener);
|
||||
}
|
||||
};
|
||||
@@ -2119,8 +2150,7 @@ WhenDynamicCastToMatcher<To&> : public WhenDynamicCastToMatcherBase<To&> {
|
||||
|
||||
template <typename From>
|
||||
bool MatchAndExplain(From& from, MatchResultListener* listener) const {
|
||||
// We don't want an std::bad_cast here, so do the cast with pointers.
|
||||
To* to = dynamic_cast<To*>(&from);
|
||||
To* to = this->DoDynamicCast(from);
|
||||
if (to == nullptr) {
|
||||
*listener << "which cannot be dynamic_cast to " << this->GetToName();
|
||||
return false;
|
||||
|
||||
@@ -96,6 +96,12 @@
|
||||
|
||||
namespace proto2 {
|
||||
class [[nodiscard]] MessageLite;
|
||||
|
||||
// Dummy forward declaration of `DynamicCastMessage`. Does not match any actual
|
||||
// overloads of `DynamicCastMessage`, but can be used to assist name resolution
|
||||
// in templates.
|
||||
template <typename T>
|
||||
T DynamicCastMessage() = delete;
|
||||
}
|
||||
|
||||
namespace testing {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
edition = "2024";
|
||||
|
||||
package testing.internal.dynamic_cast_message_test;
|
||||
|
||||
message FooMessage {
|
||||
int32 int_field = 1;
|
||||
}
|
||||
|
||||
message BarMessage {}
|
||||
Reference in New Issue
Block a user