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 // Implementation of `BindLambdaForTesting()`, which checks preconditions before 21 // handing off to `Bind{Once,Repeating}()`. 22 template <typename Lambda, 23 typename = ExtractCallableRunType<std::decay_t<Lambda>>> 24 struct BindLambdaForTestingHelper; 25 26 template <typename Lambda, typename R, typename... Args> 27 struct BindLambdaForTestingHelper<Lambda, R(Args...)> { 28 private: 29 using F = std::decay_t<Lambda>; 30 31 template <typename = decltype(&F::operator())> 32 static constexpr bool kHasConstCallOperator = false; 33 template <> 34 static constexpr bool kHasConstCallOperator<R (F::*)(Args...) const> = true; 35 36 // For context on this "templated struct with a lambda that asserts" pattern, 37 // see comments in MakeBindStateTypeImpl. 38 template <bool v = std::is_rvalue_reference_v<Lambda&&> && 39 !std::is_const_v<std::remove_reference_t<Lambda>>> 40 struct IsNonConstRvalueRef { 41 static constexpr bool value = [] { 42 static_assert( 43 v, 44 "BindLambdaForTesting() requires non-const rvalue for mutable lambda " 45 "binding, i.e. base::BindLambdaForTesting(std::move(lambda))."); 46 return v; 47 }(); 48 }; 49 50 static R Run(const F& f, Args... args) { 51 return f(std::forward<Args>(args)...); 52 } 53 54 static R RunOnce(F&& f, Args... args) { 55 return f(std::forward<Args>(args)...); 56 } 57 58 public: 59 static auto BindLambdaForTesting(Lambda&& lambda) { 60 if constexpr (kHasConstCallOperator<>) { 61 // If WTF::BindRepeating is available, and a callback argument is in WTF, 62 // then this call is ambiguous without the full namespace path. 63 return ::base::BindRepeating(&Run, std::forward<Lambda>(lambda)); 64 } else if constexpr (IsNonConstRvalueRef<>::value) { 65 // Since a mutable lambda potentially can invalidate its state after being 66 // run once, this method returns a `OnceCallback` instead of a 67 // `RepeatingCallback`. 68 return BindOnce(&RunOnce, std::move(lambda)); 69 } 70 } 71 }; 72 73 } // namespace internal 74 75 // A variant of `Bind{Once,Repeating}()` that can bind capturing lambdas for 76 // testing. This doesn't support extra arguments binding as the lambda itself 77 // can do. 78 template <typename Lambda> 79 auto BindLambdaForTesting(Lambda&& lambda) { 80 return internal::BindLambdaForTestingHelper<Lambda>::BindLambdaForTesting( 81 std::forward<Lambda>(lambda)); 82 } 83 84 // Returns a closure that fails on destruction if it hasn't been run. 85 OnceClosure MakeExpectedRunClosure(const Location& location, 86 StringPiece message = StringPiece()); 87 RepeatingClosure MakeExpectedRunAtLeastOnceClosure( 88 const Location& location, 89 StringPiece message = StringPiece()); 90 91 // Returns a closure that fails the test if run. 92 RepeatingClosure MakeExpectedNotRunClosure(const Location& location, 93 StringPiece message = StringPiece()); 94 95 } // namespace base 96 97 #endif // BASE_TEST_BIND_H_ 98