1 // Copyright 2021 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/task/delayed_task_handle.h"
6
7 #include "base/memory/raw_ptr.h"
8 #include "base/test/gtest_util.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10
11 namespace base {
12
13 namespace {
14
15 // A non-working delegate that allows the testing of DelayedTaskHandle.
16 class TestDelegate : public DelayedTaskHandle::Delegate {
17 public:
TestDelegate(bool * was_cancel_task_called=nullptr)18 explicit TestDelegate(bool* was_cancel_task_called = nullptr)
19 : was_cancel_task_called_(was_cancel_task_called) {
20 DCHECK(!was_cancel_task_called_ || !*was_cancel_task_called_);
21 }
22 ~TestDelegate() override = default;
23
IsValid() const24 bool IsValid() const override { return is_valid_; }
CancelTask()25 void CancelTask() override {
26 is_valid_ = false;
27
28 if (was_cancel_task_called_)
29 *was_cancel_task_called_ = true;
30 }
31
32 private:
33 // Indicates if this delegate is currently valid.
34 bool is_valid_ = true;
35
36 // Indicates if CancelTask() was invoked, if not null. Must outlives |this|.
37 raw_ptr<bool> was_cancel_task_called_;
38 };
39
40 } // namespace
41
42 // Tests that a default-constructed handle is invalid.
TEST(DelayedTaskHandleTest,DefaultConstructor)43 TEST(DelayedTaskHandleTest, DefaultConstructor) {
44 DelayedTaskHandle delayed_task_handle;
45 EXPECT_FALSE(delayed_task_handle.IsValid());
46 }
47
48 // Tests that creating a handle with an invalid delegate will DCHECK.
TEST(DelayedTaskHandleTest,RequiresValidDelegateOnConstruction)49 TEST(DelayedTaskHandleTest, RequiresValidDelegateOnConstruction) {
50 auto delegate = std::make_unique<TestDelegate>();
51 EXPECT_TRUE(delegate->IsValid());
52
53 // Invalidate the delegate before creating the handle.
54 delegate->CancelTask();
55 EXPECT_FALSE(delegate->IsValid());
56
57 EXPECT_DCHECK_DEATH(
58 { DelayedTaskHandle delayed_task_handle(std::move(delegate)); });
59 }
60
61 // Tests that calling CancelTask() on the handle will call CancelTask() on the
62 // delegate and invalidate it.
TEST(DelayedTaskHandleTest,CancelTask)63 TEST(DelayedTaskHandleTest, CancelTask) {
64 bool was_cancel_task_called = false;
65 auto delegate = std::make_unique<TestDelegate>(&was_cancel_task_called);
66 EXPECT_FALSE(was_cancel_task_called);
67 EXPECT_TRUE(delegate->IsValid());
68
69 auto* delegate_ptr = delegate.get();
70 DelayedTaskHandle delayed_task_handle(std::move(delegate));
71 EXPECT_FALSE(was_cancel_task_called);
72 EXPECT_TRUE(delegate_ptr->IsValid());
73 EXPECT_TRUE(delayed_task_handle.IsValid());
74
75 delayed_task_handle.CancelTask();
76
77 EXPECT_TRUE(was_cancel_task_called);
78 EXPECT_FALSE(delayed_task_handle.IsValid());
79 }
80
81 // Tests that calling CancelTask() on a handle with no delegate will no-op.
TEST(DelayedTaskHandleTest,CancelTaskNoDelegate)82 TEST(DelayedTaskHandleTest, CancelTaskNoDelegate) {
83 DelayedTaskHandle delayed_task_handle;
84 EXPECT_FALSE(delayed_task_handle.IsValid());
85
86 delayed_task_handle.CancelTask();
87 EXPECT_FALSE(delayed_task_handle.IsValid());
88 }
89
90 // Tests that calling CancelTask() on a handle with an invalid delegate doesn't
91 // crash and keeps the handle invalid.
TEST(DelayedTaskHandleTest,CancelTaskInvalidDelegate)92 TEST(DelayedTaskHandleTest, CancelTaskInvalidDelegate) {
93 bool was_cancel_task_called = false;
94 auto delegate = std::make_unique<TestDelegate>(&was_cancel_task_called);
95 EXPECT_FALSE(was_cancel_task_called);
96 EXPECT_TRUE(delegate->IsValid());
97
98 auto* delegate_ptr = delegate.get();
99 DelayedTaskHandle delayed_task_handle(std::move(delegate));
100 EXPECT_FALSE(was_cancel_task_called);
101 EXPECT_TRUE(delegate_ptr->IsValid());
102 EXPECT_TRUE(delayed_task_handle.IsValid());
103
104 delegate_ptr->CancelTask();
105
106 EXPECT_TRUE(was_cancel_task_called);
107 EXPECT_FALSE(delegate_ptr->IsValid());
108 EXPECT_FALSE(delayed_task_handle.IsValid());
109
110 // Reset |was_cancel_task_called| to ensure Delegate::CancelTask() is still
111 // invoked on an invalid delegate.
112 was_cancel_task_called = false;
113
114 delayed_task_handle.CancelTask();
115
116 EXPECT_TRUE(was_cancel_task_called);
117 EXPECT_FALSE(delayed_task_handle.IsValid());
118 }
119
120 // Tests that invalidating the delegate will also invalidate the handle.
TEST(DelayedTaskHandleTest,InvalidateDelegate)121 TEST(DelayedTaskHandleTest, InvalidateDelegate) {
122 auto delegate = std::make_unique<TestDelegate>();
123 EXPECT_TRUE(delegate->IsValid());
124
125 auto* delegate_ptr = delegate.get();
126 DelayedTaskHandle delayed_task_handle(std::move(delegate));
127 EXPECT_TRUE(delegate_ptr->IsValid());
128 EXPECT_TRUE(delayed_task_handle.IsValid());
129
130 delegate_ptr->CancelTask();
131
132 EXPECT_FALSE(delegate_ptr->IsValid());
133 EXPECT_FALSE(delayed_task_handle.IsValid());
134 }
135
136 // Tests that destroying a valid handle will DCHECK.
TEST(DelayedTaskHandleTest,InvalidOnDestuction)137 TEST(DelayedTaskHandleTest, InvalidOnDestuction) {
138 auto delegate = std::make_unique<TestDelegate>();
139 EXPECT_TRUE(delegate->IsValid());
140
141 auto* delegate_ptr = delegate.get();
142 EXPECT_DCHECK_DEATH({
143 DelayedTaskHandle delayed_task_handle(std::move(delegate));
144 EXPECT_TRUE(delegate_ptr->IsValid());
145 EXPECT_TRUE(delayed_task_handle.IsValid());
146 });
147 }
148
149 // Tests the move-constructor.
TEST(DelayedTaskHandleTest,MoveConstructor)150 TEST(DelayedTaskHandleTest, MoveConstructor) {
151 auto delegate = std::make_unique<TestDelegate>();
152 EXPECT_TRUE(delegate->IsValid());
153
154 auto* delegate_ptr = delegate.get();
155 DelayedTaskHandle delayed_task_handle(std::move(delegate));
156 EXPECT_TRUE(delegate_ptr->IsValid());
157 EXPECT_TRUE(delayed_task_handle.IsValid());
158
159 DelayedTaskHandle other_delayed_task_handle(std::move(delayed_task_handle));
160 EXPECT_TRUE(delegate_ptr->IsValid());
161 EXPECT_TRUE(other_delayed_task_handle.IsValid());
162
163 // Clean-up.
164 other_delayed_task_handle.CancelTask();
165 }
166
167 // Tests the move-assignment.
TEST(DelayedTaskHandleTest,MoveAssignment)168 TEST(DelayedTaskHandleTest, MoveAssignment) {
169 auto delegate = std::make_unique<TestDelegate>();
170 EXPECT_TRUE(delegate->IsValid());
171
172 auto* delegate_ptr = delegate.get();
173 DelayedTaskHandle delayed_task_handle(std::move(delegate));
174 EXPECT_TRUE(delegate_ptr->IsValid());
175 EXPECT_TRUE(delayed_task_handle.IsValid());
176
177 DelayedTaskHandle other_delayed_task_handle;
178 EXPECT_FALSE(other_delayed_task_handle.IsValid());
179
180 other_delayed_task_handle = std::move(delayed_task_handle);
181 EXPECT_TRUE(delegate_ptr->IsValid());
182 EXPECT_TRUE(other_delayed_task_handle.IsValid());
183
184 // Clean-up.
185 other_delayed_task_handle.CancelTask();
186 }
187
188 // Tests that assigning to a valid handle will DCHECK.
TEST(DelayedTaskHandleTest,AssignToValidHandle)189 TEST(DelayedTaskHandleTest, AssignToValidHandle) {
190 auto delegate = std::make_unique<TestDelegate>();
191 EXPECT_TRUE(delegate->IsValid());
192
193 auto* delegate_ptr = delegate.get();
194 DelayedTaskHandle delayed_task_handle(std::move(delegate));
195 EXPECT_TRUE(delegate_ptr->IsValid());
196 EXPECT_TRUE(delayed_task_handle.IsValid());
197
198 EXPECT_DCHECK_DEATH({ delayed_task_handle = DelayedTaskHandle(); });
199
200 // Clean-up.
201 delayed_task_handle.CancelTask();
202 }
203
204 } // namespace base
205