diff options
Diffstat (limited to 'googlemock')
-rw-r--r-- | googlemock/include/gmock/gmock-matchers.h | 69 | ||||
-rw-r--r-- | 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 3336eff..3975cd0 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 <typename Functor> struct CallableTraits { - typedef typename Functor::result_type ResultType; typedef Functor StorageType; static void CheckIsValid(Functor /* functor */) {} + +#if GTEST_LANG_CXX11 + template <typename T> + static auto Invoke(Functor f, T arg) -> decltype(f(arg)) { return f(arg); } +#else + typedef typename Functor::result_type ResultType; template <typename T> static ResultType Invoke(Functor f, T arg) { return f(arg); } +#endif }; // Specialization for function pointers. @@ -2632,13 +2636,11 @@ struct CallableTraits<ResType(*)(ArgType)> { // Implements the ResultOf() matcher for matching a return value of a // unary function of an object. -template <typename Callable> +template <typename Callable, typename InnerMatcher> class ResultOfMatcher { public: - typedef typename CallableTraits<Callable>::ResultType ResultType; - - ResultOfMatcher(Callable callable, const Matcher<ResultType>& matcher) - : callable_(callable), matcher_(matcher) { + ResultOfMatcher(Callable callable, InnerMatcher matcher) + : callable_(internal::move(callable)), matcher_(internal::move(matcher)) { CallableTraits<Callable>::CheckIsValid(callable_); } @@ -2652,9 +2654,17 @@ class ResultOfMatcher { template <typename T> class Impl : public MatcherInterface<T> { +#if GTEST_LANG_CXX11 + using ResultType = decltype(CallableTraits<Callable>::template Invoke<T>( + std::declval<CallableStorageType>(), std::declval<T>())); +#else + typedef typename CallableTraits<Callable>::ResultType ResultType; +#endif + public: - Impl(CallableStorageType callable, const Matcher<ResultType>& matcher) - : callable_(callable), matcher_(matcher) {} + template <typename M> + Impl(const CallableStorageType& callable, const M& matcher) + : callable_(callable), matcher_(MatcherCast<ResultType>(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<Uncopyable&>). ResultType result = CallableTraits<Callable>::template Invoke<T>(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<ResultType> matcher_; @@ -2688,7 +2700,7 @@ class ResultOfMatcher { }; // class Impl const CallableStorageType callable_; - const Matcher<ResultType> 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 <typename Callable, typename ResultOfMatcher> -internal::ResultOfMatcher<Callable> ResultOf( - Callable callable, const ResultOfMatcher& matcher) { - return internal::ResultOfMatcher<Callable>( - callable, - MatcherCast<typename internal::CallableTraits<Callable>::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 <typename Callable, typename InnerMatcher> +internal::ResultOfMatcher<Callable, InnerMatcher> ResultOf( + Callable callable, InnerMatcher matcher) { + return internal::ResultOfMatcher<Callable, InnerMatcher>( + 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 d08f08f..4697f0b 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<int>(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<int*> matcher = ResultOf(PolymorphicFunctor(), "good ptr"); + + int n = 0; + EXPECT_TRUE(matcher.Matches(&n)); + EXPECT_FALSE(matcher.Matches(nullptr)); +} + +TEST(ResultOfTest, WorksForLambdas) { + Matcher<int> 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 { |