xref: /aosp_15_r20/external/cronet/base/test/run_until_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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