1 // Copyright 2017 The Chromium Authors. All rights reserved.
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_BIND_H_
6 #define BASE_TEST_BIND_H_
7 
8 #include <type_traits>
9 #include <utility>
10 
11 #include "base/bind.h"
12 #include "base/strings/string_piece.h"
13 
14 namespace base {
15 
16 class Location;
17 
18 namespace internal {
19 
20 template <typename Callable,
21           typename Signature = decltype(&Callable::operator())>
22 struct HasConstCallOperatorImpl : std::false_type {};
23 
24 template <typename Callable, typename R, typename... Args>
25 struct HasConstCallOperatorImpl<Callable, R (Callable::*)(Args...) const>
26     : std::true_type {};
27 
28 template <typename Callable>
29 constexpr bool HasConstCallOperator =
30     HasConstCallOperatorImpl<std::decay_t<Callable>>::value;
31 
32 template <typename F, typename Signature>
33 struct BindLambdaHelper;
34 
35 template <typename F, typename R, typename... Args>
36 struct BindLambdaHelper<F, R(Args...)> {
37   static R Run(const std::decay_t<F>& f, Args... args) {
38     return f(std::forward<Args>(args)...);
39   }
40 
41   static R RunOnce(std::decay_t<F>&& f, Args... args) {
42     return f(std::forward<Args>(args)...);
43   }
44 };
45 
46 }  // namespace internal
47 
48 // A variant of BindRepeating() that can bind capturing lambdas for testing.
49 // This doesn't support extra arguments binding as the lambda itself can do.
50 template <typename Lambda,
51           std::enable_if_t<internal::HasConstCallOperator<Lambda>>* = nullptr>
52 decltype(auto) BindLambdaForTesting(Lambda&& lambda) {
53   using Signature = internal::ExtractCallableRunType<std::decay_t<Lambda>>;
54   return BindRepeating(&internal::BindLambdaHelper<Lambda, Signature>::Run,
55                        std::forward<Lambda>(lambda));
56 }
57 
58 // A variant of BindRepeating() that can bind mutable capturing lambdas for
59 // testing. This doesn't support extra arguments binding as the lambda itself
60 // can do. Since a mutable lambda potentially can invalidate its state after
61 // being run once, this method returns a OnceCallback instead of a
62 // RepeatingCallback.
63 template <typename Lambda,
64           std::enable_if_t<!internal::HasConstCallOperator<Lambda>>* = nullptr>
65 decltype(auto) BindLambdaForTesting(Lambda&& lambda) {
66   static_assert(
67       std::is_rvalue_reference<Lambda&&>() &&
68           !std::is_const<std::remove_reference_t<Lambda>>(),
69       "BindLambdaForTesting requires non-const rvalue for mutable lambda "
70       "binding. I.e.: base::BindLambdaForTesting(std::move(lambda)).");
71   using Signature = internal::ExtractCallableRunType<std::decay_t<Lambda>>;
72   return BindOnce(&internal::BindLambdaHelper<Lambda, Signature>::RunOnce,
73                   std::move(lambda));
74 }
75 
76 // Returns a closure that fails on destruction if it hasn't been run.
77 OnceClosure MakeExpectedRunClosure(const Location& location,
78                                    StringPiece message = StringPiece());
79 RepeatingClosure MakeExpectedRunAtLeastOnceClosure(
80     const Location& location,
81     StringPiece message = StringPiece());
82 
83 // Returns a closure that fails the test if run.
84 RepeatingClosure MakeExpectedNotRunClosure(const Location& location,
85                                            StringPiece message = StringPiece());
86 
87 }  // namespace base
88 
89 #endif  // BASE_TEST_BIND_H_
90