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