1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef BASE_TEST_GMOCK_MOVE_SUPPORT_H_
6 #define BASE_TEST_GMOCK_MOVE_SUPPORT_H_
7
8 #include <cstddef>
9 #include <tuple>
10 #include <utility>
11
12 // Moves the `I`th argument to `out`. Analogous to `testing::SaveArg()`, which
13 // copies instead.
14 //
15 // Example:
16 //
17 // std::unique_ptr<int> result;
18 // EXPECT_CALL(mocked_object, Method).WillOnce(MoveArg<0>(&result));
19 // mocked_object.Method(std::make_unique<int>(123));
20 // EXPECT_THAT(result, Pointee(Eq(123)));
21 //
22 // Important: it is not possible to use multiple `MoveArg()` actions in a single
23 // `DoAll()`: per the googlemock documentation, all but the last action receive
24 // a read-only view of the arguments. Allowing an intermediate action to consume
25 // the arguments would leave the original arguments in an unspecified state for
26 // invoking subsequent actions, which is dubious.
27 //
28 // A simple workaround is to use `Invoke()` with a lambda instead, e.g.
29 //
30 // std::unique_ptr<int> int_result;
31 // std::unique_ptr<double> double_result;
32 // EXPECT_CALL(mocked_object, Method).WillOnce(Invoke(
33 // [&] (auto&& arg1, auto&& arg2) {
34 // int_result = std::move(arg1);
35 // double_result = std::move(arg2);
36 // return 42;
37 // }));
38 // EXPECT_EQ(42, mocked_object.Method(std::make_unique<int>(123),
39 // std::make_unique<double>(0.5)));
40 // EXPECT_THAT(int_result, Pointee(Eq(123)));
41 // EXPECT_THAT(double_result, Pointee(DoubleEq(0.5)));
42
43 template <size_t I = 0, typename T>
MoveArg(T * out)44 auto MoveArg(T* out) {
45 return [out](auto&&... args) {
46 *out = std::move(std::get<I>(std::tie(args...)));
47 };
48 }
49
50 // Moves the `I`th argument to `*out` and returns `return_value`.
51 //
52 // This is a convenience helper for code that wants to write the following:
53 //
54 // DoAll(MoveArg<N>(&saved_arg), Return(value))
55 //
56 // The above is not actually possible to write because:
57 // - `DoAll()` requires that its final action has a return type that matches the
58 // mocked call's return type. So `Return()` must be last.
59 // - But any actions before the last receive a read-only view of the arguments.
60 // So `MoveArg()` receives a read-only view and cannot move out of it.
61 //
62 // Example:
63 //
64 // std::unique_ptr<int> result;
65 // EXPECT_CALL(mocked_object, Method).WillOnce(
66 // MoveArgAndReturn<0>(&result, true));
67 // EXPECT_TRUE(mocked_object.Method(std::make_unique<int>(123)));
68 // EXPECT_THAT(int_result, Pointee(Eq(123)));
69 //
70 template <size_t I = 0, typename T1, typename T2>
MoveArgAndReturn(T1 * out,T2 && return_value)71 auto MoveArgAndReturn(T1* out, T2&& return_value) {
72 return [out, value = std::forward<T2>(return_value)](auto&&... args) mutable {
73 *out = std::move(std::get<I>(std::tie(args...)));
74 return std::forward<T2>(value);
75 };
76 }
77
78 #endif // BASE_TEST_GMOCK_MOVE_SUPPORT_H_
79