1*6777b538SAndroid Build Coastguard Worker // Copyright 2021 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_TEST_REPEATING_TEST_FUTURE_H_ 6*6777b538SAndroid Build Coastguard Worker #define BASE_TEST_REPEATING_TEST_FUTURE_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <optional> 9*6777b538SAndroid Build Coastguard Worker #include <utility> 10*6777b538SAndroid Build Coastguard Worker 11*6777b538SAndroid Build Coastguard Worker #include "base/check.h" 12*6777b538SAndroid Build Coastguard Worker #include "base/containers/queue.h" 13*6777b538SAndroid Build Coastguard Worker #include "base/memory/weak_ptr.h" 14*6777b538SAndroid Build Coastguard Worker #include "base/run_loop.h" 15*6777b538SAndroid Build Coastguard Worker #include "base/sequence_checker.h" 16*6777b538SAndroid Build Coastguard Worker #include "base/test/test_future_internal.h" 17*6777b538SAndroid Build Coastguard Worker #include "base/thread_annotations.h" 18*6777b538SAndroid Build Coastguard Worker 19*6777b538SAndroid Build Coastguard Worker namespace base::test { 20*6777b538SAndroid Build Coastguard Worker 21*6777b538SAndroid Build Coastguard Worker // DEPRECATED! 22*6777b538SAndroid Build Coastguard Worker // 23*6777b538SAndroid Build Coastguard Worker // Please use `TestFuture` with `TestFuture::GetRepeatingCallback()` instead. 24*6777b538SAndroid Build Coastguard Worker template <typename... Types> 25*6777b538SAndroid Build Coastguard Worker class RepeatingTestFuture { 26*6777b538SAndroid Build Coastguard Worker public: 27*6777b538SAndroid Build Coastguard Worker using TupleType = std::tuple<std::decay_t<Types>...>; 28*6777b538SAndroid Build Coastguard Worker 29*6777b538SAndroid Build Coastguard Worker RepeatingTestFuture() = default; 30*6777b538SAndroid Build Coastguard Worker RepeatingTestFuture(const RepeatingTestFuture&) = delete; 31*6777b538SAndroid Build Coastguard Worker RepeatingTestFuture& operator=(const RepeatingTestFuture&) = delete; 32*6777b538SAndroid Build Coastguard Worker RepeatingTestFuture(RepeatingTestFuture&&) = delete; 33*6777b538SAndroid Build Coastguard Worker RepeatingTestFuture& operator=(RepeatingTestFuture&&) = delete; 34*6777b538SAndroid Build Coastguard Worker ~RepeatingTestFuture() = default; 35*6777b538SAndroid Build Coastguard Worker AddValue(Types...values)36*6777b538SAndroid Build Coastguard Worker void AddValue(Types... values) { 37*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 38*6777b538SAndroid Build Coastguard Worker 39*6777b538SAndroid Build Coastguard Worker elements_.push(std::make_tuple(std::forward<Types>(values)...)); 40*6777b538SAndroid Build Coastguard Worker SignalElementIsAvailable(); 41*6777b538SAndroid Build Coastguard Worker } 42*6777b538SAndroid Build Coastguard Worker 43*6777b538SAndroid Build Coastguard Worker // Waits until an element is available. 44*6777b538SAndroid Build Coastguard Worker // Returns immediately if one or more elements are already available. 45*6777b538SAndroid Build Coastguard Worker // 46*6777b538SAndroid Build Coastguard Worker // Returns true if an element arrived, or false if a timeout happens. 47*6777b538SAndroid Build Coastguard Worker // 48*6777b538SAndroid Build Coastguard Worker // Directly calling Wait() is not required as Take() will also wait for 49*6777b538SAndroid Build Coastguard Worker // the value to arrive, however you can use a direct call to Wait() to 50*6777b538SAndroid Build Coastguard Worker // improve the error reported: 51*6777b538SAndroid Build Coastguard Worker // 52*6777b538SAndroid Build Coastguard Worker // ASSERT_TRUE(queue.Wait()) << "Detailed error message"; 53*6777b538SAndroid Build Coastguard Worker // Wait()54*6777b538SAndroid Build Coastguard Worker [[nodiscard]] bool Wait() { 55*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 56*6777b538SAndroid Build Coastguard Worker 57*6777b538SAndroid Build Coastguard Worker if (IsEmpty()) { 58*6777b538SAndroid Build Coastguard Worker WaitForANewElement(); 59*6777b538SAndroid Build Coastguard Worker } 60*6777b538SAndroid Build Coastguard Worker 61*6777b538SAndroid Build Coastguard Worker return !IsEmpty(); 62*6777b538SAndroid Build Coastguard Worker } 63*6777b538SAndroid Build Coastguard Worker 64*6777b538SAndroid Build Coastguard Worker // Returns a callback that when invoked will store all the argument values, 65*6777b538SAndroid Build Coastguard Worker // and unblock any waiters. 66*6777b538SAndroid Build Coastguard Worker // This method is templated so you can specify how you need the arguments to 67*6777b538SAndroid Build Coastguard Worker // be passed - be it const, as reference, or anything you can think off. 68*6777b538SAndroid Build Coastguard Worker // By default the callback accepts the arguments as `Types...`. 69*6777b538SAndroid Build Coastguard Worker // 70*6777b538SAndroid Build Coastguard Worker // Example usage: 71*6777b538SAndroid Build Coastguard Worker // 72*6777b538SAndroid Build Coastguard Worker // RepeatingTestFuture<int, std::string> future; 73*6777b538SAndroid Build Coastguard Worker // 74*6777b538SAndroid Build Coastguard Worker // // returns base::RepeatingCallback<void(int, std::string)> 75*6777b538SAndroid Build Coastguard Worker // future.GetCallback(); 76*6777b538SAndroid Build Coastguard Worker // 77*6777b538SAndroid Build Coastguard Worker // // returns base::RepeatingCallback<void(int, const std::string&)> 78*6777b538SAndroid Build Coastguard Worker // future.GetCallback<int, const std::string&>(); 79*6777b538SAndroid Build Coastguard Worker // 80*6777b538SAndroid Build Coastguard Worker template <typename... CallbackArgumentsTypes> GetCallback()81*6777b538SAndroid Build Coastguard Worker base::RepeatingCallback<void(CallbackArgumentsTypes...)> GetCallback() { 82*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 83*6777b538SAndroid Build Coastguard Worker return base::BindRepeating( 84*6777b538SAndroid Build Coastguard Worker [](WeakPtr<RepeatingTestFuture<Types...>> future, 85*6777b538SAndroid Build Coastguard Worker CallbackArgumentsTypes... values) { 86*6777b538SAndroid Build Coastguard Worker if (future) { 87*6777b538SAndroid Build Coastguard Worker future->AddValue(std::forward<CallbackArgumentsTypes>(values)...); 88*6777b538SAndroid Build Coastguard Worker } 89*6777b538SAndroid Build Coastguard Worker }, 90*6777b538SAndroid Build Coastguard Worker weak_ptr_factory_.GetWeakPtr()); 91*6777b538SAndroid Build Coastguard Worker } 92*6777b538SAndroid Build Coastguard Worker GetCallback()93*6777b538SAndroid Build Coastguard Worker base::RepeatingCallback<void(Types...)> GetCallback() { 94*6777b538SAndroid Build Coastguard Worker return GetCallback<Types...>(); 95*6777b538SAndroid Build Coastguard Worker } 96*6777b538SAndroid Build Coastguard Worker 97*6777b538SAndroid Build Coastguard Worker // Returns true if no elements are currently present. Note that consuming all 98*6777b538SAndroid Build Coastguard Worker // elements through Take() will cause this method to return true after the 99*6777b538SAndroid Build Coastguard Worker // last available element has been consumed. IsEmpty()100*6777b538SAndroid Build Coastguard Worker bool IsEmpty() const { 101*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 102*6777b538SAndroid Build Coastguard Worker 103*6777b538SAndroid Build Coastguard Worker return elements_.empty(); 104*6777b538SAndroid Build Coastguard Worker } 105*6777b538SAndroid Build Coastguard Worker 106*6777b538SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////// 107*6777b538SAndroid Build Coastguard Worker // Accessor methods only available if each element in the future holds a 108*6777b538SAndroid Build Coastguard Worker // single value. 109*6777b538SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////// 110*6777b538SAndroid Build Coastguard Worker 111*6777b538SAndroid Build Coastguard Worker // Wait for an element to arrive, and move its value out. 112*6777b538SAndroid Build Coastguard Worker // 113*6777b538SAndroid Build Coastguard Worker // Will DCHECK if a timeout happens. 114*6777b538SAndroid Build Coastguard Worker template <typename T = TupleType, internal::EnableIfSingleValue<T> = true> Take()115*6777b538SAndroid Build Coastguard Worker auto Take() { 116*6777b538SAndroid Build Coastguard Worker return std::get<0>(TakeTuple()); 117*6777b538SAndroid Build Coastguard Worker } 118*6777b538SAndroid Build Coastguard Worker 119*6777b538SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////// 120*6777b538SAndroid Build Coastguard Worker // Accessor methods only available if each element in the future holds 121*6777b538SAndroid Build Coastguard Worker // multiple values. 122*6777b538SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////// 123*6777b538SAndroid Build Coastguard Worker 124*6777b538SAndroid Build Coastguard Worker // Wait for an element to arrive, and move a tuple with its values out. 125*6777b538SAndroid Build Coastguard Worker // 126*6777b538SAndroid Build Coastguard Worker // Will DCHECK if a timeout happens. 127*6777b538SAndroid Build Coastguard Worker template <typename T = TupleType, internal::EnableIfMultiValue<T> = true> Take()128*6777b538SAndroid Build Coastguard Worker TupleType Take() { 129*6777b538SAndroid Build Coastguard Worker return TakeTuple(); 130*6777b538SAndroid Build Coastguard Worker } 131*6777b538SAndroid Build Coastguard Worker 132*6777b538SAndroid Build Coastguard Worker private: 133*6777b538SAndroid Build Coastguard Worker // Wait until a new element is available. WaitForANewElement()134*6777b538SAndroid Build Coastguard Worker void WaitForANewElement() VALID_CONTEXT_REQUIRED(sequence_checker_) { 135*6777b538SAndroid Build Coastguard Worker DCHECK(!run_loop_.has_value()); 136*6777b538SAndroid Build Coastguard Worker 137*6777b538SAndroid Build Coastguard Worker // Create a new run loop. 138*6777b538SAndroid Build Coastguard Worker run_loop_.emplace(); 139*6777b538SAndroid Build Coastguard Worker // Wait until 'run_loop_->Quit()' is called. 140*6777b538SAndroid Build Coastguard Worker run_loop_->Run(); 141*6777b538SAndroid Build Coastguard Worker run_loop_.reset(); 142*6777b538SAndroid Build Coastguard Worker } 143*6777b538SAndroid Build Coastguard Worker SignalElementIsAvailable()144*6777b538SAndroid Build Coastguard Worker void SignalElementIsAvailable() VALID_CONTEXT_REQUIRED(sequence_checker_) { 145*6777b538SAndroid Build Coastguard Worker if (run_loop_.has_value()) { 146*6777b538SAndroid Build Coastguard Worker run_loop_->Quit(); 147*6777b538SAndroid Build Coastguard Worker } 148*6777b538SAndroid Build Coastguard Worker } 149*6777b538SAndroid Build Coastguard Worker TakeTuple()150*6777b538SAndroid Build Coastguard Worker TupleType TakeTuple() { 151*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 152*6777b538SAndroid Build Coastguard Worker 153*6777b538SAndroid Build Coastguard Worker // Ensure an element is available. 154*6777b538SAndroid Build Coastguard Worker bool success = Wait(); 155*6777b538SAndroid Build Coastguard Worker DCHECK(success) << "Waiting for an element timed out."; 156*6777b538SAndroid Build Coastguard Worker 157*6777b538SAndroid Build Coastguard Worker auto result = std::move(elements_.front()); 158*6777b538SAndroid Build Coastguard Worker elements_.pop(); 159*6777b538SAndroid Build Coastguard Worker return result; 160*6777b538SAndroid Build Coastguard Worker } 161*6777b538SAndroid Build Coastguard Worker 162*6777b538SAndroid Build Coastguard Worker base::queue<TupleType> elements_ GUARDED_BY_CONTEXT(sequence_checker_); 163*6777b538SAndroid Build Coastguard Worker 164*6777b538SAndroid Build Coastguard Worker // Used by Wait() to know when AddValue() is called. 165*6777b538SAndroid Build Coastguard Worker std::optional<base::RunLoop> run_loop_ GUARDED_BY_CONTEXT(sequence_checker_); 166*6777b538SAndroid Build Coastguard Worker 167*6777b538SAndroid Build Coastguard Worker SEQUENCE_CHECKER(sequence_checker_); 168*6777b538SAndroid Build Coastguard Worker 169*6777b538SAndroid Build Coastguard Worker base::WeakPtrFactory<RepeatingTestFuture<Types...>> weak_ptr_factory_{this}; 170*6777b538SAndroid Build Coastguard Worker }; 171*6777b538SAndroid Build Coastguard Worker 172*6777b538SAndroid Build Coastguard Worker // Specialization so you can use `RepeatingTestFuture` to wait for a no-args 173*6777b538SAndroid Build Coastguard Worker // callback. 174*6777b538SAndroid Build Coastguard Worker template <> 175*6777b538SAndroid Build Coastguard Worker class RepeatingTestFuture<void> { 176*6777b538SAndroid Build Coastguard Worker public: AddValue()177*6777b538SAndroid Build Coastguard Worker void AddValue() { implementation_.AddValue(true); } 178*6777b538SAndroid Build Coastguard Worker 179*6777b538SAndroid Build Coastguard Worker // Waits until the callback or `AddValue()` is invoked. 180*6777b538SAndroid Build Coastguard Worker // Returns immediately if one or more invocations have already happened. 181*6777b538SAndroid Build Coastguard Worker // 182*6777b538SAndroid Build Coastguard Worker // Returns true if an invocation arrived, or false if a timeout happens. 183*6777b538SAndroid Build Coastguard Worker // 184*6777b538SAndroid Build Coastguard Worker // Directly calling Wait() is not required as Take() will also wait for 185*6777b538SAndroid Build Coastguard Worker // the invocation to arrive, however you can use a direct call to Wait() to 186*6777b538SAndroid Build Coastguard Worker // improve the error reported: 187*6777b538SAndroid Build Coastguard Worker // 188*6777b538SAndroid Build Coastguard Worker // ASSERT_TRUE(queue.Wait()) << "Detailed error message"; 189*6777b538SAndroid Build Coastguard Worker // Wait()190*6777b538SAndroid Build Coastguard Worker [[nodiscard]] bool Wait() { return implementation_.Wait(); } 191*6777b538SAndroid Build Coastguard Worker 192*6777b538SAndroid Build Coastguard Worker // Returns a callback that when invoked will unblock any waiters. GetCallback()193*6777b538SAndroid Build Coastguard Worker base::RepeatingClosure GetCallback() { 194*6777b538SAndroid Build Coastguard Worker return base::BindRepeating(implementation_.GetCallback(), true); 195*6777b538SAndroid Build Coastguard Worker } 196*6777b538SAndroid Build Coastguard Worker 197*6777b538SAndroid Build Coastguard Worker // Returns true if no elements are currently present. Note that consuming all 198*6777b538SAndroid Build Coastguard Worker // elements through Take() will cause this method to return true after the 199*6777b538SAndroid Build Coastguard Worker // last available element has been consumed. IsEmpty()200*6777b538SAndroid Build Coastguard Worker bool IsEmpty() const { return implementation_.IsEmpty(); } 201*6777b538SAndroid Build Coastguard Worker 202*6777b538SAndroid Build Coastguard Worker // Waits until the callback or `AddValue()` is invoked. 203*6777b538SAndroid Build Coastguard Worker // 204*6777b538SAndroid Build Coastguard Worker // Will DCHECK if a timeout happens. Take()205*6777b538SAndroid Build Coastguard Worker void Take() { implementation_.Take(); } 206*6777b538SAndroid Build Coastguard Worker 207*6777b538SAndroid Build Coastguard Worker private: 208*6777b538SAndroid Build Coastguard Worker RepeatingTestFuture<bool> implementation_; 209*6777b538SAndroid Build Coastguard Worker }; 210*6777b538SAndroid Build Coastguard Worker 211*6777b538SAndroid Build Coastguard Worker } // namespace base::test 212*6777b538SAndroid Build Coastguard Worker 213*6777b538SAndroid Build Coastguard Worker #endif // BASE_TEST_REPEATING_TEST_FUTURE_H_ 214