OLD | NEW |
---|---|
(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 | |
OLD | NEW |