blob: 51a2a090d800223dd6188ba21ceee7472156d328 [file] [log] [blame]
[email protected]b77576f52011-11-24 04:12:041// 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 "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/memory/ref_counted.h"
10#include "base/message_loop.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13namespace base {
14namespace {
15
16class TestRefCounted : public RefCountedThreadSafe<TestRefCounted> {
17 private:
18 friend class RefCountedThreadSafe<TestRefCounted>;
19 ~TestRefCounted() {};
20};
21
22void Increment(int* count) { (*count)++; }
23void IncrementBy(int* count, int n) { (*count) += n; }
24void RefCountedParam(const scoped_refptr<TestRefCounted>& ref_counted) {}
25
26// Cancel().
27// - Callback can be run multiple times.
28// - After Cancel(), Run() completes but has no effect.
29TEST(CancelableCallbackTest, Cancel) {
30 int count = 0;
[email protected]d4d57df2011-11-30 20:33:5231 CancelableClosure cancelable(
[email protected]b77576f52011-11-24 04:12:0432 base::Bind(&Increment, base::Unretained(&count)));
33
34 base::Closure callback = cancelable.callback();
35 callback.Run();
36 EXPECT_EQ(1, count);
37
38 callback.Run();
39 EXPECT_EQ(2, count);
40
41 cancelable.Cancel();
42 callback.Run();
43 EXPECT_EQ(2, count);
44}
45
46// Cancel() called multiple times.
47// - Cancel() cancels all copies of the wrapped callback.
[email protected]d4d57df2011-11-30 20:33:5248// - Calling Cancel() more than once has no effect.
49// - After Cancel(), callback() returns a null callback.
[email protected]b77576f52011-11-24 04:12:0450TEST(CancelableCallbackTest, MultipleCancel) {
51 int count = 0;
[email protected]d4d57df2011-11-30 20:33:5252 CancelableClosure cancelable(
[email protected]b77576f52011-11-24 04:12:0453 base::Bind(&Increment, base::Unretained(&count)));
54
55 base::Closure callback1 = cancelable.callback();
[email protected]d4d57df2011-11-30 20:33:5256 base::Closure callback2 = cancelable.callback();
[email protected]b77576f52011-11-24 04:12:0457 cancelable.Cancel();
58
59 callback1.Run();
60 EXPECT_EQ(0, count);
61
[email protected]b77576f52011-11-24 04:12:0462 callback2.Run();
63 EXPECT_EQ(0, count);
64
[email protected]d4d57df2011-11-30 20:33:5265 // Calling Cancel() again has no effect.
[email protected]b77576f52011-11-24 04:12:0466 cancelable.Cancel();
[email protected]d4d57df2011-11-30 20:33:5267
68 // callback() of a cancelled callback is null.
69 base::Closure callback3 = cancelable.callback();
70 EXPECT_TRUE(callback3.is_null());
[email protected]b77576f52011-11-24 04:12:0471}
72
73// CancelableCallback destroyed before callback is run.
74// - Destruction of CancelableCallback cancels outstanding callbacks.
75TEST(CancelableCallbackTest, CallbackCanceledOnDestruction) {
76 int count = 0;
77 base::Closure callback;
78
79 {
[email protected]d4d57df2011-11-30 20:33:5280 CancelableClosure cancelable(
[email protected]b77576f52011-11-24 04:12:0481 base::Bind(&Increment, base::Unretained(&count)));
82
83 callback = cancelable.callback();
84 callback.Run();
85 EXPECT_EQ(1, count);
86 }
87
88 callback.Run();
89 EXPECT_EQ(1, count);
90}
91
92// Cancel() called on bound closure with a RefCounted parameter.
93// - Cancel drops wrapped callback (and, implicitly, its bound arguments).
94TEST(CancelableCallbackTest, CancelDropsCallback) {
95 scoped_refptr<TestRefCounted> ref_counted = new TestRefCounted;
96 EXPECT_TRUE(ref_counted->HasOneRef());
97
[email protected]d4d57df2011-11-30 20:33:5298 CancelableClosure cancelable(base::Bind(RefCountedParam, ref_counted));
[email protected]b77576f52011-11-24 04:12:0499 EXPECT_FALSE(cancelable.IsCancelled());
100 EXPECT_TRUE(ref_counted.get());
101 EXPECT_FALSE(ref_counted->HasOneRef());
102
103 // There is only one reference to |ref_counted| after the Cancel().
104 cancelable.Cancel();
105 EXPECT_TRUE(cancelable.IsCancelled());
106 EXPECT_TRUE(ref_counted.get());
107 EXPECT_TRUE(ref_counted->HasOneRef());
108}
109
110// Reset().
111// - Reset() replaces the existing wrapped callback with a new callback.
112// - Reset() deactivates outstanding callbacks.
113TEST(CancelableCallbackTest, Reset) {
114 int count = 0;
[email protected]d4d57df2011-11-30 20:33:52115 CancelableClosure cancelable(
[email protected]b77576f52011-11-24 04:12:04116 base::Bind(&Increment, base::Unretained(&count)));
117
118 base::Closure callback = cancelable.callback();
119 callback.Run();
120 EXPECT_EQ(1, count);
121
122 callback.Run();
123 EXPECT_EQ(2, count);
124
125 cancelable.Reset(
126 base::Bind(&IncrementBy, base::Unretained(&count), 3));
127 EXPECT_FALSE(cancelable.IsCancelled());
128
129 // The stale copy of the cancelable callback is non-null.
130 ASSERT_FALSE(callback.is_null());
131
132 // The stale copy of the cancelable callback is no longer active.
133 callback.Run();
134 EXPECT_EQ(2, count);
135
136 base::Closure callback2 = cancelable.callback();
137 ASSERT_FALSE(callback2.is_null());
138
139 callback2.Run();
140 EXPECT_EQ(5, count);
141}
142
143// IsCanceled().
144// - Cancel() transforms the CancelableCallback into a cancelled state.
145TEST(CancelableCallbackTest, IsNull) {
[email protected]d4d57df2011-11-30 20:33:52146 CancelableClosure cancelable;
[email protected]b77576f52011-11-24 04:12:04147 EXPECT_TRUE(cancelable.IsCancelled());
148
149 int count = 0;
150 cancelable.Reset(base::Bind(&Increment,
151 base::Unretained(&count)));
152 EXPECT_FALSE(cancelable.IsCancelled());
153
154 cancelable.Cancel();
155 EXPECT_TRUE(cancelable.IsCancelled());
156}
157
158// CancelableCallback posted to a MessageLoop with PostTask.
159// - Callbacks posted to a MessageLoop can be cancelled.
160TEST(CancelableCallbackTest, PostTask) {
161 MessageLoop loop(MessageLoop::TYPE_DEFAULT);
162
163 int count = 0;
[email protected]d4d57df2011-11-30 20:33:52164 CancelableClosure cancelable(base::Bind(&Increment,
[email protected]b77576f52011-11-24 04:12:04165 base::Unretained(&count)));
166
167 MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback());
168 MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
169 MessageLoop::current()->Run();
170
171 EXPECT_EQ(1, count);
172
173 MessageLoop::current()->PostTask(FROM_HERE, cancelable.callback());
174 MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
175
176 // Cancel before running the message loop.
177 cancelable.Cancel();
178 MessageLoop::current()->Run();
179
180 // Callback never ran due to cancellation; count is the same.
181 EXPECT_EQ(1, count);
182}
183
184} // namespace
185} // namespace base