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

base / test / gmock_move_support.h [blame]

// Copyright 2019 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_MOVE_SUPPORT_H_
#define BASE_TEST_GMOCK_MOVE_SUPPORT_H_

#include <cstddef>
#include <tuple>
#include <utility>

// Moves the `I`th argument to `out`. Analogous to `testing::SaveArg()`, which
// copies instead.
//
// Example:
//
//   std::unique_ptr<int> result;
//   EXPECT_CALL(mocked_object, Method).WillOnce(MoveArg<0>(&result));
//   mocked_object.Method(std::make_unique<int>(123));
//   EXPECT_THAT(result, Pointee(Eq(123)));
//
// Important: it is not possible to use multiple `MoveArg()` actions in a single
// `DoAll()`: per the googlemock documentation, all but the last action receive
// a read-only view of the arguments. Allowing an intermediate action to consume
// the arguments would leave the original arguments in an unspecified state for
// invoking subsequent actions, which is dubious.
//
// A simple workaround is to use `Invoke()` with a lambda instead, e.g.
//
//   std::unique_ptr<int> int_result;
//   std::unique_ptr<double> double_result;
//   EXPECT_CALL(mocked_object, Method).WillOnce(Invoke(
//       [&] (auto&& arg1, auto&& arg2) {
//         int_result = std::move(arg1);
//         double_result = std::move(arg2);
//         return 42;
//       }));
//   EXPECT_EQ(42, mocked_object.Method(std::make_unique<int>(123),
//                                      std::make_unique<double>(0.5)));
//   EXPECT_THAT(int_result, Pointee(Eq(123)));
//   EXPECT_THAT(double_result, Pointee(DoubleEq(0.5)));

template <size_t I = 0, typename T>
auto MoveArg(T* out) {
  return [out](auto&&... args) {
    *out = std::move(std::get<I>(std::tie(args...)));
  };
}

// Moves the `I`th argument to `*out` and returns `return_value`.
//
// This is a convenience helper for code that wants to write the following:
//
//   DoAll(MoveArg<N>(&saved_arg), Return(value))
//
// The above is not actually possible to write because:
// - `DoAll()` requires that its final action has a return type that matches the
//   mocked call's return type. So `Return()` must be last.
// - But any actions before the last receive a read-only view of the arguments.
//   So `MoveArg()` receives a read-only view and cannot move out of it.
//
// Example:
//
//   std::unique_ptr<int> result;
//   EXPECT_CALL(mocked_object, Method).WillOnce(
//       MoveArgAndReturn<0>(&result, true));
//   EXPECT_TRUE(mocked_object.Method(std::make_unique<int>(123)));
//   EXPECT_THAT(int_result, Pointee(Eq(123)));
//
template <size_t I = 0, typename T1, typename T2>
auto MoveArgAndReturn(T1* out, T2&& return_value) {
  return [out, value = std::forward<T2>(return_value)](auto&&... args) mutable {
    *out = std::move(std::get<I>(std::tie(args...)));
    return std::forward<T2>(value);
  };
}

#endif  // BASE_TEST_GMOCK_MOVE_SUPPORT_H_