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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
base / test / gmock_callback_support.h [blame]
// Copyright 2012 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_CALLBACK_SUPPORT_H_
#define BASE_TEST_GMOCK_CALLBACK_SUPPORT_H_
#include <ostream>
#include <tuple>
#include <utility>
#include "base/check.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace base {
namespace gmock_callback_support_internal {
// Small helper to get the `I`th argument.
template <size_t I, typename... Args>
decltype(auto) get(Args&&... args) {
return std::get<I>(std::forward_as_tuple(std::forward<Args>(args)...));
}
// Wraps `tuple` inside RefCountedData<std::unique_ptr<Tuple>> to allow creating
// shallow copies in lambda return of RunOnceCallback<>.
// Since RefCountedData<Tuple> stores Tuple directly, the indirection via
// std::unique_ptr<Tuple> is necessary to be able to CHECK() on second
// invocation instead of running the callback with a default-constructed tuple.
template <typename Tuple>
auto WrapTupleAsRefCountedData(Tuple&& tuple) {
return MakeRefCounted<RefCountedData<std::unique_ptr<Tuple>>>(
std::make_unique<Tuple>(std::forward<Tuple>(tuple)));
}
// Invokes `cb` with the arguments stored in `tuple`. Both `cb` and `tuple` are
// perfectly forwarded, allowing callers to specify whether they should be
// passed by move or copy.
template <typename Callback, typename Tuple>
decltype(auto) RunImpl(Callback&& cb, Tuple&& tuple) {
return std::apply(
[&](auto&&... args) -> decltype(auto) {
return std::forward<Callback>(cb).Run(
std::forward<decltype(args)>(args)...);
},
std::forward<Tuple>(tuple));
}
} // namespace gmock_callback_support_internal
namespace test {
// Matchers for base::{Once,Repeating}Callback and
// base::{Once,Repeating}Closure.
MATCHER(IsNullCallback, "a null callback") {
return (arg.is_null());
}
MATCHER(IsNotNullCallback, "a non-null callback") {
return (!arg.is_null());
}
// The Run[Once]Closure() action invokes the Run() method on the closure
// provided when the action is constructed. Function arguments passed when the
// action is run will be ignored.
ACTION_P(RunClosure, closure) {
closure.Run();
}
// This action can be invoked at most once. Any further invocation will trigger
// a CHECK failure.
inline auto RunOnceClosure(OnceClosure cb) {
// Mock actions need to be copyable, but OnceClosure is not. Wrap the closure
// in a base::RefCountedData<> to allow it to be copied.
using RefCountedOnceClosure = RefCountedData<OnceClosure>;
scoped_refptr<RefCountedOnceClosure> copyable_cb =
MakeRefCounted<RefCountedOnceClosure>(std::move(cb));
return [copyable_cb](auto&&...) {
CHECK(copyable_cb->data);
std::move(copyable_cb->data).Run();
};
}
// The Run[Once]Closure<N>() action invokes the Run() method on the N-th
// (0-based) argument of the mock function.
template <size_t I>
auto RunClosure() {
return [](auto&&... args) -> decltype(auto) {
return gmock_callback_support_internal::get<I>(args...).Run();
};
}
template <size_t I>
auto RunOnceClosure() {
return [](auto&&... args) -> decltype(auto) {
return std::move(gmock_callback_support_internal::get<I>(args...)).Run();
};
}
// The Run[Once]Callback<N>(p1, p2, ..., p_k) action invokes the Run() method on
// the N-th (0-based) argument of the mock function, with arguments p1, p2, ...,
// p_k.
//
// Notes:
//
// 1. The arguments are passed by value by default. If you need to
// pass an argument by reference, wrap it inside ByRef(). For example,
//
// RunCallback<1>(5, string("Hello"), ByRef(foo))
//
// passes 5 and string("Hello") by value, and passes foo by reference.
//
// 2. If the callback takes an argument by reference but ByRef() is
// not used, it will receive the reference to a copy of the value,
// instead of the original value. For example, when the 0-th
// argument of the callback takes a const string&, the action
//
// RunCallback<0>(string("Hello"))
//
// makes a copy of the temporary string("Hello") object and passes a
// reference of the copy, instead of the original temporary object,
// to the callback. This makes it easy for a user to define an
// RunCallback action from temporary values and have it performed later.
//
// 3. There are two separate APIs for interacting with OnceCallback<> --
// RunOnceCallback<> and RunOnceCallbackRepeatedly<>. In the former, arguments
// are copies during each run; in the latter, they are passed by move.
// Note that RunOnceCallback<> cannot be used with WillRepeatedly() since its
// arguments are moved out upon first invocation -- the code doing so will
// crash with a CHECK().
// Using move-only arguments with `RunCallback()` is not supported.
template <size_t I, typename... RunArgs>
auto RunOnceCallback(RunArgs&&... run_args) {
// Mock actions have to be copyable. However, since this action is only
// supposed to be invoked once and might contain move-only arguments, the arg
// tuple is explicitly wrapped as RefCountedData<> to allow shallow copies.
return
[tuple_ptr = gmock_callback_support_internal::WrapTupleAsRefCountedData(
std::make_tuple(std::forward<RunArgs>(run_args)...))](
auto&&... args) -> decltype(auto) {
CHECK(tuple_ptr->data)
<< "A RunOnceCallback() action must be called at most once. "
"Use RunOnceCallbackRepeatedly() for invoking a "
"OnceCallback<> more than once.";
auto data = std::exchange(tuple_ptr->data, nullptr);
return gmock_callback_support_internal::RunImpl(
std::move(gmock_callback_support_internal::get<I>(args...)),
std::move(*data));
};
}
template <size_t I, typename... RunArgs>
auto RunOnceCallbackRepeatedly(RunArgs&&... run_args) {
return [tuple = std::make_tuple(std::forward<RunArgs>(run_args)...)](
auto&&... args) -> decltype(auto) {
return gmock_callback_support_internal::RunImpl(
std::move(gmock_callback_support_internal::get<I>(args...)), tuple);
};
}
template <size_t I, typename... RunArgs>
auto RunCallback(RunArgs&&... run_args) {
return [tuple = std::make_tuple(std::forward<RunArgs>(run_args)...)](
auto&&... args) -> decltype(auto) {
return gmock_callback_support_internal::RunImpl(
gmock_callback_support_internal::get<I>(args...), tuple);
};
}
} // namespace test
} // namespace base
#endif // BASE_TEST_GMOCK_CALLBACK_SUPPORT_H_