Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/google/googletest.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Jacobs <jacobsa@google.com>2022-04-26 18:05:01 +0300
committerCopybara-Service <copybara-worker@google.com>2022-04-26 18:05:34 +0300
commit0498660ea575bfeb4b3b0879fa6aa6904d1df373 (patch)
tree555b8f3add5a2ceae42409040ecec37c0ca28810
parentb53547bf01ee6d5c547bc539a498c49bc6027169 (diff)
Support move-only and &&-qualified actions in DoAll.
This is necessary for generic support of these actions, since `DoAll` is a frequently-used action wrapper. PiperOrigin-RevId: 444561964 Change-Id: I02edb55e35ab4207fbd71e371255a319c8253136
-rw-r--r--googlemock/include/gmock/gmock-actions.h591
-rw-r--r--googlemock/include/gmock/gmock-spec-builders.h41
-rw-r--r--googlemock/test/gmock-actions_test.cc106
3 files changed, 480 insertions, 258 deletions
diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h
index a2b25d9b..ecc72d53 100644
--- a/googlemock/include/gmock/gmock-actions.h
+++ b/googlemock/include/gmock/gmock-actions.h
@@ -322,6 +322,191 @@ struct is_callable_r_impl<void_t<call_result_t<F, Args...>>, R, F, Args...>
template <typename R, typename F, typename... Args>
using is_callable_r = is_callable_r_impl<void, R, F, Args...>;
+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 StdFunctionAdaptor.
+ template <typename Callable>
+ using IsDirectlyCompatible = internal::conjunction<
+ // It must be possible to capture the callable in StdFunctionAdaptor.
+ 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 StdFunctionAdaptor 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
+ : function_(StdFunctionAdaptor<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)}) {}
+
+ // We are naturally copyable because we store only an std::function, but
+ // semantically we should not be copyable.
+ OnceAction(const OnceAction&) = delete;
+ OnceAction& operator=(const OnceAction&) = delete;
+ OnceAction(OnceAction&&) = default;
+
+ // Invoke the underlying action callable with which we were constructed,
+ // handing it the supplied arguments.
+ Result Call(Args... args) && {
+ return function_(std::forward<Args>(args)...);
+ }
+
+ 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
+ // StdFunctionAdaptor. This throws away type safety, but that's fine because
+ // this is only used by WillOnce, which we know calls at most once.
+ //
+ // Once we have something like std::move_only_function from C++23, we can do
+ // away with this.
+ template <typename Callable>
+ class StdFunctionAdaptor 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 StdFunctionAdaptor(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;
+ // });
+ //
+ // 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
+ // std::function, 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
+ // std::function 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;
+ };
+
+ std::function<Result(Args...)> function_;
+};
+
} // namespace internal
// When an unexpected function call is encountered, Google Mock will
@@ -484,25 +669,30 @@ class ActionInterface {
ActionInterface& operator=(const ActionInterface&) = delete;
};
-// An Action<F> is a copyable and IMMUTABLE (except by assignment)
-// object that represents an action to be taken when a mock function
-// of type F is called. The implementation of Action<T> is just a
-// std::shared_ptr to const ActionInterface<T>. Don't inherit from Action!
-// You can view an object implementing ActionInterface<F> as a
-// concrete action (including its current state), and an Action<F>
-// object as a handle to it.
template <typename F>
-class Action {
+class Action;
+
+// An Action<R(Args...)> is a copyable and IMMUTABLE (except by assignment)
+// object that represents an action to be taken when a mock function of type
+// R(Args...) is called. The implementation of Action<T> is just a
+// std::shared_ptr to const ActionInterface<T>. Don't inherit from Action! You
+// can view an object implementing ActionInterface<F> as a concrete action
+// (including its current state), and an Action<F> object as a handle to it.
+template <typename R, typename... Args>
+class Action<R(Args...)> {
+ private:
+ using F = R(Args...);
+
// Adapter class to allow constructing Action from a legacy ActionInterface.
// New code should create Actions from functors instead.
struct ActionAdapter {
// Adapter must be copyable to satisfy std::function requirements.
::std::shared_ptr<ActionInterface<F>> impl_;
- template <typename... Args>
- typename internal::Function<F>::Result operator()(Args&&... args) {
+ template <typename... InArgs>
+ typename internal::Function<F>::Result operator()(InArgs&&... args) {
return impl_->Perform(
- ::std::forward_as_tuple(::std::forward<Args>(args)...));
+ ::std::forward_as_tuple(::std::forward<InArgs>(args)...));
}
};
@@ -537,7 +727,8 @@ class Action {
// Action<F>, as long as F's arguments can be implicitly converted
// to Func's and Func's return type can be implicitly converted to F's.
template <typename Func>
- explicit Action(const Action<Func>& action) : fun_(action.fun_) {}
+ Action(const Action<Func>& action) // NOLINT
+ : fun_(action.fun_) {}
// Returns true if and only if this is the DoDefault() action.
bool IsDoDefault() const { return fun_ == nullptr; }
@@ -555,6 +746,24 @@ class Action {
return internal::Apply(fun_, ::std::move(args));
}
+ // An action can be used as a OnceAction, since it's obviously safe to call it
+ // once.
+ operator internal::OnceAction<F>() const { // NOLINT
+ // Return a OnceAction-compatible callable that calls Perform with the
+ // arguments it is provided. We could instead just return fun_, but then
+ // we'd need to handle the IsDoDefault() case separately.
+ struct OA {
+ Action<F> action;
+
+ R operator()(Args... args) && {
+ return action.Perform(
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ }
+ };
+
+ return OA{*this};
+ }
+
private:
template <typename G>
friend class Action;
@@ -571,8 +780,8 @@ class Action {
template <typename FunctionImpl>
struct IgnoreArgs {
- template <typename... Args>
- Result operator()(const Args&...) const {
+ template <typename... InArgs>
+ Result operator()(const InArgs&...) const {
return function_impl();
}
@@ -655,213 +864,6 @@ inline PolymorphicAction<Impl> MakePolymorphicAction(const Impl& impl) {
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
// on return. Useful for move-only types, but could be used on any type.
template <typename T>
@@ -1295,8 +1297,53 @@ struct WithArgsAction {
};
template <typename... Actions>
-struct DoAllAction {
+class DoAllAction;
+
+// Base case: only a single action.
+template <typename FinalAction>
+class DoAllAction<FinalAction> {
+ public:
+ struct UserConstructorTag {};
+
+ template <typename T>
+ explicit DoAllAction(UserConstructorTag, T&& action)
+ : final_action_(std::forward<T>(action)) {}
+
+ // Rather than a call operator, we must define conversion operators to
+ // particular action types. This is necessary for embedded actions like
+ // DoDefault(), which rely on an action conversion operators rather than
+ // providing a call operator because even with a particular set of arguments
+ // they don't have a fixed return type.
+
+ template <typename R, typename... Args,
+ typename std::enable_if<
+ std::is_convertible<FinalAction, OnceAction<R(Args...)>>::value,
+ int>::type = 0>
+ operator OnceAction<R(Args...)>() && { // NOLINT
+ return std::move(final_action_);
+ }
+
+ template <
+ typename R, typename... Args,
+ typename std::enable_if<
+ std::is_convertible<const FinalAction&, Action<R(Args...)>>::value,
+ int>::type = 0>
+ operator Action<R(Args...)>() const { // NOLINT
+ return final_action_;
+ }
+
private:
+ FinalAction final_action_;
+};
+
+// Recursive case: support N actions by calling the initial action and then
+// calling through to the base class containing N-1 actions.
+template <typename InitialAction, typename... OtherActions>
+class DoAllAction<InitialAction, OtherActions...>
+ : private DoAllAction<OtherActions...> {
+ private:
+ using Base = DoAllAction<OtherActions...>;
+
// The type of reference that should be provided to an initial action for a
// mocked function parameter of type T.
//
@@ -1315,14 +1362,14 @@ struct DoAllAction {
//
// * More surprisingly, `const T&` is often not a const reference type.
// By the reference collapsing rules in C++17 [dcl.ref]/6, if T refers to
- // U& or U&& for some non-scalar type U, then NonFinalType<T> is U&. In
- // other words, we may hand over a non-const reference.
+ // U& or U&& for some non-scalar type U, then InitialActionArgType<T> is
+ // U&. In other words, we may hand over a non-const reference.
//
// So for example, given some non-scalar type Obj we have the following
// mappings:
//
- // T NonFinalType<T>
- // ------- ---------------
+ // T InitialActionArgType<T>
+ // ------- -----------------------
// Obj const Obj&
// Obj& Obj&
// Obj&& Obj&
@@ -1343,34 +1390,85 @@ struct DoAllAction {
// .WillOnce(DoAll(SetArgReferee<0>(17), Return(19)));
//
template <typename T>
- using NonFinalType =
+ using InitialActionArgType =
typename std::conditional<std::is_scalar<T>::value, T, const T&>::type;
- template <typename ActionT, size_t... I>
- std::vector<ActionT> Convert(IndexSequence<I...>) const {
- return {ActionT(std::get<I>(actions))...};
- }
-
public:
- std::tuple<Actions...> actions;
+ struct UserConstructorTag {};
- template <typename R, typename... Args>
+ template <typename T, typename... U>
+ explicit DoAllAction(UserConstructorTag, T&& initial_action,
+ U&&... other_actions)
+ : Base({}, std::forward<U>(other_actions)...),
+ initial_action_(std::forward<T>(initial_action)) {}
+
+ template <typename R, typename... Args,
+ typename std::enable_if<
+ conjunction<
+ // Both the initial action and the rest must support
+ // conversion to OnceAction.
+ std::is_convertible<
+ InitialAction,
+ OnceAction<void(InitialActionArgType<Args>...)>>,
+ std::is_convertible<Base, OnceAction<R(Args...)>>>::value,
+ int>::type = 0>
+ operator OnceAction<R(Args...)>() && { // NOLINT
+ // Return an action that first calls the initial action with arguments
+ // filtered through InitialActionArgType, then forwards arguments directly
+ // to the base class to deal with the remaining actions.
+ struct OA {
+ OnceAction<void(InitialActionArgType<Args>...)> initial_action;
+ OnceAction<R(Args...)> remaining_actions;
+
+ R operator()(Args... args) && {
+ std::move(initial_action)
+ .Call(static_cast<InitialActionArgType<Args>>(args)...);
+
+ return std::move(remaining_actions).Call(std::forward<Args>(args)...);
+ }
+ };
+
+ return OA{
+ std::move(initial_action_),
+ std::move(static_cast<Base&>(*this)),
+ };
+ }
+
+ template <
+ typename R, typename... Args,
+ typename std::enable_if<
+ conjunction<
+ // Both the initial action and the rest must support conversion to
+ // Action.
+ std::is_convertible<const InitialAction&,
+ Action<void(InitialActionArgType<Args>...)>>,
+ std::is_convertible<const Base&, Action<R(Args...)>>>::value,
+ int>::type = 0>
operator Action<R(Args...)>() const { // NOLINT
- struct Op {
- std::vector<Action<void(NonFinalType<Args>...)>> converted;
- Action<R(Args...)> last;
+ // Return an action that first calls the initial action with arguments
+ // filtered through InitialActionArgType, then forwards arguments directly
+ // to the base class to deal with the remaining actions.
+ struct OA {
+ Action<void(InitialActionArgType<Args>...)> initial_action;
+ Action<R(Args...)> remaining_actions;
+
R operator()(Args... args) const {
- auto tuple_args = std::forward_as_tuple(std::forward<Args>(args)...);
- for (auto& a : converted) {
- a.Perform(tuple_args);
- }
- return last.Perform(std::move(tuple_args));
+ initial_action.Perform(std::forward_as_tuple(
+ static_cast<InitialActionArgType<Args>>(args)...));
+
+ return remaining_actions.Perform(
+ std::forward_as_tuple(std::forward<Args>(args)...));
}
};
- return Op{Convert<Action<void(NonFinalType<Args>...)>>(
- MakeIndexSequence<sizeof...(Actions) - 1>()),
- std::get<sizeof...(Actions) - 1>(actions)};
+
+ return OA{
+ initial_action_,
+ static_cast<const Base&>(*this),
+ };
}
+
+ private:
+ InitialAction initial_action_;
};
template <typename T, typename... Params>
@@ -1513,7 +1611,8 @@ typedef internal::IgnoredValue Unused;
template <typename... Action>
internal::DoAllAction<typename std::decay<Action>::type...> DoAll(
Action&&... action) {
- return {std::forward_as_tuple(std::forward<Action>(action)...)};
+ return internal::DoAllAction<typename std::decay<Action>::type...>(
+ {}, std::forward<Action>(action)...);
}
// WithArg<k>(an_action) creates an action that passes the k-th
diff --git a/googlemock/include/gmock/gmock-spec-builders.h b/googlemock/include/gmock/gmock-spec-builders.h
index a3e32a49..835e518b 100644
--- a/googlemock/include/gmock/gmock-spec-builders.h
+++ b/googlemock/include/gmock/gmock-spec-builders.h
@@ -878,9 +878,15 @@ class GTEST_API_ ExpectationBase {
mutable Mutex mutex_; // Protects action_count_checked_.
}; // class ExpectationBase
-// Implements an expectation for the given function type.
template <typename F>
-class TypedExpectation : public ExpectationBase {
+class TypedExpectation;
+
+// Implements an expectation for the given function type.
+template <typename R, typename... Args>
+class TypedExpectation<R(Args...)> : public ExpectationBase {
+ private:
+ using F = R(Args...);
+
public:
typedef typename Function<F>::ArgumentTuple ArgumentTuple;
typedef typename Function<F>::ArgumentMatcherTuple ArgumentMatcherTuple;
@@ -993,15 +999,30 @@ class TypedExpectation : public ExpectationBase {
return After(s1, s2, s3, s4).After(s5);
}
- // Implements the .WillOnce() clause for copyable actions.
+ // Preferred, type-safe overload: consume anything that can be directly
+ // converted to a OnceAction, except for Action<F> objects themselves.
TypedExpectation& WillOnce(OnceAction<F> once_action) {
+ // Call the overload below, smuggling the OnceAction as a copyable callable.
+ // We know this is safe because a WillOnce action will not be called more
+ // than once.
+ return WillOnce(Action<F>(ActionAdaptor{
+ std::make_shared<OnceAction<F>>(std::move(once_action)),
+ }));
+ }
+
+ // Fallback overload: accept Action<F> objects and those actions that define
+ // `operator Action<F>` but not `operator OnceAction<F>`.
+ //
+ // This is templated in order to cause the overload above to be preferred
+ // when the input is convertible to either type.
+ template <int&... ExplicitArgumentBarrier, typename = void>
+ TypedExpectation& WillOnce(Action<F> action) {
ExpectSpecProperty(last_clause_ <= kWillOnce,
".WillOnce() cannot appear after "
".WillRepeatedly() or .RetiresOnSaturation().");
last_clause_ = kWillOnce;
- untyped_actions_.push_back(
- new Action<F>(std::move(once_action).ReleaseAction()));
+ untyped_actions_.push_back(new Action<F>(std::move(action)));
if (!cardinality_specified()) {
set_cardinality(Exactly(static_cast<int>(untyped_actions_.size())));
@@ -1074,6 +1095,16 @@ class TypedExpectation : public ExpectationBase {
template <typename Function>
friend class FunctionMocker;
+ // An adaptor that turns a OneAction<F> into something compatible with
+ // Action<F>. Must be called at most once.
+ struct ActionAdaptor {
+ std::shared_ptr<OnceAction<R(Args...)>> once_action;
+
+ R operator()(Args&&... args) const {
+ return std::move(*once_action).Call(std::forward<Args>(args)...);
+ }
+ };
+
// Returns an Expectation object that references and co-owns this
// expectation.
Expectation GetHandle() override { return owner_->GetHandleOf(this); }
diff --git a/googlemock/test/gmock-actions_test.cc b/googlemock/test/gmock-actions_test.cc
index cce3f4b2..e41845e7 100644
--- a/googlemock/test/gmock-actions_test.cc
+++ b/googlemock/test/gmock-actions_test.cc
@@ -31,10 +31,12 @@
//
// This file tests the built-in actions.
-// Silence C4100 (unreferenced formal parameter) for MSVC
+// Silence C4100 (unreferenced formal parameter) and C4503 (decorated name
+// length exceeded) for MSVC.
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4100)
+#pragma warning(disable : 4503)
#if _MSC_VER == 1900
// and silence C4800 (C4800: 'int *const ': forcing value
// to bool 'true' or 'false') for MSVC 15
@@ -1193,6 +1195,21 @@ TEST(AssignTest, CompatibleTypes) {
EXPECT_DOUBLE_EQ(5, x);
}
+// DoAll should support &&-qualified actions when used with WillOnce.
+TEST(DoAll, SupportsRefQualifiedActions) {
+ struct InitialAction {
+ void operator()(const int arg) && { EXPECT_EQ(17, arg); }
+ };
+
+ struct FinalAction {
+ int operator()() && { return 19; }
+ };
+
+ MockFunction<int(int)> mock;
+ EXPECT_CALL(mock, Call).WillOnce(DoAll(InitialAction{}, FinalAction{}));
+ EXPECT_EQ(19, mock.AsStdFunction()(17));
+}
+
// DoAll should never provide rvalue references to the initial actions. If the
// mock action itself accepts an rvalue reference or a non-scalar object by
// value then the final action should receive an rvalue reference, but initial
@@ -1274,6 +1291,62 @@ TEST(DoAll, ProvidesLvalueReferencesToInitialActions) {
mock.AsStdFunction()(Obj{});
mock.AsStdFunction()(Obj{});
}
+
+ // &&-qualified initial actions should also be allowed with WillOnce.
+ {
+ struct InitialAction {
+ void operator()(Obj&) && {}
+ };
+
+ MockFunction<void(Obj&)> mock;
+ EXPECT_CALL(mock, Call)
+ .WillOnce(DoAll(InitialAction{}, InitialAction{}, [](Obj&) {}));
+
+ Obj obj;
+ mock.AsStdFunction()(obj);
+ }
+
+ {
+ struct InitialAction {
+ void operator()(Obj&) && {}
+ };
+
+ MockFunction<void(Obj &&)> mock;
+ EXPECT_CALL(mock, Call)
+ .WillOnce(DoAll(InitialAction{}, InitialAction{}, [](Obj&&) {}));
+
+ mock.AsStdFunction()(Obj{});
+ }
+}
+
+// DoAll should support being used with type-erased Action objects, both through
+// WillOnce and WillRepeatedly.
+TEST(DoAll, SupportsTypeErasedActions) {
+ // With only type-erased actions.
+ const Action<void()> initial_action = [] {};
+ const Action<int()> final_action = [] { return 17; };
+
+ MockFunction<int()> mock;
+ EXPECT_CALL(mock, Call)
+ .WillOnce(DoAll(initial_action, initial_action, final_action))
+ .WillRepeatedly(DoAll(initial_action, initial_action, final_action));
+
+ EXPECT_EQ(17, mock.AsStdFunction()());
+
+ // With &&-qualified and move-only final action.
+ {
+ struct FinalAction {
+ FinalAction() = default;
+ FinalAction(FinalAction&&) = default;
+
+ int operator()() && { return 17; }
+ };
+
+ EXPECT_CALL(mock, Call)
+ .WillOnce(DoAll(initial_action, initial_action, FinalAction{}));
+
+ EXPECT_EQ(17, mock.AsStdFunction()());
+ }
}
// Tests using WithArgs and with an action that takes 1 argument.
@@ -1793,6 +1866,31 @@ TEST(MockMethodTest, ActionSwallowsAllArguments) {
EXPECT_EQ(17, mock.AsStdFunction()(0));
}
+struct ActionWithTemplatedConversionOperators {
+ template <typename... Args>
+ operator internal::OnceAction<int(Args...)>() && { // NOLINT
+ return [] { return 17; };
+ }
+
+ template <typename... Args>
+ operator Action<int(Args...)>() const { // NOLINT
+ return [] { return 19; };
+ }
+};
+
+// It should be fine to hand both WillOnce and WillRepeatedly a function that
+// defines templated conversion operators to OnceAction and Action. WillOnce
+// should prefer the OnceAction version.
+TEST(MockMethodTest, ActionHasTemplatedConversionOperators) {
+ MockFunction<int()> mock;
+ EXPECT_CALL(mock, Call)
+ .WillOnce(ActionWithTemplatedConversionOperators{})
+ .WillRepeatedly(ActionWithTemplatedConversionOperators{});
+
+ EXPECT_EQ(17, mock.AsStdFunction()());
+ EXPECT_EQ(19, mock.AsStdFunction()());
+}
+
// Tests for std::function based action.
int Add(int val, int& ref, int* ptr) { // NOLINT
@@ -1919,9 +2017,3 @@ TEST(ActionMacro, LargeArity) {
} // namespace
} // namespace testing
-
-#ifdef _MSC_VER
-#if _MSC_VER == 1900
-#pragma warning(pop)
-#endif
-#endif