1 // Copyright 2023 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 #include "base/test/run_until.h"
6
7 #include "base/functional/callback_forward.h"
8 #include "base/functional/callback_helpers.h"
9 #include "base/task/single_thread_task_runner.h"
10 #include "base/test/bind.h"
11 #include "base/test/task_environment.h"
12 #include "base/timer/timer.h"
13 #include "testing/gtest/include/gtest/gtest-spi.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace base::test {
17
18 namespace {
19
20 template <typename Lambda>
RunLater(Lambda lambda)21 void RunLater(Lambda lambda) {
22 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
23 FROM_HERE, base::BindLambdaForTesting(lambda));
24 }
25
PostDelayedTask(base::OnceClosure closure,base::TimeDelta delay)26 void PostDelayedTask(base::OnceClosure closure, base::TimeDelta delay) {
27 base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
28 FROM_HERE, std::move(closure), delay);
29 }
30
31 } // namespace
32
33 class RunUntilTest : public ::testing::Test {
34 public:
35 RunUntilTest() = default;
36 RunUntilTest(const RunUntilTest&) = delete;
37 RunUntilTest& operator=(const RunUntilTest&) = delete;
38 ~RunUntilTest() override = default;
39
40 private:
41 test::SingleThreadTaskEnvironment environment_;
42 };
43
TEST_F(RunUntilTest,ShouldReturnTrueIfPredicateIsAlreadyFulfilled)44 TEST_F(RunUntilTest, ShouldReturnTrueIfPredicateIsAlreadyFulfilled) {
45 EXPECT_TRUE(RunUntil([]() { return true; }));
46 }
47
TEST_F(RunUntilTest,ShouldReturnTrueOncePredicateIsFulfilled)48 TEST_F(RunUntilTest, ShouldReturnTrueOncePredicateIsFulfilled) {
49 bool done = false;
50
51 RunLater([&done]() { done = true; });
52
53 EXPECT_TRUE(RunUntil([&done]() { return done; }));
54 }
55
TEST_F(RunUntilTest,ShouldNotSimplyActivelyInvokePredicateInALoop)56 TEST_F(RunUntilTest, ShouldNotSimplyActivelyInvokePredicateInALoop) {
57 bool done = false;
58 int call_count = 0;
59
60 PostDelayedTask(base::BindLambdaForTesting([&done]() { done = true; }),
61 base::Milliseconds(50));
62
63 EXPECT_TRUE(RunUntil([&]() {
64 call_count++;
65 return done;
66 }));
67
68 // Ensure the predicate is not called a ton of times.
69 EXPECT_LT(call_count, 10);
70 }
71
TEST_F(RunUntilTest,ShouldNotSimplyReturnOnFirstIdle)72 TEST_F(RunUntilTest, ShouldNotSimplyReturnOnFirstIdle) {
73 bool done = false;
74
75 PostDelayedTask(base::DoNothing(), base::Milliseconds(1));
76 PostDelayedTask(base::DoNothing(), base::Milliseconds(5));
77 PostDelayedTask(base::BindLambdaForTesting([&done]() { done = true; }),
78 base::Milliseconds(10));
79
80 EXPECT_TRUE(RunUntil([&]() { return done; }));
81 }
82
TEST_F(RunUntilTest,ShouldAlwaysLetOtherTasksRunFirstEvenIfPredicateIsAlreadyFulfilled)83 TEST_F(RunUntilTest,
84 ShouldAlwaysLetOtherTasksRunFirstEvenIfPredicateIsAlreadyFulfilled) {
85 // This ensures that no tests can (accidentally) rely on `RunUntil`
86 // immediately returning.
87 bool other_job_done = false;
88 RunLater([&other_job_done] { other_job_done = true; });
89
90 EXPECT_TRUE(RunUntil([]() { return true; }));
91
92 EXPECT_TRUE(other_job_done);
93 }
94
TEST_F(RunUntilTest,ShouldWorkEvenWhenTimerIsRunning)95 TEST_F(RunUntilTest, ShouldWorkEvenWhenTimerIsRunning) {
96 bool done = false;
97
98 base::RepeatingTimer timer;
99 timer.Start(FROM_HERE, base::Seconds(1), base::DoNothing());
100
101 PostDelayedTask(base::BindLambdaForTesting([&done]() { done = true; }),
102 base::Milliseconds(10));
103
104 EXPECT_TRUE(RunUntil([&]() { return done; }));
105 }
106
TEST_F(RunUntilTest,ShouldReturnFalseIfTimeoutHappens)107 TEST_F(RunUntilTest, ShouldReturnFalseIfTimeoutHappens) {
108 test::ScopedRunLoopTimeout timeout(FROM_HERE, Milliseconds(1));
109
110 // `ScopedRunLoopTimeout` will automatically fail the test when a timeout
111 // happens, so we use EXPECT_FATAL_FAILURE to handle this failure.
112 // EXPECT_FATAL_FAILURE only works on static objects.
113 static bool success;
114
115 EXPECT_NONFATAL_FAILURE({ success = RunUntil([]() { return false; }); },
116 "timed out");
117
118 EXPECT_FALSE(success);
119 }
120
121 } // namespace base::test
122