blob: 61b880d9475b2ba6847084f1161c86232a97cfe5 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// 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 <functional>
#include <tuple>
#include <utility>
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace base {
namespace test {
// TODO(crbug.com/752720): Simplify using std::apply once C++17 is available.
template <typename CallbackFunc, typename ArgTuple, size_t... I>
decltype(auto) RunOnceCallbackUnwrapped(CallbackFunc&& f,
ArgTuple&& t,
std::index_sequence<I...>) {
return std::move(f).Run(std::get<I>(t)...);
}
// TODO(crbug.com/752720): Simplify using std::apply once C++17 is available.
template <typename CallbackFunc, typename ArgTuple, size_t... I>
decltype(auto) RunRepeatingCallbackUnwrapped(CallbackFunc&& f,
ArgTuple&& t,
std::index_sequence<I...>) {
return f.Run(std::get<I>(t)...);
}
// Functor used for RunOnceClosure<N>() and RunOnceCallback<N>() actions.
template <size_t I, typename... Vals>
struct RunOnceCallbackAction {
std::tuple<Vals...> vals;
template <typename... Args>
decltype(auto) operator()(Args&&... args) {
constexpr size_t size = std::tuple_size<decltype(vals)>::value;
return RunOnceCallbackUnwrapped(
std::get<I>(std::forward_as_tuple(std::forward<Args>(args)...)),
std::move(vals), std::make_index_sequence<size>{});
}
};
// Functor used for RunClosure<N>() and RunCallback<N>() actions.
template <size_t I, typename... Vals>
struct RunRepeatingCallbackAction {
std::tuple<Vals...> vals;
template <typename... Args>
decltype(auto) operator()(Args&&... args) {
constexpr size_t size = std::tuple_size<decltype(vals)>::value;
return RunRepeatingCallbackUnwrapped(
std::get<I>(std::forward_as_tuple(std::forward<Args>(args)...)),
std::move(vals), std::make_index_sequence<size>{});
}
};
// 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(base::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. An alternative would
// be to use AdaptCallbackForRepeating(), but that allows the closure to be
// run more than once and silently ignores any invocation after the first.
// Since this is for use by tests, it's better to crash or CHECK-fail and
// surface the incorrect usage, rather than have a silent unexpected success.
using RefCountedOnceClosure = base::RefCountedData<base::OnceClosure>;
scoped_refptr<RefCountedOnceClosure> copyable_cb =
base::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>
RunRepeatingCallbackAction<I> RunClosure() {
return {};
}
template <size_t I>
RunOnceCallbackAction<I> RunOnceClosure() {
return {};
}
// 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.
template <size_t I, typename... Vals>
RunOnceCallbackAction<I, std::decay_t<Vals>...> RunOnceCallback(
Vals&&... vals) {
return {std::forward_as_tuple(std::forward<Vals>(vals)...)};
}
template <size_t I, typename... Vals>
RunRepeatingCallbackAction<I, std::decay_t<Vals>...> RunCallback(
Vals&&... vals) {
return {std::forward_as_tuple(std::forward<Vals>(vals)...)};
}
} // namespace test
} // namespace base
#endif // BASE_TEST_GMOCK_CALLBACK_SUPPORT_H_