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

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: Move internal bits to base::internal, fix leaks 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 typedef base::Callback<void(void)> TestCallback;
awong 2013/08/29 19:30:48 TestCallback here is just a Closure. Why not use b
Cait (Slow) 2013/08/30 00:28:02 Done.
19 typedef CallbackList TestCallbackList;
20
21 typedef base::Callback<void(const int&)> OneParamCallback;
22 typedef CallbackListWithDetails<int> TestCallbackListWithParam;
23
24 class Listener {
25 public:
26 explicit Listener() : total(0), scaler_(1) {}
27 Listener(int scaler) : total(0), scaler_(scaler) {}
28 virtual ~Listener() {}
29 virtual void OnEvent() {
awong 2013/08/29 19:30:48 Naming the function with what their action is, rat
Cait (Slow) 2013/08/30 00:28:02 Done.
30 total++;
31 }
32 virtual void OnEventWithParam(const int& x) {
33 total += x * scaler_;
34 }
35 int total;
36 private:
37 int scaler_;
38 };
39
40 class Remover : public Listener {
awong 2013/08/29 19:30:48 Is there a reason for the inheritance? If it'st j
Cait (Slow) 2013/08/30 00:28:02 Done.
41 public:
42 explicit Remover() : removal_cb_(base::Closure()) {}
43 virtual ~Remover() {}
44 virtual void OnEvent() OVERRIDE {
45 Listener::OnEvent();
46 removal_cb_.Run();
47 }
48 virtual void SetCallback(const base::Closure& cb) {
49 removal_cb_ = cb;
50 }
51
52 private:
53 base::Closure removal_cb_;
54 };
55
56 class Adder : public Listener {
57 public:
58 explicit Adder(TestCallbackList* cb_list)
59 : added(false),
60 cb_list_(cb_list) {}
61 virtual ~Adder() {}
62 virtual void OnAddedEvent() {
63 if (!added) {
64 added = true;
65 cb_list_->Add(
66 base::Bind(&Adder::OnEvent, base::Unretained(this)));
67 }
68 }
69 bool added;
awong 2013/08/29 19:30:48 Should be added_
Cait (Slow) 2013/08/30 00:28:02 Done.
70
71 private:
72 TestCallbackList* cb_list_;
73 };
74
75 class Clearer : public Listener {
76 public:
77 explicit Clearer(TestCallbackList* cb_list)
78 : added(false),
79 cb_list_(cb_list) {}
80 virtual ~Clearer() {}
81 virtual void OnClearAndAddEvent() {
82 cb_list_->Clear();
83 cb_list_->Add(
84 base::Bind(&Clearer::OnEvent, base::Unretained(this)));
85 added = true;
86 }
87 bool added;
awong 2013/08/29 19:30:48 nit: added -> added_
Cait (Slow) 2013/08/30 00:28:02 Done.
88
89 private:
90 TestCallbackList* cb_list_;
91 };
92
93 class ListDestructor {
94 public:
95 explicit ListDestructor(TestCallbackList* cb_list)
96 : cb_list_(cb_list) {}
97 virtual ~ListDestructor() {}
98 virtual void OnEvent() {
99 cb_list_->Clear();
100 delete cb_list_;
101 }
102
103 private:
104 TestCallbackList* cb_list_;
105 };
106
107 TEST(CallbackListTest, BasicTest) {
awong 2013/08/29 19:30:48 Can you add a comment listing the invariants being
108 TestCallbackList cb_list(TestCallbackList::NOTIFY_ALL);
109 Listener a, b, c;
110 TestCallback a_cb = base::Bind(&Listener::OnEvent, base::Unretained(&a));
111 TestCallback b_cb = base::Bind(&Listener::OnEvent, base::Unretained(&b));
112
113 base::Closure remove_a = cb_list.Add(a_cb);
114 base::Closure remove_b = cb_list.Add(b_cb);
115
116 EXPECT_FALSE(remove_a.is_null());
117 EXPECT_FALSE(remove_b.is_null());
118
119 cb_list.Run();
120
121 EXPECT_EQ(1, a.total);
122 EXPECT_EQ(1, b.total);
123
124 remove_b.Run();
125
126 base::Closure remove_c = cb_list.Add(
127 base::Bind(&Listener::OnEvent, base::Unretained(&c)));
128
129 cb_list.Run();
130
131 EXPECT_EQ(2, a.total);
132 EXPECT_EQ(1, b.total);
133 EXPECT_EQ(1, c.total);
134
135 {
136 scoped_ptr<ScopedClosureRunner> r1;
137 r1.reset(new ScopedClosureRunner(remove_a));
138 }
139
140 //remove_a.Run();
awong 2013/08/29 19:30:48 is this supposed to be commented out?
Cait (Slow) 2013/08/30 00:28:02 Done.
141 remove_b.Run();
142 remove_c.Run();
143
144 EXPECT_FALSE(cb_list.might_have_callbacks());
145 }
146
147 TEST(CallbackListTest, BasicTestWithParams) {
148 TestCallbackListWithParam cb_list(TestCallbackListWithParam::NOTIFY_ALL);
149 Listener a(1), b(-1), c(1);
150 OneParamCallback a_cb =
151 base::Bind(&Listener::OnEventWithParam, base::Unretained(&a));
152
153 OneParamCallback b_cb =
154 base::Bind(&Listener::OnEventWithParam, base::Unretained(&b));
155
156 base::Closure remove_a = cb_list.Add(a_cb);
157
awong 2013/08/29 19:30:48 this newline seems inconsistent with how the previ
Cait (Slow) 2013/08/30 00:28:02 Done.
158 base::Closure remove_b = cb_list.Add(b_cb);
159
160 EXPECT_FALSE(remove_a.is_null());
161 EXPECT_FALSE(remove_b.is_null());
162
163 cb_list.Run(10);
164
165 EXPECT_EQ(10, a.total);
166 EXPECT_EQ(-10, b.total);
167
168 remove_b.Run();
169
170 base::Closure remove_c = cb_list.Add(
171 base::Bind(&Listener::OnEventWithParam, base::Unretained(&c)));
172
173 cb_list.Run(10);
174
175 EXPECT_EQ(20, a.total);
176 EXPECT_EQ(-10, b.total);
177 EXPECT_EQ(10, c.total);
178
179 remove_a.Run();
180 remove_b.Run();
181 remove_c.Run();
182
183 EXPECT_FALSE(cb_list.might_have_callbacks());
184 }
185
186 TEST(CallbackListTest, RemoveCallbacksDuringIteration) {
187 TestCallbackList cb_list(TestCallbackList::NOTIFY_ALL);
188 Listener a, b;
189 Remover remover_1, remover_2;
190
191 base::Closure remover_1_cb = cb_list.Add(
192 base::Bind(&Remover::OnEvent, base::Unretained(&remover_1)));
193 base::Closure remover_2_cb = cb_list.Add(
194 base::Bind(&Remover::OnEvent, base::Unretained(&remover_2)));
195 base::Closure a_cb = cb_list.Add(
196 base::Bind(&Listener::OnEvent, base::Unretained(&a)));
197 base::Closure b_cb = cb_list.Add(
198 base::Bind(&Listener::OnEvent, base::Unretained(&b)));
199
200 // |remover_1| will remove itself.
201 remover_1.SetCallback(remover_1_cb);
202 // |remover_2| will remove a.
203 remover_2.SetCallback(a_cb);
204
205 cb_list.Run();
206
207 // |remover_1| runs once (and removes itself), |remover_2| runs once (and
208 // removes a), |a| never runs, and |b| runs once.
209 EXPECT_EQ(1, remover_1.total);
210 EXPECT_EQ(1, remover_2.total);
211 EXPECT_EQ(0, a.total);
212 EXPECT_EQ(1, b.total);
213
214 cb_list.Run();
215
216 // Only |remover_2| and |b| run this time.
217 EXPECT_EQ(1, remover_1.total);
218 EXPECT_EQ(2, remover_2.total);
219 EXPECT_EQ(0, a.total);
220 EXPECT_EQ(2, b.total);
221
222 EXPECT_TRUE(cb_list.might_have_callbacks());
223
224 remover_2_cb.Run();
225 b_cb.Run();
226
227 EXPECT_FALSE(cb_list.might_have_callbacks());
228 }
229
230 TEST(CallbackListTest, AddCallbacksDuringIteration) {
231 TestCallbackList cb_list(TestCallbackList::NOTIFY_ALL);
232 Adder a(&cb_list);
233 Listener b;
234 cb_list.Add(
235 base::Bind(&Adder::OnAddedEvent, base::Unretained(&a)));
236 cb_list.Add(
237 base::Bind(&Listener::OnEvent, base::Unretained(&b)));
238
239 cb_list.Run();
240
241 EXPECT_EQ(1, a.total);
242 EXPECT_EQ(1, b.total);
243 EXPECT_TRUE(a.added);
244
245 cb_list.Run();
246
247 EXPECT_EQ(2, a.total);
248 EXPECT_EQ(2, b.total);
249
250 cb_list.Clear();
251 }
252
253 TEST(CallbackListTest, AddCallbacksDuringIteration_Existing) {
254 TestCallbackList cb_list(TestCallbackList::NOTIFY_EXISTING_ONLY);
255 Adder a(&cb_list);
256 Listener b;
257 cb_list.Add(
258 base::Bind(&Adder::OnAddedEvent, base::Unretained(&a)));
259 cb_list.Add(
260 base::Bind(&Listener::OnEvent, base::Unretained(&b)));
261
262 cb_list.Run();
263
264 EXPECT_EQ(0, a.total);
265 EXPECT_EQ(1, b.total);
266 EXPECT_TRUE(a.added);
267
268 cb_list.Run();
269
270 EXPECT_EQ(1, a.total);
271 EXPECT_EQ(2, b.total);
272
273 cb_list.Clear();
274 }
275
276 TEST(CallbackListTest, AddAndRemoveCallbacksDuringIteration_Existing) {
277 TestCallbackList cb_list(TestCallbackList::NOTIFY_EXISTING_ONLY);
278 Adder a(&cb_list);
279 Remover b;
280 Listener c;
281
282 base::Closure c_cb = cb_list.Add(
283 base::Bind(&Listener::OnEvent, base::Unretained(&c)));
284
285 // |b| removes |c|.
286 b.SetCallback(c_cb);
287 cb_list.Add(
288 base::Bind(&Remover::OnEvent, base::Unretained(&b)));
289
290 // |a| adds a new callback.
291 base::Closure a_cb = cb_list.Add(
292 base::Bind(&Adder::OnAddedEvent, base::Unretained(&a)));
293
294 cb_list.Run();
295
296 // |c| ran once, new callback should have been added but not yet run.
297 EXPECT_EQ(1, c.total);
298 EXPECT_EQ(0, a.total);
299 EXPECT_TRUE(a.added);
300
301 cb_list.Run();
302
303 // Now it should have been run.
304 EXPECT_EQ(1, c.total);
305 EXPECT_EQ(1, a.total);
306
307 cb_list.Clear();
308 }
309
310 TEST(CallbackListTest, ClearCallbacksDuringIteration) {
311 TestCallbackList cb_list(TestCallbackList::NOTIFY_ALL);
312 Clearer a(&cb_list);
313 Listener b;
314 cb_list.Add(
315 base::Bind(&Clearer::OnClearAndAddEvent, base::Unretained(&a)));
316 cb_list.Add(
317 base::Bind(&Listener::OnEvent, base::Unretained(&b)));
318
319 cb_list.Run();
320
321 EXPECT_EQ(1, a.total);
322 EXPECT_EQ(0, b.total);
323 EXPECT_TRUE(a.added);
324
325 cb_list.Clear();
326 }
327
328 TEST(CallbackListTest, IteratorOutlivesList) {
329 TestCallbackList* cb_list =
330 new TestCallbackList(TestCallbackList::NOTIFY_ALL);
331 ListDestructor destructor(cb_list);
332 cb_list->Add(
333 base::Bind(&ListDestructor::OnEvent, base::Unretained(&destructor)));
334 Listener a;
335 cb_list->Add(
336 base::Bind(&Listener::OnEvent, base::Unretained(&a)));
337
338 cb_list->Run();
339
340 // |a| never gets called, as |cb_list| got deleted first.
341 EXPECT_EQ(0, a.total);
342 }
343
344 } // namespace
345 } // namespace base
OLDNEW
« base/callback_list_internal.cc ('K') | « base/callback_list_internal.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698