blob: 9b92d9a09a2b0a74e03b47c5c39c32ad5d373086 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2011 The Chromium Authors
[email protected]b77576f52011-11-24 04:12:042// 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/cancelable_callback.h"
6
kuznetsovsb020bcd82016-04-13 13:01:477#include <memory>
Mikel Astiz239acc172024-01-11 14:16:268#include <optional>
kuznetsovsb020bcd82016-04-13 13:01:479
Avi Drissman63e1f992023-01-13 18:54:4310#include "base/functional/bind.h"
11#include "base/functional/callback_helpers.h"
skyostil054861d2015-04-30 19:06:1512#include "base/location.h"
[email protected]b77576f52011-11-24 04:12:0413#include "base/memory/ref_counted.h"
[email protected]f7b98b32013-02-05 08:14:1514#include "base/run_loop.h"
Patrick Monette643cdf62021-10-15 19:13:4215#include "base/task/single_thread_task_runner.h"
Gabriel Charettec7108742019-08-23 03:31:4016#include "base/test/task_environment.h"
[email protected]b77576f52011-11-24 04:12:0417#include "testing/gtest/include/gtest/gtest.h"
18
19namespace base {
20namespace {
21
22class TestRefCounted : public RefCountedThreadSafe<TestRefCounted> {
23 private:
24 friend class RefCountedThreadSafe<TestRefCounted>;
Chris Watkinsbb7211c2017-11-29 07:16:3825 ~TestRefCounted() = default;
[email protected]b77576f52011-11-24 04:12:0426};
27
Peter Kasting134ef9af2024-12-28 02:30:0928void Increment(int* count) {
29 (*count)++;
30}
31void IncrementBy(int* count, int n) {
32 (*count) += n;
33}
[email protected]b77576f52011-11-24 04:12:0434void RefCountedParam(const scoped_refptr<TestRefCounted>& ref_counted) {}
35
kuznetsovsb020bcd82016-04-13 13:01:4736void OnMoveOnlyReceived(int* value, std::unique_ptr<int> result) {
37 *value = *result;
38}
39
[email protected]b77576f52011-11-24 04:12:0440// Cancel().
41// - Callback can be run multiple times.
42// - After Cancel(), Run() completes but has no effect.
43TEST(CancelableCallbackTest, Cancel) {
44 int count = 0;
kylechar650caf02019-07-17 03:25:4145 CancelableRepeatingClosure cancelable(
Mikel Astiz239acc172024-01-11 14:16:2646 BindRepeating(&Increment, Unretained(&count)));
[email protected]b77576f52011-11-24 04:12:0447
Mikel Astiz239acc172024-01-11 14:16:2648 RepeatingClosure callback = cancelable.callback();
[email protected]b77576f52011-11-24 04:12:0449 callback.Run();
50 EXPECT_EQ(1, count);
51
52 callback.Run();
53 EXPECT_EQ(2, count);
54
55 cancelable.Cancel();
56 callback.Run();
57 EXPECT_EQ(2, count);
58}
59
60// Cancel() called multiple times.
61// - Cancel() cancels all copies of the wrapped callback.
[email protected]d4d57df2011-11-30 20:33:5262// - Calling Cancel() more than once has no effect.
63// - After Cancel(), callback() returns a null callback.
[email protected]b77576f52011-11-24 04:12:0464TEST(CancelableCallbackTest, MultipleCancel) {
65 int count = 0;
kylechar650caf02019-07-17 03:25:4166 CancelableRepeatingClosure cancelable(
Mikel Astiz239acc172024-01-11 14:16:2667 BindRepeating(&Increment, Unretained(&count)));
[email protected]b77576f52011-11-24 04:12:0468
Mikel Astiz239acc172024-01-11 14:16:2669 RepeatingClosure callback1 = cancelable.callback();
70 RepeatingClosure callback2 = cancelable.callback();
[email protected]b77576f52011-11-24 04:12:0471 cancelable.Cancel();
72
73 callback1.Run();
74 EXPECT_EQ(0, count);
75
[email protected]b77576f52011-11-24 04:12:0476 callback2.Run();
77 EXPECT_EQ(0, count);
78
[email protected]d4d57df2011-11-30 20:33:5279 // Calling Cancel() again has no effect.
[email protected]b77576f52011-11-24 04:12:0480 cancelable.Cancel();
[email protected]d4d57df2011-11-30 20:33:5281
82 // callback() of a cancelled callback is null.
Mikel Astiz239acc172024-01-11 14:16:2683 RepeatingClosure callback3 = cancelable.callback();
[email protected]d4d57df2011-11-30 20:33:5284 EXPECT_TRUE(callback3.is_null());
[email protected]b77576f52011-11-24 04:12:0485}
86
Colin Blundellea615d422021-05-12 09:35:4187// CancelableRepeatingCallback destroyed before callback is run.
88// - Destruction of CancelableRepeatingCallback cancels outstanding callbacks.
[email protected]b77576f52011-11-24 04:12:0489TEST(CancelableCallbackTest, CallbackCanceledOnDestruction) {
90 int count = 0;
Mikel Astiz239acc172024-01-11 14:16:2691 RepeatingClosure callback;
[email protected]b77576f52011-11-24 04:12:0492
93 {
kylechar650caf02019-07-17 03:25:4194 CancelableRepeatingClosure cancelable(
Mikel Astiz239acc172024-01-11 14:16:2695 BindRepeating(&Increment, Unretained(&count)));
[email protected]b77576f52011-11-24 04:12:0496
97 callback = cancelable.callback();
98 callback.Run();
99 EXPECT_EQ(1, count);
100 }
101
102 callback.Run();
103 EXPECT_EQ(1, count);
104}
105
106// Cancel() called on bound closure with a RefCounted parameter.
107// - Cancel drops wrapped callback (and, implicitly, its bound arguments).
108TEST(CancelableCallbackTest, CancelDropsCallback) {
109 scoped_refptr<TestRefCounted> ref_counted = new TestRefCounted;
110 EXPECT_TRUE(ref_counted->HasOneRef());
111
Mikel Astiz239acc172024-01-11 14:16:26112 CancelableOnceClosure cancelable(BindOnce(RefCountedParam, ref_counted));
[email protected]b77576f52011-11-24 04:12:04113 EXPECT_FALSE(cancelable.IsCancelled());
114 EXPECT_TRUE(ref_counted.get());
115 EXPECT_FALSE(ref_counted->HasOneRef());
116
117 // There is only one reference to |ref_counted| after the Cancel().
118 cancelable.Cancel();
119 EXPECT_TRUE(cancelable.IsCancelled());
120 EXPECT_TRUE(ref_counted.get());
121 EXPECT_TRUE(ref_counted->HasOneRef());
122}
123
124// Reset().
125// - Reset() replaces the existing wrapped callback with a new callback.
126// - Reset() deactivates outstanding callbacks.
127TEST(CancelableCallbackTest, Reset) {
128 int count = 0;
kylechar650caf02019-07-17 03:25:41129 CancelableRepeatingClosure cancelable(
Mikel Astiz239acc172024-01-11 14:16:26130 BindRepeating(&Increment, Unretained(&count)));
[email protected]b77576f52011-11-24 04:12:04131
Mikel Astiz239acc172024-01-11 14:16:26132 RepeatingClosure callback = cancelable.callback();
[email protected]b77576f52011-11-24 04:12:04133 callback.Run();
134 EXPECT_EQ(1, count);
135
136 callback.Run();
137 EXPECT_EQ(2, count);
138
Mikel Astiz239acc172024-01-11 14:16:26139 cancelable.Reset(BindRepeating(&IncrementBy, Unretained(&count), 3));
[email protected]b77576f52011-11-24 04:12:04140 EXPECT_FALSE(cancelable.IsCancelled());
141
142 // The stale copy of the cancelable callback is non-null.
143 ASSERT_FALSE(callback.is_null());
144
145 // The stale copy of the cancelable callback is no longer active.
146 callback.Run();
147 EXPECT_EQ(2, count);
148
Mikel Astiz239acc172024-01-11 14:16:26149 RepeatingClosure callback2 = cancelable.callback();
[email protected]b77576f52011-11-24 04:12:04150 ASSERT_FALSE(callback2.is_null());
151
152 callback2.Run();
153 EXPECT_EQ(5, count);
154}
155
156// IsCanceled().
Colin Blundellea615d422021-05-12 09:35:41157// - Cancel() transforms the CancelableOnceCallback into a cancelled state.
[email protected]b77576f52011-11-24 04:12:04158TEST(CancelableCallbackTest, IsNull) {
kylechar650caf02019-07-17 03:25:41159 CancelableOnceClosure cancelable;
[email protected]b77576f52011-11-24 04:12:04160 EXPECT_TRUE(cancelable.IsCancelled());
161
162 int count = 0;
Mikel Astiz239acc172024-01-11 14:16:26163 cancelable.Reset(BindOnce(&Increment, Unretained(&count)));
[email protected]b77576f52011-11-24 04:12:04164 EXPECT_FALSE(cancelable.IsCancelled());
165
166 cancelable.Cancel();
167 EXPECT_TRUE(cancelable.IsCancelled());
168}
169
Colin Blundellea615d422021-05-12 09:35:41170// CancelableRepeatingCallback posted to a task environment with PostTask.
Sami Kyostila3f49cb572018-11-19 13:01:09171// - Posted callbacks can be cancelled.
Peter Kasting40753712023-12-22 01:22:05172// - Chained callbacks from `.Then()` still run on cancelled callbacks.
[email protected]b77576f52011-11-24 04:12:04173TEST(CancelableCallbackTest, PostTask) {
Mikel Astiz239acc172024-01-11 14:16:26174 test::SingleThreadTaskEnvironment task_environment;
[email protected]b77576f52011-11-24 04:12:04175
176 int count = 0;
kylechar650caf02019-07-17 03:25:41177 CancelableRepeatingClosure cancelable(
Mikel Astiz239acc172024-01-11 14:16:26178 BindRepeating(&Increment, Unretained(&count)));
[email protected]b77576f52011-11-24 04:12:04179
Sean Maher7d0e8052022-12-09 01:46:32180 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE,
181 cancelable.callback());
[email protected]f7b98b32013-02-05 08:14:15182 RunLoop().RunUntilIdle();
[email protected]b77576f52011-11-24 04:12:04183
184 EXPECT_EQ(1, count);
185
Sean Maher7d0e8052022-12-09 01:46:32186 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE,
187 cancelable.callback());
[email protected]b77576f52011-11-24 04:12:04188
Peter Kasting40753712023-12-22 01:22:05189 // Cancel before running the task.
[email protected]b77576f52011-11-24 04:12:04190 cancelable.Cancel();
[email protected]f7b98b32013-02-05 08:14:15191 RunLoop().RunUntilIdle();
[email protected]b77576f52011-11-24 04:12:04192
193 // Callback never ran due to cancellation; count is the same.
194 EXPECT_EQ(1, count);
Peter Kasting40753712023-12-22 01:22:05195
196 // Chain a callback to the cancelable callback.
Mikel Astiz239acc172024-01-11 14:16:26197 cancelable.Reset(BindRepeating(&Increment, Unretained(&count)));
Peter Kasting40753712023-12-22 01:22:05198 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
Mikel Astiz239acc172024-01-11 14:16:26199 FROM_HERE, cancelable.callback().Then(
200 BindRepeating(&IncrementBy, Unretained(&count), 2)));
Peter Kasting40753712023-12-22 01:22:05201
202 // Cancel before running the task.
203 cancelable.Cancel();
204 RunLoop().RunUntilIdle();
205
206 // Callback never ran due to cancellation, but chained callback still should
207 // have. Count should increase by exactly two.
208 EXPECT_EQ(3, count);
[email protected]b77576f52011-11-24 04:12:04209}
210
Mikel Astiz239acc172024-01-11 14:16:26211// CancelableRepeatingCallback posted to a task environment with
212// PostTaskAndReply.
213// - Posted callbacks can be cancelled.
214TEST(CancelableCallbackTest, PostTaskAndReply) {
215 std::optional<test::SingleThreadTaskEnvironment> task_environment;
216 task_environment.emplace();
217
218 int count = 0;
219 CancelableRepeatingClosure cancelable_reply(
220 BindRepeating(&Increment, Unretained(&count)));
221
222 std::optional<RunLoop> loop;
223 loop.emplace();
224 SingleThreadTaskRunner::GetCurrentDefault()->PostTaskAndReply(
225 FROM_HERE, DoNothing(),
226 cancelable_reply.callback().Then(loop->QuitClosure()));
227 loop->Run();
228
229 EXPECT_EQ(1, count);
230
231 loop.emplace();
232 SingleThreadTaskRunner::GetCurrentDefault()->PostTaskAndReply(
233 FROM_HERE, DoNothing(),
234 cancelable_reply.callback().Then(loop->QuitClosure()));
235
236 // Cancel before running the tasks.
237 cancelable_reply.Cancel();
238 loop->Run();
239
240 // Callback never ran due to cancellation; count is the same. Note that
241 // QuitClosure() is still invoked because chained callbacks via Then() get
242 // invoked even if the first callback is cancelled.
243 EXPECT_EQ(1, count);
244
245 // Post it again to exercise a shutdown-like scenario.
246 cancelable_reply.Reset(BindRepeating(&Increment, Unretained(&count)));
247
248 SingleThreadTaskRunner::GetCurrentDefault()->PostTaskAndReply(
249 FROM_HERE, DoNothing(), cancelable_reply.callback());
250 task_environment.reset();
251
252 // Callback never ran due to task runner shutdown; count is the same.
253 EXPECT_EQ(1, count);
254}
255
Colin Blundellea615d422021-05-12 09:35:41256// CancelableRepeatingCallback can be used with move-only types.
kuznetsovsb020bcd82016-04-13 13:01:47257TEST(CancelableCallbackTest, MoveOnlyType) {
258 const int kExpectedResult = 42;
259
260 int result = 0;
kylechar650caf02019-07-17 03:25:41261 CancelableRepeatingCallback<void(std::unique_ptr<int>)> cb(
Mikel Astiz239acc172024-01-11 14:16:26262 BindRepeating(&OnMoveOnlyReceived, Unretained(&result)));
David Benjamindd436292018-10-11 16:28:00263 cb.callback().Run(std::make_unique<int>(kExpectedResult));
kuznetsovsb020bcd82016-04-13 13:01:47264
265 EXPECT_EQ(kExpectedResult, result);
266}
267
[email protected]b77576f52011-11-24 04:12:04268} // namespace
269} // namespace base