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
|
// 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_
|