1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 <functional>
9 #include <tuple>
10 #include <type_traits>
11 #include <utility>
12 
13 #include "base/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 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 // Invokes `cb` with the arguments stored in `tuple`. Both `cb` and `tuple` are
29 // perfectly forwarded, allowing callers to specify whether they should be
30 // passed by move or copy.
31 template <typename Callback, typename Tuple, size_t... Is>
decltype(auto)32 decltype(auto) RunImpl(Callback&& cb,
33                        Tuple&& tuple,
34                        std::index_sequence<Is...>) {
35   return std::forward<Callback>(cb).Run(
36       std::get<Is>(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. Needs to dispatch to the three arguments version to
42 // be able to construct a `std::index_sequence` of the corresponding size.
43 template <typename Callback, typename Tuple>
decltype(auto)44 decltype(auto) RunImpl(Callback&& cb, Tuple&& tuple) {
45   return RunImpl(std::forward<Callback>(cb), std::forward<Tuple>(tuple),
46                  std::make_index_sequence<
47                      std::tuple_size<std::remove_reference_t<Tuple>>::value>());
48 }
49 
50 // Invoked when the arguments to a OnceCallback are copy constructible. In this
51 // case the returned lambda will pass the arguments to the provided callback by
52 // copy, allowing it to be used multiple times.
53 template <size_t I,
54           typename Tuple,
55           std::enable_if_t<std::is_copy_constructible<Tuple>::value, int> = 0>
RunOnceCallbackImpl(Tuple && tuple)56 auto RunOnceCallbackImpl(Tuple&& tuple) {
57   return
58       [tuple = std::forward<Tuple>(tuple)](auto&&... args) -> decltype(auto) {
59         return RunImpl(std::move(internal::get<I>(args...)), tuple);
60       };
61 }
62 
63 // Invoked when the arguments to a OnceCallback are not copy constructible. In
64 // this case the returned lambda will pass the arguments to the provided
65 // callback by move, allowing it to be only used once.
66 template <size_t I,
67           typename Tuple,
68           std::enable_if_t<!std::is_copy_constructible<Tuple>::value, int> = 0>
RunOnceCallbackImpl(Tuple && tuple)69 auto RunOnceCallbackImpl(Tuple&& tuple) {
70   // Mock actions need to be copyable, but `tuple` is not. Wrap it in in a
71   // `scoped_refptr` to allow it to be copied.
72   auto tuple_ptr = base::MakeRefCounted<base::RefCountedData<Tuple>>(
73       std::forward<Tuple>(tuple));
74   return [tuple_ptr =
75               std::move(tuple_ptr)](auto&&... args) mutable -> decltype(auto) {
76     // Since running the action will move out of the arguments, `tuple_ptr` is
77     // nulled out, so that attempting to run it twice will result in a run-time
78     // crash.
79     return RunImpl(std::move(internal::get<I>(args...)),
80                    std::move(std::exchange(tuple_ptr, nullptr)->data));
81   };
82 }
83 
84 // Invoked for RepeatingCallbacks. In this case the returned lambda will pass
85 // the arguments to the provided callback by copy, allowing it to be used
86 // multiple times. Move-only arguments are not supported.
87 template <size_t I, typename Tuple>
RunRepeatingCallbackImpl(Tuple && tuple)88 auto RunRepeatingCallbackImpl(Tuple&& tuple) {
89   return
90       [tuple = std::forward<Tuple>(tuple)](auto&&... args) -> decltype(auto) {
91         return RunImpl(internal::get<I>(args...), tuple);
92       };
93 }
94 
95 }  // namespace internal
96 
97 namespace test {
98 
99 // Matchers for base::{Once,Repeating}Callback and
100 // base::{Once,Repeating}Closure.
101 MATCHER(IsNullCallback, "a null callback") {
102   return (arg.is_null());
103 }
104 
105 MATCHER(IsNotNullCallback, "a non-null callback") {
106   return (!arg.is_null());
107 }
108 
109 // The Run[Once]Closure() action invokes the Run() method on the closure
110 // provided when the action is constructed. Function arguments passed when the
111 // action is run will be ignored.
ACTION_P(RunClosure,closure)112 ACTION_P(RunClosure, closure) {
113   closure.Run();
114 }
115 
116 // This action can be invoked at most once. Any further invocation will trigger
117 // a CHECK failure.
RunOnceClosure(base::OnceClosure cb)118 inline auto RunOnceClosure(base::OnceClosure cb) {
119   // Mock actions need to be copyable, but OnceClosure is not. Wrap the closure
120   // in a base::RefCountedData<> to allow it to be copied. An alternative would
121   // be to use AdaptCallbackForRepeating(), but that allows the closure to be
122   // run more than once and silently ignores any invocation after the first.
123   // Since this is for use by tests, it's better to crash or CHECK-fail and
124   // surface the incorrect usage, rather than have a silent unexpected success.
125   using RefCountedOnceClosure = base::RefCountedData<base::OnceClosure>;
126   scoped_refptr<RefCountedOnceClosure> copyable_cb =
127       base::MakeRefCounted<RefCountedOnceClosure>(std::move(cb));
128   return [copyable_cb](auto&&...) {
129     CHECK(copyable_cb->data);
130     std::move(copyable_cb->data).Run();
131   };
132 }
133 
134 // The Run[Once]Closure<N>() action invokes the Run() method on the N-th
135 // (0-based) argument of the mock function.
136 template <size_t I>
RunClosure()137 auto RunClosure() {
138   return [](auto&&... args) -> decltype(auto) {
139     return internal::get<I>(args...).Run();
140   };
141 }
142 
143 template <size_t I>
RunOnceClosure()144 auto RunOnceClosure() {
145   return [](auto&&... args) -> decltype(auto) {
146     return std::move(internal::get<I>(args...)).Run();
147   };
148 }
149 
150 // The Run[Once]Callback<N>(p1, p2, ..., p_k) action invokes the Run() method on
151 // the N-th (0-based) argument of the mock function, with arguments p1, p2, ...,
152 // p_k.
153 //
154 // Notes:
155 //
156 //   1. The arguments are passed by value by default.  If you need to
157 //   pass an argument by reference, wrap it inside ByRef().  For example,
158 //
159 //     RunCallback<1>(5, string("Hello"), ByRef(foo))
160 //
161 //   passes 5 and string("Hello") by value, and passes foo by reference.
162 //
163 //   2. If the callback takes an argument by reference but ByRef() is
164 //   not used, it will receive the reference to a copy of the value,
165 //   instead of the original value.  For example, when the 0-th
166 //   argument of the callback takes a const string&, the action
167 //
168 //     RunCallback<0>(string("Hello"))
169 //
170 //   makes a copy of the temporary string("Hello") object and passes a
171 //   reference of the copy, instead of the original temporary object,
172 //   to the callback.  This makes it easy for a user to define an
173 //   RunCallback action from temporary values and have it performed later.
174 //
175 //   3. In order to facilitate re-use of the `RunOnceCallback()` action,
176 //   the arguments are copied during each run if possible. If this can't
177 //   be done (e.g. one of the arguments is move-only), the arguments will
178 //   be passed by move. However, since moving potentially invalidates the
179 //   arguments, the resulting action is only allowed to run once in this
180 //   case. Attempting to run it twice will result in a runtime crash.
181 //   Using move-only arguments with `RunCallback()` is not supported.
182 template <size_t I, typename... RunArgs>
RunOnceCallback(RunArgs &&...run_args)183 auto RunOnceCallback(RunArgs&&... run_args) {
184   return internal::RunOnceCallbackImpl<I>(
185       std::make_tuple(std::forward<RunArgs>(run_args)...));
186 }
187 
188 template <size_t I, typename... RunArgs>
RunCallback(RunArgs &&...run_args)189 auto RunCallback(RunArgs&&... run_args) {
190   return internal::RunRepeatingCallbackImpl<I>(
191       std::make_tuple(std::forward<RunArgs>(run_args)...));
192 }
193 
194 }  // namespace test
195 }  // namespace base
196 
197 #endif  // BASE_TEST_GMOCK_CALLBACK_SUPPORT_H_
198