| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/observer_list.h" | 5 #include "base/observer_list.h" |
| 6 #include "base/observer_list_threadsafe.h" | 6 #include "base/observer_list_threadsafe.h" |
| 7 | 7 |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
| 11 #include "base/location.h" | 11 #include "base/location.h" |
| 12 #include "base/memory/weak_ptr.h" | 12 #include "base/memory/weak_ptr.h" |
| 13 #include "base/run_loop.h" | 13 #include "base/run_loop.h" |
| 14 #include "base/single_thread_task_runner.h" | 14 #include "base/single_thread_task_runner.h" |
| 15 #include "base/threading/platform_thread.h" | 15 #include "base/threading/platform_thread.h" |
| 16 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
| 17 | 17 |
| 18 namespace base { | 18 namespace base { |
| 19 namespace { | 19 namespace { |
| 20 | 20 |
| 21 class Foo { | 21 class Foo { |
| 22 public: | 22 public: |
| 23 virtual void Observe(int x) = 0; | 23 virtual void Observe(int x) = 0; |
| 24 virtual ~Foo() {} | 24 virtual ~Foo() {} |
| 25 virtual int GetValue() const { return 0; } |
| 25 }; | 26 }; |
| 26 | 27 |
| 27 class Adder : public Foo { | 28 class Adder : public Foo { |
| 28 public: | 29 public: |
| 29 explicit Adder(int scaler) : total(0), scaler_(scaler) {} | 30 explicit Adder(int scaler) : total(0), scaler_(scaler) {} |
| 31 ~Adder() override {} |
| 32 |
| 30 void Observe(int x) override { total += x * scaler_; } | 33 void Observe(int x) override { total += x * scaler_; } |
| 31 ~Adder() override {} | 34 int GetValue() const override { return total; } |
| 35 |
| 32 int total; | 36 int total; |
| 33 | 37 |
| 34 private: | 38 private: |
| 35 int scaler_; | 39 int scaler_; |
| 36 }; | 40 }; |
| 37 | 41 |
| 38 class Disrupter : public Foo { | 42 class Disrupter : public Foo { |
| 39 public: | 43 public: |
| 44 Disrupter(ObserverList<Foo>* list, Foo* doomed, bool remove_self) |
| 45 : list_(list), doomed_(doomed), remove_self_(remove_self) {} |
| 40 Disrupter(ObserverList<Foo>* list, Foo* doomed) | 46 Disrupter(ObserverList<Foo>* list, Foo* doomed) |
| 41 : list_(list), | 47 : Disrupter(list, doomed, false) {} |
| 42 doomed_(doomed) { | 48 Disrupter(ObserverList<Foo>* list, bool remove_self) |
| 49 : Disrupter(list, nullptr, remove_self) {} |
| 50 |
| 51 ~Disrupter() override {} |
| 52 |
| 53 void Observe(int x) override { |
| 54 if (remove_self_) |
| 55 list_->RemoveObserver(this); |
| 56 if (doomed_) |
| 57 list_->RemoveObserver(doomed_); |
| 43 } | 58 } |
| 44 ~Disrupter() override {} | 59 |
| 45 void Observe(int x) override { list_->RemoveObserver(doomed_); } | 60 void SetDoomed(Foo* doomed) { doomed_ = doomed; } |
| 46 | 61 |
| 47 private: | 62 private: |
| 48 ObserverList<Foo>* list_; | 63 ObserverList<Foo>* list_; |
| 49 Foo* doomed_; | 64 Foo* doomed_; |
| 65 bool remove_self_; |
| 50 }; | 66 }; |
| 51 | 67 |
| 52 class ThreadSafeDisrupter : public Foo { | 68 class ThreadSafeDisrupter : public Foo { |
| 53 public: | 69 public: |
| 54 ThreadSafeDisrupter(ObserverListThreadSafe<Foo>* list, Foo* doomed) | 70 ThreadSafeDisrupter(ObserverListThreadSafe<Foo>* list, Foo* doomed) |
| 55 : list_(list), | 71 : list_(list), |
| 56 doomed_(doomed) { | 72 doomed_(doomed) { |
| 57 } | 73 } |
| 58 ~ThreadSafeDisrupter() override {} | 74 ~ThreadSafeDisrupter() override {} |
| 59 void Observe(int x) override { list_->RemoveObserver(doomed_); } | 75 void Observe(int x) override { list_->RemoveObserver(doomed_); } |
| 60 | 76 |
| 61 private: | 77 private: |
| 62 ObserverListThreadSafe<Foo>* list_; | 78 ObserverListThreadSafe<Foo>* list_; |
| 63 Foo* doomed_; | 79 Foo* doomed_; |
| 64 }; | 80 }; |
| 65 | 81 |
| 66 template <typename ObserverListType> | 82 template <typename ObserverListType> |
| 67 class AddInObserve : public Foo { | 83 class AddInObserve : public Foo { |
| 68 public: | 84 public: |
| 69 explicit AddInObserve(ObserverListType* observer_list) | 85 explicit AddInObserve(ObserverListType* observer_list) |
| 70 : added(false), | 86 : observer_list(observer_list), to_add_() {} |
| 71 observer_list(observer_list), | 87 |
| 72 adder(1) { | 88 void SetToAdd(Foo* to_add) { to_add_ = to_add; } |
| 73 } | |
| 74 | 89 |
| 75 void Observe(int x) override { | 90 void Observe(int x) override { |
| 76 if (!added) { | 91 if (to_add_) { |
| 77 added = true; | 92 observer_list->AddObserver(to_add_); |
| 78 observer_list->AddObserver(&adder); | 93 to_add_ = nullptr; |
| 79 } | 94 } |
| 80 } | 95 } |
| 81 | 96 |
| 82 bool added; | |
| 83 ObserverListType* observer_list; | 97 ObserverListType* observer_list; |
| 84 Adder adder; | 98 Foo* to_add_; |
| 85 }; | 99 }; |
| 86 | 100 |
| 87 | 101 |
| 88 static const int kThreadRunTime = 2000; // ms to run the multi-threaded test. | 102 static const int kThreadRunTime = 2000; // ms to run the multi-threaded test. |
| 89 | 103 |
| 90 // A thread for use in the ThreadSafeObserver test | 104 // A thread for use in the ThreadSafeObserver test |
| 91 // which will add and remove itself from the notification | 105 // which will add and remove itself from the notification |
| 92 // list repeatedly. | 106 // list repeatedly. |
| 93 class AddRemoveThread : public PlatformThread::Delegate, | 107 class AddRemoveThread : public PlatformThread::Delegate, |
| 94 public Foo { | 108 public Foo { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 105 } | 119 } |
| 106 | 120 |
| 107 ~AddRemoveThread() override {} | 121 ~AddRemoveThread() override {} |
| 108 | 122 |
| 109 void ThreadMain() override { | 123 void ThreadMain() override { |
| 110 loop_ = new MessageLoop(); // Fire up a message loop. | 124 loop_ = new MessageLoop(); // Fire up a message loop. |
| 111 loop_->task_runner()->PostTask( | 125 loop_->task_runner()->PostTask( |
| 112 FROM_HERE, | 126 FROM_HERE, |
| 113 base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr())); | 127 base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr())); |
| 114 RunLoop().Run(); | 128 RunLoop().Run(); |
| 115 //LOG(ERROR) << "Loop 0x" << std::hex << loop_ << " done. " << | |
| 116 // count_observes_ << ", " << count_addtask_; | |
| 117 delete loop_; | 129 delete loop_; |
| 118 loop_ = reinterpret_cast<MessageLoop*>(0xdeadbeef); | 130 loop_ = reinterpret_cast<MessageLoop*>(0xdeadbeef); |
| 119 delete this; | 131 delete this; |
| 120 } | 132 } |
| 121 | 133 |
| 122 // This task just keeps posting to itself in an attempt | 134 // This task just keeps posting to itself in an attempt |
| 123 // to race with the notifier. | 135 // to race with the notifier. |
| 124 void AddTask() { | 136 void AddTask() { |
| 125 count_addtask_++; | 137 count_addtask_++; |
| 126 | 138 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 // in_list_ is only used on |this| thread. | 181 // in_list_ is only used on |this| thread. |
| 170 Time start_; // The time we started the test. | 182 Time start_; // The time we started the test. |
| 171 | 183 |
| 172 int count_observes_; // Number of times we observed. | 184 int count_observes_; // Number of times we observed. |
| 173 int count_addtask_; // Number of times thread AddTask was called | 185 int count_addtask_; // Number of times thread AddTask was called |
| 174 bool do_notifies_; // Whether these threads should do notifications. | 186 bool do_notifies_; // Whether these threads should do notifications. |
| 175 | 187 |
| 176 base::WeakPtrFactory<AddRemoveThread> weak_factory_; | 188 base::WeakPtrFactory<AddRemoveThread> weak_factory_; |
| 177 }; | 189 }; |
| 178 | 190 |
| 191 } // namespace |
| 192 |
| 179 TEST(ObserverListTest, BasicTest) { | 193 TEST(ObserverListTest, BasicTest) { |
| 180 ObserverList<Foo> observer_list; | 194 ObserverList<Foo> observer_list; |
| 181 Adder a(1), b(-1), c(1), d(-1), e(-1); | 195 Adder a(1), b(-1), c(1), d(-1), e(-1); |
| 182 Disrupter evil(&observer_list, &c); | 196 Disrupter evil(&observer_list, &c); |
| 183 | 197 |
| 184 observer_list.AddObserver(&a); | 198 observer_list.AddObserver(&a); |
| 185 observer_list.AddObserver(&b); | 199 observer_list.AddObserver(&b); |
| 186 | 200 |
| 187 EXPECT_TRUE(observer_list.HasObserver(&a)); | 201 EXPECT_TRUE(observer_list.HasObserver(&a)); |
| 188 EXPECT_FALSE(observer_list.HasObserver(&c)); | 202 EXPECT_FALSE(observer_list.HasObserver(&c)); |
| 189 | 203 |
| 190 FOR_EACH_OBSERVER(Foo, observer_list, Observe(10)); | 204 FOR_EACH_OBSERVER(Foo, observer_list, Observe(10)); |
| 191 | 205 |
| 192 observer_list.AddObserver(&evil); | 206 observer_list.AddObserver(&evil); |
| 193 observer_list.AddObserver(&c); | 207 observer_list.AddObserver(&c); |
| 194 observer_list.AddObserver(&d); | 208 observer_list.AddObserver(&d); |
| 195 | 209 |
| 196 // Removing an observer not in the list should do nothing. | 210 // Removing an observer not in the list should do nothing. |
| 197 observer_list.RemoveObserver(&e); | 211 observer_list.RemoveObserver(&e); |
| 198 | 212 |
| 199 FOR_EACH_OBSERVER(Foo, observer_list, Observe(10)); | 213 FOR_EACH_OBSERVER(Foo, observer_list, Observe(10)); |
| 200 | 214 |
| 201 EXPECT_EQ(20, a.total); | 215 EXPECT_EQ(20, a.total); |
| 202 EXPECT_EQ(-20, b.total); | 216 EXPECT_EQ(-20, b.total); |
| 203 EXPECT_EQ(0, c.total); | 217 EXPECT_EQ(0, c.total); |
| 204 EXPECT_EQ(-10, d.total); | 218 EXPECT_EQ(-10, d.total); |
| 205 EXPECT_EQ(0, e.total); | 219 EXPECT_EQ(0, e.total); |
| 206 } | 220 } |
| 207 | 221 |
| 222 TEST(ObserverListTest, DisruptSelf) { |
| 223 ObserverList<Foo> observer_list; |
| 224 Adder a(1), b(-1), c(1), d(-1); |
| 225 Disrupter evil(&observer_list, true); |
| 226 |
| 227 observer_list.AddObserver(&a); |
| 228 observer_list.AddObserver(&b); |
| 229 |
| 230 FOR_EACH_OBSERVER(Foo, observer_list, Observe(10)); |
| 231 |
| 232 observer_list.AddObserver(&evil); |
| 233 observer_list.AddObserver(&c); |
| 234 observer_list.AddObserver(&d); |
| 235 |
| 236 FOR_EACH_OBSERVER(Foo, observer_list, Observe(10)); |
| 237 |
| 238 EXPECT_EQ(20, a.total); |
| 239 EXPECT_EQ(-20, b.total); |
| 240 EXPECT_EQ(10, c.total); |
| 241 EXPECT_EQ(-10, d.total); |
| 242 } |
| 243 |
| 244 TEST(ObserverListTest, DisruptBefore) { |
| 245 ObserverList<Foo> observer_list; |
| 246 Adder a(1), b(-1), c(1), d(-1); |
| 247 Disrupter evil(&observer_list, &b); |
| 248 |
| 249 observer_list.AddObserver(&a); |
| 250 observer_list.AddObserver(&b); |
| 251 observer_list.AddObserver(&evil); |
| 252 observer_list.AddObserver(&c); |
| 253 observer_list.AddObserver(&d); |
| 254 |
| 255 FOR_EACH_OBSERVER(Foo, observer_list, Observe(10)); |
| 256 FOR_EACH_OBSERVER(Foo, observer_list, Observe(10)); |
| 257 |
| 258 EXPECT_EQ(20, a.total); |
| 259 EXPECT_EQ(-10, b.total); |
| 260 EXPECT_EQ(20, c.total); |
| 261 EXPECT_EQ(-20, d.total); |
| 262 } |
| 263 |
| 208 TEST(ObserverListThreadSafeTest, BasicTest) { | 264 TEST(ObserverListThreadSafeTest, BasicTest) { |
| 209 MessageLoop loop; | 265 MessageLoop loop; |
| 210 | 266 |
| 211 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( | 267 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( |
| 212 new ObserverListThreadSafe<Foo>); | 268 new ObserverListThreadSafe<Foo>); |
| 213 Adder a(1); | 269 Adder a(1); |
| 214 Adder b(-1); | 270 Adder b(-1); |
| 215 Adder c(1); | 271 Adder c(1); |
| 216 Adder d(-1); | 272 Adder d(-1); |
| 217 ThreadSafeDisrupter evil(observer_list.get(), &c); | 273 ThreadSafeDisrupter evil(observer_list.get(), &c); |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 426 observer_list->AddObserver(&a); | 482 observer_list->AddObserver(&a); |
| 427 delete loop; | 483 delete loop; |
| 428 // Test passes if we don't crash here. | 484 // Test passes if we don't crash here. |
| 429 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); | 485 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); |
| 430 } | 486 } |
| 431 | 487 |
| 432 TEST(ObserverListTest, Existing) { | 488 TEST(ObserverListTest, Existing) { |
| 433 ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY); | 489 ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY); |
| 434 Adder a(1); | 490 Adder a(1); |
| 435 AddInObserve<ObserverList<Foo> > b(&observer_list); | 491 AddInObserve<ObserverList<Foo> > b(&observer_list); |
| 492 Adder c(1); |
| 493 b.SetToAdd(&c); |
| 436 | 494 |
| 437 observer_list.AddObserver(&a); | 495 observer_list.AddObserver(&a); |
| 438 observer_list.AddObserver(&b); | 496 observer_list.AddObserver(&b); |
| 439 | 497 |
| 440 FOR_EACH_OBSERVER(Foo, observer_list, Observe(1)); | 498 FOR_EACH_OBSERVER(Foo, observer_list, Observe(1)); |
| 441 | 499 |
| 442 EXPECT_TRUE(b.added); | 500 EXPECT_FALSE(b.to_add_); |
| 443 // B's adder should not have been notified because it was added during | 501 // B's adder should not have been notified because it was added during |
| 444 // notification. | 502 // notification. |
| 445 EXPECT_EQ(0, b.adder.total); | 503 EXPECT_EQ(0, c.total); |
| 446 | 504 |
| 447 // Notify again to make sure b's adder is notified. | 505 // Notify again to make sure b's adder is notified. |
| 448 FOR_EACH_OBSERVER(Foo, observer_list, Observe(1)); | 506 FOR_EACH_OBSERVER(Foo, observer_list, Observe(1)); |
| 449 EXPECT_EQ(1, b.adder.total); | 507 EXPECT_EQ(1, c.total); |
| 450 } | 508 } |
| 451 | 509 |
| 452 // Same as above, but for ObserverListThreadSafe | 510 // Same as above, but for ObserverListThreadSafe |
| 453 TEST(ObserverListThreadSafeTest, Existing) { | 511 TEST(ObserverListThreadSafeTest, Existing) { |
| 454 MessageLoop loop; | 512 MessageLoop loop; |
| 455 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( | 513 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( |
| 456 new ObserverListThreadSafe<Foo>(ObserverList<Foo>::NOTIFY_EXISTING_ONLY)); | 514 new ObserverListThreadSafe<Foo>(ObserverList<Foo>::NOTIFY_EXISTING_ONLY)); |
| 457 Adder a(1); | 515 Adder a(1); |
| 458 AddInObserve<ObserverListThreadSafe<Foo> > b(observer_list.get()); | 516 AddInObserve<ObserverListThreadSafe<Foo> > b(observer_list.get()); |
| 517 Adder c(1); |
| 518 b.SetToAdd(&c); |
| 459 | 519 |
| 460 observer_list->AddObserver(&a); | 520 observer_list->AddObserver(&a); |
| 461 observer_list->AddObserver(&b); | 521 observer_list->AddObserver(&b); |
| 462 | 522 |
| 463 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); | 523 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); |
| 464 RunLoop().RunUntilIdle(); | 524 RunLoop().RunUntilIdle(); |
| 465 | 525 |
| 466 EXPECT_TRUE(b.added); | 526 EXPECT_FALSE(b.to_add_); |
| 467 // B's adder should not have been notified because it was added during | 527 // B's adder should not have been notified because it was added during |
| 468 // notification. | 528 // notification. |
| 469 EXPECT_EQ(0, b.adder.total); | 529 EXPECT_EQ(0, c.total); |
| 470 | 530 |
| 471 // Notify again to make sure b's adder is notified. | 531 // Notify again to make sure b's adder is notified. |
| 472 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); | 532 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); |
| 473 RunLoop().RunUntilIdle(); | 533 RunLoop().RunUntilIdle(); |
| 474 EXPECT_EQ(1, b.adder.total); | 534 EXPECT_EQ(1, c.total); |
| 475 } | 535 } |
| 476 | 536 |
| 477 class AddInClearObserve : public Foo { | 537 class AddInClearObserve : public Foo { |
| 478 public: | 538 public: |
| 479 explicit AddInClearObserve(ObserverList<Foo>* list) | 539 explicit AddInClearObserve(ObserverList<Foo>* list) |
| 480 : list_(list), added_(false), adder_(1) {} | 540 : list_(list), added_(false), adder_(1) {} |
| 481 | 541 |
| 482 void Observe(int /* x */) override { | 542 void Observe(int /* x */) override { |
| 483 list_->Clear(); | 543 list_->Clear(); |
| 484 list_->AddObserver(&adder_); | 544 list_->AddObserver(&adder_); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 534 TEST(ObserverListTest, IteratorOutlivesList) { | 594 TEST(ObserverListTest, IteratorOutlivesList) { |
| 535 ObserverList<Foo>* observer_list = new ObserverList<Foo>; | 595 ObserverList<Foo>* observer_list = new ObserverList<Foo>; |
| 536 ListDestructor a(observer_list); | 596 ListDestructor a(observer_list); |
| 537 observer_list->AddObserver(&a); | 597 observer_list->AddObserver(&a); |
| 538 | 598 |
| 539 FOR_EACH_OBSERVER(Foo, *observer_list, Observe(0)); | 599 FOR_EACH_OBSERVER(Foo, *observer_list, Observe(0)); |
| 540 // If this test fails, there'll be Valgrind errors when this function goes out | 600 // If this test fails, there'll be Valgrind errors when this function goes out |
| 541 // of scope. | 601 // of scope. |
| 542 } | 602 } |
| 543 | 603 |
| 544 } // namespace | 604 TEST(ObserverListTest, BasicStdIterator) { |
| 605 using FooList = ObserverList<Foo>; |
| 606 FooList observer_list; |
| 607 |
| 608 // An optimization: begin() and end() do not involve weak pointers on |
| 609 // empty list. |
| 610 EXPECT_FALSE(observer_list.begin().list_); |
| 611 EXPECT_FALSE(observer_list.end().list_); |
| 612 |
| 613 // Iterate over empty list: no effect, no crash. |
| 614 for (auto& i : observer_list) |
| 615 i.Observe(10); |
| 616 |
| 617 Adder a(1), b(-1), c(1), d(-1); |
| 618 |
| 619 observer_list.AddObserver(&a); |
| 620 observer_list.AddObserver(&b); |
| 621 observer_list.AddObserver(&c); |
| 622 observer_list.AddObserver(&d); |
| 623 |
| 624 for (FooList::iterator i = observer_list.begin(), e = observer_list.end(); |
| 625 i != e; ++i) |
| 626 i->Observe(1); |
| 627 |
| 628 EXPECT_EQ(1, a.total); |
| 629 EXPECT_EQ(-1, b.total); |
| 630 EXPECT_EQ(1, c.total); |
| 631 EXPECT_EQ(-1, d.total); |
| 632 |
| 633 // Check an iteration over a 'const view' for a given container. |
| 634 const FooList& const_list = observer_list; |
| 635 for (FooList::const_iterator i = const_list.begin(), e = const_list.end(); |
| 636 i != e; ++i) { |
| 637 EXPECT_EQ(1, std::abs(i->GetValue())); |
| 638 } |
| 639 |
| 640 for (const auto& o : const_list) |
| 641 EXPECT_EQ(1, std::abs(o.GetValue())); |
| 642 } |
| 643 |
| 644 TEST(ObserverListTest, StdIteratorRemoveItself) { |
| 645 ObserverList<Foo> observer_list; |
| 646 Adder a(1), b(-1), c(1), d(-1); |
| 647 Disrupter disrupter(&observer_list, true); |
| 648 |
| 649 observer_list.AddObserver(&a); |
| 650 observer_list.AddObserver(&b); |
| 651 observer_list.AddObserver(&disrupter); |
| 652 observer_list.AddObserver(&c); |
| 653 observer_list.AddObserver(&d); |
| 654 |
| 655 for (auto& o : observer_list) |
| 656 o.Observe(1); |
| 657 |
| 658 for (auto& o : observer_list) |
| 659 o.Observe(10); |
| 660 |
| 661 EXPECT_EQ(11, a.total); |
| 662 EXPECT_EQ(-11, b.total); |
| 663 EXPECT_EQ(11, c.total); |
| 664 EXPECT_EQ(-11, d.total); |
| 665 } |
| 666 |
| 667 TEST(ObserverListTest, StdIteratorRemoveBefore) { |
| 668 ObserverList<Foo> observer_list; |
| 669 Adder a(1), b(-1), c(1), d(-1); |
| 670 Disrupter disrupter(&observer_list, &b); |
| 671 |
| 672 observer_list.AddObserver(&a); |
| 673 observer_list.AddObserver(&b); |
| 674 observer_list.AddObserver(&disrupter); |
| 675 observer_list.AddObserver(&c); |
| 676 observer_list.AddObserver(&d); |
| 677 |
| 678 for (auto& o : observer_list) |
| 679 o.Observe(1); |
| 680 |
| 681 for (auto& o : observer_list) |
| 682 o.Observe(10); |
| 683 |
| 684 EXPECT_EQ(11, a.total); |
| 685 EXPECT_EQ(-1, b.total); |
| 686 EXPECT_EQ(11, c.total); |
| 687 EXPECT_EQ(-11, d.total); |
| 688 } |
| 689 |
| 690 TEST(ObserverListTest, StdIteratorRemoveAfter) { |
| 691 ObserverList<Foo> observer_list; |
| 692 Adder a(1), b(-1), c(1), d(-1); |
| 693 Disrupter disrupter(&observer_list, &c); |
| 694 |
| 695 observer_list.AddObserver(&a); |
| 696 observer_list.AddObserver(&b); |
| 697 observer_list.AddObserver(&disrupter); |
| 698 observer_list.AddObserver(&c); |
| 699 observer_list.AddObserver(&d); |
| 700 |
| 701 for (auto& o : observer_list) |
| 702 o.Observe(1); |
| 703 |
| 704 for (auto& o : observer_list) |
| 705 o.Observe(10); |
| 706 |
| 707 EXPECT_EQ(11, a.total); |
| 708 EXPECT_EQ(-11, b.total); |
| 709 EXPECT_EQ(0, c.total); |
| 710 EXPECT_EQ(-11, d.total); |
| 711 } |
| 712 |
| 713 TEST(ObserverListTest, StdIteratorRemoveAfterFront) { |
| 714 ObserverList<Foo> observer_list; |
| 715 Adder a(1), b(-1), c(1), d(-1); |
| 716 Disrupter disrupter(&observer_list, &a); |
| 717 |
| 718 observer_list.AddObserver(&a); |
| 719 observer_list.AddObserver(&disrupter); |
| 720 observer_list.AddObserver(&b); |
| 721 observer_list.AddObserver(&c); |
| 722 observer_list.AddObserver(&d); |
| 723 |
| 724 for (auto& o : observer_list) |
| 725 o.Observe(1); |
| 726 |
| 727 for (auto& o : observer_list) |
| 728 o.Observe(10); |
| 729 |
| 730 EXPECT_EQ(1, a.total); |
| 731 EXPECT_EQ(-11, b.total); |
| 732 EXPECT_EQ(11, c.total); |
| 733 EXPECT_EQ(-11, d.total); |
| 734 } |
| 735 |
| 736 TEST(ObserverListTest, StdIteratorRemoveBeforeBack) { |
| 737 ObserverList<Foo> observer_list; |
| 738 Adder a(1), b(-1), c(1), d(-1); |
| 739 Disrupter disrupter(&observer_list, &d); |
| 740 |
| 741 observer_list.AddObserver(&a); |
| 742 observer_list.AddObserver(&b); |
| 743 observer_list.AddObserver(&c); |
| 744 observer_list.AddObserver(&disrupter); |
| 745 observer_list.AddObserver(&d); |
| 746 |
| 747 for (auto& o : observer_list) |
| 748 o.Observe(1); |
| 749 |
| 750 for (auto& o : observer_list) |
| 751 o.Observe(10); |
| 752 |
| 753 EXPECT_EQ(11, a.total); |
| 754 EXPECT_EQ(-11, b.total); |
| 755 EXPECT_EQ(11, c.total); |
| 756 EXPECT_EQ(0, d.total); |
| 757 } |
| 758 |
| 759 TEST(ObserverListTest, StdIteratorRemoveFront) { |
| 760 using FooList = ObserverList<Foo>; |
| 761 FooList observer_list; |
| 762 Adder a(1), b(-1), c(1), d(-1); |
| 763 Disrupter disrupter(&observer_list, true); |
| 764 |
| 765 observer_list.AddObserver(&disrupter); |
| 766 observer_list.AddObserver(&a); |
| 767 observer_list.AddObserver(&b); |
| 768 observer_list.AddObserver(&c); |
| 769 observer_list.AddObserver(&d); |
| 770 |
| 771 bool test_disruptor = true; |
| 772 for (FooList::iterator i = observer_list.begin(), e = observer_list.end(); |
| 773 i != e; ++i) { |
| 774 i->Observe(1); |
| 775 // Check that second call to i->Observe() would crash here. |
| 776 if (test_disruptor) { |
| 777 EXPECT_FALSE(i.GetCurrent()); |
| 778 test_disruptor = false; |
| 779 } |
| 780 } |
| 781 |
| 782 for (auto& o : observer_list) |
| 783 o.Observe(10); |
| 784 |
| 785 EXPECT_EQ(11, a.total); |
| 786 EXPECT_EQ(-11, b.total); |
| 787 EXPECT_EQ(11, c.total); |
| 788 EXPECT_EQ(-11, d.total); |
| 789 } |
| 790 |
| 791 TEST(ObserverListTest, StdIteratorRemoveBack) { |
| 792 ObserverList<Foo> observer_list; |
| 793 Adder a(1), b(-1), c(1), d(-1); |
| 794 Disrupter disrupter(&observer_list, true); |
| 795 |
| 796 observer_list.AddObserver(&a); |
| 797 observer_list.AddObserver(&b); |
| 798 observer_list.AddObserver(&c); |
| 799 observer_list.AddObserver(&d); |
| 800 observer_list.AddObserver(&disrupter); |
| 801 |
| 802 for (auto& o : observer_list) |
| 803 o.Observe(1); |
| 804 |
| 805 for (auto& o : observer_list) |
| 806 o.Observe(10); |
| 807 |
| 808 EXPECT_EQ(11, a.total); |
| 809 EXPECT_EQ(-11, b.total); |
| 810 EXPECT_EQ(11, c.total); |
| 811 EXPECT_EQ(-11, d.total); |
| 812 } |
| 813 |
| 814 TEST(ObserverListTest, NestedLoop) { |
| 815 ObserverList<Foo> observer_list; |
| 816 Adder a(1), b(-1), c(1), d(-1); |
| 817 Disrupter disrupter(&observer_list, true); |
| 818 |
| 819 observer_list.AddObserver(&disrupter); |
| 820 observer_list.AddObserver(&a); |
| 821 observer_list.AddObserver(&b); |
| 822 observer_list.AddObserver(&c); |
| 823 observer_list.AddObserver(&d); |
| 824 |
| 825 for (auto& o : observer_list) { |
| 826 o.Observe(10); |
| 827 |
| 828 for (auto& o : observer_list) |
| 829 o.Observe(1); |
| 830 } |
| 831 |
| 832 EXPECT_EQ(15, a.total); |
| 833 EXPECT_EQ(-15, b.total); |
| 834 EXPECT_EQ(15, c.total); |
| 835 EXPECT_EQ(-15, d.total); |
| 836 } |
| 837 |
| 838 TEST(ObserverListTest, NonCompactList) { |
| 839 ObserverList<Foo> observer_list; |
| 840 Adder a(1), b(-1); |
| 841 |
| 842 Disrupter disrupter1(&observer_list, true); |
| 843 Disrupter disrupter2(&observer_list, true); |
| 844 |
| 845 // Disrupt itself and another guy. |
| 846 disrupter1.SetDoomed(&disrupter2); |
| 847 |
| 848 observer_list.AddObserver(&disrupter1); |
| 849 observer_list.AddObserver(&disrupter2); |
| 850 observer_list.AddObserver(&a); |
| 851 observer_list.AddObserver(&b); |
| 852 |
| 853 for (auto& o : observer_list) { |
| 854 // Get the { nullptr, nullptr, &a, &b } non-compact list |
| 855 // on the first inner pass. |
| 856 o.Observe(10); |
| 857 |
| 858 for (auto& o : observer_list) |
| 859 o.Observe(1); |
| 860 } |
| 861 |
| 862 EXPECT_EQ(13, a.total); |
| 863 EXPECT_EQ(-13, b.total); |
| 864 } |
| 865 |
| 866 TEST(ObserverListTest, BecomesEmptyThanNonEmpty) { |
| 867 ObserverList<Foo> observer_list; |
| 868 Adder a(1), b(-1); |
| 869 |
| 870 Disrupter disrupter1(&observer_list, true); |
| 871 Disrupter disrupter2(&observer_list, true); |
| 872 |
| 873 // Disrupt itself and another guy. |
| 874 disrupter1.SetDoomed(&disrupter2); |
| 875 |
| 876 observer_list.AddObserver(&disrupter1); |
| 877 observer_list.AddObserver(&disrupter2); |
| 878 |
| 879 bool add_observers = true; |
| 880 for (auto& o : observer_list) { |
| 881 // Get the { nullptr, nullptr } empty list on the first inner pass. |
| 882 o.Observe(10); |
| 883 |
| 884 for (auto& o : observer_list) |
| 885 o.Observe(1); |
| 886 |
| 887 if (add_observers) { |
| 888 observer_list.AddObserver(&a); |
| 889 observer_list.AddObserver(&b); |
| 890 add_observers = false; |
| 891 } |
| 892 } |
| 893 |
| 894 EXPECT_EQ(12, a.total); |
| 895 EXPECT_EQ(-12, b.total); |
| 896 } |
| 897 |
| 898 TEST(ObserverListTest, AddObserverInTheLastObserve) { |
| 899 using FooList = ObserverList<Foo>; |
| 900 FooList observer_list; |
| 901 |
| 902 AddInObserve<FooList> a(&observer_list); |
| 903 Adder b(-1); |
| 904 |
| 905 a.SetToAdd(&b); |
| 906 observer_list.AddObserver(&a); |
| 907 |
| 908 FooList::Iterator it(&observer_list); |
| 909 Foo* foo; |
| 910 while ((foo = it.GetNext()) != nullptr) |
| 911 foo->Observe(10); |
| 912 |
| 913 EXPECT_EQ(-10, b.total); |
| 914 } |
| 915 |
| 545 } // namespace base | 916 } // namespace base |
| OLD | NEW |