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

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