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