• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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_TEST_FUTURE_H_
6 #define BASE_TEST_TEST_FUTURE_H_
7 
8 #include <memory>
9 #include <tuple>
10 
11 #include "base/auto_reset.h"
12 #include "base/check.h"
13 #include "base/functional/bind.h"
14 #include "base/functional/callback_forward.h"
15 #include "base/functional/callback_helpers.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/run_loop.h"
18 #include "base/sequence_checker.h"
19 #include "base/strings/to_string.h"
20 #include "base/test/test_future_internal.h"
21 #include "base/thread_annotations.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "third_party/abseil-cpp/absl/types/optional.h"
24 
25 namespace base::test {
26 
27 // Helper class to test code that returns its result(s) asynchronously through a
28 // callback:
29 //
30 //    - Pass the callback provided by `GetCallback()` to the code under test.
31 //    - Wait for the callback to be invoked by calling `Wait(),` or `Get()` to
32 //      access the value(s) passed to the callback.
33 //
34 //   Example usage:
35 //
36 //     TEST_F(MyTestFixture, MyTest) {
37 //       TestFuture<ResultType> future;
38 //
39 //       object_under_test.DoSomethingAsync(future.GetCallback());
40 //
41 //       const ResultType& actual_result = future.Get();
42 //
43 //       // When you come here, DoSomethingAsync has finished and
44 //       // `actual_result` contains the result passed to the callback.
45 //     }
46 //
47 //   Example using `Wait()`:
48 //
49 //     TEST_F(MyTestFixture, MyWaitTest) {
50 //       TestFuture<ResultType> future;
51 //
52 //       object_under_test.DoSomethingAsync(future.GetCallback());
53 //
54 //       // Optional. The Get() call below will also wait until the value
55 //       // arrives, but this explicit call to Wait() can be useful if you want
56 //       // to add extra information.
57 //       ASSERT_TRUE(future.Wait()) << "Detailed error message";
58 //
59 //       const ResultType& actual_result = future.Get();
60 //     }
61 //
62 // `TestFuture` supports both single- and multiple-argument callbacks.
63 // `TestFuture` provides both index and type based accessors for multi-argument
64 // callbacks. `Get()` and `Take()` return tuples for multi-argument callbacks.
65 //
66 //   TestFuture<int, std::string> future;
67 //   future.Get<0>();   // Reads the first argument
68 //   future.Get<int>(); // Also reads the first argument
69 //   future.Get();      // Returns a `const std::tuple<int, std::string>&`
70 //
71 //   Example for a multi-argument callback:
72 //
73 //     TEST_F(MyTestFixture, MyTest) {
74 //       TestFuture<int, std::string> future;
75 //
76 //       object_under_test.DoSomethingAsync(future.GetCallback());
77 //
78 //       // You can use type based accessors:
79 //       int first_argument = future.Get<int>();
80 //       const std::string& second_argument = future.Get<std::string>();
81 //
82 //       // or index based accessors:
83 //       int first_argument = future.Get<0>();
84 //       const std::string& second_argument = future.Get<1>();
85 //     }
86 //
87 // You can also satisfy a `TestFuture` by calling `SetValue()` from the sequence
88 // on which the `TestFuture` was created. This is mostly useful when
89 // implementing an observer:
90 //
91 //     class MyTestObserver: public MyObserver {
92 //       public:
93 //         // `MyObserver` implementation:
94 //         void ObserveAnInt(int value) override {
95 //           future_.SetValue(value);
96 //         }
97 //
98 //         int Wait() { return future_.Take(); }
99 //
100 //      private:
101 //        TestFuture<int> future_;
102 //     };
103 //
104 //     TEST_F(MyTestFixture, MyTest) {
105 //       MyTestObserver observer;
106 //
107 //       object_under_test.DoSomethingAsync(observer);
108 //
109 //       int value_passed_to_observer = observer.Wait();
110 //     };
111 //
112 // `GetRepeatingCallback()` allows you to use a single `TestFuture` in code
113 // that invokes the callback multiple times.
114 // Your test must take care to consume each value before the next value
115 // arrives. You can consume the value by calling either `Take()` or `Clear()`.
116 //
117 //   Example for reusing a `TestFuture`:
118 //
119 //     TEST_F(MyTestFixture, MyReuseTest) {
120 //       TestFuture<std::string> future;
121 //
122 //       object_under_test.InstallCallback(future.GetRepeatingCallback());
123 //
124 //       object_under_test.DoSomething();
125 //       EXPECT_EQ(future.Take(), "expected-first-value");
126 //       // Because we used `Take()` the test future is ready for reuse.
127 //
128 //       object_under_test.DoSomethingElse();
129 //       EXPECT_EQ(future.Take(), "expected-second-value");
130 //     }
131 //
132 //   Example for reusing  a `TestFuture` using `Get()` + `Clear()`:
133 //
134 //     TEST_F(MyTestFixture, MyReuseTest) {
135 //       TestFuture<std::string, int> future;
136 //
137 //       object_under_test.InstallCallback(future.GetRepeatingCallback());
138 //
139 //       object_under_test.DoSomething();
140 //
141 //       EXPECT_EQ(future.Get<std::string>(), "expected-first-value");
142 //       EXPECT_EQ(future.Get<int>(), 5);
143 //       // Because we used `Get()`, the test future is not ready for reuse,
144 //       //so we need an explicit `Clear()` call.
145 //       future.Clear();
146 //
147 //       object_under_test.DoSomethingElse();
148 //       EXPECT_EQ(future.Get<std::string>(), "expected-second-value");
149 //       EXPECT_EQ(future.Get<int>(), 2);
150 //     }
151 //
152 // Finally, `TestFuture` also supports no-args callbacks:
153 //
154 //   Example for no-args callbacks:
155 //
156 //     TEST_F(MyTestFixture, MyTest) {
157 //       TestFuture<void> signal;
158 //
159 //       object_under_test.DoSomethingAsync(signal.GetCallback());
160 //
161 //       EXPECT_TRUE(signal.Wait());
162 //       // When you come here you know the callback was invoked and the async
163 //       // code is ready.
164 //     }
165 //
166 // All access to this class and its callbacks must be made from the sequence on
167 // which the `TestFuture` was constructed.
168 //
169 template <typename... Types>
170 class TestFuture {
171  public:
172   using TupleType = std::tuple<std::decay_t<Types>...>;
173 
174   static_assert(std::tuple_size_v<TupleType> > 0,
175                 "Don't use TestFuture<> but use TestFuture<void> instead");
176 
177   TestFuture() = default;
178   TestFuture(const TestFuture&) = delete;
179   TestFuture& operator=(const TestFuture&) = delete;
180   ~TestFuture() = default;
181 
182   // Waits for the value to arrive.
183   //
184   // Returns true if the value arrived, or false if a timeout happens.
185   //
186   // Directly calling Wait() is not required as Get()/Take() will also wait for
187   // the value to arrive, however you can use a direct call to Wait() to
188   // improve the error reported:
189   //
190   //   ASSERT_TRUE(queue.Wait()) << "Detailed error message";
191   //
Wait()192   [[nodiscard]] bool Wait() {
193     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
194 
195     if (values_) {
196       return true;
197     }
198 
199     // Wait for the value to arrive.
200     RunLoop loop;
201     AutoReset<RepeatingClosure> quit_loop(&ready_signal_, loop.QuitClosure());
202     loop.Run();
203 
204     return IsReady();
205   }
206 
207   // Returns true if the value has arrived.
IsReady()208   bool IsReady() const {
209     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
210     return values_.has_value();
211   }
212 
213   // Waits for the value to arrive, and returns the I-th value.
214   //
215   // Will CHECK if a timeout happens.
216   //
217   // Example usage:
218   //
219   //   TestFuture<int, std::string> future;
220   //   int first = future.Get<0>();
221   //   std::string second = future.Get<1>();
222   //
223   template <std::size_t I,
224             typename T = TupleType,
225             internal::EnableIfOneOrMoreValues<T> = true>
Get()226   const auto& Get() {
227     return std::get<I>(GetTuple());
228   }
229 
230   // Waits for the value to arrive, and returns the value with the given type.
231   //
232   // Will CHECK if a timeout happens.
233   //
234   // Example usage:
235   //
236   //   TestFuture<int, std::string> future;
237   //   int first = future.Get<int>();
238   //   std::string second = future.Get<std::string>();
239   //
240   template <typename Type>
Get()241   const auto& Get() {
242     return std::get<Type>(GetTuple());
243   }
244 
245   // Returns a callback that when invoked will store all the argument values,
246   // and unblock any waiters.
247   // Templated so you can specify how you need the arguments to be passed -
248   // const, reference, .... Defaults to simply `Types...`.
249   //
250   // Example usage:
251   //
252   //   TestFuture<int, std::string> future;
253   //
254   //   // returns base::OnceCallback<void(int, std::string)>
255   //   future.GetCallback();
256   //
257   //   // returns base::OnceCallback<void(int, const std::string&)>
258   //   future.GetCallback<int, const std::string&>();
259   //
260   template <typename... CallbackArgumentsTypes>
GetCallback()261   OnceCallback<void(CallbackArgumentsTypes...)> GetCallback() {
262     return GetRepeatingCallback<CallbackArgumentsTypes...>();
263   }
264 
GetCallback()265   OnceCallback<void(Types...)> GetCallback() { return GetCallback<Types...>(); }
266 
267   // Returns a repeating callback that when invoked will store all the argument
268   // values, and unblock any waiters.
269   //
270   // You must take care that the stored value is consumed before the callback
271   // is invoked a second time.
272   // You can consume the value by calling either `Take()` or `Clear()`.
273   //
274   // Example usage:
275   //
276   //   TestFuture<std::string> future;
277   //
278   //   object_under_test.InstallCallback(future.GetRepeatingCallback());
279   //
280   //   object_under_test.DoSomething();
281   //   EXPECT_EQ(future.Take(), "expected-first-value");
282   //   // Because we used `Take()` the test future is ready for reuse.
283   //
284   //   object_under_test.DoSomethingElse();
285   //   // We can also use `Get()` + `Clear()` to reuse the callback.
286   //   EXPECT_EQ(future.Get(), "expected-second-value");
287   //   future.Clear();
288   //
289   //   object_under_test.DoSomethingElse();
290   //   EXPECT_EQ(future.Take(), "expected-third-value");
291   //
292   template <typename... CallbackArgumentsTypes>
GetRepeatingCallback()293   RepeatingCallback<void(CallbackArgumentsTypes...)> GetRepeatingCallback() {
294     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
295     return BindRepeating(
296         [](WeakPtr<TestFuture<Types...>> future,
297            CallbackArgumentsTypes... values) {
298           if (future) {
299             future->SetValue(std::forward<CallbackArgumentsTypes>(values)...);
300           }
301         },
302         weak_ptr_factory_.GetWeakPtr());
303   }
304 
GetRepeatingCallback()305   RepeatingCallback<void(Types...)> GetRepeatingCallback() {
306     return GetRepeatingCallback<Types...>();
307   }
308 
309   // Sets the value of the future.
310   // This will unblock any pending Wait() or Get() call.
SetValue(Types...values)311   void SetValue(Types... values) {
312     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
313 
314     auto new_values = std::make_tuple(std::forward<Types>(values)...);
315 
316     EXPECT_FALSE(values_.has_value())
317         << "Received new value " << ToString(new_values)  //
318         << " before old value " << ToString(GetTuple())
319         << " was consumed through Take() or Clear().";
320 
321     values_ = std::move(new_values);
322 
323     ready_signal_.Run();
324   }
325 
326   // Clears the future, allowing it to be reused and accept a new value.
327   //
328   // All outstanding callbacks issued through `GetCallback()` remain valid.
Clear()329   void Clear() {
330     if (IsReady()) {
331       std::ignore = Take();
332     }
333   }
334 
335   //////////////////////////////////////////////////////////////////////////////
336   //  Accessor methods only available if the future holds a single value.
337   //////////////////////////////////////////////////////////////////////////////
338 
339   // Waits for the value to arrive, and returns a reference to it.
340   //
341   // Will CHECK if a timeout happens.
342   template <typename T = TupleType, internal::EnableIfSingleValue<T> = true>
Get()343   [[nodiscard]] const auto& Get() {
344     return std::get<0>(GetTuple());
345   }
346 
347   // Waits for the value to arrive, and returns it.
348   //
349   // Will CHECK if a timeout happens.
350   template <typename T = TupleType, internal::EnableIfSingleValue<T> = true>
Take()351   [[nodiscard]] auto Take() {
352     return std::get<0>(TakeTuple());
353   }
354 
355   //////////////////////////////////////////////////////////////////////////////
356   //  Accessor methods only available if the future holds multiple values.
357   //////////////////////////////////////////////////////////////////////////////
358 
359   // Waits for the values to arrive, and returns a tuple with the values.
360   //
361   // Will CHECK if a timeout happens.
362   template <typename T = TupleType, internal::EnableIfMultiValue<T> = true>
Get()363   [[nodiscard]] const TupleType& Get() {
364     return GetTuple();
365   }
366 
367   // Waits for the values to arrive, and moves a tuple with the values out.
368   //
369   // Will CHECK if a timeout happens.
370   template <typename T = TupleType, internal::EnableIfMultiValue<T> = true>
Take()371   [[nodiscard]] TupleType Take() {
372     return TakeTuple();
373   }
374 
375  private:
GetTuple()376   [[nodiscard]] const TupleType& GetTuple() {
377     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
378     bool success = Wait();
379     CHECK(success) << "Waiting for value timed out.";
380     return values_.value();
381   }
382 
TakeTuple()383   [[nodiscard]] TupleType TakeTuple() {
384     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
385     bool success = Wait();
386     CHECK(success) << "Waiting for value timed out.";
387 
388     return std::exchange(values_, {}).value();
389   }
390 
391   SEQUENCE_CHECKER(sequence_checker_);
392 
393   base::RepeatingClosure ready_signal_ GUARDED_BY_CONTEXT(sequence_checker_) =
394       base::DoNothing();
395 
396   absl::optional<TupleType> values_ GUARDED_BY_CONTEXT(sequence_checker_);
397 
398   WeakPtrFactory<TestFuture<Types...>> weak_ptr_factory_{this};
399 };
400 
401 // Specialization so you can use `TestFuture` to wait for a no-args callback.
402 //
403 // This specialization offers a subset of the methods provided on the base
404 // `TestFuture`, as there is no value to be returned.
405 template <>
406 class TestFuture<void> {
407  public:
408   // Waits until the callback or `SetValue()` is invoked.
409   //
410   // Fails your test if a timeout happens, but you can check the return value
411   // to improve the error reported:
412   //
413   //   ASSERT_TRUE(future.Wait()) << "Detailed error message";
Wait()414   [[nodiscard]] bool Wait() { return implementation_.Wait(); }
415 
416   // Waits until the callback or `SetValue()` is invoked.
Get()417   void Get() { std::ignore = implementation_.Get(); }
418 
419   // Returns true if the callback or `SetValue()` was invoked.
IsReady()420   bool IsReady() const { return implementation_.IsReady(); }
421 
422   // Returns a callback that when invoked will unblock any waiters.
GetCallback()423   OnceCallback<void()> GetCallback() {
424     return BindOnce(implementation_.GetCallback(), true);
425   }
426 
427   // Returns a callback that when invoked will unblock any waiters.
GetRepeatingCallback()428   RepeatingCallback<void()> GetRepeatingCallback() {
429     return BindRepeating(implementation_.GetRepeatingCallback(), true);
430   }
431 
432   // Indicates this `TestFuture` is ready, and unblocks any waiters.
SetValue()433   void SetValue() { implementation_.SetValue(true); }
434 
435   // Clears the future, allowing it to be reused and accept a new value.
436   //
437   // All outstanding callbacks issued through `GetCallback()` remain valid.
Clear()438   void Clear() { implementation_.Clear(); }
439 
440  private:
441   TestFuture<bool> implementation_;
442 };
443 
444 }  // namespace base::test
445 
446 #endif  // BASE_TEST_TEST_FUTURE_H_
447