[M94 Dev][Tizen] Fix for errors for generating ninja files
[platform/framework/web/chromium-efl.git] / base / callback_list_unittest.cc
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;
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
27   void IncrementByMultipleOfScaler(int x) { total_ += x * scaler_; }
28
29   int total() const { return total_; }
30
31  private:
32   int total_ = 0;
33   int scaler_ = 1;
34 };
35
36 class Remover {
37  public:
38   Remover() = default;
39   Remover(const Remover&) = delete;
40   Remover& operator=(const Remover&) = delete;
41   ~Remover() = default;
42
43   void IncrementTotalAndRemove() {
44     ++total_;
45     removal_subscription_ = {};
46   }
47
48   void SetSubscriptionToRemove(CallbackListSubscription subscription) {
49     removal_subscription_ = std::move(subscription);
50   }
51
52   int total() const { return total_; }
53
54  private:
55   int total_ = 0;
56   CallbackListSubscription removal_subscription_;
57 };
58
59 class Adder {
60  public:
61   explicit Adder(RepeatingClosureList* cb_reg) : cb_reg_(cb_reg) {}
62   Adder(const Adder&) = delete;
63   Adder& operator=(const Adder&) = delete;
64   ~Adder() = default;
65
66   void AddCallback() {
67     if (!added_) {
68       added_ = true;
69       subscription_ =
70           cb_reg_->Add(BindRepeating(&Adder::IncrementTotal, Unretained(this)));
71     }
72   }
73
74   void IncrementTotal() { ++total_; }
75
76   bool added() const { return added_; }
77   int total() const { return total_; }
78
79  private:
80   bool added_ = false;
81   int total_ = 0;
82   RepeatingClosureList* cb_reg_;
83   CallbackListSubscription subscription_;
84 };
85
86 class Summer {
87  public:
88   Summer() = default;
89   Summer(const Summer&) = delete;
90   Summer& operator=(const Summer&) = delete;
91   ~Summer() = default;
92
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
104   int value() const { return value_; }
105
106  private:
107   int value_ = 0;
108 };
109
110 class Counter {
111  public:
112   Counter() = default;
113   Counter(const Counter&) = delete;
114   Counter& operator=(const Counter&) = delete;
115   ~Counter() = default;
116
117   void Increment() { ++value_; }
118
119   int value() const { return value_; }
120
121  private:
122   int value_ = 0;
123 };
124
125 // Sanity check that we can instantiate a CallbackList for each arity.
126 TEST(CallbackListTest, ArityTest) {
127   Summer s;
128
129   RepeatingCallbackList<void(int)> c1;
130   CallbackListSubscription subscription1 =
131       c1.Add(BindRepeating(&Summer::AddOneParam, Unretained(&s)));
132
133   c1.Notify(1);
134   EXPECT_EQ(1, s.value());
135
136   RepeatingCallbackList<void(int, int)> c2;
137   CallbackListSubscription subscription2 =
138       c2.Add(BindRepeating(&Summer::AddTwoParam, Unretained(&s)));
139
140   c2.Notify(1, 2);
141   EXPECT_EQ(3, s.value());
142
143   RepeatingCallbackList<void(int, int, int)> c3;
144   CallbackListSubscription subscription3 =
145       c3.Add(BindRepeating(&Summer::AddThreeParam, Unretained(&s)));
146
147   c3.Notify(1, 2, 3);
148   EXPECT_EQ(6, s.value());
149
150   RepeatingCallbackList<void(int, int, int, int)> c4;
151   CallbackListSubscription subscription4 =
152       c4.Add(BindRepeating(&Summer::AddFourParam, Unretained(&s)));
153
154   c4.Notify(1, 2, 3, 4);
155   EXPECT_EQ(10, s.value());
156
157   RepeatingCallbackList<void(int, int, int, int, int)> c5;
158   CallbackListSubscription subscription5 =
159       c5.Add(BindRepeating(&Summer::AddFiveParam, Unretained(&s)));
160
161   c5.Notify(1, 2, 3, 4, 5);
162   EXPECT_EQ(15, s.value());
163
164   RepeatingCallbackList<void(int, int, int, int, int, int)> c6;
165   CallbackListSubscription subscription6 =
166       c6.Add(BindRepeating(&Summer::AddSixParam, Unretained(&s)));
167
168   c6.Notify(1, 2, 3, 4, 5, 6);
169   EXPECT_EQ(21, s.value());
170 }
171
172 // Sanity check that closures added to the list will be run, and those removed
173 // from the list will not be run.
174 TEST(CallbackListTest, BasicTest) {
175   Listener a, b, c;
176   RepeatingClosureList cb_reg;
177
178   CallbackListSubscription a_subscription =
179       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&a)));
180   CallbackListSubscription b_subscription =
181       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
182   cb_reg.AddUnsafe(BindRepeating(&Listener::IncrementTotal, Unretained(&c)));
183
184   EXPECT_TRUE(a_subscription);
185   EXPECT_TRUE(b_subscription);
186
187   cb_reg.Notify();
188
189   EXPECT_EQ(1, a.total());
190   EXPECT_EQ(1, b.total());
191   EXPECT_EQ(1, c.total());
192
193   b_subscription = {};
194
195   CallbackListSubscription c_subscription =
196       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&c)));
197
198   cb_reg.Notify();
199
200   EXPECT_EQ(2, a.total());
201   EXPECT_EQ(1, b.total());
202   EXPECT_EQ(3, c.total());
203 }
204
205 // Similar to BasicTest but with OnceCallbacks instead of Repeating.
206 TEST(CallbackListTest, OnceCallbacks) {
207   OnceClosureList cb_reg;
208   Listener a, b, c;
209
210   CallbackListSubscription a_subscription =
211       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
212   CallbackListSubscription b_subscription =
213       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&b)));
214
215   EXPECT_TRUE(a_subscription);
216   EXPECT_TRUE(b_subscription);
217
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.
228   b_subscription = {};
229
230   CallbackListSubscription c_subscription =
231       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
240 // 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.
242 TEST(CallbackListTest, BasicTestWithParams) {
243   using CallbackListType = RepeatingCallbackList<void(int)>;
244   CallbackListType cb_reg;
245   Listener a(1), b(-1), c(1);
246
247   CallbackListSubscription a_subscription = cb_reg.Add(
248       BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&a)));
249   CallbackListSubscription b_subscription = cb_reg.Add(
250       BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&b)));
251
252   EXPECT_TRUE(a_subscription);
253   EXPECT_TRUE(b_subscription);
254
255   cb_reg.Notify(10);
256
257   EXPECT_EQ(10, a.total());
258   EXPECT_EQ(-10, b.total());
259
260   b_subscription = {};
261
262   CallbackListSubscription c_subscription = cb_reg.Add(
263       BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&c)));
264
265   cb_reg.Notify(10);
266
267   EXPECT_EQ(20, a.total());
268   EXPECT_EQ(-10, b.total());
269   EXPECT_EQ(10, c.total());
270 }
271
272 // Test the a callback can remove itself or a different callback from the list
273 // during iteration without invalidating the iterator.
274 TEST(CallbackListTest, RemoveCallbacksDuringIteration) {
275   RepeatingClosureList cb_reg;
276   Listener a, b;
277   Remover remover_1, remover_2;
278
279   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 =
284       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&a)));
285   CallbackListSubscription b_subscription =
286       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
287
288   // |remover_1| will remove itself.
289   remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
290   // |remover_2| will remove a.
291   remover_2.SetSubscriptionToRemove(std::move(a_subscription));
292
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.
297   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());
301
302   cb_reg.Notify();
303
304   // Only |remover_2| and |b| run this time.
305   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());
309 }
310
311 // Similar to RemoveCallbacksDuringIteration but with OnceCallbacks instead of
312 // Repeating.
313 TEST(CallbackListTest, RemoveOnceCallbacksDuringIteration) {
314   OnceClosureList cb_reg;
315   Listener a, b;
316   Remover remover_1, remover_2;
317
318   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 =
323       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
324   CallbackListSubscription b_subscription =
325       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
350 // 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.
353 TEST(CallbackListTest, AddCallbacksDuringIteration) {
354   RepeatingClosureList cb_reg;
355   Adder a(&cb_reg);
356   Listener b;
357   CallbackListSubscription a_subscription =
358       cb_reg.Add(BindRepeating(&Adder::AddCallback, Unretained(&a)));
359   CallbackListSubscription b_subscription =
360       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
361
362   cb_reg.Notify();
363
364   EXPECT_EQ(1, a.total());
365   EXPECT_EQ(1, b.total());
366   EXPECT_TRUE(a.added());
367
368   cb_reg.Notify();
369
370   EXPECT_EQ(2, a.total());
371   EXPECT_EQ(2, b.total());
372 }
373
374 // Sanity check: notifying an empty list is a no-op.
375 TEST(CallbackListTest, EmptyList) {
376   RepeatingClosureList cb_reg;
377
378   cb_reg.Notify();
379 }
380
381 // empty() should be callable during iteration, and return false if not all the
382 // remaining callbacks in the list are null.
383 TEST(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.
387   Remover remover;
388   Listener listener;
389   CallbackListSubscription remover_sub, listener_sub;
390   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(
398       BindRepeating(&Remover::IncrementTotalAndRemove, Unretained(&remover)));
399   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.
413 TEST(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
419   Remover remover;
420   Listener listener;
421   CallbackListSubscription remover_sub = cb_reg.Add(
422       BindOnce(&Remover::IncrementTotalAndRemove, Unretained(&remover)));
423   CallbackListSubscription listener_sub =
424       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
435 TEST(CallbackListTest, RemovalCallback) {
436   Counter remove_count;
437   RepeatingClosureList cb_reg;
438   cb_reg.set_removal_callback(
439       BindRepeating(&Counter::Increment, Unretained(&remove_count)));
440
441   CallbackListSubscription subscription = cb_reg.Add(DoNothing());
442
443   // Removing a subscription outside of iteration signals the callback.
444   EXPECT_EQ(0, remove_count.value());
445   subscription = {};
446   EXPECT_EQ(1, remove_count.value());
447
448   // Configure two subscriptions to remove themselves.
449   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)));
454   remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
455   remover_2.SetSubscriptionToRemove(std::move(remover_2_sub));
456
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
464 TEST(CallbackListTest, AbandonSubscriptions) {
465   Listener listener;
466   CallbackListSubscription subscription;
467   {
468     RepeatingClosureList cb_reg;
469     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());
476
477   // Destroying the subscription after the list should not cause any problems.
478   subscription = {};
479 }
480
481 // Subscriptions should be movable.
482 TEST(CallbackListTest, MoveSubscription) {
483   RepeatingClosureList cb_reg;
484   Listener listener;
485   CallbackListSubscription subscription1 = cb_reg.Add(
486       BindRepeating(&Listener::IncrementTotal, Unretained(&listener)));
487   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
494   subscription2 = {};
495   cb_reg.Notify();
496   EXPECT_EQ(2, listener.total());
497 }
498
499 TEST(CallbackListTest, CancelBeforeRunning) {
500   OnceClosureList cb_reg;
501   Listener a;
502
503   CallbackListSubscription a_subscription =
504       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
505
506   EXPECT_TRUE(a_subscription);
507
508   // Canceling a OnceCallback before running it should not cause problems.
509   a_subscription = {};
510   cb_reg.Notify();
511
512   // |a| should not have received any callbacks.
513   EXPECT_EQ(0, a.total());
514 }
515
516 // Verifies Notify() can be called reentrantly and what its expected effects
517 // are.
518 TEST(CallbackListTest, ReentrantNotify) {
519   RepeatingClosureList cb_reg;
520   Listener a, b, c, d;
521   CallbackListSubscription a_subscription, c_subscription;
522
523   // A callback to run for |a|.
524   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());
534
535     // Increment |a| once.
536     a->IncrementTotal();
537
538     // 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 = {};
542
543     // 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)));
548
549     // 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());
555
556     // 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   };
561
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)));
567   CallbackListSubscription b_subscription =
568       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
578 }  // namespace
579 }  // namespace base