From 466a49ae305145cf1fa32d172e4f5e8919ee6f4d Mon Sep 17 00:00:00 2001 From: Gennadiy Civil Date: Fri, 23 Mar 2018 11:23:54 -0400 Subject: [PATCH] gmock-matchers merging -2 --- googlemock/include/gmock/gmock-matchers.h | 260 +++++++++++++++++++++- 1 file changed, 250 insertions(+), 10 deletions(-) diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index 044a323e..dea1070c 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -179,6 +179,35 @@ class MatcherInterface : public MatcherDescriberInterface { // virtual void DescribeNegationTo(::std::ostream* os) const; }; +namespace internal { + +// Converts a MatcherInterface to a MatcherInterface. +template +class MatcherInterfaceAdapter : public MatcherInterface { + public: + explicit MatcherInterfaceAdapter(const MatcherInterface* impl) + : impl_(impl) {} + virtual ~MatcherInterfaceAdapter() { delete impl_; } + + virtual void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); } + + virtual void DescribeNegationTo(::std::ostream* os) const { + impl_->DescribeNegationTo(os); + } + + virtual bool MatchAndExplain(const T& x, + MatchResultListener* listener) const { + return impl_->MatchAndExplain(x, listener); + } + + private: + const MatcherInterface* const impl_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MatcherInterfaceAdapter); +}; + +} // namespace internal + // A match result listener that stores the explanation in a string. class StringMatchResultListener : public MatchResultListener { public: @@ -290,6 +319,14 @@ class MatcherBase { explicit MatcherBase(const MatcherInterface* impl) : impl_(impl) {} + template + explicit MatcherBase( + const MatcherInterface* impl, + typename internal::EnableIf< + !internal::IsSame::value>::type* = + NULL) + : impl_(new internal::MatcherInterfaceAdapter(impl)) {} + virtual ~MatcherBase() {} private: @@ -551,21 +588,18 @@ class MatcherCastImpl { return CastImpl( polymorphic_matcher_or_value, BooleanConstant< - internal::ImplicitlyConvertible >::value>()); + internal::ImplicitlyConvertible >::value>(), + BooleanConstant< + internal::ImplicitlyConvertible::value>()); } private: - static Matcher CastImpl(const M& value, BooleanConstant) { - // M can't be implicitly converted to Matcher, so M isn't a polymorphic - // matcher. It must be a value then. Use direct initialization to create - // a matcher. - return Matcher(ImplicitCast_(value)); - } - + template static Matcher CastImpl(const M& polymorphic_matcher_or_value, - BooleanConstant) { + BooleanConstant /* convertible_to_matcher */, + BooleanConstant) { // M is implicitly convertible to Matcher, which means that either - // M is a polymorhpic matcher or Matcher has an implicit constructor + // M is a polymorphic matcher or Matcher has an implicit constructor // from M. In both cases using the implicit conversion will produce a // matcher. // @@ -574,6 +608,29 @@ class MatcherCastImpl { // (first to create T from M and then to create Matcher from T). return polymorphic_matcher_or_value; } + + // M can't be implicitly converted to Matcher, so M isn't a polymorphic + // matcher. It's a value of a type implicitly convertible to T. Use direct + // initialization to create a matcher. + static Matcher CastImpl( + const M& value, BooleanConstant /* convertible_to_matcher */, + BooleanConstant /* convertible_to_T */) { + return Matcher(ImplicitCast_(value)); + } + + // M can't be implicitly converted to either Matcher or T. Attempt to use + // polymorphic matcher Eq(value) in this case. + // + // Note that we first attempt to perform an implicit cast on the value and + // only fall back to the polymorphic Eq() matcher afterwards because the + // latter calls bool operator==(const Lhs& lhs, const Rhs& rhs) in the end + // which might be undefined even when Rhs is implicitly convertible to Lhs + // (e.g. std::pair vs. std::pair). + // + // We don't define this method inline as we need the declaration of Eq(). + static Matcher CastImpl( + const M& value, BooleanConstant /* convertible_to_matcher */, + BooleanConstant /* convertible_to_T */); }; // This more specialized version is used when MatcherCast()'s argument @@ -2057,6 +2114,78 @@ class FloatingEqMatcher { GTEST_DISALLOW_ASSIGN_(FloatingEqMatcher); }; +// A 2-tuple ("binary") wrapper around FloatingEqMatcher: +// FloatingEq2Matcher() matches (x, y) by matching FloatingEqMatcher(x, false) +// against y, and FloatingEq2Matcher(e) matches FloatingEqMatcher(x, false, e) +// against y. The former implements "Eq", the latter "Near". At present, there +// is no version that compares NaNs as equal. +template +class FloatingEq2Matcher { + public: + FloatingEq2Matcher() : FloatingEq2Matcher(-1, false) {} + + explicit FloatingEq2Matcher(bool nan_eq_nan) + : FloatingEq2Matcher(-1, nan_eq_nan) {} + + explicit FloatingEq2Matcher(FloatType max_abs_error) + : FloatingEq2Matcher(max_abs_error, false) {} + + FloatingEq2Matcher(FloatType max_abs_error, bool nan_eq_nan) + : max_abs_error_(max_abs_error), + nan_eq_nan_(nan_eq_nan) {} + + template + operator Matcher< ::testing::tuple >() const { + return MakeMatcher( + new Impl< ::testing::tuple >(max_abs_error_, nan_eq_nan_)); + } + template + operator Matcher&>() const { + return MakeMatcher( + new Impl&>(max_abs_error_, nan_eq_nan_)); + } + + private: + static ::std::ostream& GetDesc(::std::ostream& os) { // NOLINT + return os << "an almost-equal pair"; + } + + template + class Impl : public MatcherInterface { + public: + Impl(FloatType max_abs_error, bool nan_eq_nan) : + max_abs_error_(max_abs_error), + nan_eq_nan_(nan_eq_nan) {} + + virtual bool MatchAndExplain(Tuple args, + MatchResultListener* listener) const { + if (max_abs_error_ == -1) { + FloatingEqMatcher fm(::testing::get<0>(args), nan_eq_nan_); + return static_cast >(fm).MatchAndExplain( + ::testing::get<1>(args), listener); + } else { + FloatingEqMatcher fm(::testing::get<0>(args), nan_eq_nan_, + max_abs_error_); + return static_cast >(fm).MatchAndExplain( + ::testing::get<1>(args), listener); + } + } + virtual void DescribeTo(::std::ostream* os) const { + *os << "are " << GetDesc; + } + virtual void DescribeNegationTo(::std::ostream* os) const { + *os << "aren't " << GetDesc; + } + + private: + FloatType max_abs_error_; + const bool nan_eq_nan_; + }; + + FloatType max_abs_error_; + const bool nan_eq_nan_; +}; + // Implements the Pointee(m) matcher for matching a pointer whose // pointee matches matcher m. The pointer can be either raw or smart. template @@ -2953,6 +3082,50 @@ class EachMatcher { GTEST_DISALLOW_ASSIGN_(EachMatcher); }; +struct Rank1 {}; +struct Rank0 : Rank1 {}; + +namespace pair_getters { +#if GTEST_LANG_CXX11 +using std::get; +template +auto First(T& x, Rank1) -> decltype(get<0>(x)) { // NOLINT + return get<0>(x); +} +template +auto First(T& x, Rank0) -> decltype((x.first)) { // NOLINT + return x.first; +} + +template +auto Second(T& x, Rank1) -> decltype(get<1>(x)) { // NOLINT + return get<1>(x); +} +template +auto Second(T& x, Rank0) -> decltype((x.second)) { // NOLINT + return x.second; +} +#else +template +typename T::first_type& First(T& x, Rank0) { // NOLINT + return x.first; +} +template +const typename T::first_type& First(const T& x, Rank0) { + return x.first; +} + +template +typename T::second_type& Second(T& x, Rank0) { // NOLINT + return x.second; +} +template +const typename T::second_type& Second(const T& x, Rank0) { + return x.second; +} +#endif // GTEST_LANG_CXX11 +} // namespace pair_getters + // Implements Key(inner_matcher) for the given argument pair type. // Key(inner_matcher) matches an std::pair whose 'first' field matches // inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an @@ -3717,6 +3890,65 @@ class VariantMatcher { } // namespace variant_matcher +namespace any_cast_matcher { + +// Overloads to allow AnyCastMatcher to do proper ADL lookup. +template +void any_cast() {} + +// Implements a matcher that any_casts the value. +template +class AnyCastMatcher { + public: + explicit AnyCastMatcher(const ::testing::Matcher& matcher) + : matcher_(matcher) {} + + template + bool MatchAndExplain(const AnyType& value, + ::testing::MatchResultListener* listener) const { + if (!listener->IsInterested()) { + const T* ptr = any_cast(&value); + return ptr != NULL && matcher_.Matches(*ptr); + } + + const T* elem = any_cast(&value); + if (elem == NULL) { + *listener << "whose value is not of type '" << GetTypeName() << "'"; + return false; + } + + StringMatchResultListener elem_listener; + const bool match = matcher_.MatchAndExplain(*elem, &elem_listener); + *listener << "whose value " << PrintToString(*elem) + << (match ? " matches" : " doesn't match"); + PrintIfNotEmpty(elem_listener.str(), listener->stream()); + return match; + } + + void DescribeTo(std::ostream* os) const { + *os << "is an 'any' type with value of type '" << GetTypeName() + << "' and the value "; + matcher_.DescribeTo(os); + } + + void DescribeNegationTo(std::ostream* os) const { + *os << "is an 'any' type with value of type other than '" << GetTypeName() + << "' or the value "; + matcher_.DescribeNegationTo(os); + } + + private: + static std::string GetTypeName() { +#if GTEST_HAS_RTTI + return internal::GetTypeName(); +#endif + return "the element type"; + } + + const ::testing::Matcher matcher_; +}; + +} // namespace any_cast_matcher } // namespace internal // ElementsAreArray(iterator_first, iterator_last) @@ -3848,6 +4080,14 @@ inline internal::EqMatcher Eq(T x) { return internal::EqMatcher(x); } template Matcher::Matcher(T value) { *this = Eq(value); } +template +Matcher internal::MatcherCastImpl::CastImpl( + const M& value, + internal::BooleanConstant /* convertible_to_matcher */, + internal::BooleanConstant /* convertible_to_T */) { + return Eq(value); +} + // Creates a monomorphic matcher that matches anything with type Lhs // and equal to rhs. A user may need to use this instead of Eq(...) // in order to resolve an overloading ambiguity.