// Copyright 2021 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_TEST_TEST_FUTURE_H_ #define BASE_TEST_TEST_FUTURE_H_ #include <memory> #include <optional> #include <tuple> #include "base/auto_reset.h" #include "base/check.h" #include "base/functional/bind.h" #include "base/functional/callback_forward.h" #include "base/functional/callback_helpers.h" #include "base/memory/weak_ptr.h" #include "base/run_loop.h" #include "base/sequence_checker.h" #include "base/strings/to_string.h" #include "base/task/bind_post_task.h" #include "base/task/sequenced_task_runner.h" #include "base/test/test_future_internal.h" #include "base/thread_annotations.h" #include "testing/gtest/include/gtest/gtest.h" namespace base::test { // Helper class to test code that returns its result(s) asynchronously through a // callback: // // - Pass the callback provided by `GetCallback()` to the code under test. // - Wait for the callback to be invoked by calling `Wait(),` or `Get()` to // access the value(s) passed to the callback. // // Example usage: // // TEST_F(MyTestFixture, MyTest) { // TestFuture<ResultType> future; // // object_under_test.DoSomethingAsync(future.GetCallback()); // // const ResultType& actual_result = future.Get(); // // // When you come here, DoSomethingAsync has finished and // // `actual_result` contains the result passed to the callback. // } // // Example using `Wait()`: // // TEST_F(MyTestFixture, MyWaitTest) { // TestFuture<ResultType> future; // // object_under_test.DoSomethingAsync(future.GetCallback()); // // // Optional. The Get() call below will also wait until the value // // arrives, but this explicit call to Wait() can be useful if you want // // to add extra information. // ASSERT_TRUE(future.Wait()) << "Detailed error message"; // // const ResultType& actual_result = future.Get(); // } // // `TestFuture` supports both single- and multiple-argument callbacks. // `TestFuture` provides both index and type based accessors for multi-argument // callbacks. `Get()` and `Take()` return tuples for multi-argument callbacks. // // TestFuture<int, std::string> future; // future.Get<0>(); // Reads the first argument // future.Get<int>(); // Also reads the first argument // future.Get(); // Returns a `const std::tuple<int, std::string>&` // // Example for a multi-argument callback: // // TEST_F(MyTestFixture, MyTest) { // TestFuture<int, std::string> future; // // object_under_test.DoSomethingAsync(future.GetCallback()); // // // You can use type based accessors: // int first_argument = future.Get<int>(); // const std::string& second_argument = future.Get<std::string>(); // // // or index based accessors: // int first_argument = future.Get<0>(); // const std::string& second_argument = future.Get<1>(); // } // // You can also satisfy a `TestFuture` by calling `SetValue()` from the sequence // on which the `TestFuture` was created. This is mostly useful when // implementing an observer: // // class MyTestObserver: public MyObserver { // public: // // `MyObserver` implementation: // void ObserveAnInt(int value) override { // future_.SetValue(value); // } // // int Wait() { return future_.Take(); } // // private: // TestFuture<int> future_; // }; // // TEST_F(MyTestFixture, MyTest) { // MyTestObserver observer; // // object_under_test.DoSomethingAsync(observer); // // int value_passed_to_observer = observer.Wait(); // }; // // `GetRepeatingCallback()` allows you to use a single `TestFuture` in code // that invokes the callback multiple times. // Your test must take care to consume each value before the next value // arrives. You can consume the value by calling either `Take()` or `Clear()`. // // Example for reusing a `TestFuture`: // // TEST_F(MyTestFixture, MyReuseTest) { // TestFuture<std::string> future; // // object_under_test.InstallCallback(future.GetRepeatingCallback()); // // object_under_test.DoSomething(); // EXPECT_EQ(future.Take(), "expected-first-value"); // // Because we used `Take()` the test future is ready for reuse. // // object_under_test.DoSomethingElse(); // EXPECT_EQ(future.Take(), "expected-second-value"); // } // // Example for reusing a `TestFuture` using `Get()` + `Clear()`: // // TEST_F(MyTestFixture, MyReuseTest) { // TestFuture<std::string, int> future; // // object_under_test.InstallCallback(future.GetRepeatingCallback()); // // object_under_test.DoSomething(); // // EXPECT_EQ(future.Get<std::string>(), "expected-first-value"); // EXPECT_EQ(future.Get<int>(), 5); // // Because we used `Get()`, the test future is not ready for reuse, // //so we need an explicit `Clear()` call. // future.Clear(); // // object_under_test.DoSomethingElse(); // EXPECT_EQ(future.Get<std::string>(), "expected-second-value"); // EXPECT_EQ(future.Get<int>(), 2); // } // // Finally, `TestFuture` also supports no-args callbacks: // // Example for no-args callbacks: // // TEST_F(MyTestFixture, MyTest) { // TestFuture<void> signal; // // object_under_test.DoSomethingAsync(signal.GetCallback()); // // EXPECT_TRUE(signal.Wait()); // // When you come here you know the callback was invoked and the async // // code is ready. // } // // All access to this class and its callbacks must be made from the sequence on // which the `TestFuture` was constructed. // template <typename... Types> class TestFuture { … }; // Specialization so you can use `TestFuture` to wait for a no-args callback. // // This specialization offers a subset of the methods provided on the base // `TestFuture`, as there is no value to be returned. template <> class TestFuture<void> { … }; // A gmock action that when invoked will store the argument values and // unblock any waiters. The action must be invoked on the sequence the // TestFuture was created on. // // Usually the action will be used with `WillOnce()` and only invoked once, // but if you consume the value with `Take()` or `Clear()` it is safe to // invoke it again. // // Example usage: // TestFuture<int> future; // // EXPECT_CALL(delegate, OnReadComplete) // .WillOnce(InvokeFuture(future)); // // object_under_test.Read(buffer, 16); // // EXPECT_EQ(future.Take(), 16); // // // // Implementation note: this is not implemented using the MATCHER_P macro as the // C++03-compatible way it implements varargs would make this too verbose. // Instead, it takes advantage of the ability to pass a functor to .WillOnce() // and .WillRepeatedly(). template <typename... Types> class InvokeFuture { … }; // Specialization for TestFuture<void>. template <> class InvokeFuture<void> { … }; // Deduction guide so the compiler can choose the correct specialisation of // InvokeFuture. template <typename... Types> InvokeFuture(TestFuture<Types...>&) -> InvokeFuture<Types...>; } // namespace base::test #endif // BASE_TEST_TEST_FUTURE_H_