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