1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker
5*635a8641SAndroid Build Coastguard Worker #include "base/cancelable_callback.h"
6*635a8641SAndroid Build Coastguard Worker
7*635a8641SAndroid Build Coastguard Worker #include <memory>
8*635a8641SAndroid Build Coastguard Worker
9*635a8641SAndroid Build Coastguard Worker #include "base/bind.h"
10*635a8641SAndroid Build Coastguard Worker #include "base/bind_helpers.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/location.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/memory/ref_counted.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/message_loop/message_loop.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/run_loop.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/single_thread_task_runner.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_task_runner_handle.h"
18*635a8641SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
19*635a8641SAndroid Build Coastguard Worker
20*635a8641SAndroid Build Coastguard Worker namespace base {
21*635a8641SAndroid Build Coastguard Worker namespace {
22*635a8641SAndroid Build Coastguard Worker
23*635a8641SAndroid Build Coastguard Worker class TestRefCounted : public RefCountedThreadSafe<TestRefCounted> {
24*635a8641SAndroid Build Coastguard Worker private:
25*635a8641SAndroid Build Coastguard Worker friend class RefCountedThreadSafe<TestRefCounted>;
26*635a8641SAndroid Build Coastguard Worker ~TestRefCounted() = default;
27*635a8641SAndroid Build Coastguard Worker ;
28*635a8641SAndroid Build Coastguard Worker };
29*635a8641SAndroid Build Coastguard Worker
Increment(int * count)30*635a8641SAndroid Build Coastguard Worker void Increment(int* count) { (*count)++; }
IncrementBy(int * count,int n)31*635a8641SAndroid Build Coastguard Worker void IncrementBy(int* count, int n) { (*count) += n; }
RefCountedParam(const scoped_refptr<TestRefCounted> & ref_counted)32*635a8641SAndroid Build Coastguard Worker void RefCountedParam(const scoped_refptr<TestRefCounted>& ref_counted) {}
33*635a8641SAndroid Build Coastguard Worker
OnMoveOnlyReceived(int * value,std::unique_ptr<int> result)34*635a8641SAndroid Build Coastguard Worker void OnMoveOnlyReceived(int* value, std::unique_ptr<int> result) {
35*635a8641SAndroid Build Coastguard Worker *value = *result;
36*635a8641SAndroid Build Coastguard Worker }
37*635a8641SAndroid Build Coastguard Worker
38*635a8641SAndroid Build Coastguard Worker // Cancel().
39*635a8641SAndroid Build Coastguard Worker // - Callback can be run multiple times.
40*635a8641SAndroid Build Coastguard Worker // - After Cancel(), Run() completes but has no effect.
TEST(CancelableCallbackTest,Cancel)41*635a8641SAndroid Build Coastguard Worker TEST(CancelableCallbackTest, Cancel) {
42*635a8641SAndroid Build Coastguard Worker int count = 0;
43*635a8641SAndroid Build Coastguard Worker CancelableClosure cancelable(
44*635a8641SAndroid Build Coastguard Worker base::Bind(&Increment, base::Unretained(&count)));
45*635a8641SAndroid Build Coastguard Worker
46*635a8641SAndroid Build Coastguard Worker base::Closure callback = cancelable.callback();
47*635a8641SAndroid Build Coastguard Worker callback.Run();
48*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(1, count);
49*635a8641SAndroid Build Coastguard Worker
50*635a8641SAndroid Build Coastguard Worker callback.Run();
51*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(2, count);
52*635a8641SAndroid Build Coastguard Worker
53*635a8641SAndroid Build Coastguard Worker cancelable.Cancel();
54*635a8641SAndroid Build Coastguard Worker callback.Run();
55*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(2, count);
56*635a8641SAndroid Build Coastguard Worker }
57*635a8641SAndroid Build Coastguard Worker
58*635a8641SAndroid Build Coastguard Worker // Cancel() called multiple times.
59*635a8641SAndroid Build Coastguard Worker // - Cancel() cancels all copies of the wrapped callback.
60*635a8641SAndroid Build Coastguard Worker // - Calling Cancel() more than once has no effect.
61*635a8641SAndroid Build Coastguard Worker // - After Cancel(), callback() returns a null callback.
TEST(CancelableCallbackTest,MultipleCancel)62*635a8641SAndroid Build Coastguard Worker TEST(CancelableCallbackTest, MultipleCancel) {
63*635a8641SAndroid Build Coastguard Worker int count = 0;
64*635a8641SAndroid Build Coastguard Worker CancelableClosure cancelable(
65*635a8641SAndroid Build Coastguard Worker base::Bind(&Increment, base::Unretained(&count)));
66*635a8641SAndroid Build Coastguard Worker
67*635a8641SAndroid Build Coastguard Worker base::Closure callback1 = cancelable.callback();
68*635a8641SAndroid Build Coastguard Worker base::Closure callback2 = cancelable.callback();
69*635a8641SAndroid Build Coastguard Worker cancelable.Cancel();
70*635a8641SAndroid Build Coastguard Worker
71*635a8641SAndroid Build Coastguard Worker callback1.Run();
72*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, count);
73*635a8641SAndroid Build Coastguard Worker
74*635a8641SAndroid Build Coastguard Worker callback2.Run();
75*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, count);
76*635a8641SAndroid Build Coastguard Worker
77*635a8641SAndroid Build Coastguard Worker // Calling Cancel() again has no effect.
78*635a8641SAndroid Build Coastguard Worker cancelable.Cancel();
79*635a8641SAndroid Build Coastguard Worker
80*635a8641SAndroid Build Coastguard Worker // callback() of a cancelled callback is null.
81*635a8641SAndroid Build Coastguard Worker base::Closure callback3 = cancelable.callback();
82*635a8641SAndroid Build Coastguard Worker EXPECT_TRUE(callback3.is_null());
83*635a8641SAndroid Build Coastguard Worker }
84*635a8641SAndroid Build Coastguard Worker
85*635a8641SAndroid Build Coastguard Worker // CancelableCallback destroyed before callback is run.
86*635a8641SAndroid Build Coastguard Worker // - Destruction of CancelableCallback cancels outstanding callbacks.
TEST(CancelableCallbackTest,CallbackCanceledOnDestruction)87*635a8641SAndroid Build Coastguard Worker TEST(CancelableCallbackTest, CallbackCanceledOnDestruction) {
88*635a8641SAndroid Build Coastguard Worker int count = 0;
89*635a8641SAndroid Build Coastguard Worker base::Closure callback;
90*635a8641SAndroid Build Coastguard Worker
91*635a8641SAndroid Build Coastguard Worker {
92*635a8641SAndroid Build Coastguard Worker CancelableClosure cancelable(
93*635a8641SAndroid Build Coastguard Worker base::Bind(&Increment, base::Unretained(&count)));
94*635a8641SAndroid Build Coastguard Worker
95*635a8641SAndroid Build Coastguard Worker callback = cancelable.callback();
96*635a8641SAndroid Build Coastguard Worker callback.Run();
97*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(1, count);
98*635a8641SAndroid Build Coastguard Worker }
99*635a8641SAndroid Build Coastguard Worker
100*635a8641SAndroid Build Coastguard Worker callback.Run();
101*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(1, count);
102*635a8641SAndroid Build Coastguard Worker }
103*635a8641SAndroid Build Coastguard Worker
104*635a8641SAndroid Build Coastguard Worker // Cancel() called on bound closure with a RefCounted parameter.
105*635a8641SAndroid Build Coastguard Worker // - Cancel drops wrapped callback (and, implicitly, its bound arguments).
TEST(CancelableCallbackTest,CancelDropsCallback)106*635a8641SAndroid Build Coastguard Worker TEST(CancelableCallbackTest, CancelDropsCallback) {
107*635a8641SAndroid Build Coastguard Worker scoped_refptr<TestRefCounted> ref_counted = new TestRefCounted;
108*635a8641SAndroid Build Coastguard Worker EXPECT_TRUE(ref_counted->HasOneRef());
109*635a8641SAndroid Build Coastguard Worker
110*635a8641SAndroid Build Coastguard Worker CancelableClosure cancelable(base::Bind(RefCountedParam, ref_counted));
111*635a8641SAndroid Build Coastguard Worker EXPECT_FALSE(cancelable.IsCancelled());
112*635a8641SAndroid Build Coastguard Worker EXPECT_TRUE(ref_counted.get());
113*635a8641SAndroid Build Coastguard Worker EXPECT_FALSE(ref_counted->HasOneRef());
114*635a8641SAndroid Build Coastguard Worker
115*635a8641SAndroid Build Coastguard Worker // There is only one reference to |ref_counted| after the Cancel().
116*635a8641SAndroid Build Coastguard Worker cancelable.Cancel();
117*635a8641SAndroid Build Coastguard Worker EXPECT_TRUE(cancelable.IsCancelled());
118*635a8641SAndroid Build Coastguard Worker EXPECT_TRUE(ref_counted.get());
119*635a8641SAndroid Build Coastguard Worker EXPECT_TRUE(ref_counted->HasOneRef());
120*635a8641SAndroid Build Coastguard Worker }
121*635a8641SAndroid Build Coastguard Worker
122*635a8641SAndroid Build Coastguard Worker // Reset().
123*635a8641SAndroid Build Coastguard Worker // - Reset() replaces the existing wrapped callback with a new callback.
124*635a8641SAndroid Build Coastguard Worker // - Reset() deactivates outstanding callbacks.
TEST(CancelableCallbackTest,Reset)125*635a8641SAndroid Build Coastguard Worker TEST(CancelableCallbackTest, Reset) {
126*635a8641SAndroid Build Coastguard Worker int count = 0;
127*635a8641SAndroid Build Coastguard Worker CancelableClosure cancelable(
128*635a8641SAndroid Build Coastguard Worker base::Bind(&Increment, base::Unretained(&count)));
129*635a8641SAndroid Build Coastguard Worker
130*635a8641SAndroid Build Coastguard Worker base::Closure callback = cancelable.callback();
131*635a8641SAndroid Build Coastguard Worker callback.Run();
132*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(1, count);
133*635a8641SAndroid Build Coastguard Worker
134*635a8641SAndroid Build Coastguard Worker callback.Run();
135*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(2, count);
136*635a8641SAndroid Build Coastguard Worker
137*635a8641SAndroid Build Coastguard Worker cancelable.Reset(
138*635a8641SAndroid Build Coastguard Worker base::Bind(&IncrementBy, base::Unretained(&count), 3));
139*635a8641SAndroid Build Coastguard Worker EXPECT_FALSE(cancelable.IsCancelled());
140*635a8641SAndroid Build Coastguard Worker
141*635a8641SAndroid Build Coastguard Worker // The stale copy of the cancelable callback is non-null.
142*635a8641SAndroid Build Coastguard Worker ASSERT_FALSE(callback.is_null());
143*635a8641SAndroid Build Coastguard Worker
144*635a8641SAndroid Build Coastguard Worker // The stale copy of the cancelable callback is no longer active.
145*635a8641SAndroid Build Coastguard Worker callback.Run();
146*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(2, count);
147*635a8641SAndroid Build Coastguard Worker
148*635a8641SAndroid Build Coastguard Worker base::Closure callback2 = cancelable.callback();
149*635a8641SAndroid Build Coastguard Worker ASSERT_FALSE(callback2.is_null());
150*635a8641SAndroid Build Coastguard Worker
151*635a8641SAndroid Build Coastguard Worker callback2.Run();
152*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(5, count);
153*635a8641SAndroid Build Coastguard Worker }
154*635a8641SAndroid Build Coastguard Worker
155*635a8641SAndroid Build Coastguard Worker // IsCanceled().
156*635a8641SAndroid Build Coastguard Worker // - Cancel() transforms the CancelableCallback into a cancelled state.
TEST(CancelableCallbackTest,IsNull)157*635a8641SAndroid Build Coastguard Worker TEST(CancelableCallbackTest, IsNull) {
158*635a8641SAndroid Build Coastguard Worker CancelableClosure cancelable;
159*635a8641SAndroid Build Coastguard Worker EXPECT_TRUE(cancelable.IsCancelled());
160*635a8641SAndroid Build Coastguard Worker
161*635a8641SAndroid Build Coastguard Worker int count = 0;
162*635a8641SAndroid Build Coastguard Worker cancelable.Reset(base::Bind(&Increment,
163*635a8641SAndroid Build Coastguard Worker base::Unretained(&count)));
164*635a8641SAndroid Build Coastguard Worker EXPECT_FALSE(cancelable.IsCancelled());
165*635a8641SAndroid Build Coastguard Worker
166*635a8641SAndroid Build Coastguard Worker cancelable.Cancel();
167*635a8641SAndroid Build Coastguard Worker EXPECT_TRUE(cancelable.IsCancelled());
168*635a8641SAndroid Build Coastguard Worker }
169*635a8641SAndroid Build Coastguard Worker
170*635a8641SAndroid Build Coastguard Worker // CancelableCallback posted to a MessageLoop with PostTask.
171*635a8641SAndroid Build Coastguard Worker // - Callbacks posted to a MessageLoop can be cancelled.
TEST(CancelableCallbackTest,PostTask)172*635a8641SAndroid Build Coastguard Worker TEST(CancelableCallbackTest, PostTask) {
173*635a8641SAndroid Build Coastguard Worker MessageLoop loop;
174*635a8641SAndroid Build Coastguard Worker
175*635a8641SAndroid Build Coastguard Worker int count = 0;
176*635a8641SAndroid Build Coastguard Worker CancelableClosure cancelable(base::Bind(&Increment,
177*635a8641SAndroid Build Coastguard Worker base::Unretained(&count)));
178*635a8641SAndroid Build Coastguard Worker
179*635a8641SAndroid Build Coastguard Worker ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
180*635a8641SAndroid Build Coastguard Worker RunLoop().RunUntilIdle();
181*635a8641SAndroid Build Coastguard Worker
182*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(1, count);
183*635a8641SAndroid Build Coastguard Worker
184*635a8641SAndroid Build Coastguard Worker ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
185*635a8641SAndroid Build Coastguard Worker
186*635a8641SAndroid Build Coastguard Worker // Cancel before running the message loop.
187*635a8641SAndroid Build Coastguard Worker cancelable.Cancel();
188*635a8641SAndroid Build Coastguard Worker RunLoop().RunUntilIdle();
189*635a8641SAndroid Build Coastguard Worker
190*635a8641SAndroid Build Coastguard Worker // Callback never ran due to cancellation; count is the same.
191*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(1, count);
192*635a8641SAndroid Build Coastguard Worker }
193*635a8641SAndroid Build Coastguard Worker
194*635a8641SAndroid Build Coastguard Worker // CancelableCallback can be used with move-only types.
TEST(CancelableCallbackTest,MoveOnlyType)195*635a8641SAndroid Build Coastguard Worker TEST(CancelableCallbackTest, MoveOnlyType) {
196*635a8641SAndroid Build Coastguard Worker const int kExpectedResult = 42;
197*635a8641SAndroid Build Coastguard Worker
198*635a8641SAndroid Build Coastguard Worker int result = 0;
199*635a8641SAndroid Build Coastguard Worker CancelableCallback<void(std::unique_ptr<int>)> cb(
200*635a8641SAndroid Build Coastguard Worker base::Bind(&OnMoveOnlyReceived, base::Unretained(&result)));
201*635a8641SAndroid Build Coastguard Worker cb.callback().Run(base::WrapUnique(new int(kExpectedResult)));
202*635a8641SAndroid Build Coastguard Worker
203*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(kExpectedResult, result);
204*635a8641SAndroid Build Coastguard Worker }
205*635a8641SAndroid Build Coastguard Worker
206*635a8641SAndroid Build Coastguard Worker } // namespace
207*635a8641SAndroid Build Coastguard Worker } // namespace base
208