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