text: // 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 "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.
  ACTION_P(RunClosure, closure) {
    closure.Run();
  }
  
  // TODO(kylechar): This action can't take a OnceClosure by value, fix that.
  ACTION_P(RunOnceClosure, closure) {
    std::move(closure).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_
  