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

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

Powered by Google App Engine
This is Rietveld 408576698