blob: 945592b4e51845c46c3069133f611721b6acb2d8 [file] [log] [blame]
[email protected]893c8162013-09-11 15:16:331// 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
[email protected]2a7cac02013-09-26 19:20:185#include "base/callback_list.h"
[email protected]893c8162013-09-11 15:16:336
dcheng093de9b2016-04-04 21:25:517#include <memory>
dcheng9dfa1232015-12-15 05:11:178#include <utility>
9
[email protected]893c8162013-09-11 15:16:3310#include "base/bind.h"
danakjdb9ae7942020-11-11 16:01:3511#include "base/callback_helpers.h"
[email protected]893c8162013-09-11 15:16:3312#include "testing/gtest/include/gtest/gtest.h"
13
14namespace base {
15namespace {
16
17class Listener {
18 public:
Peter Kasting182606c52020-05-04 23:13:5119 Listener() = default;
20 explicit Listener(int scaler) : scaler_(scaler) {}
21 Listener(const Listener&) = delete;
22 Listener& operator=(const Listener&) = delete;
23 ~Listener() = default;
24
25 void IncrementTotal() { ++total_; }
26
[email protected]243576f2013-09-25 13:56:2327 void IncrementByMultipleOfScaler(int x) { total_ += x * scaler_; }
[email protected]893c8162013-09-11 15:16:3328
[email protected]abdd66e2013-10-09 23:28:2129 int total() const { return total_; }
[email protected]893c8162013-09-11 15:16:3330
31 private:
Peter Kasting182606c52020-05-04 23:13:5132 int total_ = 0;
33 int scaler_ = 1;
[email protected]893c8162013-09-11 15:16:3334};
35
36class Remover {
37 public:
Peter Kasting182606c52020-05-04 23:13:5138 Remover() = default;
39 Remover(const Remover&) = delete;
40 Remover& operator=(const Remover&) = delete;
41 ~Remover() = default;
42
[email protected]893c8162013-09-11 15:16:3343 void IncrementTotalAndRemove() {
Peter Kasting182606c52020-05-04 23:13:5144 ++total_;
Peter Kasting7ba9440c2020-11-22 01:49:0245 removal_subscription_ = {};
[email protected]893c8162013-09-11 15:16:3346 }
Peter Kasting182606c52020-05-04 23:13:5147
Peter Kasting7ba9440c2020-11-22 01:49:0248 void SetSubscriptionToRemove(CallbackListSubscription subscription) {
49 removal_subscription_ = std::move(subscription);
[email protected]893c8162013-09-11 15:16:3350 }
51
[email protected]abdd66e2013-10-09 23:28:2152 int total() const { return total_; }
[email protected]893c8162013-09-11 15:16:3353
54 private:
Peter Kasting182606c52020-05-04 23:13:5155 int total_ = 0;
Peter Kasting7ba9440c2020-11-22 01:49:0256 CallbackListSubscription removal_subscription_;
[email protected]893c8162013-09-11 15:16:3357};
58
59class Adder {
60 public:
Peter Kasting670a86b2020-05-06 22:50:0261 explicit Adder(RepeatingClosureList* cb_reg) : cb_reg_(cb_reg) {}
Peter Kasting182606c52020-05-04 23:13:5162 Adder(const Adder&) = delete;
63 Adder& operator=(const Adder&) = delete;
64 ~Adder() = default;
65
[email protected]893c8162013-09-11 15:16:3366 void AddCallback() {
67 if (!added_) {
68 added_ = true;
69 subscription_ =
kylecharb2695fc2019-04-24 14:51:2070 cb_reg_->Add(BindRepeating(&Adder::IncrementTotal, Unretained(this)));
[email protected]893c8162013-09-11 15:16:3371 }
72 }
Peter Kasting182606c52020-05-04 23:13:5173
74 void IncrementTotal() { ++total_; }
[email protected]893c8162013-09-11 15:16:3375
[email protected]abdd66e2013-10-09 23:28:2176 bool added() const { return added_; }
[email protected]abdd66e2013-10-09 23:28:2177 int total() const { return total_; }
[email protected]893c8162013-09-11 15:16:3378
79 private:
Peter Kasting182606c52020-05-04 23:13:5180 bool added_ = false;
81 int total_ = 0;
Peter Kasting670a86b2020-05-06 22:50:0282 RepeatingClosureList* cb_reg_;
Peter Kasting7ba9440c2020-11-22 01:49:0283 CallbackListSubscription subscription_;
[email protected]893c8162013-09-11 15:16:3384};
85
[email protected]243576f2013-09-25 13:56:2386class Summer {
87 public:
Peter Kasting182606c52020-05-04 23:13:5188 Summer() = default;
89 Summer(const Summer&) = delete;
90 Summer& operator=(const Summer&) = delete;
91 ~Summer() = default;
[email protected]243576f2013-09-25 13:56:2392
93 void AddOneParam(int a) { value_ = a; }
94 void AddTwoParam(int a, int b) { value_ = a + b; }
95 void AddThreeParam(int a, int b, int c) { value_ = a + b + c; }
96 void AddFourParam(int a, int b, int c, int d) { value_ = a + b + c + d; }
97 void AddFiveParam(int a, int b, int c, int d, int e) {
98 value_ = a + b + c + d + e;
99 }
100 void AddSixParam(int a, int b, int c, int d, int e , int f) {
101 value_ = a + b + c + d + e + f;
102 }
103
[email protected]abdd66e2013-10-09 23:28:21104 int value() const { return value_; }
[email protected]243576f2013-09-25 13:56:23105
106 private:
Peter Kasting182606c52020-05-04 23:13:51107 int value_ = 0;
[email protected]243576f2013-09-25 13:56:23108};
109
davidbenf126cb22015-10-30 20:42:07110class Counter {
111 public:
Peter Kasting182606c52020-05-04 23:13:51112 Counter() = default;
113 Counter(const Counter&) = delete;
114 Counter& operator=(const Counter&) = delete;
115 ~Counter() = default;
davidbenf126cb22015-10-30 20:42:07116
Peter Kasting182606c52020-05-04 23:13:51117 void Increment() { ++value_; }
davidbenf126cb22015-10-30 20:42:07118
119 int value() const { return value_; }
120
121 private:
Peter Kasting182606c52020-05-04 23:13:51122 int value_ = 0;
davidbenf126cb22015-10-30 20:42:07123};
124
[email protected]2a7cac02013-09-26 19:20:18125// Sanity check that we can instantiate a CallbackList for each arity.
126TEST(CallbackListTest, ArityTest) {
[email protected]243576f2013-09-25 13:56:23127 Summer s;
128
Peter Kasting670a86b2020-05-06 22:50:02129 RepeatingCallbackList<void(int)> c1;
Peter Kasting7ba9440c2020-11-22 01:49:02130 CallbackListSubscription subscription1 =
131 c1.Add(BindRepeating(&Summer::AddOneParam, Unretained(&s)));
[email protected]243576f2013-09-25 13:56:23132
133 c1.Notify(1);
[email protected]abdd66e2013-10-09 23:28:21134 EXPECT_EQ(1, s.value());
[email protected]243576f2013-09-25 13:56:23135
Peter Kasting670a86b2020-05-06 22:50:02136 RepeatingCallbackList<void(int, int)> c2;
Peter Kasting7ba9440c2020-11-22 01:49:02137 CallbackListSubscription subscription2 =
138 c2.Add(BindRepeating(&Summer::AddTwoParam, Unretained(&s)));
[email protected]243576f2013-09-25 13:56:23139
140 c2.Notify(1, 2);
[email protected]abdd66e2013-10-09 23:28:21141 EXPECT_EQ(3, s.value());
[email protected]243576f2013-09-25 13:56:23142
Peter Kasting670a86b2020-05-06 22:50:02143 RepeatingCallbackList<void(int, int, int)> c3;
Peter Kasting7ba9440c2020-11-22 01:49:02144 CallbackListSubscription subscription3 =
145 c3.Add(BindRepeating(&Summer::AddThreeParam, Unretained(&s)));
[email protected]243576f2013-09-25 13:56:23146
147 c3.Notify(1, 2, 3);
[email protected]abdd66e2013-10-09 23:28:21148 EXPECT_EQ(6, s.value());
[email protected]243576f2013-09-25 13:56:23149
Peter Kasting670a86b2020-05-06 22:50:02150 RepeatingCallbackList<void(int, int, int, int)> c4;
Peter Kasting7ba9440c2020-11-22 01:49:02151 CallbackListSubscription subscription4 =
152 c4.Add(BindRepeating(&Summer::AddFourParam, Unretained(&s)));
[email protected]243576f2013-09-25 13:56:23153
154 c4.Notify(1, 2, 3, 4);
[email protected]abdd66e2013-10-09 23:28:21155 EXPECT_EQ(10, s.value());
[email protected]243576f2013-09-25 13:56:23156
Peter Kasting670a86b2020-05-06 22:50:02157 RepeatingCallbackList<void(int, int, int, int, int)> c5;
Peter Kasting7ba9440c2020-11-22 01:49:02158 CallbackListSubscription subscription5 =
159 c5.Add(BindRepeating(&Summer::AddFiveParam, Unretained(&s)));
[email protected]243576f2013-09-25 13:56:23160
161 c5.Notify(1, 2, 3, 4, 5);
[email protected]abdd66e2013-10-09 23:28:21162 EXPECT_EQ(15, s.value());
[email protected]243576f2013-09-25 13:56:23163
Peter Kasting670a86b2020-05-06 22:50:02164 RepeatingCallbackList<void(int, int, int, int, int, int)> c6;
Peter Kasting7ba9440c2020-11-22 01:49:02165 CallbackListSubscription subscription6 =
166 c6.Add(BindRepeating(&Summer::AddSixParam, Unretained(&s)));
[email protected]243576f2013-09-25 13:56:23167
168 c6.Notify(1, 2, 3, 4, 5, 6);
[email protected]abdd66e2013-10-09 23:28:21169 EXPECT_EQ(21, s.value());
[email protected]243576f2013-09-25 13:56:23170}
171
[email protected]893c8162013-09-11 15:16:33172// Sanity check that closures added to the list will be run, and those removed
173// from the list will not be run.
[email protected]2a7cac02013-09-26 19:20:18174TEST(CallbackListTest, BasicTest) {
[email protected]893c8162013-09-11 15:16:33175 Listener a, b, c;
Peter Kasting0fdb3282020-08-06 05:23:24176 RepeatingClosureList cb_reg;
[email protected]893c8162013-09-11 15:16:33177
Peter Kasting7ba9440c2020-11-22 01:49:02178 CallbackListSubscription a_subscription =
kylecharb2695fc2019-04-24 14:51:20179 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&a)));
Peter Kasting7ba9440c2020-11-22 01:49:02180 CallbackListSubscription b_subscription =
kylecharb2695fc2019-04-24 14:51:20181 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
Peter Kasting0fdb3282020-08-06 05:23:24182 cb_reg.AddUnsafe(BindRepeating(&Listener::IncrementTotal, Unretained(&c)));
[email protected]893c8162013-09-11 15:16:33183
Peter Kasting7ba9440c2020-11-22 01:49:02184 EXPECT_TRUE(a_subscription);
185 EXPECT_TRUE(b_subscription);
[email protected]893c8162013-09-11 15:16:33186
187 cb_reg.Notify();
188
[email protected]abdd66e2013-10-09 23:28:21189 EXPECT_EQ(1, a.total());
190 EXPECT_EQ(1, b.total());
Peter Kasting0fdb3282020-08-06 05:23:24191 EXPECT_EQ(1, c.total());
[email protected]893c8162013-09-11 15:16:33192
Peter Kasting7ba9440c2020-11-22 01:49:02193 b_subscription = {};
[email protected]893c8162013-09-11 15:16:33194
Peter Kasting7ba9440c2020-11-22 01:49:02195 CallbackListSubscription c_subscription =
kylecharb2695fc2019-04-24 14:51:20196 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&c)));
[email protected]893c8162013-09-11 15:16:33197
198 cb_reg.Notify();
199
[email protected]abdd66e2013-10-09 23:28:21200 EXPECT_EQ(2, a.total());
201 EXPECT_EQ(1, b.total());
Peter Kasting0fdb3282020-08-06 05:23:24202 EXPECT_EQ(3, c.total());
[email protected]893c8162013-09-11 15:16:33203}
204
Peter Kasting670a86b2020-05-06 22:50:02205// Similar to BasicTest but with OnceCallbacks instead of Repeating.
206TEST(CallbackListTest, OnceCallbacks) {
207 OnceClosureList cb_reg;
208 Listener a, b, c;
209
Peter Kasting7ba9440c2020-11-22 01:49:02210 CallbackListSubscription a_subscription =
Peter Kasting670a86b2020-05-06 22:50:02211 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
Peter Kasting7ba9440c2020-11-22 01:49:02212 CallbackListSubscription b_subscription =
Peter Kasting670a86b2020-05-06 22:50:02213 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&b)));
214
Peter Kasting7ba9440c2020-11-22 01:49:02215 EXPECT_TRUE(a_subscription);
216 EXPECT_TRUE(b_subscription);
Peter Kasting670a86b2020-05-06 22:50:02217
218 cb_reg.Notify();
219
220 EXPECT_EQ(1, a.total());
221 EXPECT_EQ(1, b.total());
222
223 // OnceCallbacks should auto-remove themselves after calling Notify().
224 EXPECT_TRUE(cb_reg.empty());
225
226 // Destroying a subscription after the callback is canceled should not cause
227 // any problems.
Peter Kasting7ba9440c2020-11-22 01:49:02228 b_subscription = {};
Peter Kasting670a86b2020-05-06 22:50:02229
Peter Kasting7ba9440c2020-11-22 01:49:02230 CallbackListSubscription c_subscription =
Peter Kasting670a86b2020-05-06 22:50:02231 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&c)));
232
233 cb_reg.Notify();
234
235 EXPECT_EQ(1, a.total());
236 EXPECT_EQ(1, b.total());
237 EXPECT_EQ(1, c.total());
238}
239
[email protected]893c8162013-09-11 15:16:33240// Sanity check that callbacks with details added to the list will be run, with
241// the correct details, and those removed from the list will not be run.
[email protected]2a7cac02013-09-26 19:20:18242TEST(CallbackListTest, BasicTestWithParams) {
Peter Kasting670a86b2020-05-06 22:50:02243 using CallbackListType = RepeatingCallbackList<void(int)>;
Peter Kasting182606c52020-05-04 23:13:51244 CallbackListType cb_reg;
[email protected]893c8162013-09-11 15:16:33245 Listener a(1), b(-1), c(1);
246
Peter Kasting7ba9440c2020-11-22 01:49:02247 CallbackListSubscription a_subscription = cb_reg.Add(
Peter Kasting182606c52020-05-04 23:13:51248 BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&a)));
Peter Kasting7ba9440c2020-11-22 01:49:02249 CallbackListSubscription b_subscription = cb_reg.Add(
Peter Kasting182606c52020-05-04 23:13:51250 BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&b)));
[email protected]893c8162013-09-11 15:16:33251
Peter Kasting7ba9440c2020-11-22 01:49:02252 EXPECT_TRUE(a_subscription);
253 EXPECT_TRUE(b_subscription);
[email protected]893c8162013-09-11 15:16:33254
255 cb_reg.Notify(10);
256
[email protected]abdd66e2013-10-09 23:28:21257 EXPECT_EQ(10, a.total());
258 EXPECT_EQ(-10, b.total());
[email protected]893c8162013-09-11 15:16:33259
Peter Kasting7ba9440c2020-11-22 01:49:02260 b_subscription = {};
[email protected]893c8162013-09-11 15:16:33261
Peter Kasting7ba9440c2020-11-22 01:49:02262 CallbackListSubscription c_subscription = cb_reg.Add(
Peter Kasting182606c52020-05-04 23:13:51263 BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&c)));
[email protected]893c8162013-09-11 15:16:33264
265 cb_reg.Notify(10);
266
[email protected]abdd66e2013-10-09 23:28:21267 EXPECT_EQ(20, a.total());
268 EXPECT_EQ(-10, b.total());
269 EXPECT_EQ(10, c.total());
[email protected]893c8162013-09-11 15:16:33270}
271
272// Test the a callback can remove itself or a different callback from the list
273// during iteration without invalidating the iterator.
[email protected]2a7cac02013-09-26 19:20:18274TEST(CallbackListTest, RemoveCallbacksDuringIteration) {
Peter Kasting670a86b2020-05-06 22:50:02275 RepeatingClosureList cb_reg;
[email protected]893c8162013-09-11 15:16:33276 Listener a, b;
Peter Kasting7ba9440c2020-11-22 01:49:02277 Remover remover_1, remover_2;
[email protected]893c8162013-09-11 15:16:33278
Peter Kasting7ba9440c2020-11-22 01:49:02279 CallbackListSubscription remover_1_sub = cb_reg.Add(
280 BindRepeating(&Remover::IncrementTotalAndRemove, Unretained(&remover_1)));
281 CallbackListSubscription remover_2_sub = cb_reg.Add(
282 BindRepeating(&Remover::IncrementTotalAndRemove, Unretained(&remover_2)));
283 CallbackListSubscription a_subscription =
kylecharb2695fc2019-04-24 14:51:20284 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&a)));
Peter Kasting7ba9440c2020-11-22 01:49:02285 CallbackListSubscription b_subscription =
kylecharb2695fc2019-04-24 14:51:20286 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
[email protected]893c8162013-09-11 15:16:33287
288 // |remover_1| will remove itself.
dcheng9dfa1232015-12-15 05:11:17289 remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
[email protected]893c8162013-09-11 15:16:33290 // |remover_2| will remove a.
dcheng9dfa1232015-12-15 05:11:17291 remover_2.SetSubscriptionToRemove(std::move(a_subscription));
[email protected]893c8162013-09-11 15:16:33292
293 cb_reg.Notify();
294
295 // |remover_1| runs once (and removes itself), |remover_2| runs once (and
296 // removes a), |a| never runs, and |b| runs once.
[email protected]abdd66e2013-10-09 23:28:21297 EXPECT_EQ(1, remover_1.total());
298 EXPECT_EQ(1, remover_2.total());
299 EXPECT_EQ(0, a.total());
300 EXPECT_EQ(1, b.total());
[email protected]893c8162013-09-11 15:16:33301
302 cb_reg.Notify();
303
304 // Only |remover_2| and |b| run this time.
[email protected]abdd66e2013-10-09 23:28:21305 EXPECT_EQ(1, remover_1.total());
306 EXPECT_EQ(2, remover_2.total());
307 EXPECT_EQ(0, a.total());
308 EXPECT_EQ(2, b.total());
[email protected]893c8162013-09-11 15:16:33309}
310
Peter Kasting670a86b2020-05-06 22:50:02311// Similar to RemoveCallbacksDuringIteration but with OnceCallbacks instead of
312// Repeating.
313TEST(CallbackListTest, RemoveOnceCallbacksDuringIteration) {
314 OnceClosureList cb_reg;
315 Listener a, b;
Peter Kasting7ba9440c2020-11-22 01:49:02316 Remover remover_1, remover_2;
Peter Kasting670a86b2020-05-06 22:50:02317
Peter Kasting7ba9440c2020-11-22 01:49:02318 CallbackListSubscription remover_1_sub = cb_reg.Add(
319 BindOnce(&Remover::IncrementTotalAndRemove, Unretained(&remover_1)));
320 CallbackListSubscription remover_2_sub = cb_reg.Add(
321 BindOnce(&Remover::IncrementTotalAndRemove, Unretained(&remover_2)));
322 CallbackListSubscription a_subscription =
Peter Kasting670a86b2020-05-06 22:50:02323 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
Peter Kasting7ba9440c2020-11-22 01:49:02324 CallbackListSubscription b_subscription =
Peter Kasting670a86b2020-05-06 22:50:02325 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&b)));
326
327 // |remover_1| will remove itself.
328 remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
329 // |remover_2| will remove a.
330 remover_2.SetSubscriptionToRemove(std::move(a_subscription));
331
332 cb_reg.Notify();
333
334 // |remover_1| runs once (and removes itself), |remover_2| runs once (and
335 // removes a), |a| never runs, and |b| runs once.
336 EXPECT_EQ(1, remover_1.total());
337 EXPECT_EQ(1, remover_2.total());
338 EXPECT_EQ(0, a.total());
339 EXPECT_EQ(1, b.total());
340
341 cb_reg.Notify();
342
343 // Nothing runs this time.
344 EXPECT_EQ(1, remover_1.total());
345 EXPECT_EQ(1, remover_2.total());
346 EXPECT_EQ(0, a.total());
347 EXPECT_EQ(1, b.total());
348}
349
[email protected]893c8162013-09-11 15:16:33350// Test that a callback can add another callback to the list durning iteration
351// without invalidating the iterator. The newly added callback should be run on
352// the current iteration as will all other callbacks in the list.
[email protected]2a7cac02013-09-26 19:20:18353TEST(CallbackListTest, AddCallbacksDuringIteration) {
Peter Kasting670a86b2020-05-06 22:50:02354 RepeatingClosureList cb_reg;
[email protected]893c8162013-09-11 15:16:33355 Adder a(&cb_reg);
356 Listener b;
Peter Kasting7ba9440c2020-11-22 01:49:02357 CallbackListSubscription a_subscription =
kylecharb2695fc2019-04-24 14:51:20358 cb_reg.Add(BindRepeating(&Adder::AddCallback, Unretained(&a)));
Peter Kasting7ba9440c2020-11-22 01:49:02359 CallbackListSubscription b_subscription =
kylecharb2695fc2019-04-24 14:51:20360 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
[email protected]893c8162013-09-11 15:16:33361
362 cb_reg.Notify();
363
[email protected]abdd66e2013-10-09 23:28:21364 EXPECT_EQ(1, a.total());
365 EXPECT_EQ(1, b.total());
366 EXPECT_TRUE(a.added());
[email protected]893c8162013-09-11 15:16:33367
368 cb_reg.Notify();
369
[email protected]abdd66e2013-10-09 23:28:21370 EXPECT_EQ(2, a.total());
371 EXPECT_EQ(2, b.total());
[email protected]893c8162013-09-11 15:16:33372}
373
374// Sanity check: notifying an empty list is a no-op.
[email protected]2a7cac02013-09-26 19:20:18375TEST(CallbackListTest, EmptyList) {
Peter Kasting670a86b2020-05-06 22:50:02376 RepeatingClosureList cb_reg;
[email protected]893c8162013-09-11 15:16:33377
378 cb_reg.Notify();
379}
380
Peter Kastingc8b3cc942020-08-11 03:03:54381// empty() should be callable during iteration, and return false if not all the
382// remaining callbacks in the list are null.
383TEST(CallbackListTest, NonEmptyListDuringIteration) {
384 // Declare items such that |cb_reg| is torn down before the subscriptions.
385 // This ensures the removal callback's invariant that the callback list is
386 // nonempty will always hold.
Peter Kasting7ba9440c2020-11-22 01:49:02387 Remover remover;
Peter Kastingc8b3cc942020-08-11 03:03:54388 Listener listener;
Peter Kasting7ba9440c2020-11-22 01:49:02389 CallbackListSubscription remover_sub, listener_sub;
Peter Kastingc8b3cc942020-08-11 03:03:54390 RepeatingClosureList cb_reg;
391 cb_reg.set_removal_callback(base::BindRepeating(
392 [](const RepeatingClosureList* callbacks) {
393 EXPECT_FALSE(callbacks->empty());
394 },
395 Unretained(&cb_reg)));
396
397 remover_sub = cb_reg.Add(
Peter Kasting7ba9440c2020-11-22 01:49:02398 BindRepeating(&Remover::IncrementTotalAndRemove, Unretained(&remover)));
Peter Kastingc8b3cc942020-08-11 03:03:54399 listener_sub = cb_reg.Add(
400 BindRepeating(&Listener::IncrementTotal, Unretained(&listener)));
401
402 // |remover| will remove |listener|.
403 remover.SetSubscriptionToRemove(std::move(listener_sub));
404
405 cb_reg.Notify();
406
407 EXPECT_EQ(1, remover.total());
408 EXPECT_EQ(0, listener.total());
409}
410
411// empty() should be callable during iteration, and return true if all the
412// remaining callbacks in the list are null.
413TEST(CallbackListTest, EmptyListDuringIteration) {
414 OnceClosureList cb_reg;
415 cb_reg.set_removal_callback(base::BindRepeating(
416 [](const OnceClosureList* callbacks) { EXPECT_TRUE(callbacks->empty()); },
417 Unretained(&cb_reg)));
418
Peter Kasting7ba9440c2020-11-22 01:49:02419 Remover remover;
Peter Kastingc8b3cc942020-08-11 03:03:54420 Listener listener;
Peter Kasting7ba9440c2020-11-22 01:49:02421 CallbackListSubscription remover_sub = cb_reg.Add(
422 BindOnce(&Remover::IncrementTotalAndRemove, Unretained(&remover)));
423 CallbackListSubscription listener_sub =
Peter Kastingc8b3cc942020-08-11 03:03:54424 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&listener)));
425
426 // |remover| will remove |listener|.
427 remover.SetSubscriptionToRemove(std::move(listener_sub));
428
429 cb_reg.Notify();
430
431 EXPECT_EQ(1, remover.total());
432 EXPECT_EQ(0, listener.total());
433}
434
Peter Kasting182606c52020-05-04 23:13:51435TEST(CallbackListTest, RemovalCallback) {
davidbenf126cb22015-10-30 20:42:07436 Counter remove_count;
Peter Kasting670a86b2020-05-06 22:50:02437 RepeatingClosureList cb_reg;
davidbenf126cb22015-10-30 20:42:07438 cb_reg.set_removal_callback(
kylecharb2695fc2019-04-24 14:51:20439 BindRepeating(&Counter::Increment, Unretained(&remove_count)));
davidbenf126cb22015-10-30 20:42:07440
Peter Kasting7ba9440c2020-11-22 01:49:02441 CallbackListSubscription subscription = cb_reg.Add(DoNothing());
davidbenf126cb22015-10-30 20:42:07442
443 // Removing a subscription outside of iteration signals the callback.
444 EXPECT_EQ(0, remove_count.value());
Peter Kasting7ba9440c2020-11-22 01:49:02445 subscription = {};
davidbenf126cb22015-10-30 20:42:07446 EXPECT_EQ(1, remove_count.value());
447
448 // Configure two subscriptions to remove themselves.
Peter Kasting7ba9440c2020-11-22 01:49:02449 Remover remover_1, remover_2;
450 CallbackListSubscription remover_1_sub = cb_reg.Add(
451 BindRepeating(&Remover::IncrementTotalAndRemove, Unretained(&remover_1)));
452 CallbackListSubscription remover_2_sub = cb_reg.Add(
453 BindRepeating(&Remover::IncrementTotalAndRemove, Unretained(&remover_2)));
dcheng9dfa1232015-12-15 05:11:17454 remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
455 remover_2.SetSubscriptionToRemove(std::move(remover_2_sub));
davidbenf126cb22015-10-30 20:42:07456
457 // The callback should be signaled exactly once.
458 EXPECT_EQ(1, remove_count.value());
459 cb_reg.Notify();
460 EXPECT_EQ(2, remove_count.value());
461 EXPECT_TRUE(cb_reg.empty());
462}
463
Peter Kasting182606c52020-05-04 23:13:51464TEST(CallbackListTest, AbandonSubscriptions) {
Allen Bauer82686302019-05-14 22:37:47465 Listener listener;
Peter Kasting7ba9440c2020-11-22 01:49:02466 CallbackListSubscription subscription;
Allen Bauer82686302019-05-14 22:37:47467 {
Peter Kasting670a86b2020-05-06 22:50:02468 RepeatingClosureList cb_reg;
Allen Bauer82686302019-05-14 22:37:47469 subscription = cb_reg.Add(
470 BindRepeating(&Listener::IncrementTotal, Unretained(&listener)));
471 // Make sure the callback is signaled while cb_reg is in scope.
472 cb_reg.Notify();
473 // Exiting this scope and running the cb_reg destructor shouldn't fail.
474 }
475 EXPECT_EQ(1, listener.total());
Peter Kasting182606c52020-05-04 23:13:51476
477 // Destroying the subscription after the list should not cause any problems.
Peter Kasting7ba9440c2020-11-22 01:49:02478 subscription = {};
Allen Bauer82686302019-05-14 22:37:47479}
480
Peter Kastingc8b3cc942020-08-11 03:03:54481// Subscriptions should be movable.
482TEST(CallbackListTest, MoveSubscription) {
483 RepeatingClosureList cb_reg;
484 Listener listener;
Peter Kasting7ba9440c2020-11-22 01:49:02485 CallbackListSubscription subscription1 = cb_reg.Add(
486 BindRepeating(&Listener::IncrementTotal, Unretained(&listener)));
Peter Kastingc8b3cc942020-08-11 03:03:54487 cb_reg.Notify();
488 EXPECT_EQ(1, listener.total());
489
490 auto subscription2 = std::move(subscription1);
491 cb_reg.Notify();
492 EXPECT_EQ(2, listener.total());
493
Peter Kasting7ba9440c2020-11-22 01:49:02494 subscription2 = {};
Peter Kastingc8b3cc942020-08-11 03:03:54495 cb_reg.Notify();
496 EXPECT_EQ(2, listener.total());
497}
498
Peter Kasting670a86b2020-05-06 22:50:02499TEST(CallbackListTest, CancelBeforeRunning) {
500 OnceClosureList cb_reg;
501 Listener a;
502
Peter Kasting7ba9440c2020-11-22 01:49:02503 CallbackListSubscription a_subscription =
Peter Kasting670a86b2020-05-06 22:50:02504 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
505
Peter Kasting7ba9440c2020-11-22 01:49:02506 EXPECT_TRUE(a_subscription);
Peter Kasting670a86b2020-05-06 22:50:02507
508 // Canceling a OnceCallback before running it should not cause problems.
Peter Kasting7ba9440c2020-11-22 01:49:02509 a_subscription = {};
Peter Kasting670a86b2020-05-06 22:50:02510 cb_reg.Notify();
511
512 // |a| should not have received any callbacks.
513 EXPECT_EQ(0, a.total());
514}
515
Peter Kastingc8b3cc942020-08-11 03:03:54516// Verifies Notify() can be called reentrantly and what its expected effects
517// are.
518TEST(CallbackListTest, ReentrantNotify) {
519 RepeatingClosureList cb_reg;
520 Listener a, b, c, d;
Peter Kasting7ba9440c2020-11-22 01:49:02521 CallbackListSubscription a_subscription, c_subscription;
Peter Kastingc8b3cc942020-08-11 03:03:54522
523 // A callback to run for |a|.
Peter Kasting7ba9440c2020-11-22 01:49:02524 const auto a_callback = [](RepeatingClosureList* callbacks, Listener* a,
525 CallbackListSubscription* a_subscription,
526 const Listener* b, Listener* c,
527 CallbackListSubscription* c_subscription,
528 Listener* d) {
529 // This should be the first callback.
530 EXPECT_EQ(0, a->total());
531 EXPECT_EQ(0, b->total());
532 EXPECT_EQ(0, c->total());
533 EXPECT_EQ(0, d->total());
Peter Kastingc8b3cc942020-08-11 03:03:54534
Peter Kasting7ba9440c2020-11-22 01:49:02535 // Increment |a| once.
536 a->IncrementTotal();
Peter Kastingc8b3cc942020-08-11 03:03:54537
Peter Kasting7ba9440c2020-11-22 01:49:02538 // Prevent |a| from being incremented again during the reentrant Notify().
539 // Since this is the first callback, this also verifies the inner Notify()
540 // doesn't assume the first callback (or all callbacks) are valid.
541 *a_subscription = {};
Peter Kastingc8b3cc942020-08-11 03:03:54542
Peter Kasting7ba9440c2020-11-22 01:49:02543 // Add |c| and |d| to be incremented by the reentrant Notify().
544 *c_subscription =
545 callbacks->Add(BindRepeating(&Listener::IncrementTotal, Unretained(c)));
546 CallbackListSubscription d_subscription =
547 callbacks->Add(BindRepeating(&Listener::IncrementTotal, Unretained(d)));
Peter Kastingc8b3cc942020-08-11 03:03:54548
Peter Kasting7ba9440c2020-11-22 01:49:02549 // Notify reentrantly. This should not increment |a|, but all the others
550 // should be incremented.
551 callbacks->Notify();
552 EXPECT_EQ(1, b->total());
553 EXPECT_EQ(1, c->total());
554 EXPECT_EQ(1, d->total());
Peter Kastingc8b3cc942020-08-11 03:03:54555
Peter Kasting7ba9440c2020-11-22 01:49:02556 // Since |d_subscription| is locally scoped, it should be canceled before
557 // the outer Notify() increments |d|. |c_subscription| already exists and
558 // thus |c| should get incremented again by the outer Notify() even though
559 // it wasn't scoped when that was called.
560 };
Peter Kastingc8b3cc942020-08-11 03:03:54561
562 // Add |a| and |b| to the list to be notified, and notify.
563 a_subscription = cb_reg.Add(
564 BindRepeating(a_callback, Unretained(&cb_reg), Unretained(&a),
565 Unretained(&a_subscription), Unretained(&b), Unretained(&c),
566 Unretained(&c_subscription), Unretained(&d)));
Peter Kasting7ba9440c2020-11-22 01:49:02567 CallbackListSubscription b_subscription =
Peter Kastingc8b3cc942020-08-11 03:03:54568 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
569
570 // Execute both notifications and check the cumulative effect.
571 cb_reg.Notify();
572 EXPECT_EQ(1, a.total());
573 EXPECT_EQ(2, b.total());
574 EXPECT_EQ(2, c.total());
575 EXPECT_EQ(1, d.total());
576}
577
[email protected]893c8162013-09-11 15:16:33578} // namespace
579} // namespace base