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
This commit is contained in:
parent
9c96f500a3
commit
a0e62d9f1a
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue
Block a user