Add support for move-only and &&-qualified actions in WillOnce.
This provides a type-safe way for an action to express that it wants to be called only once, or to capture move-only objects. It is a generalization of the type system-evading hack in ByMove, with the improvement that it works for _any_ action (including user-defined ones), and correctly expresses that the action can only be used with WillOnce. I'll make existing actions benefit in a future commit. PiperOrigin-RevId: 440496139 Change-Id: I4145d191cca5655995ef41360bb126c123cb41d3
This commit is contained in:
parent
5f467ec04d
commit
a1cc8c5519
@ -248,7 +248,9 @@ EXPECT_CALL(my_mock, GetNumber())
|
|||||||
.WillOnce(Return(3));
|
.WillOnce(Return(3));
|
||||||
```
|
```
|
||||||
|
|
||||||
The `WillOnce` clause can be used any number of times on an expectation.
|
The `WillOnce` clause can be used any number of times on an expectation. Unlike
|
||||||
|
`WillRepeatedly`, the action fed to each `WillOnce` call will be called at most
|
||||||
|
once, so may be a move-only type and/or have an `&&`-qualified call operator.
|
||||||
|
|
||||||
#### WillRepeatedly {#EXPECT_CALL.WillRepeatedly}
|
#### WillRepeatedly {#EXPECT_CALL.WillRepeatedly}
|
||||||
|
|
||||||
|
@ -262,9 +262,65 @@ GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0);
|
|||||||
|
|
||||||
#undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_
|
#undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_
|
||||||
|
|
||||||
// Simple two-arg form of std::disjunction.
|
// Partial implementations of metaprogramming types from the standard library
|
||||||
template <typename P, typename Q>
|
// not available in C++11.
|
||||||
using disjunction = typename ::std::conditional<P::value, P, Q>::type;
|
|
||||||
|
template <typename P>
|
||||||
|
struct negation
|
||||||
|
// NOLINTNEXTLINE
|
||||||
|
: std::integral_constant<bool, bool(!P::value)> {};
|
||||||
|
|
||||||
|
// Base case: with zero predicates the answer is always true.
|
||||||
|
template <typename...>
|
||||||
|
struct conjunction : std::true_type {};
|
||||||
|
|
||||||
|
// With a single predicate, the answer is that predicate.
|
||||||
|
template <typename P1>
|
||||||
|
struct conjunction<P1> : P1 {};
|
||||||
|
|
||||||
|
// With multiple predicates the answer is the first predicate if that is false,
|
||||||
|
// and we recurse otherwise.
|
||||||
|
template <typename P1, typename... Ps>
|
||||||
|
struct conjunction<P1, Ps...>
|
||||||
|
: std::conditional<bool(P1::value), conjunction<Ps...>, P1>::type {};
|
||||||
|
|
||||||
|
template <typename...>
|
||||||
|
struct disjunction : std::false_type {};
|
||||||
|
|
||||||
|
template <typename P1>
|
||||||
|
struct disjunction<P1> : P1 {};
|
||||||
|
|
||||||
|
template <typename P1, typename... Ps>
|
||||||
|
struct disjunction<P1, Ps...>
|
||||||
|
// NOLINTNEXTLINE
|
||||||
|
: std::conditional<!bool(P1::value), disjunction<Ps...>, P1>::type {};
|
||||||
|
|
||||||
|
template <typename...>
|
||||||
|
using void_t = void;
|
||||||
|
|
||||||
|
// Like std::invoke_result_t from C++17, but works only for objects with call
|
||||||
|
// operators (not e.g. member function pointers, which we don't need specific
|
||||||
|
// support for in OnceAction because std::function deals with them).
|
||||||
|
template <typename F, typename... Args>
|
||||||
|
using call_result_t = decltype(std::declval<F>()(std::declval<Args>()...));
|
||||||
|
|
||||||
|
template <typename Void, typename R, typename F, typename... Args>
|
||||||
|
struct is_callable_r_impl : std::false_type {};
|
||||||
|
|
||||||
|
// Specialize the struct for those template arguments where call_result_t is
|
||||||
|
// well-formed. When it's not, the generic template above is chosen, resulting
|
||||||
|
// in std::false_type.
|
||||||
|
template <typename R, typename F, typename... Args>
|
||||||
|
struct is_callable_r_impl<void_t<call_result_t<F, Args...>>, R, F, Args...>
|
||||||
|
: std::conditional<
|
||||||
|
std::is_same<R, void>::value, //
|
||||||
|
std::true_type, //
|
||||||
|
std::is_convertible<call_result_t<F, Args...>, R>>::type {};
|
||||||
|
|
||||||
|
// Like std::is_invocable_r from C++17, but works only for objects with call
|
||||||
|
// operators. See the note on call_result_t.
|
||||||
|
template <typename R, typename F, typename... Args>
|
||||||
|
using is_callable_r = is_callable_r_impl<void, R, F, Args...>;
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
@ -596,6 +652,213 @@ inline PolymorphicAction<Impl> MakePolymorphicAction(const Impl& impl) {
|
|||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
class TypedExpectation;
|
||||||
|
|
||||||
|
// Specialized for function types below.
|
||||||
|
template <typename F>
|
||||||
|
class OnceAction;
|
||||||
|
|
||||||
|
// An action that can only be used once.
|
||||||
|
//
|
||||||
|
// This is what is accepted by WillOnce, which doesn't require the underlying
|
||||||
|
// action to be copy-constructible (only move-constructible), and promises to
|
||||||
|
// invoke it as an rvalue reference. This allows the action to work with
|
||||||
|
// move-only types like std::move_only_function in a type-safe manner.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// // Assume we have some API that needs to accept a unique pointer to some
|
||||||
|
// // non-copyable object Foo.
|
||||||
|
// void AcceptUniquePointer(std::unique_ptr<Foo> foo);
|
||||||
|
//
|
||||||
|
// // We can define an action that provides a Foo to that API. Because It
|
||||||
|
// // has to give away its unique pointer, it must not be called more than
|
||||||
|
// // once, so its call operator is &&-qualified.
|
||||||
|
// struct ProvideFoo {
|
||||||
|
// std::unique_ptr<Foo> foo;
|
||||||
|
//
|
||||||
|
// void operator()() && {
|
||||||
|
// AcceptUniquePointer(std::move(Foo));
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// // This action can be used with WillOnce.
|
||||||
|
// EXPECT_CALL(mock, Call)
|
||||||
|
// .WillOnce(ProvideFoo{std::make_unique<Foo>(...)});
|
||||||
|
//
|
||||||
|
// // But a call to WillRepeatedly will fail to compile. This is correct,
|
||||||
|
// // since the action cannot correctly be used repeatedly.
|
||||||
|
// EXPECT_CALL(mock, Call)
|
||||||
|
// .WillRepeatedly(ProvideFoo{std::make_unique<Foo>(...)});
|
||||||
|
//
|
||||||
|
// A less-contrived example would be an action that returns an arbitrary type,
|
||||||
|
// whose &&-qualified call operator is capable of dealing with move-only types.
|
||||||
|
template <typename Result, typename... Args>
|
||||||
|
class OnceAction<Result(Args...)> final {
|
||||||
|
private:
|
||||||
|
// True iff we can use the given callable type (or lvalue reference) directly
|
||||||
|
// via ActionAdaptor.
|
||||||
|
template <typename Callable>
|
||||||
|
using IsDirectlyCompatible = internal::conjunction<
|
||||||
|
// It must be possible to capture the callable in ActionAdaptor.
|
||||||
|
std::is_constructible<typename std::decay<Callable>::type, Callable>,
|
||||||
|
// The callable must be compatible with our signature.
|
||||||
|
internal::is_callable_r<Result, typename std::decay<Callable>::type,
|
||||||
|
Args...>>;
|
||||||
|
|
||||||
|
// True iff we can use the given callable type via ActionAdaptor once we
|
||||||
|
// ignore incoming arguments.
|
||||||
|
template <typename Callable>
|
||||||
|
using IsCompatibleAfterIgnoringArguments = internal::conjunction<
|
||||||
|
// It must be possible to capture the callable in a lambda.
|
||||||
|
std::is_constructible<typename std::decay<Callable>::type, Callable>,
|
||||||
|
// The callable must be invocable with zero arguments, returning something
|
||||||
|
// convertible to Result.
|
||||||
|
internal::is_callable_r<Result, typename std::decay<Callable>::type>>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Construct from a callable that is directly compatible with our mocked
|
||||||
|
// signature: it accepts our function type's arguments and returns something
|
||||||
|
// convertible to our result type.
|
||||||
|
template <typename Callable,
|
||||||
|
typename std::enable_if<
|
||||||
|
internal::conjunction<
|
||||||
|
// Teach clang on macOS that we're not talking about a
|
||||||
|
// copy/move constructor here. Otherwise it gets confused
|
||||||
|
// when checking the is_constructible requirement of our
|
||||||
|
// traits above.
|
||||||
|
internal::negation<std::is_same<
|
||||||
|
OnceAction, typename std::decay<Callable>::type>>,
|
||||||
|
IsDirectlyCompatible<Callable>> //
|
||||||
|
::value,
|
||||||
|
int>::type = 0>
|
||||||
|
OnceAction(Callable&& callable) // NOLINT
|
||||||
|
: action_(ActionAdaptor<typename std::decay<Callable>::type>(
|
||||||
|
{}, std::forward<Callable>(callable))) {}
|
||||||
|
|
||||||
|
// As above, but for a callable that ignores the mocked function's arguments.
|
||||||
|
template <typename Callable,
|
||||||
|
typename std::enable_if<
|
||||||
|
internal::conjunction<
|
||||||
|
// Teach clang on macOS that we're not talking about a
|
||||||
|
// copy/move constructor here. Otherwise it gets confused
|
||||||
|
// when checking the is_constructible requirement of our
|
||||||
|
// traits above.
|
||||||
|
internal::negation<std::is_same<
|
||||||
|
OnceAction, typename std::decay<Callable>::type>>,
|
||||||
|
// Exclude callables for which the overload above works.
|
||||||
|
// We'd rather provide the arguments if possible.
|
||||||
|
internal::negation<IsDirectlyCompatible<Callable>>,
|
||||||
|
IsCompatibleAfterIgnoringArguments<Callable>>::value,
|
||||||
|
int>::type = 0>
|
||||||
|
OnceAction(Callable&& callable) // NOLINT
|
||||||
|
// Call the constructor above with a callable
|
||||||
|
// that ignores the input arguments.
|
||||||
|
: OnceAction(IgnoreIncomingArguments<typename std::decay<Callable>::type>{
|
||||||
|
std::forward<Callable>(callable)}) {}
|
||||||
|
|
||||||
|
// A fallback constructor for anything that is convertible to Action, for use
|
||||||
|
// with legacy actions that uses older styles like implementing
|
||||||
|
// ActionInterface or a conversion operator to Action. Modern code should
|
||||||
|
// implement a call operator with appropriate restrictions.
|
||||||
|
template <typename T,
|
||||||
|
typename std::enable_if<
|
||||||
|
internal::conjunction<
|
||||||
|
// Teach clang on macOS that we're not talking about a
|
||||||
|
// copy/move constructor here. Otherwise it gets confused
|
||||||
|
// when checking the is_constructible requirement of our
|
||||||
|
// traits above.
|
||||||
|
internal::negation<
|
||||||
|
std::is_same<OnceAction, typename std::decay<T>::type>>,
|
||||||
|
// Exclude the overloads above, which we want to take
|
||||||
|
// precedence.
|
||||||
|
internal::negation<IsDirectlyCompatible<T>>,
|
||||||
|
internal::negation<IsCompatibleAfterIgnoringArguments<T>>,
|
||||||
|
// It must be possible to turn the object into an action of
|
||||||
|
// the appropriate type.
|
||||||
|
std::is_convertible<T, Action<Result(Args...)>> //
|
||||||
|
>::value,
|
||||||
|
int>::type = 0>
|
||||||
|
OnceAction(T&& action) : action_(std::forward<T>(action)) {} // NOLINT
|
||||||
|
|
||||||
|
// We are naturally copyable because we store only an Action, but semantically
|
||||||
|
// we should not be copyable.
|
||||||
|
OnceAction(const OnceAction&) = delete;
|
||||||
|
OnceAction& operator=(const OnceAction&) = delete;
|
||||||
|
OnceAction(OnceAction&&) = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Allow TypedExpectation::WillOnce to use our type-unsafe API below.
|
||||||
|
friend class TypedExpectation<Result(Args...)>;
|
||||||
|
|
||||||
|
// An adaptor that wraps a callable that is compatible with our signature and
|
||||||
|
// being invoked as an rvalue reference so that it can be used as an
|
||||||
|
// Action. This throws away type safety, but that's fine because this is only
|
||||||
|
// used by WillOnce, which we know calls at most once.
|
||||||
|
template <typename Callable>
|
||||||
|
class ActionAdaptor final {
|
||||||
|
public:
|
||||||
|
// A tag indicating that the (otherwise universal) constructor is accepting
|
||||||
|
// the callable itself, instead of e.g. stealing calls for the move
|
||||||
|
// constructor.
|
||||||
|
struct CallableTag final {};
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
explicit ActionAdaptor(CallableTag, F&& callable)
|
||||||
|
: callable_(std::make_shared<Callable>(std::forward<F>(callable))) {}
|
||||||
|
|
||||||
|
// Rather than explicitly returning Result, we return whatever the wrapped
|
||||||
|
// callable returns. This allows for compatibility with existing uses like
|
||||||
|
// the following, when the mocked function returns void:
|
||||||
|
//
|
||||||
|
// EXPECT_CALL(mock_fn_, Call)
|
||||||
|
// .WillOnce([&] {
|
||||||
|
// [...]
|
||||||
|
// return 0;
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// This works with Action since such a callable can be turned into
|
||||||
|
// std::function<void()>. If we use an explicit return type of Result here
|
||||||
|
// then it *doesn't* work with OnceAction, because we'll get a "void
|
||||||
|
// function should not return a value" error.
|
||||||
|
//
|
||||||
|
// We need not worry about incompatible result types because the SFINAE on
|
||||||
|
// OnceAction already checks this for us. std::is_invocable_r_v itself makes
|
||||||
|
// the same allowance for void result types.
|
||||||
|
template <typename... ArgRefs>
|
||||||
|
internal::call_result_t<Callable, ArgRefs...> operator()(
|
||||||
|
ArgRefs&&... args) const {
|
||||||
|
return std::move(*callable_)(std::forward<ArgRefs>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// We must put the callable on the heap so that we are copyable, which
|
||||||
|
// Action needs.
|
||||||
|
std::shared_ptr<Callable> callable_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// An adaptor that makes a callable that accepts zero arguments callable with
|
||||||
|
// our mocked arguments.
|
||||||
|
template <typename Callable>
|
||||||
|
struct IgnoreIncomingArguments {
|
||||||
|
internal::call_result_t<Callable> operator()(Args&&...) {
|
||||||
|
return std::move(callable)();
|
||||||
|
}
|
||||||
|
|
||||||
|
Callable callable;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return an Action that calls the underlying callable in a type-safe manner.
|
||||||
|
// The action's Perform method must be called at most once.
|
||||||
|
//
|
||||||
|
// This is the transition from a type-safe API to a type-unsafe one, since
|
||||||
|
// "must be called at most once" is no longer reflecting in the type system.
|
||||||
|
Action<Result(Args...)> ReleaseAction() && { return std::move(action_); }
|
||||||
|
|
||||||
|
Action<Result(Args...)> action_;
|
||||||
|
};
|
||||||
|
|
||||||
// Helper struct to specialize ReturnAction to execute a move instead of a copy
|
// Helper struct to specialize ReturnAction to execute a move instead of a copy
|
||||||
// on return. Useful for move-only types, but could be used on any type.
|
// on return. Useful for move-only types, but could be used on any type.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -992,14 +992,16 @@ class TypedExpectation : public ExpectationBase {
|
|||||||
return After(s1, s2, s3, s4).After(s5);
|
return After(s1, s2, s3, s4).After(s5);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements the .WillOnce() clause.
|
// Implements the .WillOnce() clause for copyable actions.
|
||||||
TypedExpectation& WillOnce(const Action<F>& action) {
|
TypedExpectation& WillOnce(OnceAction<F> once_action) {
|
||||||
ExpectSpecProperty(last_clause_ <= kWillOnce,
|
ExpectSpecProperty(last_clause_ <= kWillOnce,
|
||||||
".WillOnce() cannot appear after "
|
".WillOnce() cannot appear after "
|
||||||
".WillRepeatedly() or .RetiresOnSaturation().");
|
".WillRepeatedly() or .RetiresOnSaturation().");
|
||||||
last_clause_ = kWillOnce;
|
last_clause_ = kWillOnce;
|
||||||
|
|
||||||
untyped_actions_.push_back(new Action<F>(action));
|
untyped_actions_.push_back(
|
||||||
|
new Action<F>(std::move(once_action).ReleaseAction()));
|
||||||
|
|
||||||
if (!cardinality_specified()) {
|
if (!cardinality_specified()) {
|
||||||
set_cardinality(Exactly(static_cast<int>(untyped_actions_.size())));
|
set_cardinality(Exactly(static_cast<int>(untyped_actions_.size())));
|
||||||
}
|
}
|
||||||
|
@ -55,37 +55,170 @@
|
|||||||
#include "gtest/gtest-spi.h"
|
#include "gtest/gtest-spi.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using ::testing::_;
|
|
||||||
using ::testing::Action;
|
|
||||||
using ::testing::ActionInterface;
|
|
||||||
using ::testing::Assign;
|
|
||||||
using ::testing::ByMove;
|
|
||||||
using ::testing::ByRef;
|
|
||||||
using ::testing::DefaultValue;
|
|
||||||
using ::testing::DoAll;
|
|
||||||
using ::testing::DoDefault;
|
|
||||||
using ::testing::IgnoreResult;
|
|
||||||
using ::testing::Invoke;
|
|
||||||
using ::testing::InvokeWithoutArgs;
|
|
||||||
using ::testing::MakePolymorphicAction;
|
|
||||||
using ::testing::PolymorphicAction;
|
|
||||||
using ::testing::Return;
|
|
||||||
using ::testing::ReturnNew;
|
|
||||||
using ::testing::ReturnNull;
|
|
||||||
using ::testing::ReturnRef;
|
|
||||||
using ::testing::ReturnRefOfCopy;
|
|
||||||
using ::testing::ReturnRoundRobin;
|
|
||||||
using ::testing::SetArgPointee;
|
|
||||||
using ::testing::SetArgumentPointee;
|
|
||||||
using ::testing::Unused;
|
|
||||||
using ::testing::WithArgs;
|
|
||||||
using ::testing::internal::BuiltInDefaultValue;
|
using ::testing::internal::BuiltInDefaultValue;
|
||||||
|
|
||||||
#if !GTEST_OS_WINDOWS_MOBILE
|
TEST(TypeTraits, Negation) {
|
||||||
using ::testing::SetErrnoAndReturn;
|
// Direct use with std types.
|
||||||
#endif
|
static_assert(std::is_base_of<std::false_type,
|
||||||
|
internal::negation<std::true_type>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
static_assert(std::is_base_of<std::true_type,
|
||||||
|
internal::negation<std::false_type>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
// With other types that fit the requirement of a value member that is
|
||||||
|
// convertible to bool.
|
||||||
|
static_assert(std::is_base_of<
|
||||||
|
std::true_type,
|
||||||
|
internal::negation<std::integral_constant<int, 0>>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
static_assert(std::is_base_of<
|
||||||
|
std::false_type,
|
||||||
|
internal::negation<std::integral_constant<int, 1>>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
static_assert(std::is_base_of<
|
||||||
|
std::false_type,
|
||||||
|
internal::negation<std::integral_constant<int, -1>>>::value,
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Weird false/true types that aren't actually bool constants (but should still
|
||||||
|
// be legal according to [meta.logical] because `bool(T::value)` is valid), are
|
||||||
|
// distinct from std::false_type and std::true_type, and are distinct from other
|
||||||
|
// instantiations of the same template.
|
||||||
|
//
|
||||||
|
// These let us check finicky details mandated by the standard like
|
||||||
|
// "std::conjunction should evaluate to a type that inherits from the first
|
||||||
|
// false-y input".
|
||||||
|
template <int>
|
||||||
|
struct MyFalse : std::integral_constant<int, 0> {};
|
||||||
|
|
||||||
|
template <int>
|
||||||
|
struct MyTrue : std::integral_constant<int, -1> {};
|
||||||
|
|
||||||
|
TEST(TypeTraits, Conjunction) {
|
||||||
|
// Base case: always true.
|
||||||
|
static_assert(std::is_base_of<std::true_type, internal::conjunction<>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
// One predicate: inherits from that predicate, regardless of value.
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of<MyFalse<0>, internal::conjunction<MyFalse<0>>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of<MyTrue<0>, internal::conjunction<MyTrue<0>>>::value, "");
|
||||||
|
|
||||||
|
// Multiple predicates, with at least one false: inherits from that one.
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of<MyFalse<1>, internal::conjunction<MyTrue<0>, MyFalse<1>,
|
||||||
|
MyTrue<2>>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of<MyFalse<1>, internal::conjunction<MyTrue<0>, MyFalse<1>,
|
||||||
|
MyFalse<2>>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
// Short circuiting: in the case above, additional predicates need not even
|
||||||
|
// define a value member.
|
||||||
|
struct Empty {};
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of<MyFalse<1>, internal::conjunction<MyTrue<0>, MyFalse<1>,
|
||||||
|
Empty>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
// All predicates true: inherits from the last.
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of<MyTrue<2>, internal::conjunction<MyTrue<0>, MyTrue<1>,
|
||||||
|
MyTrue<2>>>::value,
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TypeTraits, Disjunction) {
|
||||||
|
// Base case: always false.
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of<std::false_type, internal::disjunction<>>::value, "");
|
||||||
|
|
||||||
|
// One predicate: inherits from that predicate, regardless of value.
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of<MyFalse<0>, internal::disjunction<MyFalse<0>>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of<MyTrue<0>, internal::disjunction<MyTrue<0>>>::value, "");
|
||||||
|
|
||||||
|
// Multiple predicates, with at least one true: inherits from that one.
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of<MyTrue<1>, internal::disjunction<MyFalse<0>, MyTrue<1>,
|
||||||
|
MyFalse<2>>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of<MyTrue<1>, internal::disjunction<MyFalse<0>, MyTrue<1>,
|
||||||
|
MyTrue<2>>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
// Short circuiting: in the case above, additional predicates need not even
|
||||||
|
// define a value member.
|
||||||
|
struct Empty {};
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of<MyTrue<1>, internal::disjunction<MyFalse<0>, MyTrue<1>,
|
||||||
|
Empty>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
// All predicates false: inherits from the last.
|
||||||
|
static_assert(
|
||||||
|
std::is_base_of<MyFalse<2>, internal::disjunction<MyFalse<0>, MyFalse<1>,
|
||||||
|
MyFalse<2>>>::value,
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TypeTraits, IsInvocableRV) {
|
||||||
|
struct C {
|
||||||
|
int operator()() const { return 0; }
|
||||||
|
void operator()(int) & {}
|
||||||
|
std::string operator()(int) && { return ""; };
|
||||||
|
};
|
||||||
|
|
||||||
|
// The first overload is callable for const and non-const rvalues and lvalues.
|
||||||
|
// It can be used to obtain an int, void, or anything int is convertible too.
|
||||||
|
static_assert(internal::is_callable_r<int, C>::value, "");
|
||||||
|
static_assert(internal::is_callable_r<int, C&>::value, "");
|
||||||
|
static_assert(internal::is_callable_r<int, const C>::value, "");
|
||||||
|
static_assert(internal::is_callable_r<int, const C&>::value, "");
|
||||||
|
|
||||||
|
static_assert(internal::is_callable_r<void, C>::value, "");
|
||||||
|
static_assert(internal::is_callable_r<char, C>::value, "");
|
||||||
|
|
||||||
|
// It's possible to provide an int. If it's given to an lvalue, the result is
|
||||||
|
// void. Otherwise it is std::string (which is also treated as allowed for a
|
||||||
|
// void result type).
|
||||||
|
static_assert(internal::is_callable_r<void, C&, int>::value, "");
|
||||||
|
static_assert(!internal::is_callable_r<int, C&, int>::value, "");
|
||||||
|
static_assert(!internal::is_callable_r<std::string, C&, int>::value, "");
|
||||||
|
static_assert(!internal::is_callable_r<void, const C&, int>::value, "");
|
||||||
|
|
||||||
|
static_assert(internal::is_callable_r<std::string, C, int>::value, "");
|
||||||
|
static_assert(internal::is_callable_r<void, C, int>::value, "");
|
||||||
|
static_assert(!internal::is_callable_r<int, C, int>::value, "");
|
||||||
|
|
||||||
|
// It's not possible to provide other arguments.
|
||||||
|
static_assert(!internal::is_callable_r<void, C, std::string>::value, "");
|
||||||
|
static_assert(!internal::is_callable_r<void, C, int, int>::value, "");
|
||||||
|
|
||||||
|
// Nothing should choke when we try to call other arguments besides directly
|
||||||
|
// callable objects, but they should not show up as callable.
|
||||||
|
static_assert(!internal::is_callable_r<void, int>::value, "");
|
||||||
|
static_assert(!internal::is_callable_r<void, void (C::*)()>::value, "");
|
||||||
|
static_assert(!internal::is_callable_r<void, void (C::*)(), C*>::value, "");
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that BuiltInDefaultValue<T*>::Get() returns NULL.
|
// Tests that BuiltInDefaultValue<T*>::Get() returns NULL.
|
||||||
TEST(BuiltInDefaultValueTest, IsNullForPointerTypes) {
|
TEST(BuiltInDefaultValueTest, IsNullForPointerTypes) {
|
||||||
@ -1428,6 +1561,154 @@ TEST(MockMethodTest, CanTakeMoveOnlyValue) {
|
|||||||
EXPECT_EQ(42, *saved);
|
EXPECT_EQ(42, *saved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It should be possible to use callables with an &&-qualified call operator
|
||||||
|
// with WillOnce, since they will be called only once. This allows actions to
|
||||||
|
// contain and manipulate move-only types.
|
||||||
|
TEST(MockMethodTest, ActionHasRvalueRefQualifiedCallOperator) {
|
||||||
|
struct Return17 {
|
||||||
|
int operator()() && { return 17; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Action is directly compatible with mocked function type.
|
||||||
|
{
|
||||||
|
MockFunction<int()> mock;
|
||||||
|
EXPECT_CALL(mock, Call).WillOnce(Return17());
|
||||||
|
|
||||||
|
EXPECT_EQ(17, mock.AsStdFunction()());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action doesn't want mocked function arguments.
|
||||||
|
{
|
||||||
|
MockFunction<int(int)> mock;
|
||||||
|
EXPECT_CALL(mock, Call).WillOnce(Return17());
|
||||||
|
|
||||||
|
EXPECT_EQ(17, mock.AsStdFunction()(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edge case: if an action has both a const-qualified and an &&-qualified call
|
||||||
|
// operator, there should be no "ambiguous call" errors. The &&-qualified
|
||||||
|
// operator should be used by WillOnce (since it doesn't need to retain the
|
||||||
|
// action beyond one call), and the const-qualified one by WillRepeatedly.
|
||||||
|
TEST(MockMethodTest, ActionHasMultipleCallOperators) {
|
||||||
|
struct ReturnInt {
|
||||||
|
int operator()() && { return 17; }
|
||||||
|
int operator()() const& { return 19; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Directly compatible with mocked function type.
|
||||||
|
{
|
||||||
|
MockFunction<int()> mock;
|
||||||
|
EXPECT_CALL(mock, Call).WillOnce(ReturnInt()).WillRepeatedly(ReturnInt());
|
||||||
|
|
||||||
|
EXPECT_EQ(17, mock.AsStdFunction()());
|
||||||
|
EXPECT_EQ(19, mock.AsStdFunction()());
|
||||||
|
EXPECT_EQ(19, mock.AsStdFunction()());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignores function arguments.
|
||||||
|
{
|
||||||
|
MockFunction<int(int)> mock;
|
||||||
|
EXPECT_CALL(mock, Call).WillOnce(ReturnInt()).WillRepeatedly(ReturnInt());
|
||||||
|
|
||||||
|
EXPECT_EQ(17, mock.AsStdFunction()(0));
|
||||||
|
EXPECT_EQ(19, mock.AsStdFunction()(0));
|
||||||
|
EXPECT_EQ(19, mock.AsStdFunction()(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WillOnce should have no problem coping with a move-only action, whether it is
|
||||||
|
// &&-qualified or not.
|
||||||
|
TEST(MockMethodTest, MoveOnlyAction) {
|
||||||
|
// &&-qualified
|
||||||
|
{
|
||||||
|
struct Return17 {
|
||||||
|
Return17() = default;
|
||||||
|
Return17(Return17&&) = default;
|
||||||
|
|
||||||
|
Return17(const Return17&) = delete;
|
||||||
|
Return17 operator=(const Return17&) = delete;
|
||||||
|
|
||||||
|
int operator()() && { return 17; }
|
||||||
|
};
|
||||||
|
|
||||||
|
MockFunction<int()> mock;
|
||||||
|
EXPECT_CALL(mock, Call).WillOnce(Return17());
|
||||||
|
EXPECT_EQ(17, mock.AsStdFunction()());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not &&-qualified
|
||||||
|
{
|
||||||
|
struct Return17 {
|
||||||
|
Return17() = default;
|
||||||
|
Return17(Return17&&) = default;
|
||||||
|
|
||||||
|
Return17(const Return17&) = delete;
|
||||||
|
Return17 operator=(const Return17&) = delete;
|
||||||
|
|
||||||
|
int operator()() const { return 17; }
|
||||||
|
};
|
||||||
|
|
||||||
|
MockFunction<int()> mock;
|
||||||
|
EXPECT_CALL(mock, Call).WillOnce(Return17());
|
||||||
|
EXPECT_EQ(17, mock.AsStdFunction()());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// It should be possible to use an action that returns a value with a mock
|
||||||
|
// function that doesn't, both through WillOnce and WillRepeatedly.
|
||||||
|
TEST(MockMethodTest, ActionReturnsIgnoredValue) {
|
||||||
|
struct ReturnInt {
|
||||||
|
int operator()() const { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
MockFunction<void()> mock;
|
||||||
|
EXPECT_CALL(mock, Call).WillOnce(ReturnInt()).WillRepeatedly(ReturnInt());
|
||||||
|
|
||||||
|
mock.AsStdFunction()();
|
||||||
|
mock.AsStdFunction()();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Despite the fanciness around move-only actions and so on, it should still be
|
||||||
|
// possible to hand an lvalue reference to a copyable action to WillOnce.
|
||||||
|
TEST(MockMethodTest, WillOnceCanAcceptLvalueReference) {
|
||||||
|
MockFunction<int()> mock;
|
||||||
|
|
||||||
|
const auto action = [] { return 17; };
|
||||||
|
EXPECT_CALL(mock, Call).WillOnce(action);
|
||||||
|
|
||||||
|
EXPECT_EQ(17, mock.AsStdFunction()());
|
||||||
|
}
|
||||||
|
|
||||||
|
// A callable that doesn't use SFINAE to restrict its call operator's overload
|
||||||
|
// set, but is still picky about which arguments it will accept.
|
||||||
|
struct StaticAssertSingleArgument {
|
||||||
|
template <typename... Args>
|
||||||
|
static constexpr bool CheckArgs() {
|
||||||
|
static_assert(sizeof...(Args) == 1, "");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args, bool = CheckArgs<Args...>()>
|
||||||
|
int operator()(Args...) const {
|
||||||
|
return 17;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// WillOnce and WillRepeatedly should both work fine with naïve implementations
|
||||||
|
// of actions that don't use SFINAE to limit the overload set for their call
|
||||||
|
// operator. If they are compatible with the actual mocked signature, we
|
||||||
|
// shouldn't probe them with no arguments and trip a static_assert.
|
||||||
|
TEST(MockMethodTest, ActionSwallowsAllArguments) {
|
||||||
|
MockFunction<int(int)> mock;
|
||||||
|
EXPECT_CALL(mock, Call)
|
||||||
|
.WillOnce(StaticAssertSingleArgument{})
|
||||||
|
.WillRepeatedly(StaticAssertSingleArgument{});
|
||||||
|
|
||||||
|
EXPECT_EQ(17, mock.AsStdFunction()(0));
|
||||||
|
EXPECT_EQ(17, mock.AsStdFunction()(0));
|
||||||
|
}
|
||||||
|
|
||||||
// Tests for std::function based action.
|
// Tests for std::function based action.
|
||||||
|
|
||||||
int Add(int val, int& ref, int* ptr) { // NOLINT
|
int Add(int val, int& ref, int* ptr) { // NOLINT
|
||||||
@ -1552,7 +1833,8 @@ TEST(ActionMacro, LargeArity) {
|
|||||||
14, 15, 16, 17, 18, 19)));
|
14, 15, 16, 17, 18, 19)));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Unnamed namespace
|
} // namespace
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#if _MSC_VER == 1900
|
#if _MSC_VER == 1900
|
||||||
|
Loading…
Reference in New Issue
Block a user