blob: f37d6938e0b49d4d93f72d4be7bbd16c35ee3dba [file] [log] [blame]
[email protected]3fe674d2012-04-05 17:52:101// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
5#include "base/observer_list.h"
[email protected]3c0d45e2010-09-17 19:33:066
Trent Apted4d207362018-08-15 23:48:157#include "base/strings/string_piece.h"
Wez0c9c93c2018-04-26 16:23:248#include "base/test/gtest_util.h"
Oskar Sundbomc92fda62018-10-24 11:38:029#include "base/threading/simple_thread.h"
Fabrice de Gans-Riberi62c715552018-06-18 19:36:3510#include "build/build_config.h"
Mitsuru Oshima538b1db2018-02-28 04:05:2311#include "testing/gmock/include/gmock/gmock.h"
initial.commitd7cae122008-07-26 21:49:3812#include "testing/gtest/include/gtest/gtest.h"
13
[email protected]7ff48ca2013-02-06 16:56:1914namespace base {
initial.commitd7cae122008-07-26 21:49:3815namespace {
16
Trent Apted30f97fd2018-08-21 09:03:4717class CheckedBase : public CheckedObserver {
initial.commitd7cae122008-07-26 21:49:3818 public:
19 virtual void Observe(int x) = 0;
Trent Apted30f97fd2018-08-21 09:03:4720 ~CheckedBase() override = default;
loyso29025b62016-10-11 06:51:3321 virtual int GetValue() const { return 0; }
initial.commitd7cae122008-07-26 21:49:3822};
23
Trent Apted30f97fd2018-08-21 09:03:4724class UncheckedBase {
initial.commitd7cae122008-07-26 21:49:3825 public:
Trent Apted30f97fd2018-08-21 09:03:4726 virtual void Observe(int x) = 0;
27 virtual ~UncheckedBase() = default;
28 virtual int GetValue() const { return 0; }
29};
30
Victor Costanebc52732019-02-15 02:39:4731// Helper for TYPED_TEST_SUITE machinery to pick the ObserverList under test.
Trent Apted30f97fd2018-08-21 09:03:4732// Keyed off the observer type since ObserverList has too many template args and
33// it gets ugly.
34template <class Foo>
35struct PickObserverList {};
36template <>
37struct PickObserverList<CheckedBase> {
38 template <class TypeParam,
39 bool check_empty = false,
40 bool allow_reentrancy = true>
41 using ObserverListType =
42 ObserverList<TypeParam, check_empty, allow_reentrancy>;
43};
44template <>
45struct PickObserverList<UncheckedBase> {
46 template <class TypeParam,
47 bool check_empty = false,
48 bool allow_reentrancy = true>
49 using ObserverListType = typename ObserverList<TypeParam,
50 check_empty,
51 allow_reentrancy>::Unchecked;
52};
53
54template <class Foo>
55class AdderT : public Foo {
56 public:
57 explicit AdderT(int scaler) : total(0), scaler_(scaler) {}
58 ~AdderT() override = default;
loyso29025b62016-10-11 06:51:3359
60 void Observe(int x) override { total += x * scaler_; }
61 int GetValue() const override { return total; }
62
initial.commitd7cae122008-07-26 21:49:3863 int total;
[email protected]44106182012-04-06 03:53:0264
initial.commitd7cae122008-07-26 21:49:3865 private:
66 int scaler_;
67};
68
Trent Apted30f97fd2018-08-21 09:03:4769template <class ObserverListType,
70 class Foo = typename ObserverListType::value_type>
71class DisrupterT : public Foo {
initial.commitd7cae122008-07-26 21:49:3872 public:
Trent Apted30f97fd2018-08-21 09:03:4773 DisrupterT(ObserverListType* list, Foo* doomed, bool remove_self)
loyso29025b62016-10-11 06:51:3374 : list_(list), doomed_(doomed), remove_self_(remove_self) {}
Trent Apted30f97fd2018-08-21 09:03:4775 DisrupterT(ObserverListType* list, Foo* doomed)
76 : DisrupterT(list, doomed, false) {}
77 DisrupterT(ObserverListType* list, bool remove_self)
78 : DisrupterT(list, nullptr, remove_self) {}
loyso29025b62016-10-11 06:51:3379
Trent Apted30f97fd2018-08-21 09:03:4780 ~DisrupterT() override = default;
loyso29025b62016-10-11 06:51:3381
82 void Observe(int x) override {
83 if (remove_self_)
84 list_->RemoveObserver(this);
85 if (doomed_)
86 list_->RemoveObserver(doomed_);
87 }
88
89 void SetDoomed(Foo* doomed) { doomed_ = doomed; }
[email protected]44106182012-04-06 03:53:0290
initial.commitd7cae122008-07-26 21:49:3891 private:
Trent Apted30f97fd2018-08-21 09:03:4792 ObserverListType* list_;
initial.commitd7cae122008-07-26 21:49:3893 Foo* doomed_;
loyso29025b62016-10-11 06:51:3394 bool remove_self_;
initial.commitd7cae122008-07-26 21:49:3895};
96
Trent Apted30f97fd2018-08-21 09:03:4797template <class ObserverListType,
98 class Foo = typename ObserverListType::value_type>
[email protected]b3e2fad02008-10-31 03:32:0699class AddInObserve : public Foo {
100 public:
Trent Apted30f97fd2018-08-21 09:03:47101 explicit AddInObserve(ObserverListType* observer_list)
loyso29025b62016-10-11 06:51:33102 : observer_list(observer_list), to_add_() {}
103
104 void SetToAdd(Foo* to_add) { to_add_ = to_add; }
[email protected]44106182012-04-06 03:53:02105
nickc0b001062015-04-22 23:17:20106 void Observe(int x) override {
loyso29025b62016-10-11 06:51:33107 if (to_add_) {
108 observer_list->AddObserver(to_add_);
109 to_add_ = nullptr;
[email protected]b3e2fad02008-10-31 03:32:06110 }
111 }
112
Trent Apted30f97fd2018-08-21 09:03:47113 ObserverListType* observer_list;
loyso29025b62016-10-11 06:51:33114 Foo* to_add_;
[email protected]b3e2fad02008-10-31 03:32:06115};
116
Oskar Sundbomc92fda62018-10-24 11:38:02117template <class ObserverListType>
118class ObserverListCreator : public DelegateSimpleThread::Delegate {
119 public:
120 std::unique_ptr<ObserverListType> Create(
121 base::Optional<base::ObserverListPolicy> policy = nullopt) {
122 policy_ = policy;
123 DelegateSimpleThread thread(this, "ListCreator");
124 thread.Start();
125 thread.Join();
126 return std::move(observer_list_);
127 }
128
129 private:
130 void Run() override {
131 if (policy_) {
132 observer_list_ = std::make_unique<ObserverListType>(*policy_);
133 } else {
134 observer_list_ = std::make_unique<ObserverListType>();
135 }
136 }
137
138 std::unique_ptr<ObserverListType> observer_list_;
139 base::Optional<base::ObserverListPolicy> policy_;
140};
141
loyso29025b62016-10-11 06:51:33142} // namespace
143
Trent Apted30f97fd2018-08-21 09:03:47144class ObserverListTestBase {
145 public:
146 ObserverListTestBase() {}
147
148 template <class T>
Trent Aptedf59cdf0d32018-10-04 03:42:22149 const decltype(T::list_.get()) list(const T& iter) {
150 return iter.list_.get();
Trent Apted30f97fd2018-08-21 09:03:47151 }
152
153 template <class T>
154 typename T::value_type* GetCurrent(T* iter) {
155 return iter->GetCurrent();
156 }
157
158 // Override GetCurrent() for CheckedObserver. When StdIteratorRemoveFront
159 // tries to simulate a sequence to see if it "would" crash, CheckedObservers
160 // do, actually, crash with a DCHECK(). Note this check is different to the
161 // check during an observer _iteration_. Hence, DCHECK(), not CHECK().
162 CheckedBase* GetCurrent(ObserverList<CheckedBase>::iterator* iter) {
163 EXPECT_DCHECK_DEATH(return iter->GetCurrent());
164 return nullptr;
165 }
166
167 private:
168 DISALLOW_COPY_AND_ASSIGN(ObserverListTestBase);
169};
170
171// Templatized test fixture that can pick between CheckedBase and UncheckedBase.
172template <class ObserverType>
173class ObserverListTest : public ObserverListTestBase, public ::testing::Test {
174 public:
175 template <class T>
176 using ObserverList =
177 typename PickObserverList<ObserverType>::template ObserverListType<T>;
178
179 using iterator = typename ObserverList<ObserverType>::iterator;
180 using const_iterator = typename ObserverList<ObserverType>::const_iterator;
181
182 ObserverListTest() {}
183
184 private:
185 DISALLOW_COPY_AND_ASSIGN(ObserverListTest);
186};
187
188using ObserverTypes = ::testing::Types<CheckedBase, UncheckedBase>;
Victor Costanebc52732019-02-15 02:39:47189TYPED_TEST_SUITE(ObserverListTest, ObserverTypes);
Trent Apted30f97fd2018-08-21 09:03:47190
191// TYPED_TEST causes the test parent class to be a template parameter, which
192// makes the syntax for referring to the types awkward. Create aliases in local
193// scope with clearer names. Unfortunately, we also need some trailing cruft to
194// avoid "unused local type alias" warnings.
195#define DECLARE_TYPES \
196 using Foo = TypeParam; \
197 using ObserverListFoo = \
198 typename PickObserverList<TypeParam>::template ObserverListType<Foo>; \
199 using Adder = AdderT<Foo>; \
200 using Disrupter = DisrupterT<ObserverListFoo>; \
201 using const_iterator = typename TestFixture::const_iterator; \
202 using iterator = typename TestFixture::iterator; \
203 (void)(Disrupter*)(0); \
204 (void)(Adder*)(0); \
205 (void)(const_iterator*)(0); \
Nico Weber51c45a72019-01-30 17:58:17206 (void)(iterator*)(0)
Trent Apted30f97fd2018-08-21 09:03:47207
208TYPED_TEST(ObserverListTest, BasicTest) {
209 DECLARE_TYPES;
210 ObserverListFoo observer_list;
211 const ObserverListFoo& const_observer_list = observer_list;
François Degros0659d69332017-11-15 09:31:44212
213 {
Trent Apted30f97fd2018-08-21 09:03:47214 const const_iterator it1 = const_observer_list.begin();
François Degros0659d69332017-11-15 09:31:44215 EXPECT_EQ(it1, const_observer_list.end());
216 // Iterator copy.
Trent Apted30f97fd2018-08-21 09:03:47217 const const_iterator it2 = it1;
François Degros0659d69332017-11-15 09:31:44218 EXPECT_EQ(it2, it1);
219 // Iterator assignment.
Trent Apted30f97fd2018-08-21 09:03:47220 const_iterator it3;
François Degros0659d69332017-11-15 09:31:44221 it3 = it2;
222 EXPECT_EQ(it3, it1);
223 EXPECT_EQ(it3, it2);
224 // Self assignment.
Hans Wennborg792903f2018-04-09 11:20:06225 it3 = *&it3; // The *& defeats Clang's -Wself-assign warning.
François Degros0659d69332017-11-15 09:31:44226 EXPECT_EQ(it3, it1);
227 EXPECT_EQ(it3, it2);
228 }
229
230 {
Trent Apted30f97fd2018-08-21 09:03:47231 const iterator it1 = observer_list.begin();
François Degros0659d69332017-11-15 09:31:44232 EXPECT_EQ(it1, observer_list.end());
233 // Iterator copy.
Trent Apted30f97fd2018-08-21 09:03:47234 const iterator it2 = it1;
François Degros0659d69332017-11-15 09:31:44235 EXPECT_EQ(it2, it1);
236 // Iterator assignment.
Trent Apted30f97fd2018-08-21 09:03:47237 iterator it3;
François Degros0659d69332017-11-15 09:31:44238 it3 = it2;
239 EXPECT_EQ(it3, it1);
240 EXPECT_EQ(it3, it2);
241 // Self assignment.
Hans Wennborg792903f2018-04-09 11:20:06242 it3 = *&it3; // The *& defeats Clang's -Wself-assign warning.
François Degros0659d69332017-11-15 09:31:44243 EXPECT_EQ(it3, it1);
244 EXPECT_EQ(it3, it2);
245 }
246
[email protected]631739f2011-06-05 07:07:12247 Adder a(1), b(-1), c(1), d(-1), e(-1);
[email protected]503631c2008-10-22 23:09:21248 Disrupter evil(&observer_list, &c);
initial.commitd7cae122008-07-26 21:49:38249
250 observer_list.AddObserver(&a);
251 observer_list.AddObserver(&b);
252
François Degros0659d69332017-11-15 09:31:44253 EXPECT_TRUE(const_observer_list.HasObserver(&a));
254 EXPECT_FALSE(const_observer_list.HasObserver(&c));
255
256 {
Trent Apted30f97fd2018-08-21 09:03:47257 const const_iterator it1 = const_observer_list.begin();
François Degros0659d69332017-11-15 09:31:44258 EXPECT_NE(it1, const_observer_list.end());
259 // Iterator copy.
Trent Apted30f97fd2018-08-21 09:03:47260 const const_iterator it2 = it1;
François Degros0659d69332017-11-15 09:31:44261 EXPECT_EQ(it2, it1);
262 EXPECT_NE(it2, const_observer_list.end());
263 // Iterator assignment.
Trent Apted30f97fd2018-08-21 09:03:47264 const_iterator it3;
François Degros0659d69332017-11-15 09:31:44265 it3 = it2;
266 EXPECT_EQ(it3, it1);
267 EXPECT_EQ(it3, it2);
268 // Self assignment.
Hans Wennborg792903f2018-04-09 11:20:06269 it3 = *&it3; // The *& defeats Clang's -Wself-assign warning.
François Degros0659d69332017-11-15 09:31:44270 EXPECT_EQ(it3, it1);
271 EXPECT_EQ(it3, it2);
jdoerrie977dc3f2017-12-12 09:23:34272 // Iterator post increment.
Trent Apted30f97fd2018-08-21 09:03:47273 const_iterator it4 = it3++;
jdoerrie977dc3f2017-12-12 09:23:34274 EXPECT_EQ(it4, it1);
275 EXPECT_EQ(it4, it2);
276 EXPECT_NE(it4, it3);
François Degros0659d69332017-11-15 09:31:44277 }
278
279 {
Trent Apted30f97fd2018-08-21 09:03:47280 const iterator it1 = observer_list.begin();
François Degros0659d69332017-11-15 09:31:44281 EXPECT_NE(it1, observer_list.end());
282 // Iterator copy.
Trent Apted30f97fd2018-08-21 09:03:47283 const iterator it2 = it1;
François Degros0659d69332017-11-15 09:31:44284 EXPECT_EQ(it2, it1);
285 EXPECT_NE(it2, observer_list.end());
286 // Iterator assignment.
Trent Apted30f97fd2018-08-21 09:03:47287 iterator it3;
François Degros0659d69332017-11-15 09:31:44288 it3 = it2;
289 EXPECT_EQ(it3, it1);
290 EXPECT_EQ(it3, it2);
291 // Self assignment.
Hans Wennborg792903f2018-04-09 11:20:06292 it3 = *&it3; // The *& defeats Clang's -Wself-assign warning.
François Degros0659d69332017-11-15 09:31:44293 EXPECT_EQ(it3, it1);
294 EXPECT_EQ(it3, it2);
jdoerrie977dc3f2017-12-12 09:23:34295 // Iterator post increment.
Trent Apted30f97fd2018-08-21 09:03:47296 iterator it4 = it3++;
jdoerrie977dc3f2017-12-12 09:23:34297 EXPECT_EQ(it4, it1);
298 EXPECT_EQ(it4, it2);
299 EXPECT_NE(it4, it3);
François Degros0659d69332017-11-15 09:31:44300 }
mgiuca64ccf2362014-11-10 06:44:23301
ericwilligersa60549cd2016-10-16 00:09:05302 for (auto& observer : observer_list)
303 observer.Observe(10);
initial.commitd7cae122008-07-26 21:49:38304
305 observer_list.AddObserver(&evil);
306 observer_list.AddObserver(&c);
307 observer_list.AddObserver(&d);
308
[email protected]631739f2011-06-05 07:07:12309 // Removing an observer not in the list should do nothing.
310 observer_list.RemoveObserver(&e);
311
ericwilligersa60549cd2016-10-16 00:09:05312 for (auto& observer : observer_list)
313 observer.Observe(10);
initial.commitd7cae122008-07-26 21:49:38314
[email protected]14cf9102012-08-23 09:59:19315 EXPECT_EQ(20, a.total);
316 EXPECT_EQ(-20, b.total);
317 EXPECT_EQ(0, c.total);
318 EXPECT_EQ(-10, d.total);
319 EXPECT_EQ(0, e.total);
initial.commitd7cae122008-07-26 21:49:38320}
license.botbf09a502008-08-24 00:55:55321
Oskar Sundbomc92fda62018-10-24 11:38:02322TYPED_TEST(ObserverListTest, CreatedAndUsedOnDifferentThreads) {
323 DECLARE_TYPES;
324
325 ObserverListCreator<ObserverListFoo> list_creator;
326 Adder a(1);
327 // Check with default constructor
328 {
329 std::unique_ptr<ObserverListFoo> observer_list = list_creator.Create();
330 observer_list->AddObserver(&a);
331 for (auto& observer : *observer_list) {
332 observer.Observe(1);
333 }
334 EXPECT_EQ(1, a.GetValue());
335 }
336
337 // Check with constructor taking explicit policy
338 {
339 std::unique_ptr<ObserverListFoo> observer_list =
340 list_creator.Create(base::ObserverListPolicy::EXISTING_ONLY);
341 observer_list->AddObserver(&a);
342 for (auto& observer : *observer_list) {
343 observer.Observe(1);
344 }
345 EXPECT_EQ(2, a.GetValue());
346 }
347}
348
Trent Apted30f97fd2018-08-21 09:03:47349TYPED_TEST(ObserverListTest, CompactsWhenNoActiveIterator) {
350 DECLARE_TYPES;
351 using ObserverListConstFoo =
352 typename TestFixture::template ObserverList<const Foo>;
353
354 ObserverListConstFoo ol;
355 const ObserverListConstFoo& col = ol;
François Degros0659d69332017-11-15 09:31:44356
357 const Adder a(1);
358 const Adder b(2);
359 const Adder c(3);
360
361 ol.AddObserver(&a);
362 ol.AddObserver(&b);
363
364 EXPECT_TRUE(col.HasObserver(&a));
365 EXPECT_FALSE(col.HasObserver(&c));
366
367 EXPECT_TRUE(col.might_have_observers());
368
Trent Apted30f97fd2018-08-21 09:03:47369 using It = typename ObserverListConstFoo::const_iterator;
François Degros0659d69332017-11-15 09:31:44370
371 {
372 It it = col.begin();
373 EXPECT_NE(it, col.end());
374 It ita = it;
375 EXPECT_EQ(ita, it);
376 EXPECT_NE(++it, col.end());
377 EXPECT_NE(ita, it);
378 It itb = it;
379 EXPECT_EQ(itb, it);
380 EXPECT_EQ(++it, col.end());
381
382 EXPECT_TRUE(col.might_have_observers());
383 EXPECT_EQ(&*ita, &a);
384 EXPECT_EQ(&*itb, &b);
385
386 ol.RemoveObserver(&a);
387 EXPECT_TRUE(col.might_have_observers());
388 EXPECT_FALSE(col.HasObserver(&a));
389 EXPECT_EQ(&*itb, &b);
390
391 ol.RemoveObserver(&b);
392 EXPECT_TRUE(col.might_have_observers());
393 EXPECT_FALSE(col.HasObserver(&a));
394 EXPECT_FALSE(col.HasObserver(&b));
395
396 it = It();
397 ita = It();
398 EXPECT_TRUE(col.might_have_observers());
399 ita = itb;
400 itb = It();
401 EXPECT_TRUE(col.might_have_observers());
402 ita = It();
403 EXPECT_FALSE(col.might_have_observers());
404 }
405
406 ol.AddObserver(&a);
407 ol.AddObserver(&b);
408 EXPECT_TRUE(col.might_have_observers());
409 ol.Clear();
410 EXPECT_FALSE(col.might_have_observers());
411
412 ol.AddObserver(&a);
413 ol.AddObserver(&b);
414 EXPECT_TRUE(col.might_have_observers());
415 {
416 const It it = col.begin();
417 ol.Clear();
418 EXPECT_TRUE(col.might_have_observers());
419 }
420 EXPECT_FALSE(col.might_have_observers());
421}
422
Trent Apted30f97fd2018-08-21 09:03:47423TYPED_TEST(ObserverListTest, DisruptSelf) {
424 DECLARE_TYPES;
425 ObserverListFoo observer_list;
loyso29025b62016-10-11 06:51:33426 Adder a(1), b(-1), c(1), d(-1);
427 Disrupter evil(&observer_list, true);
428
429 observer_list.AddObserver(&a);
430 observer_list.AddObserver(&b);
431
ericwilligersa60549cd2016-10-16 00:09:05432 for (auto& observer : observer_list)
433 observer.Observe(10);
loyso29025b62016-10-11 06:51:33434
435 observer_list.AddObserver(&evil);
436 observer_list.AddObserver(&c);
437 observer_list.AddObserver(&d);
438
ericwilligersa60549cd2016-10-16 00:09:05439 for (auto& observer : observer_list)
440 observer.Observe(10);
loyso29025b62016-10-11 06:51:33441
442 EXPECT_EQ(20, a.total);
443 EXPECT_EQ(-20, b.total);
444 EXPECT_EQ(10, c.total);
445 EXPECT_EQ(-10, d.total);
446}
447
Trent Apted30f97fd2018-08-21 09:03:47448TYPED_TEST(ObserverListTest, DisruptBefore) {
449 DECLARE_TYPES;
450 ObserverListFoo observer_list;
loyso29025b62016-10-11 06:51:33451 Adder a(1), b(-1), c(1), d(-1);
452 Disrupter evil(&observer_list, &b);
453
454 observer_list.AddObserver(&a);
455 observer_list.AddObserver(&b);
456 observer_list.AddObserver(&evil);
457 observer_list.AddObserver(&c);
458 observer_list.AddObserver(&d);
459
ericwilligersa60549cd2016-10-16 00:09:05460 for (auto& observer : observer_list)
461 observer.Observe(10);
462 for (auto& observer : observer_list)
463 observer.Observe(10);
loyso29025b62016-10-11 06:51:33464
465 EXPECT_EQ(20, a.total);
466 EXPECT_EQ(-10, b.total);
467 EXPECT_EQ(20, c.total);
468 EXPECT_EQ(-20, d.total);
469}
470
Trent Apted30f97fd2018-08-21 09:03:47471TYPED_TEST(ObserverListTest, Existing) {
472 DECLARE_TYPES;
473 ObserverListFoo observer_list(ObserverListPolicy::EXISTING_ONLY);
[email protected]b3e2fad02008-10-31 03:32:06474 Adder a(1);
Trent Apted30f97fd2018-08-21 09:03:47475 AddInObserve<ObserverListFoo> b(&observer_list);
loyso29025b62016-10-11 06:51:33476 Adder c(1);
477 b.SetToAdd(&c);
[email protected]b3e2fad02008-10-31 03:32:06478
479 observer_list.AddObserver(&a);
480 observer_list.AddObserver(&b);
481
ericwilligersa60549cd2016-10-16 00:09:05482 for (auto& observer : observer_list)
483 observer.Observe(1);
[email protected]b3e2fad02008-10-31 03:32:06484
loyso29025b62016-10-11 06:51:33485 EXPECT_FALSE(b.to_add_);
[email protected]b3e2fad02008-10-31 03:32:06486 // B's adder should not have been notified because it was added during
[email protected]6be50d72014-05-08 23:49:40487 // notification.
loyso29025b62016-10-11 06:51:33488 EXPECT_EQ(0, c.total);
[email protected]b3e2fad02008-10-31 03:32:06489
490 // Notify again to make sure b's adder is notified.
ericwilligersa60549cd2016-10-16 00:09:05491 for (auto& observer : observer_list)
492 observer.Observe(1);
loyso29025b62016-10-11 06:51:33493 EXPECT_EQ(1, c.total);
[email protected]b3e2fad02008-10-31 03:32:06494}
[email protected]84aebed2010-02-25 03:09:41495
Trent Apted30f97fd2018-08-21 09:03:47496template <class ObserverListType,
497 class Foo = typename ObserverListType::value_type>
[email protected]84aebed2010-02-25 03:09:41498class AddInClearObserve : public Foo {
499 public:
Trent Apted30f97fd2018-08-21 09:03:47500 explicit AddInClearObserve(ObserverListType* list)
[email protected]84aebed2010-02-25 03:09:41501 : list_(list), added_(false), adder_(1) {}
502
dcheng56488182014-10-21 10:54:51503 void Observe(int /* x */) override {
[email protected]84aebed2010-02-25 03:09:41504 list_->Clear();
505 list_->AddObserver(&adder_);
506 added_ = true;
507 }
508
509 bool added() const { return added_; }
Trent Apted30f97fd2018-08-21 09:03:47510 const AdderT<Foo>& adder() const { return adder_; }
[email protected]84aebed2010-02-25 03:09:41511
512 private:
Trent Apted30f97fd2018-08-21 09:03:47513 ObserverListType* const list_;
[email protected]84aebed2010-02-25 03:09:41514
515 bool added_;
Trent Apted30f97fd2018-08-21 09:03:47516 AdderT<Foo> adder_;
[email protected]84aebed2010-02-25 03:09:41517};
518
Trent Apted30f97fd2018-08-21 09:03:47519TYPED_TEST(ObserverListTest, ClearNotifyAll) {
520 DECLARE_TYPES;
521 ObserverListFoo observer_list;
522 AddInClearObserve<ObserverListFoo> a(&observer_list);
[email protected]84aebed2010-02-25 03:09:41523
524 observer_list.AddObserver(&a);
525
ericwilligersa60549cd2016-10-16 00:09:05526 for (auto& observer : observer_list)
527 observer.Observe(1);
[email protected]84aebed2010-02-25 03:09:41528 EXPECT_TRUE(a.added());
529 EXPECT_EQ(1, a.adder().total)
530 << "Adder should observe once and have sum of 1.";
531}
532
Trent Apted30f97fd2018-08-21 09:03:47533TYPED_TEST(ObserverListTest, ClearNotifyExistingOnly) {
534 DECLARE_TYPES;
535 ObserverListFoo observer_list(ObserverListPolicy::EXISTING_ONLY);
536 AddInClearObserve<ObserverListFoo> a(&observer_list);
[email protected]84aebed2010-02-25 03:09:41537
538 observer_list.AddObserver(&a);
539
ericwilligersa60549cd2016-10-16 00:09:05540 for (auto& observer : observer_list)
541 observer.Observe(1);
[email protected]84aebed2010-02-25 03:09:41542 EXPECT_TRUE(a.added());
543 EXPECT_EQ(0, a.adder().total)
544 << "Adder should not observe, so sum should still be 0.";
545}
546
Trent Apted30f97fd2018-08-21 09:03:47547template <class ObserverListType,
548 class Foo = typename ObserverListType::value_type>
[email protected]671b74d2011-06-09 03:41:18549class ListDestructor : public Foo {
550 public:
Trent Apted30f97fd2018-08-21 09:03:47551 explicit ListDestructor(ObserverListType* list) : list_(list) {}
Chris Watkinsbb7211c2017-11-29 07:16:38552 ~ListDestructor() override = default;
[email protected]44106182012-04-06 03:53:02553
dcheng56488182014-10-21 10:54:51554 void Observe(int x) override { delete list_; }
[email protected]2e58cbd2012-08-06 01:03:05555
[email protected]671b74d2011-06-09 03:41:18556 private:
Trent Apted30f97fd2018-08-21 09:03:47557 ObserverListType* list_;
[email protected]671b74d2011-06-09 03:41:18558};
559
Trent Apted30f97fd2018-08-21 09:03:47560TYPED_TEST(ObserverListTest, IteratorOutlivesList) {
561 DECLARE_TYPES;
562 ObserverListFoo* observer_list = new ObserverListFoo;
563 ListDestructor<ObserverListFoo> a(observer_list);
[email protected]671b74d2011-06-09 03:41:18564 observer_list->AddObserver(&a);
565
loyso802c2132016-10-26 07:13:06566 for (auto& observer : *observer_list)
567 observer.Observe(0);
Mostyn Bramley-Moored0ecd6a2017-12-06 19:13:21568
569 // There are no EXPECT* statements for this test, if we catch
570 // use-after-free errors for observer_list (eg with ASan) then
571 // this test has failed. See http://crbug.com/85296.
[email protected]671b74d2011-06-09 03:41:18572}
573
Trent Apted30f97fd2018-08-21 09:03:47574TYPED_TEST(ObserverListTest, BasicStdIterator) {
575 DECLARE_TYPES;
576 ObserverListFoo observer_list;
loyso29025b62016-10-11 06:51:33577
578 // An optimization: begin() and end() do not involve weak pointers on
579 // empty list.
Trent Apted30f97fd2018-08-21 09:03:47580 EXPECT_FALSE(this->list(observer_list.begin()));
581 EXPECT_FALSE(this->list(observer_list.end()));
loyso29025b62016-10-11 06:51:33582
583 // Iterate over empty list: no effect, no crash.
584 for (auto& i : observer_list)
585 i.Observe(10);
586
587 Adder a(1), b(-1), c(1), d(-1);
588
589 observer_list.AddObserver(&a);
590 observer_list.AddObserver(&b);
591 observer_list.AddObserver(&c);
592 observer_list.AddObserver(&d);
593
Trent Apted30f97fd2018-08-21 09:03:47594 for (iterator i = observer_list.begin(), e = observer_list.end(); i != e; ++i)
loyso29025b62016-10-11 06:51:33595 i->Observe(1);
596
597 EXPECT_EQ(1, a.total);
598 EXPECT_EQ(-1, b.total);
599 EXPECT_EQ(1, c.total);
600 EXPECT_EQ(-1, d.total);
601
602 // Check an iteration over a 'const view' for a given container.
Trent Apted30f97fd2018-08-21 09:03:47603 const ObserverListFoo& const_list = observer_list;
604 for (const_iterator i = const_list.begin(), e = const_list.end(); i != e;
605 ++i) {
loyso29025b62016-10-11 06:51:33606 EXPECT_EQ(1, std::abs(i->GetValue()));
607 }
608
609 for (const auto& o : const_list)
610 EXPECT_EQ(1, std::abs(o.GetValue()));
611}
612
Trent Apted30f97fd2018-08-21 09:03:47613TYPED_TEST(ObserverListTest, StdIteratorRemoveItself) {
614 DECLARE_TYPES;
615 ObserverListFoo observer_list;
loyso29025b62016-10-11 06:51:33616 Adder a(1), b(-1), c(1), d(-1);
617 Disrupter disrupter(&observer_list, true);
618
619 observer_list.AddObserver(&a);
620 observer_list.AddObserver(&b);
621 observer_list.AddObserver(&disrupter);
622 observer_list.AddObserver(&c);
623 observer_list.AddObserver(&d);
624
625 for (auto& o : observer_list)
626 o.Observe(1);
627
628 for (auto& o : observer_list)
629 o.Observe(10);
630
631 EXPECT_EQ(11, a.total);
632 EXPECT_EQ(-11, b.total);
633 EXPECT_EQ(11, c.total);
634 EXPECT_EQ(-11, d.total);
635}
636
Trent Apted30f97fd2018-08-21 09:03:47637TYPED_TEST(ObserverListTest, StdIteratorRemoveBefore) {
638 DECLARE_TYPES;
639 ObserverListFoo observer_list;
loyso29025b62016-10-11 06:51:33640 Adder a(1), b(-1), c(1), d(-1);
641 Disrupter disrupter(&observer_list, &b);
642
643 observer_list.AddObserver(&a);
644 observer_list.AddObserver(&b);
645 observer_list.AddObserver(&disrupter);
646 observer_list.AddObserver(&c);
647 observer_list.AddObserver(&d);
648
649 for (auto& o : observer_list)
650 o.Observe(1);
651
652 for (auto& o : observer_list)
653 o.Observe(10);
654
655 EXPECT_EQ(11, a.total);
656 EXPECT_EQ(-1, b.total);
657 EXPECT_EQ(11, c.total);
658 EXPECT_EQ(-11, d.total);
659}
660
Trent Apted30f97fd2018-08-21 09:03:47661TYPED_TEST(ObserverListTest, StdIteratorRemoveAfter) {
662 DECLARE_TYPES;
663 ObserverListFoo observer_list;
loyso29025b62016-10-11 06:51:33664 Adder a(1), b(-1), c(1), d(-1);
665 Disrupter disrupter(&observer_list, &c);
666
667 observer_list.AddObserver(&a);
668 observer_list.AddObserver(&b);
669 observer_list.AddObserver(&disrupter);
670 observer_list.AddObserver(&c);
671 observer_list.AddObserver(&d);
672
673 for (auto& o : observer_list)
674 o.Observe(1);
675
676 for (auto& o : observer_list)
677 o.Observe(10);
678
679 EXPECT_EQ(11, a.total);
680 EXPECT_EQ(-11, b.total);
681 EXPECT_EQ(0, c.total);
682 EXPECT_EQ(-11, d.total);
683}
684
Trent Apted30f97fd2018-08-21 09:03:47685TYPED_TEST(ObserverListTest, StdIteratorRemoveAfterFront) {
686 DECLARE_TYPES;
687 ObserverListFoo observer_list;
loyso29025b62016-10-11 06:51:33688 Adder a(1), b(-1), c(1), d(-1);
689 Disrupter disrupter(&observer_list, &a);
690
691 observer_list.AddObserver(&a);
692 observer_list.AddObserver(&disrupter);
693 observer_list.AddObserver(&b);
694 observer_list.AddObserver(&c);
695 observer_list.AddObserver(&d);
696
697 for (auto& o : observer_list)
698 o.Observe(1);
699
700 for (auto& o : observer_list)
701 o.Observe(10);
702
703 EXPECT_EQ(1, a.total);
704 EXPECT_EQ(-11, b.total);
705 EXPECT_EQ(11, c.total);
706 EXPECT_EQ(-11, d.total);
707}
708
Trent Apted30f97fd2018-08-21 09:03:47709TYPED_TEST(ObserverListTest, StdIteratorRemoveBeforeBack) {
710 DECLARE_TYPES;
711 ObserverListFoo observer_list;
loyso29025b62016-10-11 06:51:33712 Adder a(1), b(-1), c(1), d(-1);
713 Disrupter disrupter(&observer_list, &d);
714
715 observer_list.AddObserver(&a);
716 observer_list.AddObserver(&b);
717 observer_list.AddObserver(&c);
718 observer_list.AddObserver(&disrupter);
719 observer_list.AddObserver(&d);
720
721 for (auto& o : observer_list)
722 o.Observe(1);
723
724 for (auto& o : observer_list)
725 o.Observe(10);
726
727 EXPECT_EQ(11, a.total);
728 EXPECT_EQ(-11, b.total);
729 EXPECT_EQ(11, c.total);
730 EXPECT_EQ(0, d.total);
731}
732
Trent Apted30f97fd2018-08-21 09:03:47733TYPED_TEST(ObserverListTest, StdIteratorRemoveFront) {
734 DECLARE_TYPES;
735 using iterator = typename TestFixture::iterator;
736 ObserverListFoo observer_list;
loyso29025b62016-10-11 06:51:33737 Adder a(1), b(-1), c(1), d(-1);
738 Disrupter disrupter(&observer_list, true);
739
740 observer_list.AddObserver(&disrupter);
741 observer_list.AddObserver(&a);
742 observer_list.AddObserver(&b);
743 observer_list.AddObserver(&c);
744 observer_list.AddObserver(&d);
745
746 bool test_disruptor = true;
Trent Apted30f97fd2018-08-21 09:03:47747 for (iterator i = observer_list.begin(), e = observer_list.end(); i != e;
748 ++i) {
loyso29025b62016-10-11 06:51:33749 i->Observe(1);
750 // Check that second call to i->Observe() would crash here.
751 if (test_disruptor) {
Trent Apted30f97fd2018-08-21 09:03:47752 EXPECT_FALSE(this->GetCurrent(&i));
loyso29025b62016-10-11 06:51:33753 test_disruptor = false;
754 }
755 }
756
757 for (auto& o : observer_list)
758 o.Observe(10);
759
760 EXPECT_EQ(11, a.total);
761 EXPECT_EQ(-11, b.total);
762 EXPECT_EQ(11, c.total);
763 EXPECT_EQ(-11, d.total);
764}
765
Trent Apted30f97fd2018-08-21 09:03:47766TYPED_TEST(ObserverListTest, StdIteratorRemoveBack) {
767 DECLARE_TYPES;
768 ObserverListFoo observer_list;
loyso29025b62016-10-11 06:51:33769 Adder a(1), b(-1), c(1), d(-1);
770 Disrupter disrupter(&observer_list, true);
771
772 observer_list.AddObserver(&a);
773 observer_list.AddObserver(&b);
774 observer_list.AddObserver(&c);
775 observer_list.AddObserver(&d);
776 observer_list.AddObserver(&disrupter);
777
778 for (auto& o : observer_list)
779 o.Observe(1);
780
781 for (auto& o : observer_list)
782 o.Observe(10);
783
784 EXPECT_EQ(11, a.total);
785 EXPECT_EQ(-11, b.total);
786 EXPECT_EQ(11, c.total);
787 EXPECT_EQ(-11, d.total);
788}
789
Trent Apted30f97fd2018-08-21 09:03:47790TYPED_TEST(ObserverListTest, NestedLoop) {
791 DECLARE_TYPES;
792 ObserverListFoo observer_list;
loyso29025b62016-10-11 06:51:33793 Adder a(1), b(-1), c(1), d(-1);
794 Disrupter disrupter(&observer_list, true);
795
796 observer_list.AddObserver(&disrupter);
797 observer_list.AddObserver(&a);
798 observer_list.AddObserver(&b);
799 observer_list.AddObserver(&c);
800 observer_list.AddObserver(&d);
801
Dave Tapuska0b98e5c2019-09-04 13:05:46802 for (auto& observer : observer_list) {
803 observer.Observe(10);
loyso29025b62016-10-11 06:51:33804
Dave Tapuska0b98e5c2019-09-04 13:05:46805 for (auto& nested_observer : observer_list)
806 nested_observer.Observe(1);
loyso29025b62016-10-11 06:51:33807 }
808
809 EXPECT_EQ(15, a.total);
810 EXPECT_EQ(-15, b.total);
811 EXPECT_EQ(15, c.total);
812 EXPECT_EQ(-15, d.total);
813}
814
Trent Apted30f97fd2018-08-21 09:03:47815TYPED_TEST(ObserverListTest, NonCompactList) {
816 DECLARE_TYPES;
817 ObserverListFoo observer_list;
loyso29025b62016-10-11 06:51:33818 Adder a(1), b(-1);
819
820 Disrupter disrupter1(&observer_list, true);
821 Disrupter disrupter2(&observer_list, true);
822
benwells2cbda2f2016-10-24 20:18:52823 // Disrupt itself and another one.
loyso29025b62016-10-11 06:51:33824 disrupter1.SetDoomed(&disrupter2);
825
826 observer_list.AddObserver(&disrupter1);
827 observer_list.AddObserver(&disrupter2);
828 observer_list.AddObserver(&a);
829 observer_list.AddObserver(&b);
830
Dave Tapuska0b98e5c2019-09-04 13:05:46831 for (auto& observer : observer_list) {
loyso29025b62016-10-11 06:51:33832 // Get the { nullptr, nullptr, &a, &b } non-compact list
833 // on the first inner pass.
Dave Tapuska0b98e5c2019-09-04 13:05:46834 observer.Observe(10);
loyso29025b62016-10-11 06:51:33835
Dave Tapuska0b98e5c2019-09-04 13:05:46836 for (auto& nested_observer : observer_list)
837 nested_observer.Observe(1);
loyso29025b62016-10-11 06:51:33838 }
839
840 EXPECT_EQ(13, a.total);
841 EXPECT_EQ(-13, b.total);
842}
843
Trent Apted30f97fd2018-08-21 09:03:47844TYPED_TEST(ObserverListTest, BecomesEmptyThanNonEmpty) {
845 DECLARE_TYPES;
846 ObserverListFoo observer_list;
loyso29025b62016-10-11 06:51:33847 Adder a(1), b(-1);
848
849 Disrupter disrupter1(&observer_list, true);
850 Disrupter disrupter2(&observer_list, true);
851
benwells2cbda2f2016-10-24 20:18:52852 // Disrupt itself and another one.
loyso29025b62016-10-11 06:51:33853 disrupter1.SetDoomed(&disrupter2);
854
855 observer_list.AddObserver(&disrupter1);
856 observer_list.AddObserver(&disrupter2);
857
858 bool add_observers = true;
Dave Tapuska0b98e5c2019-09-04 13:05:46859 for (auto& observer : observer_list) {
loyso29025b62016-10-11 06:51:33860 // Get the { nullptr, nullptr } empty list on the first inner pass.
Dave Tapuska0b98e5c2019-09-04 13:05:46861 observer.Observe(10);
loyso29025b62016-10-11 06:51:33862
Dave Tapuska0b98e5c2019-09-04 13:05:46863 for (auto& nested_observer : observer_list)
864 nested_observer.Observe(1);
loyso29025b62016-10-11 06:51:33865
866 if (add_observers) {
867 observer_list.AddObserver(&a);
868 observer_list.AddObserver(&b);
869 add_observers = false;
870 }
871 }
872
873 EXPECT_EQ(12, a.total);
874 EXPECT_EQ(-12, b.total);
875}
876
Trent Apted30f97fd2018-08-21 09:03:47877TYPED_TEST(ObserverListTest, AddObserverInTheLastObserve) {
878 DECLARE_TYPES;
879 ObserverListFoo observer_list;
880
881 AddInObserve<ObserverListFoo> a(&observer_list);
loyso29025b62016-10-11 06:51:33882 Adder b(-1);
883
884 a.SetToAdd(&b);
885 observer_list.AddObserver(&a);
886
dchengc9dd0142016-10-15 05:43:19887 auto it = observer_list.begin();
888 while (it != observer_list.end()) {
889 auto& observer = *it;
890 // Intentionally increment the iterator before calling Observe(). The
891 // ObserverList starts with only one observer, and it == observer_list.end()
892 // should be true after the next line.
893 ++it;
894 // However, the first Observe() call will add a second observer: at this
895 // point, it != observer_list.end() should be true, and Observe() should be
896 // called on the newly added observer on the next iteration of the loop.
897 observer.Observe(10);
898 }
loyso29025b62016-10-11 06:51:33899
900 EXPECT_EQ(-10, b.total);
901}
902
Mitsuru Oshima538b1db2018-02-28 04:05:23903class MockLogAssertHandler {
904 public:
905 MOCK_METHOD4(
906 HandleLogAssert,
907 void(const char*, int, const base::StringPiece, const base::StringPiece));
908};
909
910#if DCHECK_IS_ON()
Trent Apted30f97fd2018-08-21 09:03:47911TYPED_TEST(ObserverListTest, NonReentrantObserverList) {
912 DECLARE_TYPES;
913 using NonReentrantObserverListFoo = typename PickObserverList<
914 Foo>::template ObserverListType<Foo, /*check_empty=*/false,
915 /*allow_reentrancy=*/false>;
916 NonReentrantObserverListFoo non_reentrant_observer_list;
Mitsuru Oshima538b1db2018-02-28 04:05:23917 Adder a(1);
918 non_reentrant_observer_list.AddObserver(&a);
919
Wez0c9c93c2018-04-26 16:23:24920 EXPECT_DCHECK_DEATH({
Dave Tapuska0b98e5c2019-09-04 13:05:46921 for (const Foo& observer : non_reentrant_observer_list) {
922 for (const Foo& nested_observer : non_reentrant_observer_list) {
923 std::ignore = observer;
924 std::ignore = nested_observer;
Mitsuru Oshima538b1db2018-02-28 04:05:23925 }
926 }
Wez0c9c93c2018-04-26 16:23:24927 });
Mitsuru Oshima538b1db2018-02-28 04:05:23928}
929
Trent Apted30f97fd2018-08-21 09:03:47930TYPED_TEST(ObserverListTest, ReentrantObserverList) {
931 DECLARE_TYPES;
932 using ReentrantObserverListFoo = typename PickObserverList<
933 Foo>::template ObserverListType<Foo, /*check_empty=*/false,
934 /*allow_reentrancy=*/true>;
935 ReentrantObserverListFoo reentrant_observer_list;
Mitsuru Oshima538b1db2018-02-28 04:05:23936 Adder a(1);
937 reentrant_observer_list.AddObserver(&a);
938 bool passed = false;
Dave Tapuska0b98e5c2019-09-04 13:05:46939 for (const Foo& observer : reentrant_observer_list) {
940 for (const Foo& nested_observer : reentrant_observer_list) {
941 std::ignore = observer;
942 std::ignore = nested_observer;
Mitsuru Oshima538b1db2018-02-28 04:05:23943 passed = true;
944 }
945 }
946 EXPECT_TRUE(passed);
947}
948#endif
949
Trent Apted30f97fd2018-08-21 09:03:47950class TestCheckedObserver : public CheckedObserver {
951 public:
952 explicit TestCheckedObserver(int* count) : count_(count) {}
953
954 void Observe() { ++(*count_); }
955
956 private:
957 int* count_;
958
959 DISALLOW_COPY_AND_ASSIGN(TestCheckedObserver);
960};
961
962// A second, identical observer, used to test multiple inheritance.
963class TestCheckedObserver2 : public CheckedObserver {
964 public:
965 explicit TestCheckedObserver2(int* count) : count_(count) {}
966
967 void Observe() { ++(*count_); }
968
969 private:
970 int* count_;
971
972 DISALLOW_COPY_AND_ASSIGN(TestCheckedObserver2);
973};
974
975using CheckedObserverListTest = ::testing::Test;
976
977// Test Observers that CHECK() when a UAF might otherwise occur.
978TEST_F(CheckedObserverListTest, CheckedObserver) {
979 // See comments below about why this is unique_ptr.
980 auto list = std::make_unique<ObserverList<TestCheckedObserver>>();
981 int count1 = 0;
982 int count2 = 0;
983 TestCheckedObserver l1(&count1);
984 list->AddObserver(&l1);
985 {
986 TestCheckedObserver l2(&count2);
987 list->AddObserver(&l2);
988 for (auto& observer : *list)
989 observer.Observe();
990 EXPECT_EQ(1, count1);
991 EXPECT_EQ(1, count2);
992 }
993 {
994 auto it = list->begin();
995 it->Observe();
996 // For CheckedObservers, a CHECK() occurs when advancing the iterator. (On
997 // calling the observer method would be too late since the pointer would
998 // already be null by then).
999 EXPECT_CHECK_DEATH(it++);
1000
1001 // On the non-death fork, no UAF occurs since the deleted observer is never
1002 // notified, but also the observer list still has |l2| in it. Check that.
1003 list->RemoveObserver(&l1);
1004 EXPECT_TRUE(list->might_have_observers());
1005
1006 // Now (in the non-death fork()) there's a problem. To delete |it|, we need
1007 // to compact the list, but that needs to iterate, which would CHECK again.
1008 // We can't remove |l2| (it's null). But we can delete |list|, which makes
1009 // the weak pointer in the iterator itself null.
1010 list.reset();
1011 }
1012 EXPECT_EQ(2, count1);
1013 EXPECT_EQ(1, count2);
1014}
1015
1016class MultiObserver : public TestCheckedObserver,
1017 public TestCheckedObserver2,
1018 public AdderT<UncheckedBase> {
1019 public:
1020 MultiObserver(int* checked_count, int* two_count)
1021 : TestCheckedObserver(checked_count),
1022 TestCheckedObserver2(two_count),
1023 AdderT(1) {}
1024};
1025
1026// Test that observers behave as expected when observing multiple interfaces
1027// with different traits.
1028TEST_F(CheckedObserverListTest, MultiObserver) {
1029 // Observe two checked observer lists. This is to ensure the WeakPtrFactory
1030 // in CheckedObserver can correctly service multiple ObserverLists.
1031 ObserverList<TestCheckedObserver> checked_list;
1032 ObserverList<TestCheckedObserver2> two_list;
1033
1034 ObserverList<UncheckedBase>::Unchecked unsafe_list;
1035
1036 int counts[2] = {};
1037
Dave Tapuska0b98e5c2019-09-04 13:05:461038 auto multi_observer = std::make_unique<MultiObserver>(&counts[0], &counts[1]);
1039 two_list.AddObserver(multi_observer.get());
1040 checked_list.AddObserver(multi_observer.get());
1041 unsafe_list.AddObserver(multi_observer.get());
Trent Apted30f97fd2018-08-21 09:03:471042
1043 auto iterate_over = [](auto* list) {
1044 for (auto& observer : *list)
1045 observer.Observe();
1046 };
1047 iterate_over(&two_list);
1048 iterate_over(&checked_list);
1049 for (auto& observer : unsafe_list)
1050 observer.Observe(10);
1051
Dave Tapuska0b98e5c2019-09-04 13:05:461052 EXPECT_EQ(10, multi_observer->GetValue());
Trent Apted30f97fd2018-08-21 09:03:471053 for (const auto& count : counts)
1054 EXPECT_EQ(1, count);
1055
Dave Tapuska0b98e5c2019-09-04 13:05:461056 unsafe_list.RemoveObserver(multi_observer.get()); // Avoid a use-after-free.
Trent Apted30f97fd2018-08-21 09:03:471057
Dave Tapuska0b98e5c2019-09-04 13:05:461058 multi_observer.reset();
Trent Apted30f97fd2018-08-21 09:03:471059 EXPECT_CHECK_DEATH(iterate_over(&checked_list));
1060
1061 for (const auto& count : counts)
1062 EXPECT_EQ(1, count);
1063}
1064
[email protected]7ff48ca2013-02-06 16:56:191065} // namespace base