xref: /aosp_15_r20/external/cronet/base/cancelable_callback_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2011 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/cancelable_callback.h"
6 
7 #include <memory>
8 #include <optional>
9 
10 #include "base/functional/bind.h"
11 #include "base/functional/callback_helpers.h"
12 #include "base/location.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/run_loop.h"
15 #include "base/task/single_thread_task_runner.h"
16 #include "base/test/task_environment.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 
19 namespace base {
20 namespace {
21 
22 class TestRefCounted : public RefCountedThreadSafe<TestRefCounted> {
23  private:
24   friend class RefCountedThreadSafe<TestRefCounted>;
25   ~TestRefCounted() = default;
26 };
27 
Increment(int * count)28 void Increment(int* count) { (*count)++; }
IncrementBy(int * count,int n)29 void IncrementBy(int* count, int n) { (*count) += n; }
RefCountedParam(const scoped_refptr<TestRefCounted> & ref_counted)30 void RefCountedParam(const scoped_refptr<TestRefCounted>& ref_counted) {}
31 
OnMoveOnlyReceived(int * value,std::unique_ptr<int> result)32 void OnMoveOnlyReceived(int* value, std::unique_ptr<int> result) {
33   *value = *result;
34 }
35 
36 // Cancel().
37 //  - Callback can be run multiple times.
38 //  - After Cancel(), Run() completes but has no effect.
TEST(CancelableCallbackTest,Cancel)39 TEST(CancelableCallbackTest, Cancel) {
40   int count = 0;
41   CancelableRepeatingClosure cancelable(
42       BindRepeating(&Increment, Unretained(&count)));
43 
44   RepeatingClosure callback = cancelable.callback();
45   callback.Run();
46   EXPECT_EQ(1, count);
47 
48   callback.Run();
49   EXPECT_EQ(2, count);
50 
51   cancelable.Cancel();
52   callback.Run();
53   EXPECT_EQ(2, count);
54 }
55 
56 // Cancel() called multiple times.
57 //  - Cancel() cancels all copies of the wrapped callback.
58 //  - Calling Cancel() more than once has no effect.
59 //  - After Cancel(), callback() returns a null callback.
TEST(CancelableCallbackTest,MultipleCancel)60 TEST(CancelableCallbackTest, MultipleCancel) {
61   int count = 0;
62   CancelableRepeatingClosure cancelable(
63       BindRepeating(&Increment, Unretained(&count)));
64 
65   RepeatingClosure callback1 = cancelable.callback();
66   RepeatingClosure callback2 = cancelable.callback();
67   cancelable.Cancel();
68 
69   callback1.Run();
70   EXPECT_EQ(0, count);
71 
72   callback2.Run();
73   EXPECT_EQ(0, count);
74 
75   // Calling Cancel() again has no effect.
76   cancelable.Cancel();
77 
78   // callback() of a cancelled callback is null.
79   RepeatingClosure callback3 = cancelable.callback();
80   EXPECT_TRUE(callback3.is_null());
81 }
82 
83 // CancelableRepeatingCallback destroyed before callback is run.
84 //  - Destruction of CancelableRepeatingCallback cancels outstanding callbacks.
TEST(CancelableCallbackTest,CallbackCanceledOnDestruction)85 TEST(CancelableCallbackTest, CallbackCanceledOnDestruction) {
86   int count = 0;
87   RepeatingClosure callback;
88 
89   {
90     CancelableRepeatingClosure cancelable(
91         BindRepeating(&Increment, Unretained(&count)));
92 
93     callback = cancelable.callback();
94     callback.Run();
95     EXPECT_EQ(1, count);
96   }
97 
98   callback.Run();
99   EXPECT_EQ(1, count);
100 }
101 
102 // Cancel() called on bound closure with a RefCounted parameter.
103 //  - Cancel drops wrapped callback (and, implicitly, its bound arguments).
TEST(CancelableCallbackTest,CancelDropsCallback)104 TEST(CancelableCallbackTest, CancelDropsCallback) {
105   scoped_refptr<TestRefCounted> ref_counted = new TestRefCounted;
106   EXPECT_TRUE(ref_counted->HasOneRef());
107 
108   CancelableOnceClosure cancelable(BindOnce(RefCountedParam, ref_counted));
109   EXPECT_FALSE(cancelable.IsCancelled());
110   EXPECT_TRUE(ref_counted.get());
111   EXPECT_FALSE(ref_counted->HasOneRef());
112 
113   // There is only one reference to |ref_counted| after the Cancel().
114   cancelable.Cancel();
115   EXPECT_TRUE(cancelable.IsCancelled());
116   EXPECT_TRUE(ref_counted.get());
117   EXPECT_TRUE(ref_counted->HasOneRef());
118 }
119 
120 // Reset().
121 //  - Reset() replaces the existing wrapped callback with a new callback.
122 //  - Reset() deactivates outstanding callbacks.
TEST(CancelableCallbackTest,Reset)123 TEST(CancelableCallbackTest, Reset) {
124   int count = 0;
125   CancelableRepeatingClosure cancelable(
126       BindRepeating(&Increment, Unretained(&count)));
127 
128   RepeatingClosure callback = cancelable.callback();
129   callback.Run();
130   EXPECT_EQ(1, count);
131 
132   callback.Run();
133   EXPECT_EQ(2, count);
134 
135   cancelable.Reset(BindRepeating(&IncrementBy, Unretained(&count), 3));
136   EXPECT_FALSE(cancelable.IsCancelled());
137 
138   // The stale copy of the cancelable callback is non-null.
139   ASSERT_FALSE(callback.is_null());
140 
141   // The stale copy of the cancelable callback is no longer active.
142   callback.Run();
143   EXPECT_EQ(2, count);
144 
145   RepeatingClosure callback2 = cancelable.callback();
146   ASSERT_FALSE(callback2.is_null());
147 
148   callback2.Run();
149   EXPECT_EQ(5, count);
150 }
151 
152 // IsCanceled().
153 //  - Cancel() transforms the CancelableOnceCallback into a cancelled state.
TEST(CancelableCallbackTest,IsNull)154 TEST(CancelableCallbackTest, IsNull) {
155   CancelableOnceClosure cancelable;
156   EXPECT_TRUE(cancelable.IsCancelled());
157 
158   int count = 0;
159   cancelable.Reset(BindOnce(&Increment, Unretained(&count)));
160   EXPECT_FALSE(cancelable.IsCancelled());
161 
162   cancelable.Cancel();
163   EXPECT_TRUE(cancelable.IsCancelled());
164 }
165 
166 // CancelableRepeatingCallback posted to a task environment with PostTask.
167 //  - Posted callbacks can be cancelled.
168 //  - Chained callbacks from `.Then()` still run on cancelled callbacks.
TEST(CancelableCallbackTest,PostTask)169 TEST(CancelableCallbackTest, PostTask) {
170   test::SingleThreadTaskEnvironment task_environment;
171 
172   int count = 0;
173   CancelableRepeatingClosure cancelable(
174       BindRepeating(&Increment, Unretained(&count)));
175 
176   SingleThreadTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE,
177                                                         cancelable.callback());
178   RunLoop().RunUntilIdle();
179 
180   EXPECT_EQ(1, count);
181 
182   SingleThreadTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE,
183                                                         cancelable.callback());
184 
185   // Cancel before running the task.
186   cancelable.Cancel();
187   RunLoop().RunUntilIdle();
188 
189   // Callback never ran due to cancellation; count is the same.
190   EXPECT_EQ(1, count);
191 
192   // Chain a callback to the cancelable callback.
193   cancelable.Reset(BindRepeating(&Increment, Unretained(&count)));
194   SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
195       FROM_HERE, cancelable.callback().Then(
196                      BindRepeating(&IncrementBy, Unretained(&count), 2)));
197 
198   // Cancel before running the task.
199   cancelable.Cancel();
200   RunLoop().RunUntilIdle();
201 
202   // Callback never ran due to cancellation, but chained callback still should
203   // have. Count should increase by exactly two.
204   EXPECT_EQ(3, count);
205 }
206 
207 // CancelableRepeatingCallback posted to a task environment with
208 // PostTaskAndReply.
209 //  - Posted callbacks can be cancelled.
TEST(CancelableCallbackTest,PostTaskAndReply)210 TEST(CancelableCallbackTest, PostTaskAndReply) {
211   std::optional<test::SingleThreadTaskEnvironment> task_environment;
212   task_environment.emplace();
213 
214   int count = 0;
215   CancelableRepeatingClosure cancelable_reply(
216       BindRepeating(&Increment, Unretained(&count)));
217 
218   std::optional<RunLoop> loop;
219   loop.emplace();
220   SingleThreadTaskRunner::GetCurrentDefault()->PostTaskAndReply(
221       FROM_HERE, DoNothing(),
222       cancelable_reply.callback().Then(loop->QuitClosure()));
223   loop->Run();
224 
225   EXPECT_EQ(1, count);
226 
227   loop.emplace();
228   SingleThreadTaskRunner::GetCurrentDefault()->PostTaskAndReply(
229       FROM_HERE, DoNothing(),
230       cancelable_reply.callback().Then(loop->QuitClosure()));
231 
232   // Cancel before running the tasks.
233   cancelable_reply.Cancel();
234   loop->Run();
235 
236   // Callback never ran due to cancellation; count is the same. Note that
237   // QuitClosure() is still invoked because chained callbacks via Then() get
238   // invoked even if the first callback is cancelled.
239   EXPECT_EQ(1, count);
240 
241   // Post it again to exercise a shutdown-like scenario.
242   cancelable_reply.Reset(BindRepeating(&Increment, Unretained(&count)));
243 
244   SingleThreadTaskRunner::GetCurrentDefault()->PostTaskAndReply(
245       FROM_HERE, DoNothing(), cancelable_reply.callback());
246   task_environment.reset();
247 
248   // Callback never ran due to task runner shutdown; count is the same.
249   EXPECT_EQ(1, count);
250 }
251 
252 // CancelableRepeatingCallback can be used with move-only types.
TEST(CancelableCallbackTest,MoveOnlyType)253 TEST(CancelableCallbackTest, MoveOnlyType) {
254   const int kExpectedResult = 42;
255 
256   int result = 0;
257   CancelableRepeatingCallback<void(std::unique_ptr<int>)> cb(
258       BindRepeating(&OnMoveOnlyReceived, Unretained(&result)));
259   cb.callback().Run(std::make_unique<int>(kExpectedResult));
260 
261   EXPECT_EQ(kExpectedResult, result);
262 }
263 
264 }  // namespace
265 }  // namespace base
266