xref: /aosp_15_r20/external/cronet/base/test/gmock_callback_support.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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