1 // Copyright 2013 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/one_shot_event.h"
6
7 #include "base/functional/bind.h"
8 #include "base/memory/raw_ptr.h"
9 #include "base/run_loop.h"
10 #include "base/task/single_thread_task_runner.h"
11 #include "base/test/task_environment.h"
12 #include "base/test/test_simple_task_runner.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace base {
16
Increment(int * i)17 void Increment(int* i) {
18 ++*i;
19 }
20
21 // |*did_delete_instance| will be set to true upon its destruction.
22 class RefCountedClass : public base::RefCounted<RefCountedClass> {
23 public:
RefCountedClass(bool * did_delete_instance)24 explicit RefCountedClass(bool* did_delete_instance)
25 : did_delete_instance_(did_delete_instance) {
26 DCHECK(!*did_delete_instance_);
27 }
28 RefCountedClass(const RefCountedClass&) = delete;
29 RefCountedClass& operator=(const RefCountedClass&) = delete;
30
PerformTask()31 void PerformTask() { did_perform_task_ = true; }
did_perform_task() const32 bool did_perform_task() const { return did_perform_task_; }
33
34 private:
35 friend class base::RefCounted<RefCountedClass>;
36
~RefCountedClass()37 ~RefCountedClass() { *did_delete_instance_ = true; }
38
39 const raw_ptr<bool> did_delete_instance_; // Not owned.
40
41 bool did_perform_task_ = false;
42 };
43
TEST(OneShotEventTest,RecordsSignal)44 TEST(OneShotEventTest, RecordsSignal) {
45 OneShotEvent event;
46 EXPECT_FALSE(event.is_signaled());
47 event.Signal();
48 EXPECT_TRUE(event.is_signaled());
49 }
50
TEST(OneShotEventTest,CallsQueueAsDistinctTask)51 TEST(OneShotEventTest, CallsQueueAsDistinctTask) {
52 OneShotEvent event;
53 scoped_refptr<base::TestSimpleTaskRunner> runner(
54 new base::TestSimpleTaskRunner);
55 int i = 0;
56 event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
57 event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
58 EXPECT_EQ(0U, runner->NumPendingTasks());
59 event.Signal();
60
61 auto pending_tasks = runner->TakePendingTasks();
62 ASSERT_EQ(2U, pending_tasks.size());
63 EXPECT_NE(pending_tasks[0].location.line_number(),
64 pending_tasks[1].location.line_number())
65 << "Make sure FROM_HERE is propagated.";
66 }
67
TEST(OneShotEventTest,CallsQueue)68 TEST(OneShotEventTest, CallsQueue) {
69 OneShotEvent event;
70 scoped_refptr<base::TestSimpleTaskRunner> runner(
71 new base::TestSimpleTaskRunner);
72 int i = 0;
73 event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
74 event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
75 EXPECT_EQ(0U, runner->NumPendingTasks());
76 event.Signal();
77 ASSERT_EQ(2U, runner->NumPendingTasks());
78
79 EXPECT_EQ(0, i);
80 runner->RunPendingTasks();
81 EXPECT_EQ(2, i);
82 }
83
TEST(OneShotEventTest,CallsAfterSignalDontRunInline)84 TEST(OneShotEventTest, CallsAfterSignalDontRunInline) {
85 OneShotEvent event;
86 scoped_refptr<base::TestSimpleTaskRunner> runner(
87 new base::TestSimpleTaskRunner);
88 int i = 0;
89
90 event.Signal();
91 event.Post(FROM_HERE, base::BindOnce(&Increment, &i), runner);
92 EXPECT_EQ(1U, runner->NumPendingTasks());
93 EXPECT_EQ(0, i);
94 runner->RunPendingTasks();
95 EXPECT_EQ(1, i);
96 }
97
TEST(OneShotEventTest,PostDefaultsToCurrentMessageLoop)98 TEST(OneShotEventTest, PostDefaultsToCurrentMessageLoop) {
99 OneShotEvent event;
100 scoped_refptr<base::TestSimpleTaskRunner> runner(
101 new base::TestSimpleTaskRunner);
102 base::test::SingleThreadTaskEnvironment task_environment;
103 int runner_i = 0;
104 int loop_i = 0;
105
106 event.Post(FROM_HERE, base::BindOnce(&Increment, &runner_i), runner);
107 event.Post(FROM_HERE, base::BindOnce(&Increment, &loop_i));
108 event.Signal();
109 EXPECT_EQ(1U, runner->NumPendingTasks());
110 EXPECT_EQ(0, runner_i);
111 runner->RunPendingTasks();
112 EXPECT_EQ(1, runner_i);
113 EXPECT_EQ(0, loop_i);
114 base::RunLoop().RunUntilIdle();
115 EXPECT_EQ(1, loop_i);
116 }
117
CheckSignaledAndPostIncrement(OneShotEvent * event,const scoped_refptr<base::SingleThreadTaskRunner> & runner,int * i)118 void CheckSignaledAndPostIncrement(
119 OneShotEvent* event,
120 const scoped_refptr<base::SingleThreadTaskRunner>& runner,
121 int* i) {
122 EXPECT_TRUE(event->is_signaled());
123 event->Post(FROM_HERE, base::BindOnce(&Increment, i), runner);
124 }
125
TEST(OneShotEventTest,IsSignaledAndPostsFromCallbackWork)126 TEST(OneShotEventTest, IsSignaledAndPostsFromCallbackWork) {
127 OneShotEvent event;
128 scoped_refptr<base::TestSimpleTaskRunner> runner(
129 new base::TestSimpleTaskRunner);
130 int i = 0;
131
132 event.Post(FROM_HERE,
133 base::BindOnce(&CheckSignaledAndPostIncrement, &event, runner, &i),
134 runner);
135 EXPECT_EQ(0, i);
136 event.Signal();
137
138 // CheckSignaledAndPostIncrement is queued on |runner|.
139 EXPECT_EQ(1U, runner->NumPendingTasks());
140 EXPECT_EQ(0, i);
141 runner->RunPendingTasks();
142 // Increment is queued on |runner|.
143 EXPECT_EQ(1U, runner->NumPendingTasks());
144 EXPECT_EQ(0, i);
145 runner->RunPendingTasks();
146 // Increment has run.
147 EXPECT_EQ(0U, runner->NumPendingTasks());
148 EXPECT_EQ(1, i);
149 }
150
151 // Tests that OneShotEvent does not keep references to tasks once OneShotEvent
152 // Signal()s.
TEST(OneShotEventTest,DropsCallbackRefUponSignalled)153 TEST(OneShotEventTest, DropsCallbackRefUponSignalled) {
154 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
155 bool did_delete_instance = false;
156 OneShotEvent event;
157
158 {
159 auto ref_counted_class =
160 base::MakeRefCounted<RefCountedClass>(&did_delete_instance);
161 event.Post(FROM_HERE,
162 base::BindOnce(&RefCountedClass::PerformTask, ref_counted_class),
163 runner);
164 event.Signal();
165 runner->RunPendingTasks();
166 EXPECT_TRUE(ref_counted_class->did_perform_task());
167 }
168
169 // Once OneShotEvent doesn't have any queued events, it should have dropped
170 // all the references to the callbacks it received through Post().
171 EXPECT_TRUE(did_delete_instance);
172 }
173
174 } // namespace base
175