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