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 <memory>
8 #include <utility>
9 
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 namespace base {
15 namespace {
16 
17 class Listener {
18  public:
19   Listener() = default;
Listener(int scaler)20   explicit Listener(int scaler) : scaler_(scaler) {}
21   Listener(const Listener&) = delete;
22   Listener& operator=(const Listener&) = delete;
23   ~Listener() = default;
24 
IncrementTotal()25   void IncrementTotal() { ++total_; }
26 
IncrementByMultipleOfScaler(int x)27   void IncrementByMultipleOfScaler(int x) { total_ += x * scaler_; }
28 
total() const29   int total() const { return total_; }
30 
31  private:
32   int total_ = 0;
33   int scaler_ = 1;
34 };
35 
36 template <typename T>
37 class Remover {
38  public:
39   Remover() = default;
40   Remover(const Remover&) = delete;
41   Remover& operator=(const Remover&) = delete;
42   ~Remover() = default;
43 
IncrementTotalAndRemove()44   void IncrementTotalAndRemove() {
45     ++total_;
46     removal_subscription_.reset();
47   }
48 
SetSubscriptionToRemove(std::unique_ptr<typename T::Subscription> sub)49   void SetSubscriptionToRemove(std::unique_ptr<typename T::Subscription> sub) {
50     removal_subscription_ = std::move(sub);
51   }
52 
total() const53   int total() const { return total_; }
54 
55  private:
56   int total_ = 0;
57   std::unique_ptr<typename T::Subscription> removal_subscription_;
58 };
59 
60 class Adder {
61  public:
Adder(RepeatingClosureList * cb_reg)62   explicit Adder(RepeatingClosureList* cb_reg) : cb_reg_(cb_reg) {}
63   Adder(const Adder&) = delete;
64   Adder& operator=(const Adder&) = delete;
65   ~Adder() = default;
66 
AddCallback()67   void AddCallback() {
68     if (!added_) {
69       added_ = true;
70       subscription_ =
71           cb_reg_->Add(BindRepeating(&Adder::IncrementTotal, Unretained(this)));
72     }
73   }
74 
IncrementTotal()75   void IncrementTotal() { ++total_; }
76 
added() const77   bool added() const { return added_; }
total() const78   int total() const { return total_; }
79 
80  private:
81   bool added_ = false;
82   int total_ = 0;
83   RepeatingClosureList* cb_reg_;
84   std::unique_ptr<RepeatingClosureList::Subscription> subscription_;
85 };
86 
87 class Summer {
88  public:
89   Summer() = default;
90   Summer(const Summer&) = delete;
91   Summer& operator=(const Summer&) = delete;
92   ~Summer() = default;
93 
AddOneParam(int a)94   void AddOneParam(int a) { value_ = a; }
AddTwoParam(int a,int b)95   void AddTwoParam(int a, int b) { value_ = a + b; }
AddThreeParam(int a,int b,int c)96   void AddThreeParam(int a, int b, int c) { value_ = a + b + c; }
AddFourParam(int a,int b,int c,int d)97   void AddFourParam(int a, int b, int c, int d) { value_ = a + b + c + d; }
AddFiveParam(int a,int b,int c,int d,int e)98   void AddFiveParam(int a, int b, int c, int d, int e) {
99     value_ = a + b + c + d + e;
100   }
AddSixParam(int a,int b,int c,int d,int e,int f)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 
value() const105   int value() const { return value_; }
106 
107  private:
108   int value_ = 0;
109 };
110 
111 class Counter {
112  public:
113   Counter() = default;
114   Counter(const Counter&) = delete;
115   Counter& operator=(const Counter&) = delete;
116   ~Counter() = default;
117 
Increment()118   void Increment() { ++value_; }
119 
value() const120   int value() const { return value_; }
121 
122  private:
123   int value_ = 0;
124 };
125 
126 // Sanity check that we can instantiate a CallbackList for each arity.
TEST(CallbackListTest,ArityTest)127 TEST(CallbackListTest, ArityTest) {
128   Summer s;
129 
130   RepeatingCallbackList<void(int)> c1;
131   std::unique_ptr<RepeatingCallbackList<void(int)>::Subscription>
132       subscription1 =
133           c1.Add(BindRepeating(&Summer::AddOneParam, Unretained(&s)));
134 
135   c1.Notify(1);
136   EXPECT_EQ(1, s.value());
137 
138   RepeatingCallbackList<void(int, int)> c2;
139   std::unique_ptr<RepeatingCallbackList<void(int, int)>::Subscription>
140       subscription2 =
141           c2.Add(BindRepeating(&Summer::AddTwoParam, Unretained(&s)));
142 
143   c2.Notify(1, 2);
144   EXPECT_EQ(3, s.value());
145 
146   RepeatingCallbackList<void(int, int, int)> c3;
147   std::unique_ptr<RepeatingCallbackList<void(int, int, int)>::Subscription>
148       subscription3 =
149           c3.Add(BindRepeating(&Summer::AddThreeParam, Unretained(&s)));
150 
151   c3.Notify(1, 2, 3);
152   EXPECT_EQ(6, s.value());
153 
154   RepeatingCallbackList<void(int, int, int, int)> c4;
155   std::unique_ptr<RepeatingCallbackList<void(int, int, int, int)>::Subscription>
156       subscription4 =
157           c4.Add(BindRepeating(&Summer::AddFourParam, Unretained(&s)));
158 
159   c4.Notify(1, 2, 3, 4);
160   EXPECT_EQ(10, s.value());
161 
162   RepeatingCallbackList<void(int, int, int, int, int)> c5;
163   std::unique_ptr<
164       RepeatingCallbackList<void(int, int, int, int, int)>::Subscription>
165       subscription5 =
166           c5.Add(BindRepeating(&Summer::AddFiveParam, Unretained(&s)));
167 
168   c5.Notify(1, 2, 3, 4, 5);
169   EXPECT_EQ(15, s.value());
170 
171   RepeatingCallbackList<void(int, int, int, int, int, int)> c6;
172   std::unique_ptr<
173       RepeatingCallbackList<void(int, int, int, int, int, int)>::Subscription>
174       subscription6 =
175           c6.Add(BindRepeating(&Summer::AddSixParam, Unretained(&s)));
176 
177   c6.Notify(1, 2, 3, 4, 5, 6);
178   EXPECT_EQ(21, s.value());
179 }
180 
181 // Sanity check that closures added to the list will be run, and those removed
182 // from the list will not be run.
TEST(CallbackListTest,BasicTest)183 TEST(CallbackListTest, BasicTest) {
184   Listener a, b, c;
185   RepeatingClosureList cb_reg;
186 
187   std::unique_ptr<RepeatingClosureList::Subscription> a_subscription =
188       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&a)));
189   std::unique_ptr<RepeatingClosureList::Subscription> b_subscription =
190       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
191   cb_reg.AddUnsafe(BindRepeating(&Listener::IncrementTotal, Unretained(&c)));
192 
193   EXPECT_TRUE(a_subscription.get());
194   EXPECT_TRUE(b_subscription.get());
195 
196   cb_reg.Notify();
197 
198   EXPECT_EQ(1, a.total());
199   EXPECT_EQ(1, b.total());
200   EXPECT_EQ(1, c.total());
201 
202   b_subscription.reset();
203 
204   std::unique_ptr<RepeatingClosureList::Subscription> c_subscription =
205       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&c)));
206 
207   cb_reg.Notify();
208 
209   EXPECT_EQ(2, a.total());
210   EXPECT_EQ(1, b.total());
211   EXPECT_EQ(3, c.total());
212 }
213 
214 // Similar to BasicTest but with OnceCallbacks instead of Repeating.
TEST(CallbackListTest,OnceCallbacks)215 TEST(CallbackListTest, OnceCallbacks) {
216   OnceClosureList cb_reg;
217   Listener a, b, c;
218 
219   std::unique_ptr<OnceClosureList::Subscription> a_subscription =
220       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
221   std::unique_ptr<OnceClosureList::Subscription> b_subscription =
222       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&b)));
223 
224   EXPECT_TRUE(a_subscription.get());
225   EXPECT_TRUE(b_subscription.get());
226 
227   cb_reg.Notify();
228 
229   EXPECT_EQ(1, a.total());
230   EXPECT_EQ(1, b.total());
231 
232   // OnceCallbacks should auto-remove themselves after calling Notify().
233   EXPECT_TRUE(cb_reg.empty());
234 
235   // Destroying a subscription after the callback is canceled should not cause
236   // any problems.
237   b_subscription.reset();
238 
239   std::unique_ptr<OnceClosureList::Subscription> c_subscription =
240       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&c)));
241 
242   cb_reg.Notify();
243 
244   EXPECT_EQ(1, a.total());
245   EXPECT_EQ(1, b.total());
246   EXPECT_EQ(1, c.total());
247 }
248 
249 // Sanity check that callbacks with details added to the list will be run, with
250 // the correct details, and those removed from the list will not be run.
TEST(CallbackListTest,BasicTestWithParams)251 TEST(CallbackListTest, BasicTestWithParams) {
252   using CallbackListType = RepeatingCallbackList<void(int)>;
253   CallbackListType cb_reg;
254   Listener a(1), b(-1), c(1);
255 
256   std::unique_ptr<CallbackListType::Subscription> a_subscription = cb_reg.Add(
257       BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&a)));
258   std::unique_ptr<CallbackListType::Subscription> b_subscription = cb_reg.Add(
259       BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&b)));
260 
261   EXPECT_TRUE(a_subscription.get());
262   EXPECT_TRUE(b_subscription.get());
263 
264   cb_reg.Notify(10);
265 
266   EXPECT_EQ(10, a.total());
267   EXPECT_EQ(-10, b.total());
268 
269   b_subscription.reset();
270 
271   std::unique_ptr<CallbackListType::Subscription> c_subscription = cb_reg.Add(
272       BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&c)));
273 
274   cb_reg.Notify(10);
275 
276   EXPECT_EQ(20, a.total());
277   EXPECT_EQ(-10, b.total());
278   EXPECT_EQ(10, c.total());
279 }
280 
281 // Test the a callback can remove itself or a different callback from the list
282 // during iteration without invalidating the iterator.
TEST(CallbackListTest,RemoveCallbacksDuringIteration)283 TEST(CallbackListTest, RemoveCallbacksDuringIteration) {
284   RepeatingClosureList cb_reg;
285   Listener a, b;
286   Remover<RepeatingClosureList> remover_1, remover_2;
287 
288   std::unique_ptr<RepeatingClosureList::Subscription> remover_1_sub =
289       cb_reg.Add(
290           BindRepeating(&Remover<RepeatingClosureList>::IncrementTotalAndRemove,
291                         Unretained(&remover_1)));
292   std::unique_ptr<RepeatingClosureList::Subscription> remover_2_sub =
293       cb_reg.Add(
294           BindRepeating(&Remover<RepeatingClosureList>::IncrementTotalAndRemove,
295                         Unretained(&remover_2)));
296   std::unique_ptr<RepeatingClosureList::Subscription> a_subscription =
297       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&a)));
298   std::unique_ptr<RepeatingClosureList::Subscription> b_subscription =
299       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
300 
301   // |remover_1| will remove itself.
302   remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
303   // |remover_2| will remove a.
304   remover_2.SetSubscriptionToRemove(std::move(a_subscription));
305 
306   cb_reg.Notify();
307 
308   // |remover_1| runs once (and removes itself), |remover_2| runs once (and
309   // removes a), |a| never runs, and |b| runs once.
310   EXPECT_EQ(1, remover_1.total());
311   EXPECT_EQ(1, remover_2.total());
312   EXPECT_EQ(0, a.total());
313   EXPECT_EQ(1, b.total());
314 
315   cb_reg.Notify();
316 
317   // Only |remover_2| and |b| run this time.
318   EXPECT_EQ(1, remover_1.total());
319   EXPECT_EQ(2, remover_2.total());
320   EXPECT_EQ(0, a.total());
321   EXPECT_EQ(2, b.total());
322 }
323 
324 // Similar to RemoveCallbacksDuringIteration but with OnceCallbacks instead of
325 // Repeating.
TEST(CallbackListTest,RemoveOnceCallbacksDuringIteration)326 TEST(CallbackListTest, RemoveOnceCallbacksDuringIteration) {
327   OnceClosureList cb_reg;
328   Listener a, b;
329   Remover<OnceClosureList> remover_1, remover_2;
330 
331   std::unique_ptr<OnceClosureList::Subscription> remover_1_sub =
332       cb_reg.Add(BindOnce(&Remover<OnceClosureList>::IncrementTotalAndRemove,
333                           Unretained(&remover_1)));
334   std::unique_ptr<OnceClosureList::Subscription> remover_2_sub =
335       cb_reg.Add(BindOnce(&Remover<OnceClosureList>::IncrementTotalAndRemove,
336                           Unretained(&remover_2)));
337   std::unique_ptr<OnceClosureList::Subscription> a_subscription =
338       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
339   std::unique_ptr<OnceClosureList::Subscription> b_subscription =
340       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&b)));
341 
342   // |remover_1| will remove itself.
343   remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
344   // |remover_2| will remove a.
345   remover_2.SetSubscriptionToRemove(std::move(a_subscription));
346 
347   cb_reg.Notify();
348 
349   // |remover_1| runs once (and removes itself), |remover_2| runs once (and
350   // removes a), |a| never runs, and |b| runs once.
351   EXPECT_EQ(1, remover_1.total());
352   EXPECT_EQ(1, remover_2.total());
353   EXPECT_EQ(0, a.total());
354   EXPECT_EQ(1, b.total());
355 
356   cb_reg.Notify();
357 
358   // Nothing runs this time.
359   EXPECT_EQ(1, remover_1.total());
360   EXPECT_EQ(1, remover_2.total());
361   EXPECT_EQ(0, a.total());
362   EXPECT_EQ(1, b.total());
363 }
364 
365 // Test that a callback can add another callback to the list durning iteration
366 // without invalidating the iterator. The newly added callback should be run on
367 // the current iteration as will all other callbacks in the list.
TEST(CallbackListTest,AddCallbacksDuringIteration)368 TEST(CallbackListTest, AddCallbacksDuringIteration) {
369   RepeatingClosureList cb_reg;
370   Adder a(&cb_reg);
371   Listener b;
372   std::unique_ptr<RepeatingClosureList::Subscription> a_subscription =
373       cb_reg.Add(BindRepeating(&Adder::AddCallback, Unretained(&a)));
374   std::unique_ptr<RepeatingClosureList::Subscription> b_subscription =
375       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
376 
377   cb_reg.Notify();
378 
379   EXPECT_EQ(1, a.total());
380   EXPECT_EQ(1, b.total());
381   EXPECT_TRUE(a.added());
382 
383   cb_reg.Notify();
384 
385   EXPECT_EQ(2, a.total());
386   EXPECT_EQ(2, b.total());
387 }
388 
389 // Sanity check: notifying an empty list is a no-op.
TEST(CallbackListTest,EmptyList)390 TEST(CallbackListTest, EmptyList) {
391   RepeatingClosureList cb_reg;
392 
393   cb_reg.Notify();
394 }
395 
396 // empty() should be callable during iteration, and return false if not all the
397 // remaining callbacks in the list are null.
TEST(CallbackListTest,NonEmptyListDuringIteration)398 TEST(CallbackListTest, NonEmptyListDuringIteration) {
399   // Declare items such that |cb_reg| is torn down before the subscriptions.
400   // This ensures the removal callback's invariant that the callback list is
401   // nonempty will always hold.
402   Remover<RepeatingClosureList> remover;
403   Listener listener;
404   std::unique_ptr<RepeatingClosureList::Subscription> remover_sub, listener_sub;
405   RepeatingClosureList cb_reg;
406   cb_reg.set_removal_callback(base::BindRepeating(
407       [](const RepeatingClosureList* callbacks) {
408         EXPECT_FALSE(callbacks->empty());
409       },
410       Unretained(&cb_reg)));
411 
412   remover_sub = cb_reg.Add(
413       BindRepeating(&Remover<RepeatingClosureList>::IncrementTotalAndRemove,
414                     Unretained(&remover)));
415   listener_sub = cb_reg.Add(
416       BindRepeating(&Listener::IncrementTotal, Unretained(&listener)));
417 
418   // |remover| will remove |listener|.
419   remover.SetSubscriptionToRemove(std::move(listener_sub));
420 
421   cb_reg.Notify();
422 
423   EXPECT_EQ(1, remover.total());
424   EXPECT_EQ(0, listener.total());
425 }
426 
427 // empty() should be callable during iteration, and return true if all the
428 // remaining callbacks in the list are null.
TEST(CallbackListTest,EmptyListDuringIteration)429 TEST(CallbackListTest, EmptyListDuringIteration) {
430   OnceClosureList cb_reg;
431   cb_reg.set_removal_callback(base::BindRepeating(
432       [](const OnceClosureList* callbacks) { EXPECT_TRUE(callbacks->empty()); },
433       Unretained(&cb_reg)));
434 
435   Remover<OnceClosureList> remover;
436   Listener listener;
437   std::unique_ptr<OnceClosureList::Subscription> remover_sub =
438       cb_reg.Add(BindOnce(&Remover<OnceClosureList>::IncrementTotalAndRemove,
439                           Unretained(&remover)));
440   std::unique_ptr<OnceClosureList::Subscription> listener_sub =
441       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&listener)));
442 
443   // |remover| will remove |listener|.
444   remover.SetSubscriptionToRemove(std::move(listener_sub));
445 
446   cb_reg.Notify();
447 
448   EXPECT_EQ(1, remover.total());
449   EXPECT_EQ(0, listener.total());
450 }
451 
TEST(CallbackListTest,RemovalCallback)452 TEST(CallbackListTest, RemovalCallback) {
453   Counter remove_count;
454   RepeatingClosureList cb_reg;
455   cb_reg.set_removal_callback(
456       BindRepeating(&Counter::Increment, Unretained(&remove_count)));
457 
458   std::unique_ptr<RepeatingClosureList::Subscription> subscription =
459       cb_reg.Add(DoNothing());
460 
461   // Removing a subscription outside of iteration signals the callback.
462   EXPECT_EQ(0, remove_count.value());
463   subscription.reset();
464   EXPECT_EQ(1, remove_count.value());
465 
466   // Configure two subscriptions to remove themselves.
467   Remover<RepeatingClosureList> remover_1, remover_2;
468   std::unique_ptr<RepeatingClosureList::Subscription> remover_1_sub =
469       cb_reg.Add(
470           BindRepeating(&Remover<RepeatingClosureList>::IncrementTotalAndRemove,
471                         Unretained(&remover_1)));
472   std::unique_ptr<RepeatingClosureList::Subscription> remover_2_sub =
473       cb_reg.Add(
474           BindRepeating(&Remover<RepeatingClosureList>::IncrementTotalAndRemove,
475                         Unretained(&remover_2)));
476   remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
477   remover_2.SetSubscriptionToRemove(std::move(remover_2_sub));
478 
479   // The callback should be signaled exactly once.
480   EXPECT_EQ(1, remove_count.value());
481   cb_reg.Notify();
482   EXPECT_EQ(2, remove_count.value());
483   EXPECT_TRUE(cb_reg.empty());
484 }
485 
TEST(CallbackListTest,AbandonSubscriptions)486 TEST(CallbackListTest, AbandonSubscriptions) {
487   Listener listener;
488   std::unique_ptr<RepeatingClosureList::Subscription> subscription;
489   {
490     RepeatingClosureList cb_reg;
491     subscription = cb_reg.Add(
492         BindRepeating(&Listener::IncrementTotal, Unretained(&listener)));
493     // Make sure the callback is signaled while cb_reg is in scope.
494     cb_reg.Notify();
495     // Exiting this scope and running the cb_reg destructor shouldn't fail.
496   }
497   EXPECT_EQ(1, listener.total());
498 
499   // Destroying the subscription after the list should not cause any problems.
500   subscription.reset();
501 }
502 
503 // Subscriptions should be movable.
TEST(CallbackListTest,MoveSubscription)504 TEST(CallbackListTest, MoveSubscription) {
505   RepeatingClosureList cb_reg;
506   Listener listener;
507   std::unique_ptr<RepeatingClosureList::Subscription> subscription1 =
508       cb_reg.Add(
509           BindRepeating(&Listener::IncrementTotal, Unretained(&listener)));
510   cb_reg.Notify();
511   EXPECT_EQ(1, listener.total());
512 
513   auto subscription2 = std::move(subscription1);
514   cb_reg.Notify();
515   EXPECT_EQ(2, listener.total());
516 
517   subscription2.reset();
518   cb_reg.Notify();
519   EXPECT_EQ(2, listener.total());
520 }
521 
TEST(CallbackListTest,CancelBeforeRunning)522 TEST(CallbackListTest, CancelBeforeRunning) {
523   OnceClosureList cb_reg;
524   Listener a;
525 
526   std::unique_ptr<OnceClosureList::Subscription> a_subscription =
527       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
528 
529   EXPECT_TRUE(a_subscription.get());
530 
531   // Canceling a OnceCallback before running it should not cause problems.
532   a_subscription.reset();
533   cb_reg.Notify();
534 
535   // |a| should not have received any callbacks.
536   EXPECT_EQ(0, a.total());
537 }
538 
539 // Verifies Notify() can be called reentrantly and what its expected effects
540 // are.
TEST(CallbackListTest,ReentrantNotify)541 TEST(CallbackListTest, ReentrantNotify) {
542   RepeatingClosureList cb_reg;
543   Listener a, b, c, d;
544   std::unique_ptr<RepeatingClosureList::Subscription> a_subscription,
545       c_subscription;
546 
547   // A callback to run for |a|.
548   const auto a_callback =
549       [](RepeatingClosureList* callbacks, Listener* a,
550          std::unique_ptr<RepeatingClosureList::Subscription>* a_subscription,
551          const Listener* b, Listener* c,
552          std::unique_ptr<RepeatingClosureList::Subscription>* c_subscription,
553          Listener* d) {
554         // This should be the first callback.
555         EXPECT_EQ(0, a->total());
556         EXPECT_EQ(0, b->total());
557         EXPECT_EQ(0, c->total());
558         EXPECT_EQ(0, d->total());
559 
560         // Increment |a| once.
561         a->IncrementTotal();
562 
563         // Prevent |a| from being incremented again during the reentrant
564         // Notify(). Since this is the first callback, this also verifies the
565         // inner Notify() doesn't assume the first callback (or all callbacks)
566         // are valid.
567         a_subscription->reset();
568 
569         // Add |c| and |d| to be incremented by the reentrant Notify().
570         *c_subscription = callbacks->Add(
571             BindRepeating(&Listener::IncrementTotal, Unretained(c)));
572         std::unique_ptr<RepeatingClosureList::Subscription> d_subscription =
573             callbacks->Add(
574                 BindRepeating(&Listener::IncrementTotal, Unretained(d)));
575 
576         // Notify reentrantly.  This should not increment |a|, but all the
577         // others should be incremented.
578         callbacks->Notify();
579         EXPECT_EQ(1, b->total());
580         EXPECT_EQ(1, c->total());
581         EXPECT_EQ(1, d->total());
582 
583         // Since |d_subscription| is locally scoped, it should be canceled
584         // before the outer Notify() increments |d|.  |c_subscription| already
585         // exists and thus |c| should get incremented again by the outer
586         // Notify() even though it wasn't subscribed when that was called.
587       };
588 
589   // Add |a| and |b| to the list to be notified, and notify.
590   a_subscription = cb_reg.Add(
591       BindRepeating(a_callback, Unretained(&cb_reg), Unretained(&a),
592                     Unretained(&a_subscription), Unretained(&b), Unretained(&c),
593                     Unretained(&c_subscription), Unretained(&d)));
594   std::unique_ptr<RepeatingClosureList::Subscription> b_subscription =
595       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
596 
597   // Execute both notifications and check the cumulative effect.
598   cb_reg.Notify();
599   EXPECT_EQ(1, a.total());
600   EXPECT_EQ(2, b.total());
601   EXPECT_EQ(2, c.total());
602   EXPECT_EQ(1, d.total());
603 }
604 
605 }  // namespace
606 }  // namespace base
607