[M85 Dev][EFL] Fix crashes at webview launch
[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/bind_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 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
44   void IncrementTotalAndRemove() {
45     ++total_;
46     removal_subscription_.reset();
47   }
48
49   void SetSubscriptionToRemove(std::unique_ptr<typename T::Subscription> sub) {
50     removal_subscription_ = std::move(sub);
51   }
52
53   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:
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
67   void AddCallback() {
68     if (!added_) {
69       added_ = true;
70       subscription_ =
71           cb_reg_->Add(BindRepeating(&Adder::IncrementTotal, Unretained(this)));
72     }
73   }
74
75   void IncrementTotal() { ++total_; }
76
77   bool added() const { return added_; }
78   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
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
105   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
118   void Increment() { ++value_; }
119
120   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.
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.
183 TEST(CallbackListTest, BasicTest) {
184   RepeatingClosureList cb_reg;
185   Listener a, b, c;
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
192   EXPECT_TRUE(a_subscription.get());
193   EXPECT_TRUE(b_subscription.get());
194
195   cb_reg.Notify();
196
197   EXPECT_EQ(1, a.total());
198   EXPECT_EQ(1, b.total());
199
200   b_subscription.reset();
201
202   std::unique_ptr<RepeatingClosureList::Subscription> c_subscription =
203       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&c)));
204
205   cb_reg.Notify();
206
207   EXPECT_EQ(2, a.total());
208   EXPECT_EQ(1, b.total());
209   EXPECT_EQ(1, c.total());
210 }
211
212 // Similar to BasicTest but with OnceCallbacks instead of Repeating.
213 TEST(CallbackListTest, OnceCallbacks) {
214   OnceClosureList cb_reg;
215   Listener a, b, c;
216
217   std::unique_ptr<OnceClosureList::Subscription> a_subscription =
218       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
219   std::unique_ptr<OnceClosureList::Subscription> b_subscription =
220       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&b)));
221
222   EXPECT_TRUE(a_subscription.get());
223   EXPECT_TRUE(b_subscription.get());
224
225   cb_reg.Notify();
226
227   EXPECT_EQ(1, a.total());
228   EXPECT_EQ(1, b.total());
229
230   // OnceCallbacks should auto-remove themselves after calling Notify().
231   EXPECT_TRUE(cb_reg.empty());
232
233   // Destroying a subscription after the callback is canceled should not cause
234   // any problems.
235   b_subscription.reset();
236
237   std::unique_ptr<OnceClosureList::Subscription> c_subscription =
238       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&c)));
239
240   cb_reg.Notify();
241
242   EXPECT_EQ(1, a.total());
243   EXPECT_EQ(1, b.total());
244   EXPECT_EQ(1, c.total());
245 }
246
247 // Sanity check that callbacks with details added to the list will be run, with
248 // the correct details, and those removed from the list will not be run.
249 TEST(CallbackListTest, BasicTestWithParams) {
250   using CallbackListType = RepeatingCallbackList<void(int)>;
251   CallbackListType cb_reg;
252   Listener a(1), b(-1), c(1);
253
254   std::unique_ptr<CallbackListType::Subscription> a_subscription = cb_reg.Add(
255       BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&a)));
256   std::unique_ptr<CallbackListType::Subscription> b_subscription = cb_reg.Add(
257       BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&b)));
258
259   EXPECT_TRUE(a_subscription.get());
260   EXPECT_TRUE(b_subscription.get());
261
262   cb_reg.Notify(10);
263
264   EXPECT_EQ(10, a.total());
265   EXPECT_EQ(-10, b.total());
266
267   b_subscription.reset();
268
269   std::unique_ptr<CallbackListType::Subscription> c_subscription = cb_reg.Add(
270       BindRepeating(&Listener::IncrementByMultipleOfScaler, Unretained(&c)));
271
272   cb_reg.Notify(10);
273
274   EXPECT_EQ(20, a.total());
275   EXPECT_EQ(-10, b.total());
276   EXPECT_EQ(10, c.total());
277 }
278
279 // Test the a callback can remove itself or a different callback from the list
280 // during iteration without invalidating the iterator.
281 TEST(CallbackListTest, RemoveCallbacksDuringIteration) {
282   RepeatingClosureList cb_reg;
283   Listener a, b;
284   Remover<RepeatingClosureList> remover_1, remover_2;
285
286   std::unique_ptr<RepeatingClosureList::Subscription> remover_1_sub =
287       cb_reg.Add(
288           BindRepeating(&Remover<RepeatingClosureList>::IncrementTotalAndRemove,
289                         Unretained(&remover_1)));
290   std::unique_ptr<RepeatingClosureList::Subscription> remover_2_sub =
291       cb_reg.Add(
292           BindRepeating(&Remover<RepeatingClosureList>::IncrementTotalAndRemove,
293                         Unretained(&remover_2)));
294   std::unique_ptr<RepeatingClosureList::Subscription> a_subscription =
295       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&a)));
296   std::unique_ptr<RepeatingClosureList::Subscription> b_subscription =
297       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
298
299   // |remover_1| will remove itself.
300   remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
301   // |remover_2| will remove a.
302   remover_2.SetSubscriptionToRemove(std::move(a_subscription));
303
304   cb_reg.Notify();
305
306   // |remover_1| runs once (and removes itself), |remover_2| runs once (and
307   // removes a), |a| never runs, and |b| runs once.
308   EXPECT_EQ(1, remover_1.total());
309   EXPECT_EQ(1, remover_2.total());
310   EXPECT_EQ(0, a.total());
311   EXPECT_EQ(1, b.total());
312
313   cb_reg.Notify();
314
315   // Only |remover_2| and |b| run this time.
316   EXPECT_EQ(1, remover_1.total());
317   EXPECT_EQ(2, remover_2.total());
318   EXPECT_EQ(0, a.total());
319   EXPECT_EQ(2, b.total());
320 }
321
322 // Similar to RemoveCallbacksDuringIteration but with OnceCallbacks instead of
323 // Repeating.
324 TEST(CallbackListTest, RemoveOnceCallbacksDuringIteration) {
325   OnceClosureList cb_reg;
326   Listener a, b;
327   Remover<OnceClosureList> remover_1, remover_2;
328
329   std::unique_ptr<OnceClosureList::Subscription> remover_1_sub =
330       cb_reg.Add(BindOnce(&Remover<OnceClosureList>::IncrementTotalAndRemove,
331                           Unretained(&remover_1)));
332   std::unique_ptr<OnceClosureList::Subscription> remover_2_sub =
333       cb_reg.Add(BindOnce(&Remover<OnceClosureList>::IncrementTotalAndRemove,
334                           Unretained(&remover_2)));
335   std::unique_ptr<OnceClosureList::Subscription> a_subscription =
336       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
337   std::unique_ptr<OnceClosureList::Subscription> b_subscription =
338       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&b)));
339
340   // |remover_1| will remove itself.
341   remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
342   // |remover_2| will remove a.
343   remover_2.SetSubscriptionToRemove(std::move(a_subscription));
344
345   cb_reg.Notify();
346
347   // |remover_1| runs once (and removes itself), |remover_2| runs once (and
348   // removes a), |a| never runs, and |b| runs once.
349   EXPECT_EQ(1, remover_1.total());
350   EXPECT_EQ(1, remover_2.total());
351   EXPECT_EQ(0, a.total());
352   EXPECT_EQ(1, b.total());
353
354   cb_reg.Notify();
355
356   // Nothing runs this time.
357   EXPECT_EQ(1, remover_1.total());
358   EXPECT_EQ(1, remover_2.total());
359   EXPECT_EQ(0, a.total());
360   EXPECT_EQ(1, b.total());
361 }
362
363 // Test that a callback can add another callback to the list durning iteration
364 // without invalidating the iterator. The newly added callback should be run on
365 // the current iteration as will all other callbacks in the list.
366 TEST(CallbackListTest, AddCallbacksDuringIteration) {
367   RepeatingClosureList cb_reg;
368   Adder a(&cb_reg);
369   Listener b;
370   std::unique_ptr<RepeatingClosureList::Subscription> a_subscription =
371       cb_reg.Add(BindRepeating(&Adder::AddCallback, Unretained(&a)));
372   std::unique_ptr<RepeatingClosureList::Subscription> b_subscription =
373       cb_reg.Add(BindRepeating(&Listener::IncrementTotal, Unretained(&b)));
374
375   cb_reg.Notify();
376
377   EXPECT_EQ(1, a.total());
378   EXPECT_EQ(1, b.total());
379   EXPECT_TRUE(a.added());
380
381   cb_reg.Notify();
382
383   EXPECT_EQ(2, a.total());
384   EXPECT_EQ(2, b.total());
385 }
386
387 // Sanity check: notifying an empty list is a no-op.
388 TEST(CallbackListTest, EmptyList) {
389   RepeatingClosureList cb_reg;
390
391   cb_reg.Notify();
392 }
393
394 TEST(CallbackListTest, RemovalCallback) {
395   Counter remove_count;
396   RepeatingClosureList cb_reg;
397   cb_reg.set_removal_callback(
398       BindRepeating(&Counter::Increment, Unretained(&remove_count)));
399
400   std::unique_ptr<RepeatingClosureList::Subscription> subscription =
401       cb_reg.Add(DoNothing());
402
403   // Removing a subscription outside of iteration signals the callback.
404   EXPECT_EQ(0, remove_count.value());
405   subscription.reset();
406   EXPECT_EQ(1, remove_count.value());
407
408   // Configure two subscriptions to remove themselves.
409   Remover<RepeatingClosureList> remover_1, remover_2;
410   std::unique_ptr<RepeatingClosureList::Subscription> remover_1_sub =
411       cb_reg.Add(
412           BindRepeating(&Remover<RepeatingClosureList>::IncrementTotalAndRemove,
413                         Unretained(&remover_1)));
414   std::unique_ptr<RepeatingClosureList::Subscription> remover_2_sub =
415       cb_reg.Add(
416           BindRepeating(&Remover<RepeatingClosureList>::IncrementTotalAndRemove,
417                         Unretained(&remover_2)));
418   remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
419   remover_2.SetSubscriptionToRemove(std::move(remover_2_sub));
420
421   // The callback should be signaled exactly once.
422   EXPECT_EQ(1, remove_count.value());
423   cb_reg.Notify();
424   EXPECT_EQ(2, remove_count.value());
425   EXPECT_TRUE(cb_reg.empty());
426 }
427
428 TEST(CallbackListTest, AbandonSubscriptions) {
429   Listener listener;
430   std::unique_ptr<RepeatingClosureList::Subscription> subscription;
431   {
432     RepeatingClosureList cb_reg;
433     subscription = cb_reg.Add(
434         BindRepeating(&Listener::IncrementTotal, Unretained(&listener)));
435     // Make sure the callback is signaled while cb_reg is in scope.
436     cb_reg.Notify();
437     // Exiting this scope and running the cb_reg destructor shouldn't fail.
438   }
439   EXPECT_EQ(1, listener.total());
440
441   // Destroying the subscription after the list should not cause any problems.
442   subscription.reset();
443 }
444
445 TEST(CallbackListTest, CancelBeforeRunning) {
446   OnceClosureList cb_reg;
447   Listener a;
448
449   std::unique_ptr<OnceClosureList::Subscription> a_subscription =
450       cb_reg.Add(BindOnce(&Listener::IncrementTotal, Unretained(&a)));
451
452   EXPECT_TRUE(a_subscription.get());
453
454   // Canceling a OnceCallback before running it should not cause problems.
455   a_subscription.reset();
456   cb_reg.Notify();
457
458   // |a| should not have received any callbacks.
459   EXPECT_EQ(0, a.total());
460 }
461
462 }  // namespace
463 }  // namespace base