blob: 831a8d4572cfd359d516abffcd955669cc390797 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2013 The Chromium Authors
[email protected]893c8162013-09-11 15:16:332// 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"
Keishi Hattori0e45c022021-11-27 09:25:5212#include "base/memory/raw_ptr.h"
[email protected]893c8162013-09-11 15:16:3313#include "testing/gtest/include/gtest/gtest.h"
14
15namespace base {
16namespace {
17
18class Listener {
19 public:
Peter Kasting182606c52020-05-04 23:13:5120 Listener() = default;
21 explicit Listener(int scaler) : scaler_(scaler) {}
22 Listener(const Listener&) = delete;
23 Listener& operator=(const Listener&) = delete;
24 ~Listener() = default;
25
26 void IncrementTotal() { ++total_; }
27
[email protected]243576f2013-09-25 13:56:2328 void IncrementByMultipleOfScaler(int x) { total_ += x * scaler_; }
[email protected]893c8162013-09-11 15:16:3329
[email protected]abdd66e2013-10-09 23:28:2130 int total() const { return total_; }
[email protected]893c8162013-09-11 15:16:3331
32 private:
Peter Kasting182606c52020-05-04 23:13:5133 int total_ = 0;
34 int scaler_ = 1;
[email protected]893c8162013-09-11 15:16:3335};
36
37class Remover {
38 public:
Peter Kasting182606c52020-05-04 23:13:5139 Remover() = default;
40 Remover(const Remover&) = delete;
41 Remover& operator=(const Remover&) = delete;
42 ~Remover() = default;
43
[email protected]893c8162013-09-11 15:16:3344 void IncrementTotalAndRemove() {
Peter Kasting182606c52020-05-04 23:13:5145 ++total_;
Peter Kasting7ba9440c2020-11-22 01:49:0246 removal_subscription_ = {};
[email protected]893c8162013-09-11 15:16:3347 }
Peter Kasting182606c52020-05-04 23:13:5148
Peter Kasting7ba9440c2020-11-22 01:49:0249 void SetSubscriptionToRemove(CallbackListSubscription subscription) {
50 removal_subscription_ = std::move(subscription);
[email protected]893c8162013-09-11 15:16:3351 }
52
[email protected]abdd66e2013-10-09 23:28:2153 int total() const { return total_; }
[email protected]893c8162013-09-11 15:16:3354
55 private:
Peter Kasting182606c52020-05-04 23:13:5156 int total_ = 0;
Peter Kasting7ba9440c2020-11-22 01:49:0257 CallbackListSubscription removal_subscription_;
[email protected]893c8162013-09-11 15:16:3358};
59
60class Adder {
61 public:
Peter Kasting670a86b2020-05-06 22:50:0262 explicit Adder(RepeatingClosureList* cb_reg) : cb_reg_(cb_reg) {}
Peter Kasting182606c52020-05-04 23:13:5163 Adder(const Adder&) = delete;
64 Adder& operator=(const Adder&) = delete;
65 ~Adder() = default;
66
[email protected]893c8162013-09-11 15:16:3367 void AddCallback() {
68 if (!added_) {
69 added_ = true;
70 subscription_ =
kylecharb2695fc2019-04-24 14:51:2071 cb_reg_->Add(BindRepeating(&Adder::IncrementTotal, Unretained(this)));
[email protected]893c8162013-09-11 15:16:3372 }
73 }
Peter Kasting182606c52020-05-04 23:13:5174
75 void IncrementTotal() { ++total_; }
[email protected]893c8162013-09-11 15:16:3376
[email protected]abdd66e2013-10-09 23:28:2177 bool added() const { return added_; }
[email protected]abdd66e2013-10-09 23:28:2178 int total() const { return total_; }
[email protected]893c8162013-09-11 15:16:3379
80 private:
Peter Kasting182606c52020-05-04 23:13:5181 bool added_ = false;
82 int total_ = 0;
Keishi Hattori0e45c022021-11-27 09:25:5283 raw_ptr<RepeatingClosureList> cb_reg_;
Peter Kasting7ba9440c2020-11-22 01:49:0284 CallbackListSubscription subscription_;
[email protected]893c8162013-09-11 15:16:3385};
86
[email protected]243576f2013-09-25 13:56:2387class Summer {
88 public:
Peter Kasting182606c52020-05-04 23:13:5189 Summer() = default;
90 Summer(const Summer&) = delete;
91 Summer& operator=(const Summer&) = delete;
92 ~Summer() = default;
[email protected]243576f2013-09-25 13:56:2393
94 void AddOneParam(int a) { value_ = a; }
95 void AddTwoParam(int a, int b) { value_ = a + b; }
96 void AddThreeParam(int a, int b, int c) { value_ = a + b + c; }
97 void AddFourParam(int a, int b, int c, int d) { value_ = a + b + c + d; }
98 void AddFiveParam(int a, int b, int c, int d, int e) {
99 value_ = a + b + c + d + e;
100 }
101 void AddSixParam(int a, int b, int c, int d, int e , int f) {
102 value_ = a + b + c + d + e + f;
103 }
104
[email protected]abdd66e2013-10-09 23:28:21105 int value() const { return value_; }
[email protected]243576f2013-09-25 13:56:23106
107 private:
Peter Kasting182606c52020-05-04 23:13:51108 int value_ = 0;
[email protected]243576f2013-09-25 13:56:23109};
110
davidbenf126cb22015-10-30 20:42:07111class Counter {
112 public:
Peter Kasting182606c52020-05-04 23:13:51113 Counter() = default;
114 Counter(const Counter&) = delete;
115 Counter& operator=(const Counter&) = delete;
116 ~Counter() = default;
davidbenf126cb22015-10-30 20:42:07117
Peter Kasting182606c52020-05-04 23:13:51118 void Increment() { ++value_; }
davidbenf126cb22015-10-30 20:42:07119
120 int value() const { return value_; }
121
122 private:
Peter Kasting182606c52020-05-04 23:13:51123 int value_ = 0;
davidbenf126cb22015-10-30 20:42:07124};
125
[email protected]2a7cac02013-09-26 19:20:18126// Sanity check that we can instantiate a CallbackList for each arity.
127TEST(CallbackListTest, ArityTest) {
[email protected]243576f2013-09-25 13:56:23128 Summer s;
129
Peter Kasting670a86b2020-05-06 22:50:02130 RepeatingCallbackList<void(int)> c1;
Peter Kasting7ba9440c2020-11-22 01:49:02131 CallbackListSubscription subscription1 =
132 c1.Add(BindRepeating(&Summer::AddOneParam, Unretained(&s)));
[email protected]243576f2013-09-25 13:56:23133
134 c1.Notify(1);
[email protected]abdd66e2013-10-09 23:28:21135 EXPECT_EQ(1, s.value());
[email protected]243576f2013-09-25 13:56:23136
Peter Kasting670a86b2020-05-06 22:50:02137 RepeatingCallbackList<void(int, int)> c2;
Peter Kasting7ba9440c2020-11-22 01:49:02138 CallbackListSubscription subscription2 =
139 c2.Add(BindRepeating(&Summer::AddTwoParam, Unretained(&s)));
[email protected]243576f2013-09-25 13:56:23140
141 c2.Notify(1, 2);
[email protected]abdd66e2013-10-09 23:28:21142 EXPECT_EQ(3, s.value());
[email protected]243576f2013-09-25 13:56:23143
Peter Kasting670a86b2020-05-06 22:50:02144 RepeatingCallbackList<void(int, int, int)> c3;
Peter Kasting7ba9440c2020-11-22 01:49:02145 CallbackListSubscription subscription3 =
146 c3.Add(BindRepeating(&Summer::AddThreeParam, Unretained(&s)));
[email protected]243576f2013-09-25 13:56:23147
148 c3.Notify(1, 2, 3);
[email protected]abdd66e2013-10-09 23:28:21149 EXPECT_EQ(6, s.value());
[email protected]243576f2013-09-25 13:56:23150
Peter Kasting670a86b2020-05-06 22:50:02151 RepeatingCallbackList<void(int, int, int, int)> c4;
Peter Kasting7ba9440c2020-11-22 01:49:02152 CallbackListSubscription subscription4 =
153 c4.Add(BindRepeating(&Summer::AddFourParam, Unretained(&s)));
[email protected]243576f2013-09-25 13:56:23154
155 c4.Notify(1, 2, 3, 4);
[email protected]abdd66e2013-10-09 23:28:21156 EXPECT_EQ(10, s.value());
[email protected]243576f2013-09-25 13:56:23157
Peter Kasting670a86b2020-05-06 22:50:02158 RepeatingCallbackList<void(int, int, int, int, int)> c5;
Peter Kasting7ba9440c2020-11-22 01:49:02159 CallbackListSubscription subscription5 =
160 c5.Add(BindRepeating(&Summer::AddFiveParam, Unretained(&s)));
[email protected]243576f2013-09-25 13:56:23161
162 c5.Notify(1, 2, 3, 4, 5);
[email protected]abdd66e2013-10-09 23:28:21163 EXPECT_EQ(15, s.value());
[email protected]243576f2013-09-25 13:56:23164
Peter Kasting670a86b2020-05-06 22:50:02165 RepeatingCallbackList<void(int, int, int, int, int, int)> c6;
Peter Kasting7ba9440c2020-11-22 01:49:02166 CallbackListSubscription subscription6 =
167 c6.Add(BindRepeating(&Summer::AddSixParam, Unretained(&s)));
[email protected]243576f2013-09-25 13:56:23168
169 c6.Notify(1, 2, 3, 4, 5, 6);
[email protected]abdd66e2013-10-09 23:28:21170 EXPECT_EQ(21, s.value());
[email protected]243576f2013-09-25 13:56:23171}
172
[email protected]893c8162013-09-11 15:16:33173// Sanity check that closures added to the list will be run, and those removed
174// from the list will not be run.
[email protected]2a7cac02013-09-26 19:20:18175TEST(CallbackListTest, BasicTest) {
[email protected]893c8162013-09-11 15:16:33176 Listener a, b, c;
Peter Kasting0fdb3282020-08-06 05:23:24177 RepeatingClosureList cb_reg;
[email protected]893c8162013-09-11 15:16:33178
Peter Kasting7ba9440c2020-11-22 01:49:02179 CallbackListSubscription a_subscription =
kylecharb2695fc2019-04-24 14:51:20180 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&a)));
Peter Kasting7ba9440c2020-11-22 01:49:02181 CallbackListSubscription b_subscription =
kylecharb2695fc2019-04-24 14:51:20182 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
Peter Kasting0fdb3282020-08-06 05:23:24183 cb_reg.AddUnsafe(BindRepeating(&Listener::IncrementTotal, Unretained(&c)));
[email protected]893c8162013-09-11 15:16:33184
Peter Kasting7ba9440c2020-11-22 01:49:02185 EXPECT_TRUE(a_subscription);
186 EXPECT_TRUE(b_subscription);
[email protected]893c8162013-09-11 15:16:33187
188 cb_reg.Notify();
189
[email protected]abdd66e2013-10-09 23:28:21190 EXPECT_EQ(1, a.total());
191 EXPECT_EQ(1, b.total());
Peter Kasting0fdb3282020-08-06 05:23:24192 EXPECT_EQ(1, c.total());
[email protected]893c8162013-09-11 15:16:33193
Peter Kasting7ba9440c2020-11-22 01:49:02194 b_subscription = {};
[email protected]893c8162013-09-11 15:16:33195
Peter Kasting7ba9440c2020-11-22 01:49:02196 CallbackListSubscription c_subscription =
kylecharb2695fc2019-04-24 14:51:20197 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&c)));
[email protected]893c8162013-09-11 15:16:33198
199 cb_reg.Notify();
200
[email protected]abdd66e2013-10-09 23:28:21201 EXPECT_EQ(2, a.total());
202 EXPECT_EQ(1, b.total());
Peter Kasting0fdb3282020-08-06 05:23:24203 EXPECT_EQ(3, c.total());
[email protected]893c8162013-09-11 15:16:33204}
205
Peter Kasting670a86b2020-05-06 22:50:02206// Similar to BasicTest but with OnceCallbacks instead of Repeating.
207TEST(CallbackListTest, OnceCallbacks) {
208 OnceClosureList cb_reg;
209 Listener a, b, c;
210
Peter Kasting7ba9440c2020-11-22 01:49:02211 CallbackListSubscription a_subscription =
Peter Kasting670a86b2020-05-06 22:50:02212 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
Peter Kasting7ba9440c2020-11-22 01:49:02213 CallbackListSubscription b_subscription =
Peter Kasting670a86b2020-05-06 22:50:02214 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&b)));
215
Peter Kasting7ba9440c2020-11-22 01:49:02216 EXPECT_TRUE(a_subscription);
217 EXPECT_TRUE(b_subscription);
Peter Kasting670a86b2020-05-06 22:50:02218
219 cb_reg.Notify();
220
221 EXPECT_EQ(1, a.total());
222 EXPECT_EQ(1, b.total());
223
224 // OnceCallbacks should auto-remove themselves after calling Notify().
225 EXPECT_TRUE(cb_reg.empty());
226
227 // Destroying a subscription after the callback is canceled should not cause
228 // any problems.
Peter Kasting7ba9440c2020-11-22 01:49:02229 b_subscription = {};
Peter Kasting670a86b2020-05-06 22:50:02230
Peter Kasting7ba9440c2020-11-22 01:49:02231 CallbackListSubscription c_subscription =
Peter Kasting670a86b2020-05-06 22:50:02232 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&c)));
233
234 cb_reg.Notify();
235
236 EXPECT_EQ(1, a.total());
237 EXPECT_EQ(1, b.total());
238 EXPECT_EQ(1, c.total());
239}
240
[email protected]893c8162013-09-11 15:16:33241// Sanity check that callbacks with details added to the list will be run, with
242// the correct details, and those removed from the list will not be run.
[email protected]2a7cac02013-09-26 19:20:18243TEST(CallbackListTest, BasicTestWithParams) {
Peter Kasting670a86b2020-05-06 22:50:02244 using CallbackListType = RepeatingCallbackList<void(int)>;
Peter Kasting182606c52020-05-04 23:13:51245 CallbackListType cb_reg;
[email protected]893c8162013-09-11 15:16:33246 Listener a(1), b(-1), c(1);
247
Peter Kasting7ba9440c2020-11-22 01:49:02248 CallbackListSubscription a_subscription = cb_reg.Add(
Peter Kasting182606c52020-05-04 23:13:51249 BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&a)));
Peter Kasting7ba9440c2020-11-22 01:49:02250 CallbackListSubscription b_subscription = cb_reg.Add(
Peter Kasting182606c52020-05-04 23:13:51251 BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&b)));
[email protected]893c8162013-09-11 15:16:33252
Peter Kasting7ba9440c2020-11-22 01:49:02253 EXPECT_TRUE(a_subscription);
254 EXPECT_TRUE(b_subscription);
[email protected]893c8162013-09-11 15:16:33255
256 cb_reg.Notify(10);
257
[email protected]abdd66e2013-10-09 23:28:21258 EXPECT_EQ(10, a.total());
259 EXPECT_EQ(-10, b.total());
[email protected]893c8162013-09-11 15:16:33260
Peter Kasting7ba9440c2020-11-22 01:49:02261 b_subscription = {};
[email protected]893c8162013-09-11 15:16:33262
Peter Kasting7ba9440c2020-11-22 01:49:02263 CallbackListSubscription c_subscription = cb_reg.Add(
Peter Kasting182606c52020-05-04 23:13:51264 BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&c)));
[email protected]893c8162013-09-11 15:16:33265
266 cb_reg.Notify(10);
267
[email protected]abdd66e2013-10-09 23:28:21268 EXPECT_EQ(20, a.total());
269 EXPECT_EQ(-10, b.total());
270 EXPECT_EQ(10, c.total());
[email protected]893c8162013-09-11 15:16:33271}
272
273// Test the a callback can remove itself or a different callback from the list
274// during iteration without invalidating the iterator.
[email protected]2a7cac02013-09-26 19:20:18275TEST(CallbackListTest, RemoveCallbacksDuringIteration) {
Peter Kasting670a86b2020-05-06 22:50:02276 RepeatingClosureList cb_reg;
[email protected]893c8162013-09-11 15:16:33277 Listener a, b;
Peter Kasting7ba9440c2020-11-22 01:49:02278 Remover remover_1, remover_2;
[email protected]893c8162013-09-11 15:16:33279
Peter Kasting7ba9440c2020-11-22 01:49:02280 CallbackListSubscription remover_1_sub = cb_reg.Add(
281 BindRepeating(&Remover::IncrementTotalAndRemove, Unretained(&remover_1)));
282 CallbackListSubscription remover_2_sub = cb_reg.Add(
283 BindRepeating(&Remover::IncrementTotalAndRemove, Unretained(&remover_2)));
284 CallbackListSubscription a_subscription =
kylecharb2695fc2019-04-24 14:51:20285 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&a)));
Peter Kasting7ba9440c2020-11-22 01:49:02286 CallbackListSubscription b_subscription =
kylecharb2695fc2019-04-24 14:51:20287 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
[email protected]893c8162013-09-11 15:16:33288
289 // |remover_1| will remove itself.
dcheng9dfa1232015-12-15 05:11:17290 remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
[email protected]893c8162013-09-11 15:16:33291 // |remover_2| will remove a.
dcheng9dfa1232015-12-15 05:11:17292 remover_2.SetSubscriptionToRemove(std::move(a_subscription));
[email protected]893c8162013-09-11 15:16:33293
294 cb_reg.Notify();
295
296 // |remover_1| runs once (and removes itself), |remover_2| runs once (and
297 // removes a), |a| never runs, and |b| runs once.
[email protected]abdd66e2013-10-09 23:28:21298 EXPECT_EQ(1, remover_1.total());
299 EXPECT_EQ(1, remover_2.total());
300 EXPECT_EQ(0, a.total());
301 EXPECT_EQ(1, b.total());
[email protected]893c8162013-09-11 15:16:33302
303 cb_reg.Notify();
304
305 // Only |remover_2| and |b| run this time.
[email protected]abdd66e2013-10-09 23:28:21306 EXPECT_EQ(1, remover_1.total());
307 EXPECT_EQ(2, remover_2.total());
308 EXPECT_EQ(0, a.total());
309 EXPECT_EQ(2, b.total());
[email protected]893c8162013-09-11 15:16:33310}
311
Peter Kasting670a86b2020-05-06 22:50:02312// Similar to RemoveCallbacksDuringIteration but with OnceCallbacks instead of
313// Repeating.
314TEST(CallbackListTest, RemoveOnceCallbacksDuringIteration) {
315 OnceClosureList cb_reg;
316 Listener a, b;
Peter Kasting7ba9440c2020-11-22 01:49:02317 Remover remover_1, remover_2;
Peter Kasting670a86b2020-05-06 22:50:02318
Peter Kasting7ba9440c2020-11-22 01:49:02319 CallbackListSubscription remover_1_sub = cb_reg.Add(
320 BindOnce(&Remover::IncrementTotalAndRemove, Unretained(&remover_1)));
321 CallbackListSubscription remover_2_sub = cb_reg.Add(
322 BindOnce(&Remover::IncrementTotalAndRemove, Unretained(&remover_2)));
323 CallbackListSubscription a_subscription =
Peter Kasting670a86b2020-05-06 22:50:02324 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
Peter Kasting7ba9440c2020-11-22 01:49:02325 CallbackListSubscription b_subscription =
Peter Kasting670a86b2020-05-06 22:50:02326 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&b)));
327
328 // |remover_1| will remove itself.
329 remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
330 // |remover_2| will remove a.
331 remover_2.SetSubscriptionToRemove(std::move(a_subscription));
332
333 cb_reg.Notify();
334
335 // |remover_1| runs once (and removes itself), |remover_2| runs once (and
336 // removes a), |a| never runs, and |b| runs once.
337 EXPECT_EQ(1, remover_1.total());
338 EXPECT_EQ(1, remover_2.total());
339 EXPECT_EQ(0, a.total());
340 EXPECT_EQ(1, b.total());
341
342 cb_reg.Notify();
343
344 // Nothing runs this time.
345 EXPECT_EQ(1, remover_1.total());
346 EXPECT_EQ(1, remover_2.total());
347 EXPECT_EQ(0, a.total());
348 EXPECT_EQ(1, b.total());
349}
350
[email protected]893c8162013-09-11 15:16:33351// Test that a callback can add another callback to the list durning iteration
352// without invalidating the iterator. The newly added callback should be run on
353// the current iteration as will all other callbacks in the list.
[email protected]2a7cac02013-09-26 19:20:18354TEST(CallbackListTest, AddCallbacksDuringIteration) {
Peter Kasting670a86b2020-05-06 22:50:02355 RepeatingClosureList cb_reg;
[email protected]893c8162013-09-11 15:16:33356 Adder a(&cb_reg);
357 Listener b;
Peter Kasting7ba9440c2020-11-22 01:49:02358 CallbackListSubscription a_subscription =
kylecharb2695fc2019-04-24 14:51:20359 cb_reg.Add(BindRepeating(&Adder::AddCallback, Unretained(&a)));
Peter Kasting7ba9440c2020-11-22 01:49:02360 CallbackListSubscription b_subscription =
kylecharb2695fc2019-04-24 14:51:20361 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
[email protected]893c8162013-09-11 15:16:33362
363 cb_reg.Notify();
364
[email protected]abdd66e2013-10-09 23:28:21365 EXPECT_EQ(1, a.total());
366 EXPECT_EQ(1, b.total());
367 EXPECT_TRUE(a.added());
[email protected]893c8162013-09-11 15:16:33368
369 cb_reg.Notify();
370
[email protected]abdd66e2013-10-09 23:28:21371 EXPECT_EQ(2, a.total());
372 EXPECT_EQ(2, b.total());
[email protected]893c8162013-09-11 15:16:33373}
374
375// Sanity check: notifying an empty list is a no-op.
[email protected]2a7cac02013-09-26 19:20:18376TEST(CallbackListTest, EmptyList) {
Peter Kasting670a86b2020-05-06 22:50:02377 RepeatingClosureList cb_reg;
[email protected]893c8162013-09-11 15:16:33378
379 cb_reg.Notify();
380}
381
Peter Kastingc8b3cc942020-08-11 03:03:54382// empty() should be callable during iteration, and return false if not all the
383// remaining callbacks in the list are null.
384TEST(CallbackListTest, NonEmptyListDuringIteration) {
385 // Declare items such that |cb_reg| is torn down before the subscriptions.
386 // This ensures the removal callback's invariant that the callback list is
387 // nonempty will always hold.
Peter Kasting7ba9440c2020-11-22 01:49:02388 Remover remover;
Peter Kastingc8b3cc942020-08-11 03:03:54389 Listener listener;
Peter Kasting7ba9440c2020-11-22 01:49:02390 CallbackListSubscription remover_sub, listener_sub;
Peter Kastingc8b3cc942020-08-11 03:03:54391 RepeatingClosureList cb_reg;
392 cb_reg.set_removal_callback(base::BindRepeating(
393 [](const RepeatingClosureList* callbacks) {
394 EXPECT_FALSE(callbacks->empty());
395 },
396 Unretained(&cb_reg)));
397
398 remover_sub = cb_reg.Add(
Peter Kasting7ba9440c2020-11-22 01:49:02399 BindRepeating(&Remover::IncrementTotalAndRemove, Unretained(&remover)));
Peter Kastingc8b3cc942020-08-11 03:03:54400 listener_sub = cb_reg.Add(
401 BindRepeating(&Listener::IncrementTotal, Unretained(&listener)));
402
403 // |remover| will remove |listener|.
404 remover.SetSubscriptionToRemove(std::move(listener_sub));
405
406 cb_reg.Notify();
407
408 EXPECT_EQ(1, remover.total());
409 EXPECT_EQ(0, listener.total());
410}
411
412// empty() should be callable during iteration, and return true if all the
413// remaining callbacks in the list are null.
414TEST(CallbackListTest, EmptyListDuringIteration) {
415 OnceClosureList cb_reg;
416 cb_reg.set_removal_callback(base::BindRepeating(
417 [](const OnceClosureList* callbacks) { EXPECT_TRUE(callbacks->empty()); },
418 Unretained(&cb_reg)));
419
Peter Kasting7ba9440c2020-11-22 01:49:02420 Remover remover;
Peter Kastingc8b3cc942020-08-11 03:03:54421 Listener listener;
Peter Kasting7ba9440c2020-11-22 01:49:02422 CallbackListSubscription remover_sub = cb_reg.Add(
423 BindOnce(&Remover::IncrementTotalAndRemove, Unretained(&remover)));
424 CallbackListSubscription listener_sub =
Peter Kastingc8b3cc942020-08-11 03:03:54425 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&listener)));
426
427 // |remover| will remove |listener|.
428 remover.SetSubscriptionToRemove(std::move(listener_sub));
429
430 cb_reg.Notify();
431
432 EXPECT_EQ(1, remover.total());
433 EXPECT_EQ(0, listener.total());
434}
435
Peter Kasting182606c52020-05-04 23:13:51436TEST(CallbackListTest, RemovalCallback) {
davidbenf126cb22015-10-30 20:42:07437 Counter remove_count;
Peter Kasting670a86b2020-05-06 22:50:02438 RepeatingClosureList cb_reg;
davidbenf126cb22015-10-30 20:42:07439 cb_reg.set_removal_callback(
kylecharb2695fc2019-04-24 14:51:20440 BindRepeating(&Counter::Increment, Unretained(&remove_count)));
davidbenf126cb22015-10-30 20:42:07441
Peter Kasting7ba9440c2020-11-22 01:49:02442 CallbackListSubscription subscription = cb_reg.Add(DoNothing());
davidbenf126cb22015-10-30 20:42:07443
444 // Removing a subscription outside of iteration signals the callback.
445 EXPECT_EQ(0, remove_count.value());
Peter Kasting7ba9440c2020-11-22 01:49:02446 subscription = {};
davidbenf126cb22015-10-30 20:42:07447 EXPECT_EQ(1, remove_count.value());
448
449 // Configure two subscriptions to remove themselves.
Peter Kasting7ba9440c2020-11-22 01:49:02450 Remover remover_1, remover_2;
451 CallbackListSubscription remover_1_sub = cb_reg.Add(
452 BindRepeating(&Remover::IncrementTotalAndRemove, Unretained(&remover_1)));
453 CallbackListSubscription remover_2_sub = cb_reg.Add(
454 BindRepeating(&Remover::IncrementTotalAndRemove, Unretained(&remover_2)));
dcheng9dfa1232015-12-15 05:11:17455 remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
456 remover_2.SetSubscriptionToRemove(std::move(remover_2_sub));
davidbenf126cb22015-10-30 20:42:07457
458 // The callback should be signaled exactly once.
459 EXPECT_EQ(1, remove_count.value());
460 cb_reg.Notify();
461 EXPECT_EQ(2, remove_count.value());
462 EXPECT_TRUE(cb_reg.empty());
463}
464
Peter Kasting182606c52020-05-04 23:13:51465TEST(CallbackListTest, AbandonSubscriptions) {
Allen Bauer82686302019-05-14 22:37:47466 Listener listener;
Peter Kasting7ba9440c2020-11-22 01:49:02467 CallbackListSubscription subscription;
Allen Bauer82686302019-05-14 22:37:47468 {
Peter Kasting670a86b2020-05-06 22:50:02469 RepeatingClosureList cb_reg;
Allen Bauer82686302019-05-14 22:37:47470 subscription = cb_reg.Add(
471 BindRepeating(&Listener::IncrementTotal, Unretained(&listener)));
472 // Make sure the callback is signaled while cb_reg is in scope.
473 cb_reg.Notify();
474 // Exiting this scope and running the cb_reg destructor shouldn't fail.
475 }
476 EXPECT_EQ(1, listener.total());
Peter Kasting182606c52020-05-04 23:13:51477
478 // Destroying the subscription after the list should not cause any problems.
Peter Kasting7ba9440c2020-11-22 01:49:02479 subscription = {};
Allen Bauer82686302019-05-14 22:37:47480}
481
Peter Kastingc8b3cc942020-08-11 03:03:54482// Subscriptions should be movable.
483TEST(CallbackListTest, MoveSubscription) {
484 RepeatingClosureList cb_reg;
485 Listener listener;
Peter Kasting7ba9440c2020-11-22 01:49:02486 CallbackListSubscription subscription1 = cb_reg.Add(
487 BindRepeating(&Listener::IncrementTotal, Unretained(&listener)));
Peter Kastingc8b3cc942020-08-11 03:03:54488 cb_reg.Notify();
489 EXPECT_EQ(1, listener.total());
490
491 auto subscription2 = std::move(subscription1);
492 cb_reg.Notify();
493 EXPECT_EQ(2, listener.total());
494
Peter Kasting7ba9440c2020-11-22 01:49:02495 subscription2 = {};
Peter Kastingc8b3cc942020-08-11 03:03:54496 cb_reg.Notify();
497 EXPECT_EQ(2, listener.total());
498}
499
Peter Kasting670a86b2020-05-06 22:50:02500TEST(CallbackListTest, CancelBeforeRunning) {
501 OnceClosureList cb_reg;
502 Listener a;
503
Peter Kasting7ba9440c2020-11-22 01:49:02504 CallbackListSubscription a_subscription =
Peter Kasting670a86b2020-05-06 22:50:02505 cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
506
Peter Kasting7ba9440c2020-11-22 01:49:02507 EXPECT_TRUE(a_subscription);
Peter Kasting670a86b2020-05-06 22:50:02508
509 // Canceling a OnceCallback before running it should not cause problems.
Peter Kasting7ba9440c2020-11-22 01:49:02510 a_subscription = {};
Peter Kasting670a86b2020-05-06 22:50:02511 cb_reg.Notify();
512
513 // |a| should not have received any callbacks.
514 EXPECT_EQ(0, a.total());
515}
516
Peter Kastingc8b3cc942020-08-11 03:03:54517// Verifies Notify() can be called reentrantly and what its expected effects
518// are.
519TEST(CallbackListTest, ReentrantNotify) {
520 RepeatingClosureList cb_reg;
521 Listener a, b, c, d;
Peter Kasting7ba9440c2020-11-22 01:49:02522 CallbackListSubscription a_subscription, c_subscription;
Peter Kastingc8b3cc942020-08-11 03:03:54523
524 // A callback to run for |a|.
Peter Kasting7ba9440c2020-11-22 01:49:02525 const auto a_callback = [](RepeatingClosureList* callbacks, Listener* a,
526 CallbackListSubscription* a_subscription,
527 const Listener* b, Listener* c,
528 CallbackListSubscription* c_subscription,
529 Listener* d) {
530 // This should be the first callback.
531 EXPECT_EQ(0, a->total());
532 EXPECT_EQ(0, b->total());
533 EXPECT_EQ(0, c->total());
534 EXPECT_EQ(0, d->total());
Peter Kastingc8b3cc942020-08-11 03:03:54535
Peter Kasting7ba9440c2020-11-22 01:49:02536 // Increment |a| once.
537 a->IncrementTotal();
Peter Kastingc8b3cc942020-08-11 03:03:54538
Peter Kasting7ba9440c2020-11-22 01:49:02539 // Prevent |a| from being incremented again during the reentrant Notify().
540 // Since this is the first callback, this also verifies the inner Notify()
541 // doesn't assume the first callback (or all callbacks) are valid.
542 *a_subscription = {};
Peter Kastingc8b3cc942020-08-11 03:03:54543
Peter Kasting7ba9440c2020-11-22 01:49:02544 // Add |c| and |d| to be incremented by the reentrant Notify().
545 *c_subscription =
546 callbacks->Add(BindRepeating(&Listener::IncrementTotal, Unretained(c)));
547 CallbackListSubscription d_subscription =
548 callbacks->Add(BindRepeating(&Listener::IncrementTotal, Unretained(d)));
Peter Kastingc8b3cc942020-08-11 03:03:54549
Peter Kasting7ba9440c2020-11-22 01:49:02550 // Notify reentrantly. This should not increment |a|, but all the others
551 // should be incremented.
552 callbacks->Notify();
553 EXPECT_EQ(1, b->total());
554 EXPECT_EQ(1, c->total());
555 EXPECT_EQ(1, d->total());
Peter Kastingc8b3cc942020-08-11 03:03:54556
Peter Kasting7ba9440c2020-11-22 01:49:02557 // Since |d_subscription| is locally scoped, it should be canceled before
558 // the outer Notify() increments |d|. |c_subscription| already exists and
559 // thus |c| should get incremented again by the outer Notify() even though
560 // it wasn't scoped when that was called.
561 };
Peter Kastingc8b3cc942020-08-11 03:03:54562
563 // Add |a| and |b| to the list to be notified, and notify.
564 a_subscription = cb_reg.Add(
565 BindRepeating(a_callback, Unretained(&cb_reg), Unretained(&a),
566 Unretained(&a_subscription), Unretained(&b), Unretained(&c),
567 Unretained(&c_subscription), Unretained(&d)));
Peter Kasting7ba9440c2020-11-22 01:49:02568 CallbackListSubscription b_subscription =
Peter Kastingc8b3cc942020-08-11 03:03:54569 cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
570
571 // Execute both notifications and check the cumulative effect.
572 cb_reg.Notify();
573 EXPECT_EQ(1, a.total());
574 EXPECT_EQ(2, b.total());
575 EXPECT_EQ(2, c.total());
576 EXPECT_EQ(1, d.total());
577}
578
[email protected]893c8162013-09-11 15:16:33579} // namespace
580} // namespace base