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.
5 #include "base/callback_list.h"
7 #include "base/basictypes.h"
9 #include "base/bind_helpers.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "testing/gtest/include/gtest/gtest.h"
18 Listener() : total_(0), scaler_(1) {}
19 explicit Listener(int scaler
) : total_(0), scaler_(scaler
) {}
20 void IncrementTotal() { total_
++; }
21 void IncrementByMultipleOfScaler(int x
) { total_
+= x
* scaler_
; }
23 int total() const { return total_
; }
28 DISALLOW_COPY_AND_ASSIGN(Listener
);
33 Remover() : total_(0) {}
34 void IncrementTotalAndRemove() {
36 removal_subscription_
.reset();
38 void SetSubscriptionToRemove(
39 scoped_ptr
<CallbackList
<void(void)>::Subscription
> sub
) {
40 removal_subscription_
= sub
.Pass();
43 int total() const { return total_
; }
47 scoped_ptr
<CallbackList
<void(void)>::Subscription
> removal_subscription_
;
48 DISALLOW_COPY_AND_ASSIGN(Remover
);
53 explicit Adder(CallbackList
<void(void)>* cb_reg
)
62 cb_reg_
->Add(Bind(&Adder::IncrementTotal
, Unretained(this)));
65 void IncrementTotal() { total_
++; }
67 bool added() const { return added_
; }
69 int total() const { return total_
; }
74 CallbackList
<void(void)>* cb_reg_
;
75 scoped_ptr
<CallbackList
<void(void)>::Subscription
> subscription_
;
76 DISALLOW_COPY_AND_ASSIGN(Adder
);
81 Summer() : value_(0) {}
83 void AddOneParam(int a
) { value_
= a
; }
84 void AddTwoParam(int a
, int b
) { value_
= a
+ b
; }
85 void AddThreeParam(int a
, int b
, int c
) { value_
= a
+ b
+ c
; }
86 void AddFourParam(int a
, int b
, int c
, int d
) { value_
= a
+ b
+ c
+ d
; }
87 void AddFiveParam(int a
, int b
, int c
, int d
, int e
) {
88 value_
= a
+ b
+ c
+ d
+ e
;
90 void AddSixParam(int a
, int b
, int c
, int d
, int e
, int f
) {
91 value_
= a
+ b
+ c
+ d
+ e
+ f
;
94 int value() const { return value_
; }
98 DISALLOW_COPY_AND_ASSIGN(Summer
);
101 // Sanity check that we can instantiate a CallbackList for each arity.
102 TEST(CallbackListTest
, ArityTest
) {
105 CallbackList
<void(int)> c1
;
106 scoped_ptr
<CallbackList
<void(int)>::Subscription
> subscription1
=
107 c1
.Add(Bind(&Summer::AddOneParam
, Unretained(&s
)));
110 EXPECT_EQ(1, s
.value());
112 CallbackList
<void(int, int)> c2
;
113 scoped_ptr
<CallbackList
<void(int, int)>::Subscription
> subscription2
=
114 c2
.Add(Bind(&Summer::AddTwoParam
, Unretained(&s
)));
117 EXPECT_EQ(3, s
.value());
119 CallbackList
<void(int, int, int)> c3
;
120 scoped_ptr
<CallbackList
<void(int, int, int)>::Subscription
>
121 subscription3
= c3
.Add(Bind(&Summer::AddThreeParam
, Unretained(&s
)));
124 EXPECT_EQ(6, s
.value());
126 CallbackList
<void(int, int, int, int)> c4
;
127 scoped_ptr
<CallbackList
<void(int, int, int, int)>::Subscription
>
128 subscription4
= c4
.Add(Bind(&Summer::AddFourParam
, Unretained(&s
)));
130 c4
.Notify(1, 2, 3, 4);
131 EXPECT_EQ(10, s
.value());
133 CallbackList
<void(int, int, int, int, int)> c5
;
134 scoped_ptr
<CallbackList
<void(int, int, int, int, int)>::Subscription
>
135 subscription5
= c5
.Add(Bind(&Summer::AddFiveParam
, Unretained(&s
)));
137 c5
.Notify(1, 2, 3, 4, 5);
138 EXPECT_EQ(15, s
.value());
140 CallbackList
<void(int, int, int, int, int, int)> c6
;
141 scoped_ptr
<CallbackList
<void(int, int, int, int, int, int)>::Subscription
>
142 subscription6
= c6
.Add(Bind(&Summer::AddSixParam
, Unretained(&s
)));
144 c6
.Notify(1, 2, 3, 4, 5, 6);
145 EXPECT_EQ(21, s
.value());
148 // Sanity check that closures added to the list will be run, and those removed
149 // from the list will not be run.
150 TEST(CallbackListTest
, BasicTest
) {
151 CallbackList
<void(void)> cb_reg
;
154 scoped_ptr
<CallbackList
<void(void)>::Subscription
> a_subscription
=
155 cb_reg
.Add(Bind(&Listener::IncrementTotal
, Unretained(&a
)));
156 scoped_ptr
<CallbackList
<void(void)>::Subscription
> b_subscription
=
157 cb_reg
.Add(Bind(&Listener::IncrementTotal
, Unretained(&b
)));
159 EXPECT_TRUE(a_subscription
.get());
160 EXPECT_TRUE(b_subscription
.get());
164 EXPECT_EQ(1, a
.total());
165 EXPECT_EQ(1, b
.total());
167 b_subscription
.reset();
169 scoped_ptr
<CallbackList
<void(void)>::Subscription
> c_subscription
=
170 cb_reg
.Add(Bind(&Listener::IncrementTotal
, Unretained(&c
)));
174 EXPECT_EQ(2, a
.total());
175 EXPECT_EQ(1, b
.total());
176 EXPECT_EQ(1, c
.total());
178 a_subscription
.reset();
179 b_subscription
.reset();
180 c_subscription
.reset();
183 // Sanity check that callbacks with details added to the list will be run, with
184 // the correct details, and those removed from the list will not be run.
185 TEST(CallbackListTest
, BasicTestWithParams
) {
186 CallbackList
<void(int)> cb_reg
;
187 Listener
a(1), b(-1), c(1);
189 scoped_ptr
<CallbackList
<void(int)>::Subscription
> a_subscription
=
190 cb_reg
.Add(Bind(&Listener::IncrementByMultipleOfScaler
, Unretained(&a
)));
191 scoped_ptr
<CallbackList
<void(int)>::Subscription
> b_subscription
=
192 cb_reg
.Add(Bind(&Listener::IncrementByMultipleOfScaler
, Unretained(&b
)));
194 EXPECT_TRUE(a_subscription
.get());
195 EXPECT_TRUE(b_subscription
.get());
199 EXPECT_EQ(10, a
.total());
200 EXPECT_EQ(-10, b
.total());
202 b_subscription
.reset();
204 scoped_ptr
<CallbackList
<void(int)>::Subscription
> c_subscription
=
205 cb_reg
.Add(Bind(&Listener::IncrementByMultipleOfScaler
, Unretained(&c
)));
209 EXPECT_EQ(20, a
.total());
210 EXPECT_EQ(-10, b
.total());
211 EXPECT_EQ(10, c
.total());
213 a_subscription
.reset();
214 b_subscription
.reset();
215 c_subscription
.reset();
218 // Test the a callback can remove itself or a different callback from the list
219 // during iteration without invalidating the iterator.
220 TEST(CallbackListTest
, RemoveCallbacksDuringIteration
) {
221 CallbackList
<void(void)> cb_reg
;
223 Remover remover_1
, remover_2
;
225 scoped_ptr
<CallbackList
<void(void)>::Subscription
> remover_1_sub
=
226 cb_reg
.Add(Bind(&Remover::IncrementTotalAndRemove
,
227 Unretained(&remover_1
)));
228 scoped_ptr
<CallbackList
<void(void)>::Subscription
> remover_2_sub
=
229 cb_reg
.Add(Bind(&Remover::IncrementTotalAndRemove
,
230 Unretained(&remover_2
)));
231 scoped_ptr
<CallbackList
<void(void)>::Subscription
> a_subscription
=
232 cb_reg
.Add(Bind(&Listener::IncrementTotal
, Unretained(&a
)));
233 scoped_ptr
<CallbackList
<void(void)>::Subscription
> b_subscription
=
234 cb_reg
.Add(Bind(&Listener::IncrementTotal
, Unretained(&b
)));
236 // |remover_1| will remove itself.
237 remover_1
.SetSubscriptionToRemove(remover_1_sub
.Pass());
238 // |remover_2| will remove a.
239 remover_2
.SetSubscriptionToRemove(a_subscription
.Pass());
243 // |remover_1| runs once (and removes itself), |remover_2| runs once (and
244 // removes a), |a| never runs, and |b| runs once.
245 EXPECT_EQ(1, remover_1
.total());
246 EXPECT_EQ(1, remover_2
.total());
247 EXPECT_EQ(0, a
.total());
248 EXPECT_EQ(1, b
.total());
252 // Only |remover_2| and |b| run this time.
253 EXPECT_EQ(1, remover_1
.total());
254 EXPECT_EQ(2, remover_2
.total());
255 EXPECT_EQ(0, a
.total());
256 EXPECT_EQ(2, b
.total());
259 // Test that a callback can add another callback to the list durning iteration
260 // without invalidating the iterator. The newly added callback should be run on
261 // the current iteration as will all other callbacks in the list.
262 TEST(CallbackListTest
, AddCallbacksDuringIteration
) {
263 CallbackList
<void(void)> cb_reg
;
266 scoped_ptr
<CallbackList
<void(void)>::Subscription
> a_subscription
=
267 cb_reg
.Add(Bind(&Adder::AddCallback
, Unretained(&a
)));
268 scoped_ptr
<CallbackList
<void(void)>::Subscription
> b_subscription
=
269 cb_reg
.Add(Bind(&Listener::IncrementTotal
, Unretained(&b
)));
273 EXPECT_EQ(1, a
.total());
274 EXPECT_EQ(1, b
.total());
275 EXPECT_TRUE(a
.added());
279 EXPECT_EQ(2, a
.total());
280 EXPECT_EQ(2, b
.total());
283 // Sanity check: notifying an empty list is a no-op.
284 TEST(CallbackListTest
, EmptyList
) {
285 CallbackList
<void(void)> cb_reg
;