1 // Copyright 2017 The Chromium Authors 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/functional/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 // If WTF::BindRepeating is available, and a callback argument is in WTF, then 55 // this call is ambiguous without the full namespace path. 56 return ::base::BindRepeating( 57 &internal::BindLambdaHelper<Lambda, Signature>::Run, 58 std::forward<Lambda>(lambda)); 59 } 60 61 // A variant of BindOnce() that can bind mutable capturing lambdas for 62 // testing. This doesn't support extra arguments binding as the lambda itself 63 // can do. Since a mutable lambda potentially can invalidate its state after 64 // being run once, this method returns a OnceCallback instead of a 65 // RepeatingCallback. 66 template <typename Lambda, 67 std::enable_if_t<!internal::HasConstCallOperator<Lambda>>* = nullptr> 68 decltype(auto) BindLambdaForTesting(Lambda&& lambda) { 69 static_assert( 70 std::is_rvalue_reference<Lambda&&>() && 71 !std::is_const<std::remove_reference_t<Lambda>>(), 72 "BindLambdaForTesting requires non-const rvalue for mutable lambda " 73 "binding. I.e.: base::BindLambdaForTesting(std::move(lambda))."); 74 using Signature = internal::ExtractCallableRunType<std::decay_t<Lambda>>; 75 return BindOnce(&internal::BindLambdaHelper<Lambda, Signature>::RunOnce, 76 std::move(lambda)); 77 } 78 79 // Returns a closure that fails on destruction if it hasn't been run. 80 OnceClosure MakeExpectedRunClosure(const Location& location, 81 StringPiece message = StringPiece()); 82 RepeatingClosure MakeExpectedRunAtLeastOnceClosure( 83 const Location& location, 84 StringPiece message = StringPiece()); 85 86 // Returns a closure that fails the test if run. 87 RepeatingClosure MakeExpectedNotRunClosure(const Location& location, 88 StringPiece message = StringPiece()); 89 90 } // namespace base 91 92 #endif // BASE_TEST_BIND_H_ 93