• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
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 
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/location.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/run_loop.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/threading/thread_task_runner_handle.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>;
~TestRefCounted()25   ~TestRefCounted() {};
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   CancelableClosure cancelable(
42       base::Bind(&Increment, base::Unretained(&count)));
43 
44   base::Closure 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   CancelableClosure cancelable(
63       base::Bind(&Increment, base::Unretained(&count)));
64 
65   base::Closure callback1 = cancelable.callback();
66   base::Closure 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   base::Closure callback3 = cancelable.callback();
80   EXPECT_TRUE(callback3.is_null());
81 }
82 
83 // CancelableCallback destroyed before callback is run.
84 //  - Destruction of CancelableCallback cancels outstanding callbacks.
TEST(CancelableCallbackTest,CallbackCanceledOnDestruction)85 TEST(CancelableCallbackTest, CallbackCanceledOnDestruction) {
86   int count = 0;
87   base::Closure callback;
88 
89   {
90     CancelableClosure cancelable(
91         base::Bind(&Increment, base::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   CancelableClosure cancelable(base::Bind(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   CancelableClosure cancelable(
126       base::Bind(&Increment, base::Unretained(&count)));
127 
128   base::Closure callback = cancelable.callback();
129   callback.Run();
130   EXPECT_EQ(1, count);
131 
132   callback.Run();
133   EXPECT_EQ(2, count);
134 
135   cancelable.Reset(
136       base::Bind(&IncrementBy, base::Unretained(&count), 3));
137   EXPECT_FALSE(cancelable.IsCancelled());
138 
139   // The stale copy of the cancelable callback is non-null.
140   ASSERT_FALSE(callback.is_null());
141 
142   // The stale copy of the cancelable callback is no longer active.
143   callback.Run();
144   EXPECT_EQ(2, count);
145 
146   base::Closure callback2 = cancelable.callback();
147   ASSERT_FALSE(callback2.is_null());
148 
149   callback2.Run();
150   EXPECT_EQ(5, count);
151 }
152 
153 // IsCanceled().
154 //  - Cancel() transforms the CancelableCallback into a cancelled state.
TEST(CancelableCallbackTest,IsNull)155 TEST(CancelableCallbackTest, IsNull) {
156   CancelableClosure cancelable;
157   EXPECT_TRUE(cancelable.IsCancelled());
158 
159   int count = 0;
160   cancelable.Reset(base::Bind(&Increment,
161                               base::Unretained(&count)));
162   EXPECT_FALSE(cancelable.IsCancelled());
163 
164   cancelable.Cancel();
165   EXPECT_TRUE(cancelable.IsCancelled());
166 }
167 
168 // CancelableCallback posted to a MessageLoop with PostTask.
169 //  - Callbacks posted to a MessageLoop can be cancelled.
TEST(CancelableCallbackTest,PostTask)170 TEST(CancelableCallbackTest, PostTask) {
171   MessageLoop loop;
172 
173   int count = 0;
174   CancelableClosure cancelable(base::Bind(&Increment,
175                                            base::Unretained(&count)));
176 
177   ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
178   RunLoop().RunUntilIdle();
179 
180   EXPECT_EQ(1, count);
181 
182   ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
183 
184   // Cancel before running the message loop.
185   cancelable.Cancel();
186   RunLoop().RunUntilIdle();
187 
188   // Callback never ran due to cancellation; count is the same.
189   EXPECT_EQ(1, count);
190 }
191 
192 // CancelableCallback can be used with move-only types.
TEST(CancelableCallbackTest,MoveOnlyType)193 TEST(CancelableCallbackTest, MoveOnlyType) {
194   const int kExpectedResult = 42;
195 
196   int result = 0;
197   CancelableCallback<void(std::unique_ptr<int>)> cb(
198       base::Bind(&OnMoveOnlyReceived, base::Unretained(&result)));
199   cb.callback().Run(base::WrapUnique(new int(kExpectedResult)));
200 
201   EXPECT_EQ(kExpectedResult, result);
202 }
203 
204 }  // namespace
205 }  // namespace base
206