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