Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(102)

Side by Side Diff: base/callback_list_unittest.cc

Issue 22877038: Add a CallbackRegistry class to base/ to manage callbacks (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Much clean up and removal of unneeded bits Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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/callback_list.h"
6
7 #include <vector>
8
9 #include "base/bind_helpers.h"
10 #include "base/compiler_specific.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/weak_ptr.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace base {
16 namespace {
17
18 class Listener {
19 public:
20 Listener() : total_(0), scaler_(1) {}
21 explicit Listener(int scaler) : total_(0), scaler_(scaler) {}
22 void IncrementTotal() { total_++; }
23 void MultiplyTotal(const int& x) { total_ += x * scaler_; }
24
25 int total_;
26 private:
27 int scaler_;
28 DISALLOW_COPY_AND_ASSIGN(Listener);
29 };
30
31 class Remover {
32 public:
33 Remover() : total_(0), removal_cb_(base::Closure()) {}
34 void IncrementTotalAndRemove() {
35 total_++;
36 removal_cb_.Run();
37 }
38 void SetCallback(const base::Closure& cb) { removal_cb_ = cb; }
39
40 int total_;
41 private:
42 base::Closure removal_cb_;
43 DISALLOW_COPY_AND_ASSIGN(Remover);
44 };
45
46 class Adder {
47 public:
48 explicit Adder(CallbackList<void>* cb_list)
49 : added_(false),
50 total_(0),
51 cb_list_(cb_list) {}
52 void AddCallback() {
53 if (!added_) {
54 added_ = true;
55 cb_list_->Add(
56 base::Bind(&Adder::IncrementTotal, base::Unretained(this)));
57 }
58 }
59 void IncrementTotal() { total_++; }
60
61 bool added_;
62 int total_;
63 private:
64 CallbackList<void>* cb_list_;
65 DISALLOW_COPY_AND_ASSIGN(Adder);
66 };
67
68 class Clearer {
69 public:
70 explicit Clearer(CallbackList<void>* cb_list)
71 : added_(false),
72 total_(0),
73 cb_list_(cb_list) {}
74 void ClearListAndAddCallback() {
75 cb_list_->Clear();
76 cb_list_->Add(
77 base::Bind(&Clearer::IncrementTotal, base::Unretained(this)));
78 added_ = true;
79 }
80 void IncrementTotal() { total_++; }
81
82 bool added_;
83 int total_;
84 private:
85 CallbackList<void>* cb_list_;
86 DISALLOW_COPY_AND_ASSIGN(Clearer);
87 };
88
89 // Sanity check that closures added to the list will be run, and those removed
90 // from the list will not be run.
91 TEST(CallbackListTest, BasicTest) {
92 CallbackList<void> cb_list;
93 Listener a, b, c;
94
95 base::Closure remove_a = cb_list.Add(
96 base::Bind(&Listener::IncrementTotal, base::Unretained(&a)));
97 base::Closure remove_b = cb_list.Add(
98 base::Bind(&Listener::IncrementTotal, base::Unretained(&b)));
99
100 EXPECT_FALSE(remove_a.is_null());
101 EXPECT_FALSE(remove_b.is_null());
102
103 cb_list.Run();
104
105 EXPECT_EQ(1, a.total_);
106 EXPECT_EQ(1, b.total_);
107
108 remove_b.Run();
109
110 base::Closure remove_c = cb_list.Add(
111 base::Bind(&Listener::IncrementTotal, base::Unretained(&c)));
112
113 cb_list.Run();
114
115 EXPECT_EQ(2, a.total_);
116 EXPECT_EQ(1, b.total_);
117 EXPECT_EQ(1, c.total_);
118
119 remove_a.Run();
120 remove_b.Run();
121 remove_c.Run();
122 }
123
124 // Sanity check that callbacks with details added to the list will be run, with
125 // the correct details, and those removed from the list will not be run.
126 TEST(CallbackListTest, BasicTestWithParams) {
127 CallbackList<int> cb_list;
128 Listener a(1), b(-1), c(1);
129
130 base::Closure remove_a = cb_list.Add(
131 base::Bind(&Listener::MultiplyTotal, base::Unretained(&a)));
132 base::Closure remove_b = cb_list.Add(
133 base::Bind(&Listener::MultiplyTotal, base::Unretained(&b)));
134
135 EXPECT_FALSE(remove_a.is_null());
136 EXPECT_FALSE(remove_b.is_null());
137
138 cb_list.Run(10);
139
140 EXPECT_EQ(10, a.total_);
141 EXPECT_EQ(-10, b.total_);
142
143 remove_b.Run();
144
145 base::Closure remove_c = cb_list.Add(
146 base::Bind(&Listener::MultiplyTotal, base::Unretained(&c)));
147
148 cb_list.Run(10);
149
150 EXPECT_EQ(20, a.total_);
151 EXPECT_EQ(-10, b.total_);
152 EXPECT_EQ(10, c.total_);
153
154 remove_a.Run();
155 remove_b.Run();
156 remove_c.Run();
157 }
158
159 // Test the a callback can remove itself or a different callback from the list
160 // during iteration without invalidating the iterator.
161 TEST(CallbackListTest, RemoveCallbacksDuringIteration) {
162 CallbackList<void> cb_list;
163 Listener a, b;
164 Remover remover_1, remover_2;
165
166 base::Closure remover_1_cb = cb_list.Add(
167 base::Bind(&Remover::IncrementTotalAndRemove,
168 base::Unretained(&remover_1)));
169 base::Closure remover_2_cb = cb_list.Add(
170 base::Bind(&Remover::IncrementTotalAndRemove,
171 base::Unretained(&remover_2)));
172 base::Closure a_cb = cb_list.Add(
173 base::Bind(&Listener::IncrementTotal, base::Unretained(&a)));
174 base::Closure b_cb = cb_list.Add(
175 base::Bind(&Listener::IncrementTotal, base::Unretained(&b)));
176
177 // |remover_1| will remove itself.
178 remover_1.SetCallback(remover_1_cb);
179 // |remover_2| will remove a.
180 remover_2.SetCallback(a_cb);
181
182 cb_list.Run();
183
184 // |remover_1| runs once (and removes itself), |remover_2| runs once (and
185 // removes a), |a| never runs, and |b| runs once.
186 EXPECT_EQ(1, remover_1.total_);
187 EXPECT_EQ(1, remover_2.total_);
188 EXPECT_EQ(0, a.total_);
189 EXPECT_EQ(1, b.total_);
190
191 cb_list.Run();
192
193 // Only |remover_2| and |b| run this time.
194 EXPECT_EQ(1, remover_1.total_);
195 EXPECT_EQ(2, remover_2.total_);
196 EXPECT_EQ(0, a.total_);
197 EXPECT_EQ(2, b.total_);
198 }
199
200 // Test that a callback can add another callback to the list durning iteration
201 // without invalidating the iterator.
202 // - If the CallbackNotificationType is |CALLBACKS_NOTIFY_ALL|, the newly added
203 // callback will be run on the current iteration.
204 // - All other callbacks in the list will be run as well.
205 TEST(CallbackListTest, AddCallbacksDuringIteration) {
206 CallbackList<void> cb_list;
207 Adder a(&cb_list);
208 Listener b;
209 cb_list.Add(
210 base::Bind(&Adder::AddCallback, base::Unretained(&a)));
211 cb_list.Add(
212 base::Bind(&Listener::IncrementTotal, base::Unretained(&b)));
213
214 cb_list.Run();
215
216 EXPECT_EQ(1, a.total_);
217 EXPECT_EQ(1, b.total_);
218 EXPECT_TRUE(a.added_);
219
220 cb_list.Run();
221
222 EXPECT_EQ(2, a.total_);
223 EXPECT_EQ(2, b.total_);
224 }
225
226
227 // Test that if we clear the list during iteration, no callbacks are run after
228 // the one that did the clearing.
229 TEST(CallbackListTest, ClearCallbacksDuringIteration) {
230 CallbackList<void> cb_list;
231 Clearer a(&cb_list);
232 Listener b;
233 cb_list.Add(
234 base::Bind(&Clearer::ClearListAndAddCallback, base::Unretained(&a)));
235 cb_list.Add(
236 base::Bind(&Listener::IncrementTotal, base::Unretained(&b)));
237
238 cb_list.Run();
239
240 EXPECT_EQ(1, a.total_);
241 // |b| never runs because we cleared the list first.
242 EXPECT_EQ(0, b.total_);
243 EXPECT_TRUE(a.added_);
244 }
245
246 // Test that if the iterator outlives the list (that is, for some reason or
247 // we delete the list mid-iteration) then:
248 // - no callbacks run after deletion.
249 // - the list is cleaned up properly (there will be memory errors if this is not
250 // the case).
251 TEST(CallbackListTest, IteratorOutlivesList) {
252 CallbackList<void>* cl = new CallbackList<void>();
253
254 cl->Add(Bind(&DeletePointer<CallbackList<void> >, cl));
255 cl->Add(Bind(&CallbackList<void>::Clear, Unretained(cl)));
256 Listener a;
257 cl->Add(Bind(&Listener::IncrementTotal, base::Unretained(&a)));
258
259 cl->Run();
260
261 // |a| never gets called, as |cb_list| got deleted first.
262 EXPECT_EQ(0, a.total_);
263 }
264
265 } // namespace
266 } // namespace base
OLDNEW
« base/callback_list_internal.h ('K') | « base/callback_list_internal.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698