repeating_test_future.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // Copyright 2021 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. #ifndef BASE_TEST_REPEATING_TEST_FUTURE_H_
  5. #define BASE_TEST_REPEATING_TEST_FUTURE_H_
  6. #include <utility>
  7. #include "base/check.h"
  8. #include "base/containers/queue.h"
  9. #include "base/memory/weak_ptr.h"
  10. #include "base/run_loop.h"
  11. #include "base/sequence_checker.h"
  12. #include "base/test/test_future_internal.h"
  13. #include "base/thread_annotations.h"
  14. #include "third_party/abseil-cpp/absl/types/optional.h"
  15. namespace base::test {
  16. // Related class to |base::test::TestFuture|, which allows its callback and
  17. // AddValue() method to be called multiple times.
  18. //
  19. // Each call to Take() will return one element in FIFO fashion.
  20. // If no element is available, Take() will wait until an element becomes
  21. // available.
  22. //
  23. // Just like |base::test::TestFuture|, |base::test::RepeatingTestFuture| also
  24. // supports callbacks which take multiple values. If this is the case Take()
  25. // will return a tuple containing all values passed to the callback.
  26. //
  27. // Example usage:
  28. //
  29. // TEST_F(MyTestFixture, MyTest) {
  30. // RepeatingTestFuture<ResultType> future;
  31. //
  32. // InvokeCallbackAsyncTwice(future.GetCallback());
  33. //
  34. // ResultType first_result = future.Get();
  35. // ResultType second_result = future.Get();
  36. //
  37. // // When you come here, InvokeCallbackAsyncTwice has finished,
  38. // // |first_result| contains the value passed to the first invocation
  39. // // of the callback, and |second_result| has the result of the second
  40. // // invocation.
  41. // }
  42. //
  43. // Example without using a callback but using AddValue() instead:
  44. //
  45. // TEST_F(MyTestFixture, MyTest) {
  46. // RepeatingTestFuture<std::string> future;
  47. //
  48. // // AddValue() can be used to add an element to the future.
  49. // future.AddValue("first-value");
  50. // future.AddValue("second-value");
  51. //
  52. // EXPECT_EQ("first-value", future.Take());
  53. // EXPECT_EQ("second-value", future.Take());
  54. // }
  55. //
  56. // Or an example using RepeatingTestFuture::Wait():
  57. //
  58. // TEST_F(MyTestFixture, MyWaitTest) {
  59. // RepeatingTestFuture<ResultType> future;
  60. //
  61. // object_under_test.DoSomethingAsync(future.GetCallback());
  62. //
  63. // // Optional. The Take() call below will also wait until the value
  64. // // arrives, but this explicit call to Wait() can be useful if you want to
  65. // // add extra information.
  66. // ASSERT_TRUE(future.Wait()) << "Detailed error message";
  67. //
  68. // ResultType actual_result = future.Take();
  69. // }
  70. //
  71. // All access to this class must be made from the same sequence.
  72. template <typename... Types>
  73. class RepeatingTestFuture {
  74. public:
  75. using TupleType = std::tuple<std::decay_t<Types>...>;
  76. using FirstType = typename std::tuple_element<0, TupleType>::type;
  77. RepeatingTestFuture() = default;
  78. RepeatingTestFuture(const RepeatingTestFuture&) = delete;
  79. RepeatingTestFuture& operator=(const RepeatingTestFuture&) = delete;
  80. RepeatingTestFuture(RepeatingTestFuture&&) = delete;
  81. RepeatingTestFuture& operator=(RepeatingTestFuture&&) = delete;
  82. ~RepeatingTestFuture() = default;
  83. void AddValue(Types... values) {
  84. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  85. elements_.push(std::make_tuple(std::forward<Types>(values)...));
  86. SignalElementIsAvailable();
  87. }
  88. // Waits until an element is available.
  89. // Returns immediately if one or more elements are already available.
  90. //
  91. // Returns true if an element arrived, or false if a timeout happens.
  92. //
  93. // Directly calling Wait() is not required as Take() will also wait for
  94. // the value to arrive, however you can use a direct call to Wait() to
  95. // improve the error reported:
  96. //
  97. // ASSERT_TRUE(queue.Wait()) << "Detailed error message";
  98. //
  99. [[nodiscard]] bool Wait() {
  100. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  101. if (IsEmpty())
  102. WaitForANewElement();
  103. return !IsEmpty();
  104. }
  105. // Returns a callback that when invoked will store all the argument values,
  106. // and unblock any waiters.
  107. // This method is templated so you can specify how you need the arguments to
  108. // be passed - be it const, as reference, or anything you can think off.
  109. // By default the callback accepts the arguments as |Types...|.
  110. //
  111. // Example usage:
  112. //
  113. // RepeatingTestFuture<int, std::string> future;
  114. //
  115. // // returns base::RepeatingCallback<void(int, std::string)>
  116. // future.GetCallback();
  117. //
  118. // // returns base::RepeatingCallback<void(int, const std::string&)>
  119. // future.GetCallback<int, const std::string&>();
  120. //
  121. template <typename... CallbackArgumentsTypes>
  122. base::RepeatingCallback<void(CallbackArgumentsTypes...)> GetCallback() {
  123. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  124. return base::BindRepeating(
  125. [](WeakPtr<RepeatingTestFuture<Types...>> future,
  126. CallbackArgumentsTypes... values) {
  127. if (future)
  128. future->AddValue(std::forward<CallbackArgumentsTypes>(values)...);
  129. },
  130. weak_ptr_factory_.GetWeakPtr());
  131. }
  132. base::RepeatingCallback<void(Types...)> GetCallback() {
  133. return GetCallback<Types...>();
  134. }
  135. // Returns true if no elements are currently present. Note that consuming all
  136. // elements through Take() will cause this method to return true after the
  137. // last available element has been consumed.
  138. bool IsEmpty() const {
  139. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  140. return elements_.empty();
  141. }
  142. //////////////////////////////////////////////////////////////////////////////
  143. // Accessor methods only available if each element in the future holds a
  144. // single value.
  145. //////////////////////////////////////////////////////////////////////////////
  146. // Wait for an element to arrive, and move its value out.
  147. //
  148. // Will DCHECK if a timeout happens.
  149. template <typename T = TupleType, internal::EnableIfSingleValue<T> = true>
  150. FirstType Take() {
  151. return std::get<0>(TakeTuple());
  152. }
  153. //////////////////////////////////////////////////////////////////////////////
  154. // Accessor methods only available if each element in the future holds
  155. // multiple values.
  156. //////////////////////////////////////////////////////////////////////////////
  157. // Wait for an element to arrive, and move a tuple with its values out.
  158. //
  159. // Will DCHECK if a timeout happens.
  160. template <typename T = TupleType, internal::EnableIfMultiValue<T> = true>
  161. TupleType Take() {
  162. return TakeTuple();
  163. }
  164. private:
  165. // Wait until a new element is available.
  166. void WaitForANewElement() VALID_CONTEXT_REQUIRED(sequence_checker_) {
  167. DCHECK(!run_loop_.has_value());
  168. // Create a new run loop.
  169. run_loop_.emplace();
  170. // Wait until 'run_loop_->Quit()' is called.
  171. run_loop_->Run();
  172. run_loop_.reset();
  173. }
  174. void SignalElementIsAvailable() VALID_CONTEXT_REQUIRED(sequence_checker_) {
  175. if (run_loop_.has_value())
  176. run_loop_->Quit();
  177. }
  178. TupleType TakeTuple() {
  179. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  180. // Ensure an element is available.
  181. bool success = Wait();
  182. DCHECK(success) << "Waiting for an element timed out.";
  183. auto result = std::move(elements_.front());
  184. elements_.pop();
  185. return result;
  186. }
  187. base::queue<TupleType> elements_ GUARDED_BY_CONTEXT(sequence_checker_);
  188. // Used by Wait() to know when AddValue() is called.
  189. absl::optional<base::RunLoop> run_loop_ GUARDED_BY_CONTEXT(sequence_checker_);
  190. SEQUENCE_CHECKER(sequence_checker_);
  191. base::WeakPtrFactory<RepeatingTestFuture<Types...>> weak_ptr_factory_{this};
  192. };
  193. } // namespace base::test
  194. #endif // BASE_TEST_REPEATING_TEST_FUTURE_H_