From a0e62d9f1a5f24cbc9d16bb9d1c4b606e960b2af Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 24 Aug 2018 13:30:17 -0400 Subject: [PATCH] No longer require a functor passed to ResultOf matcher to define `result_of` type. This makes ResultOf more convenient to use. In particular, the matcher now accepts lambdas. PiperOrigin-RevId: 210118509 --- googlemock/include/gmock/gmock-matchers.h | 69 ++++++++++++----------- googlemock/test/gmock-matchers_test.cc | 18 ++++++ 2 files changed, 53 insertions(+), 34 deletions(-) diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index 3336eff2..3975cd07 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -2602,16 +2602,20 @@ class PropertyMatcher { // Type traits specifying various features of different functors for ResultOf. // The default template specifies features for functor objects. -// Functor classes have to typedef argument_type and result_type -// to be compatible with ResultOf. template struct CallableTraits { - typedef typename Functor::result_type ResultType; typedef Functor StorageType; static void CheckIsValid(Functor /* functor */) {} + +#if GTEST_LANG_CXX11 + template + static auto Invoke(Functor f, T arg) -> decltype(f(arg)) { return f(arg); } +#else + typedef typename Functor::result_type ResultType; template static ResultType Invoke(Functor f, T arg) { return f(arg); } +#endif }; // Specialization for function pointers. @@ -2632,13 +2636,11 @@ struct CallableTraits { // Implements the ResultOf() matcher for matching a return value of a // unary function of an object. -template +template class ResultOfMatcher { public: - typedef typename CallableTraits::ResultType ResultType; - - ResultOfMatcher(Callable callable, const Matcher& matcher) - : callable_(callable), matcher_(matcher) { + ResultOfMatcher(Callable callable, InnerMatcher matcher) + : callable_(internal::move(callable)), matcher_(internal::move(matcher)) { CallableTraits::CheckIsValid(callable_); } @@ -2652,9 +2654,17 @@ class ResultOfMatcher { template class Impl : public MatcherInterface { +#if GTEST_LANG_CXX11 + using ResultType = decltype(CallableTraits::template Invoke( + std::declval(), std::declval())); +#else + typedef typename CallableTraits::ResultType ResultType; +#endif + public: - Impl(CallableStorageType callable, const Matcher& matcher) - : callable_(callable), matcher_(matcher) {} + template + Impl(const CallableStorageType& callable, const M& matcher) + : callable_(callable), matcher_(MatcherCast(matcher)) {} virtual void DescribeTo(::std::ostream* os) const { *os << "is mapped by the given callable to a value that "; @@ -2668,8 +2678,10 @@ class ResultOfMatcher { virtual bool MatchAndExplain(T obj, MatchResultListener* listener) const { *listener << "which is mapped by the given callable to "; - // Cannot pass the return value (for example, int) to - // MatchPrintAndExplain, which takes a non-const reference as argument. + // Cannot pass the return value directly to MatchPrintAndExplain, which + // takes a non-const reference as argument. + // Also, specifying template argument explicitly is needed because T could + // be a non-const reference (e.g. Matcher). ResultType result = CallableTraits::template Invoke(callable_, obj); return MatchPrintAndExplain(result, matcher_, listener); @@ -2679,7 +2691,7 @@ class ResultOfMatcher { // Functors often define operator() as non-const method even though // they are actually stateless. But we need to use them even when // 'this' is a const pointer. It's the user's responsibility not to - // use stateful callables with ResultOf(), which does't guarantee + // use stateful callables with ResultOf(), which doesn't guarantee // how many times the callable will be invoked. mutable CallableStorageType callable_; const Matcher matcher_; @@ -2688,7 +2700,7 @@ class ResultOfMatcher { }; // class Impl const CallableStorageType callable_; - const Matcher matcher_; + const InnerMatcher matcher_; GTEST_DISALLOW_ASSIGN_(ResultOfMatcher); }; @@ -4554,26 +4566,15 @@ Property(const std::string& property_name, // For example, // ResultOf(f, StartsWith("hi")) // matches a Foo object x iff f(x) starts with "hi". -// callable parameter can be a function, function pointer, or a functor. -// Callable has to satisfy the following conditions: -// * It is required to keep no state affecting the results of -// the calls on it and make no assumptions about how many calls -// will be made. Any state it keeps must be protected from the -// concurrent access. -// * If it is a function object, it has to define type result_type. -// We recommend deriving your functor classes from std::unary_function. -// -template -internal::ResultOfMatcher ResultOf( - Callable callable, const ResultOfMatcher& matcher) { - return internal::ResultOfMatcher( - callable, - MatcherCast::ResultType>( - matcher)); - // The call to MatcherCast() is required for supporting inner - // matchers of compatible types. For example, it allows - // ResultOf(Function, m) - // to compile where Function() returns an int32 and m is a matcher for int64. +// `callable` parameter can be a function, function pointer, or a functor. It is +// required to keep no state affecting the results of the calls on it and make +// no assumptions about how many calls will be made. Any state it keeps must be +// protected from the concurrent access. +template +internal::ResultOfMatcher ResultOf( + Callable callable, InnerMatcher matcher) { + return internal::ResultOfMatcher( + internal::move(callable), internal::move(matcher)); } // String matchers. diff --git a/googlemock/test/gmock-matchers_test.cc b/googlemock/test/gmock-matchers_test.cc index d08f08f7..4697f0bf 100644 --- a/googlemock/test/gmock-matchers_test.cc +++ b/googlemock/test/gmock-matchers_test.cc @@ -4597,6 +4597,7 @@ struct PolymorphicFunctor { typedef int result_type; int operator()(int n) { return n; } int operator()(const char* s) { return static_cast(strlen(s)); } + std::string operator()(int *p) { return p ? "good ptr" : "null"; } }; TEST(ResultOfTest, WorksForPolymorphicFunctors) { @@ -4611,6 +4612,23 @@ TEST(ResultOfTest, WorksForPolymorphicFunctors) { EXPECT_FALSE(matcher_string.Matches("shrt")); } +#if GTEST_LANG_CXX11 +TEST(ResultOfTest, WorksForPolymorphicFunctorsIgnoringResultType) { + Matcher matcher = ResultOf(PolymorphicFunctor(), "good ptr"); + + int n = 0; + EXPECT_TRUE(matcher.Matches(&n)); + EXPECT_FALSE(matcher.Matches(nullptr)); +} + +TEST(ResultOfTest, WorksForLambdas) { + Matcher matcher = + ResultOf([](int str_len) { return std::string(str_len, 'x'); }, "xxx"); + EXPECT_TRUE(matcher.Matches(3)); + EXPECT_FALSE(matcher.Matches(1)); +} +#endif + const int* ReferencingFunction(const int& n) { return &n; } struct ReferencingFunctor {