// Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/test/run_until.h" #include #include "base/callback_list.h" #include "base/functional/callback.h" #include "base/task/current_thread.h" #include "base/test/scoped_run_loop_timeout.h" #include "base/test/test_future.h" #include "base/time/time_override.h" namespace base::test { void TestPredicateOrRegisterOnNextIdleCallback( base::FunctionRef condition, CallbackListSubscription* on_idle_callback_subscription, OnceClosure ready_callback) { if (condition()) { // Invoke `ready_callback` if `condition` evaluates to true. std::move(ready_callback).Run(); } else { // Otherwise try again the next time the thread is idle. *on_idle_callback_subscription = CurrentThread::Get().RegisterOnNextIdleCallback( {}, BindOnce(TestPredicateOrRegisterOnNextIdleCallback, condition, on_idle_callback_subscription, std::move(ready_callback))); } } bool RunUntil(base::FunctionRef condition) { // We expect a RunLoop timeout except under MOCK_TIME where TaskEnvironment // disables TaskEnvironment::mock_time_domain_ after fast-forwarding into the // timeout. CHECK(test::ScopedRunLoopTimeout::ExistsForCurrentThread() || subtle::ScopedTimeClockOverrides::overrides_active()) << "No RunLoop timeout set, meaning `RunUntil` will hang forever on " "failure."; test::TestFuture ready_signal; CallbackListSubscription on_idle_callback_subscription; on_idle_callback_subscription = CurrentThread::Get().RegisterOnNextIdleCallback( {}, BindOnce(TestPredicateOrRegisterOnNextIdleCallback, condition, &on_idle_callback_subscription, ready_signal.GetCallback())); return ready_signal.Wait(); } } // namespace base::test