12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/observer_list.h"
- #include <memory>
- #include "base/memory/raw_ptr.h"
- #include "base/strings/string_piece.h"
- #include "base/test/gtest_util.h"
- #include "base/threading/simple_thread.h"
- #include "build/build_config.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- namespace base {
- namespace {
- class CheckedBase : public CheckedObserver {
- public:
- virtual void Observe(int x) = 0;
- ~CheckedBase() override = default;
- virtual int GetValue() const { return 0; }
- };
- class UncheckedBase {
- public:
- virtual void Observe(int x) = 0;
- virtual ~UncheckedBase() = default;
- virtual int GetValue() const { return 0; }
- };
- // Helper for TYPED_TEST_SUITE machinery to pick the ObserverList under test.
- // Keyed off the observer type since ObserverList has too many template args and
- // it gets ugly.
- template <class Foo>
- struct PickObserverList {};
- template <>
- struct PickObserverList<CheckedBase> {
- template <class TypeParam,
- bool check_empty = false,
- bool allow_reentrancy = true>
- using ObserverListType =
- ObserverList<TypeParam, check_empty, allow_reentrancy>;
- };
- template <>
- struct PickObserverList<UncheckedBase> {
- template <class TypeParam,
- bool check_empty = false,
- bool allow_reentrancy = true>
- using ObserverListType = typename ObserverList<TypeParam,
- check_empty,
- allow_reentrancy>::Unchecked;
- };
- template <class Foo>
- class AdderT : public Foo {
- public:
- explicit AdderT(int scaler) : total(0), scaler_(scaler) {}
- ~AdderT() override = default;
- void Observe(int x) override { total += x * scaler_; }
- int GetValue() const override { return total; }
- int total;
- private:
- int scaler_;
- };
- template <class ObserverListType,
- class Foo = typename ObserverListType::value_type>
- class DisrupterT : public Foo {
- public:
- DisrupterT(ObserverListType* list, Foo* doomed, bool remove_self)
- : list_(list), doomed_(doomed), remove_self_(remove_self) {}
- DisrupterT(ObserverListType* list, Foo* doomed)
- : DisrupterT(list, doomed, false) {}
- DisrupterT(ObserverListType* list, bool remove_self)
- : DisrupterT(list, nullptr, remove_self) {}
- ~DisrupterT() override = default;
- void Observe(int x) override {
- if (remove_self_)
- list_->RemoveObserver(this);
- if (doomed_)
- list_->RemoveObserver(doomed_.get());
- }
- void SetDoomed(Foo* doomed) { doomed_ = doomed; }
- private:
- raw_ptr<ObserverListType> list_;
- raw_ptr<Foo> doomed_;
- bool remove_self_;
- };
- template <class ObserverListType,
- class Foo = typename ObserverListType::value_type>
- class AddInObserve : public Foo {
- public:
- explicit AddInObserve(ObserverListType* observer_list)
- : observer_list(observer_list), to_add_() {}
- void SetToAdd(Foo* to_add) { to_add_ = to_add; }
- void Observe(int x) override {
- if (to_add_) {
- observer_list->AddObserver(to_add_.get());
- to_add_ = nullptr;
- }
- }
- raw_ptr<ObserverListType> observer_list;
- raw_ptr<Foo> to_add_;
- };
- template <class ObserverListType>
- class ObserverListCreator : public DelegateSimpleThread::Delegate {
- public:
- std::unique_ptr<ObserverListType> Create(
- absl::optional<base::ObserverListPolicy> policy = absl::nullopt) {
- policy_ = policy;
- DelegateSimpleThread thread(this, "ListCreator");
- thread.Start();
- thread.Join();
- return std::move(observer_list_);
- }
- private:
- void Run() override {
- if (policy_) {
- observer_list_ = std::make_unique<ObserverListType>(*policy_);
- } else {
- observer_list_ = std::make_unique<ObserverListType>();
- }
- }
- std::unique_ptr<ObserverListType> observer_list_;
- absl::optional<base::ObserverListPolicy> policy_;
- };
- } // namespace
- class ObserverListTestBase {
- public:
- ObserverListTestBase() = default;
- ObserverListTestBase(const ObserverListTestBase&) = delete;
- ObserverListTestBase& operator=(const ObserverListTestBase&) = delete;
- template <class T>
- const decltype(T::list_.get()) list(const T& iter) {
- return iter.list_.get();
- }
- template <class T>
- typename T::value_type* GetCurrent(T* iter) {
- return iter->GetCurrent();
- }
- // Override GetCurrent() for CheckedObserver. When StdIteratorRemoveFront
- // tries to simulate a sequence to see if it "would" crash, CheckedObservers
- // do, actually, crash with a DCHECK(). Note this check is different to the
- // check during an observer _iteration_. Hence, DCHECK(), not CHECK().
- CheckedBase* GetCurrent(ObserverList<CheckedBase>::iterator* iter) {
- EXPECT_DCHECK_DEATH(return iter->GetCurrent());
- return nullptr;
- }
- };
- // Templatized test fixture that can pick between CheckedBase and UncheckedBase.
- template <class ObserverType>
- class ObserverListTest : public ObserverListTestBase, public ::testing::Test {
- public:
- template <class T>
- using ObserverList =
- typename PickObserverList<ObserverType>::template ObserverListType<T>;
- using iterator = typename ObserverList<ObserverType>::iterator;
- using const_iterator = typename ObserverList<ObserverType>::const_iterator;
- ObserverListTest() = default;
- ObserverListTest(const ObserverListTest&) = delete;
- ObserverListTest& operator=(const ObserverListTest&) = delete;
- };
- using ObserverTypes = ::testing::Types<CheckedBase, UncheckedBase>;
- TYPED_TEST_SUITE(ObserverListTest, ObserverTypes);
- // TYPED_TEST causes the test parent class to be a template parameter, which
- // makes the syntax for referring to the types awkward. Create aliases in local
- // scope with clearer names. Unfortunately, we also need some trailing cruft to
- // avoid "unused local type alias" warnings.
- #define DECLARE_TYPES \
- using Foo = TypeParam; \
- using ObserverListFoo = \
- typename PickObserverList<TypeParam>::template ObserverListType<Foo>; \
- using Adder = AdderT<Foo>; \
- using Disrupter = DisrupterT<ObserverListFoo>; \
- using const_iterator = typename TestFixture::const_iterator; \
- using iterator = typename TestFixture::iterator; \
- (void)reinterpret_cast<Disrupter*>(0); \
- (void)reinterpret_cast<Adder*>(0); \
- (void)reinterpret_cast<const_iterator*>(0); \
- (void)reinterpret_cast<iterator*>(0)
- TYPED_TEST(ObserverListTest, BasicTest) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- const ObserverListFoo& const_observer_list = observer_list;
- {
- const const_iterator it1 = const_observer_list.begin();
- EXPECT_EQ(it1, const_observer_list.end());
- // Iterator copy.
- const const_iterator it2 = it1;
- EXPECT_EQ(it2, it1);
- // Iterator assignment.
- const_iterator it3;
- it3 = it2;
- EXPECT_EQ(it3, it1);
- EXPECT_EQ(it3, it2);
- // Self assignment.
- it3 = *&it3; // The *& defeats Clang's -Wself-assign warning.
- EXPECT_EQ(it3, it1);
- EXPECT_EQ(it3, it2);
- }
- {
- const iterator it1 = observer_list.begin();
- EXPECT_EQ(it1, observer_list.end());
- // Iterator copy.
- const iterator it2 = it1;
- EXPECT_EQ(it2, it1);
- // Iterator assignment.
- iterator it3;
- it3 = it2;
- EXPECT_EQ(it3, it1);
- EXPECT_EQ(it3, it2);
- // Self assignment.
- it3 = *&it3; // The *& defeats Clang's -Wself-assign warning.
- EXPECT_EQ(it3, it1);
- EXPECT_EQ(it3, it2);
- }
- Adder a(1), b(-1), c(1), d(-1), e(-1);
- Disrupter evil(&observer_list, &c);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- EXPECT_TRUE(const_observer_list.HasObserver(&a));
- EXPECT_FALSE(const_observer_list.HasObserver(&c));
- {
- const const_iterator it1 = const_observer_list.begin();
- EXPECT_NE(it1, const_observer_list.end());
- // Iterator copy.
- const const_iterator it2 = it1;
- EXPECT_EQ(it2, it1);
- EXPECT_NE(it2, const_observer_list.end());
- // Iterator assignment.
- const_iterator it3;
- it3 = it2;
- EXPECT_EQ(it3, it1);
- EXPECT_EQ(it3, it2);
- // Self assignment.
- it3 = *&it3; // The *& defeats Clang's -Wself-assign warning.
- EXPECT_EQ(it3, it1);
- EXPECT_EQ(it3, it2);
- // Iterator post increment.
- const_iterator it4 = it3++;
- EXPECT_EQ(it4, it1);
- EXPECT_EQ(it4, it2);
- EXPECT_NE(it4, it3);
- }
- {
- const iterator it1 = observer_list.begin();
- EXPECT_NE(it1, observer_list.end());
- // Iterator copy.
- const iterator it2 = it1;
- EXPECT_EQ(it2, it1);
- EXPECT_NE(it2, observer_list.end());
- // Iterator assignment.
- iterator it3;
- it3 = it2;
- EXPECT_EQ(it3, it1);
- EXPECT_EQ(it3, it2);
- // Self assignment.
- it3 = *&it3; // The *& defeats Clang's -Wself-assign warning.
- EXPECT_EQ(it3, it1);
- EXPECT_EQ(it3, it2);
- // Iterator post increment.
- iterator it4 = it3++;
- EXPECT_EQ(it4, it1);
- EXPECT_EQ(it4, it2);
- EXPECT_NE(it4, it3);
- }
- for (auto& observer : observer_list)
- observer.Observe(10);
- observer_list.AddObserver(&evil);
- observer_list.AddObserver(&c);
- observer_list.AddObserver(&d);
- // Removing an observer not in the list should do nothing.
- observer_list.RemoveObserver(&e);
- for (auto& observer : observer_list)
- observer.Observe(10);
- EXPECT_EQ(20, a.total);
- EXPECT_EQ(-20, b.total);
- EXPECT_EQ(0, c.total);
- EXPECT_EQ(-10, d.total);
- EXPECT_EQ(0, e.total);
- }
- TYPED_TEST(ObserverListTest, CreatedAndUsedOnDifferentThreads) {
- DECLARE_TYPES;
- ObserverListCreator<ObserverListFoo> list_creator;
- Adder a(1);
- // Check with default constructor
- {
- std::unique_ptr<ObserverListFoo> observer_list = list_creator.Create();
- observer_list->AddObserver(&a);
- for (auto& observer : *observer_list) {
- observer.Observe(1);
- }
- EXPECT_EQ(1, a.GetValue());
- }
- // Check with constructor taking explicit policy
- {
- std::unique_ptr<ObserverListFoo> observer_list =
- list_creator.Create(base::ObserverListPolicy::EXISTING_ONLY);
- observer_list->AddObserver(&a);
- for (auto& observer : *observer_list) {
- observer.Observe(1);
- }
- EXPECT_EQ(2, a.GetValue());
- }
- }
- TYPED_TEST(ObserverListTest, CompactsWhenNoActiveIterator) {
- DECLARE_TYPES;
- using ObserverListConstFoo =
- typename TestFixture::template ObserverList<const Foo>;
- ObserverListConstFoo ol;
- const ObserverListConstFoo& col = ol;
- const Adder a(1);
- const Adder b(2);
- const Adder c(3);
- ol.AddObserver(&a);
- ol.AddObserver(&b);
- EXPECT_TRUE(col.HasObserver(&a));
- EXPECT_FALSE(col.HasObserver(&c));
- EXPECT_TRUE(!col.empty());
- using It = typename ObserverListConstFoo::const_iterator;
- {
- It it = col.begin();
- EXPECT_NE(it, col.end());
- It ita = it;
- EXPECT_EQ(ita, it);
- EXPECT_NE(++it, col.end());
- EXPECT_NE(ita, it);
- It itb = it;
- EXPECT_EQ(itb, it);
- EXPECT_EQ(++it, col.end());
- EXPECT_TRUE(!col.empty());
- EXPECT_EQ(&*ita, &a);
- EXPECT_EQ(&*itb, &b);
- ol.RemoveObserver(&a);
- EXPECT_TRUE(!col.empty());
- EXPECT_FALSE(col.HasObserver(&a));
- EXPECT_EQ(&*itb, &b);
- ol.RemoveObserver(&b);
- EXPECT_FALSE(!col.empty());
- EXPECT_FALSE(col.HasObserver(&a));
- EXPECT_FALSE(col.HasObserver(&b));
- it = It();
- ita = It();
- EXPECT_FALSE(!col.empty());
- ita = itb;
- itb = It();
- EXPECT_FALSE(!col.empty());
- ita = It();
- EXPECT_FALSE(!col.empty());
- }
- ol.AddObserver(&a);
- ol.AddObserver(&b);
- EXPECT_TRUE(!col.empty());
- ol.Clear();
- EXPECT_FALSE(!col.empty());
- ol.AddObserver(&a);
- ol.AddObserver(&b);
- EXPECT_TRUE(!col.empty());
- {
- const It it = col.begin();
- ol.Clear();
- EXPECT_FALSE(!col.empty());
- }
- EXPECT_FALSE(!col.empty());
- }
- TYPED_TEST(ObserverListTest, DisruptSelf) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- Adder a(1), b(-1), c(1), d(-1);
- Disrupter evil(&observer_list, true);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- for (auto& observer : observer_list)
- observer.Observe(10);
- observer_list.AddObserver(&evil);
- observer_list.AddObserver(&c);
- observer_list.AddObserver(&d);
- for (auto& observer : observer_list)
- observer.Observe(10);
- EXPECT_EQ(20, a.total);
- EXPECT_EQ(-20, b.total);
- EXPECT_EQ(10, c.total);
- EXPECT_EQ(-10, d.total);
- }
- TYPED_TEST(ObserverListTest, DisruptBefore) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- Adder a(1), b(-1), c(1), d(-1);
- Disrupter evil(&observer_list, &b);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- observer_list.AddObserver(&evil);
- observer_list.AddObserver(&c);
- observer_list.AddObserver(&d);
- for (auto& observer : observer_list)
- observer.Observe(10);
- for (auto& observer : observer_list)
- observer.Observe(10);
- EXPECT_EQ(20, a.total);
- EXPECT_EQ(-10, b.total);
- EXPECT_EQ(20, c.total);
- EXPECT_EQ(-20, d.total);
- }
- TYPED_TEST(ObserverListTest, Existing) {
- DECLARE_TYPES;
- ObserverListFoo observer_list(ObserverListPolicy::EXISTING_ONLY);
- Adder a(1);
- AddInObserve<ObserverListFoo> b(&observer_list);
- Adder c(1);
- b.SetToAdd(&c);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- for (auto& observer : observer_list)
- observer.Observe(1);
- EXPECT_FALSE(b.to_add_);
- // B's adder should not have been notified because it was added during
- // notification.
- EXPECT_EQ(0, c.total);
- // Notify again to make sure b's adder is notified.
- for (auto& observer : observer_list)
- observer.Observe(1);
- EXPECT_EQ(1, c.total);
- }
- template <class ObserverListType,
- class Foo = typename ObserverListType::value_type>
- class AddInClearObserve : public Foo {
- public:
- explicit AddInClearObserve(ObserverListType* list)
- : list_(list), added_(false), adder_(1) {}
- void Observe(int /* x */) override {
- list_->Clear();
- list_->AddObserver(&adder_);
- added_ = true;
- }
- bool added() const { return added_; }
- const AdderT<Foo>& adder() const { return adder_; }
- private:
- const raw_ptr<ObserverListType> list_;
- bool added_;
- AdderT<Foo> adder_;
- };
- TYPED_TEST(ObserverListTest, ClearNotifyAll) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- AddInClearObserve<ObserverListFoo> a(&observer_list);
- observer_list.AddObserver(&a);
- for (auto& observer : observer_list)
- observer.Observe(1);
- EXPECT_TRUE(a.added());
- EXPECT_EQ(1, a.adder().total)
- << "Adder should observe once and have sum of 1.";
- }
- TYPED_TEST(ObserverListTest, ClearNotifyExistingOnly) {
- DECLARE_TYPES;
- ObserverListFoo observer_list(ObserverListPolicy::EXISTING_ONLY);
- AddInClearObserve<ObserverListFoo> a(&observer_list);
- observer_list.AddObserver(&a);
- for (auto& observer : observer_list)
- observer.Observe(1);
- EXPECT_TRUE(a.added());
- EXPECT_EQ(0, a.adder().total)
- << "Adder should not observe, so sum should still be 0.";
- }
- template <class ObserverListType,
- class Foo = typename ObserverListType::value_type>
- class ListDestructor : public Foo {
- public:
- explicit ListDestructor(ObserverListType* list) : list_(list) {}
- ~ListDestructor() override = default;
- void Observe(int x) override { delete list_; }
- private:
- raw_ptr<ObserverListType> list_;
- };
- TYPED_TEST(ObserverListTest, IteratorOutlivesList) {
- DECLARE_TYPES;
- ObserverListFoo* observer_list = new ObserverListFoo;
- ListDestructor<ObserverListFoo> a(observer_list);
- observer_list->AddObserver(&a);
- for (auto& observer : *observer_list)
- observer.Observe(0);
- // There are no EXPECT* statements for this test, if we catch
- // use-after-free errors for observer_list (eg with ASan) then
- // this test has failed. See http://crbug.com/85296.
- }
- TYPED_TEST(ObserverListTest, BasicStdIterator) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- // An optimization: begin() and end() do not involve weak pointers on
- // empty list.
- EXPECT_FALSE(this->list(observer_list.begin()));
- EXPECT_FALSE(this->list(observer_list.end()));
- // Iterate over empty list: no effect, no crash.
- for (auto& i : observer_list)
- i.Observe(10);
- Adder a(1), b(-1), c(1), d(-1);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- observer_list.AddObserver(&c);
- observer_list.AddObserver(&d);
- for (iterator i = observer_list.begin(), e = observer_list.end(); i != e; ++i)
- i->Observe(1);
- EXPECT_EQ(1, a.total);
- EXPECT_EQ(-1, b.total);
- EXPECT_EQ(1, c.total);
- EXPECT_EQ(-1, d.total);
- // Check an iteration over a 'const view' for a given container.
- const ObserverListFoo& const_list = observer_list;
- for (const_iterator i = const_list.begin(), e = const_list.end(); i != e;
- ++i) {
- EXPECT_EQ(1, std::abs(i->GetValue()));
- }
- for (const auto& o : const_list)
- EXPECT_EQ(1, std::abs(o.GetValue()));
- }
- TYPED_TEST(ObserverListTest, StdIteratorRemoveItself) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- Adder a(1), b(-1), c(1), d(-1);
- Disrupter disrupter(&observer_list, true);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- observer_list.AddObserver(&disrupter);
- observer_list.AddObserver(&c);
- observer_list.AddObserver(&d);
- for (auto& o : observer_list)
- o.Observe(1);
- for (auto& o : observer_list)
- o.Observe(10);
- EXPECT_EQ(11, a.total);
- EXPECT_EQ(-11, b.total);
- EXPECT_EQ(11, c.total);
- EXPECT_EQ(-11, d.total);
- }
- TYPED_TEST(ObserverListTest, StdIteratorRemoveBefore) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- Adder a(1), b(-1), c(1), d(-1);
- Disrupter disrupter(&observer_list, &b);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- observer_list.AddObserver(&disrupter);
- observer_list.AddObserver(&c);
- observer_list.AddObserver(&d);
- for (auto& o : observer_list)
- o.Observe(1);
- for (auto& o : observer_list)
- o.Observe(10);
- EXPECT_EQ(11, a.total);
- EXPECT_EQ(-1, b.total);
- EXPECT_EQ(11, c.total);
- EXPECT_EQ(-11, d.total);
- }
- TYPED_TEST(ObserverListTest, StdIteratorRemoveAfter) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- Adder a(1), b(-1), c(1), d(-1);
- Disrupter disrupter(&observer_list, &c);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- observer_list.AddObserver(&disrupter);
- observer_list.AddObserver(&c);
- observer_list.AddObserver(&d);
- for (auto& o : observer_list)
- o.Observe(1);
- for (auto& o : observer_list)
- o.Observe(10);
- EXPECT_EQ(11, a.total);
- EXPECT_EQ(-11, b.total);
- EXPECT_EQ(0, c.total);
- EXPECT_EQ(-11, d.total);
- }
- TYPED_TEST(ObserverListTest, StdIteratorRemoveAfterFront) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- Adder a(1), b(-1), c(1), d(-1);
- Disrupter disrupter(&observer_list, &a);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&disrupter);
- observer_list.AddObserver(&b);
- observer_list.AddObserver(&c);
- observer_list.AddObserver(&d);
- for (auto& o : observer_list)
- o.Observe(1);
- for (auto& o : observer_list)
- o.Observe(10);
- EXPECT_EQ(1, a.total);
- EXPECT_EQ(-11, b.total);
- EXPECT_EQ(11, c.total);
- EXPECT_EQ(-11, d.total);
- }
- TYPED_TEST(ObserverListTest, StdIteratorRemoveBeforeBack) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- Adder a(1), b(-1), c(1), d(-1);
- Disrupter disrupter(&observer_list, &d);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- observer_list.AddObserver(&c);
- observer_list.AddObserver(&disrupter);
- observer_list.AddObserver(&d);
- for (auto& o : observer_list)
- o.Observe(1);
- for (auto& o : observer_list)
- o.Observe(10);
- EXPECT_EQ(11, a.total);
- EXPECT_EQ(-11, b.total);
- EXPECT_EQ(11, c.total);
- EXPECT_EQ(0, d.total);
- }
- TYPED_TEST(ObserverListTest, StdIteratorRemoveFront) {
- DECLARE_TYPES;
- using iterator = typename TestFixture::iterator;
- ObserverListFoo observer_list;
- Adder a(1), b(-1), c(1), d(-1);
- Disrupter disrupter(&observer_list, true);
- observer_list.AddObserver(&disrupter);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- observer_list.AddObserver(&c);
- observer_list.AddObserver(&d);
- bool test_disruptor = true;
- for (iterator i = observer_list.begin(), e = observer_list.end(); i != e;
- ++i) {
- i->Observe(1);
- // Check that second call to i->Observe() would crash here.
- if (test_disruptor) {
- EXPECT_FALSE(this->GetCurrent(&i));
- test_disruptor = false;
- }
- }
- for (auto& o : observer_list)
- o.Observe(10);
- EXPECT_EQ(11, a.total);
- EXPECT_EQ(-11, b.total);
- EXPECT_EQ(11, c.total);
- EXPECT_EQ(-11, d.total);
- }
- TYPED_TEST(ObserverListTest, StdIteratorRemoveBack) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- Adder a(1), b(-1), c(1), d(-1);
- Disrupter disrupter(&observer_list, true);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- observer_list.AddObserver(&c);
- observer_list.AddObserver(&d);
- observer_list.AddObserver(&disrupter);
- for (auto& o : observer_list)
- o.Observe(1);
- for (auto& o : observer_list)
- o.Observe(10);
- EXPECT_EQ(11, a.total);
- EXPECT_EQ(-11, b.total);
- EXPECT_EQ(11, c.total);
- EXPECT_EQ(-11, d.total);
- }
- TYPED_TEST(ObserverListTest, NestedLoop) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- Adder a(1), b(-1), c(1), d(-1);
- Disrupter disrupter(&observer_list, true);
- observer_list.AddObserver(&disrupter);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- observer_list.AddObserver(&c);
- observer_list.AddObserver(&d);
- for (auto& observer : observer_list) {
- observer.Observe(10);
- for (auto& nested_observer : observer_list)
- nested_observer.Observe(1);
- }
- EXPECT_EQ(15, a.total);
- EXPECT_EQ(-15, b.total);
- EXPECT_EQ(15, c.total);
- EXPECT_EQ(-15, d.total);
- }
- TYPED_TEST(ObserverListTest, NonCompactList) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- Adder a(1), b(-1);
- Disrupter disrupter1(&observer_list, true);
- Disrupter disrupter2(&observer_list, true);
- // Disrupt itself and another one.
- disrupter1.SetDoomed(&disrupter2);
- observer_list.AddObserver(&disrupter1);
- observer_list.AddObserver(&disrupter2);
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- for (auto& observer : observer_list) {
- // Get the { nullptr, nullptr, &a, &b } non-compact list
- // on the first inner pass.
- observer.Observe(10);
- for (auto& nested_observer : observer_list)
- nested_observer.Observe(1);
- }
- EXPECT_EQ(13, a.total);
- EXPECT_EQ(-13, b.total);
- }
- TYPED_TEST(ObserverListTest, BecomesEmptyThanNonEmpty) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- Adder a(1), b(-1);
- Disrupter disrupter1(&observer_list, true);
- Disrupter disrupter2(&observer_list, true);
- // Disrupt itself and another one.
- disrupter1.SetDoomed(&disrupter2);
- observer_list.AddObserver(&disrupter1);
- observer_list.AddObserver(&disrupter2);
- bool add_observers = true;
- for (auto& observer : observer_list) {
- // Get the { nullptr, nullptr } empty list on the first inner pass.
- observer.Observe(10);
- for (auto& nested_observer : observer_list)
- nested_observer.Observe(1);
- if (add_observers) {
- observer_list.AddObserver(&a);
- observer_list.AddObserver(&b);
- add_observers = false;
- }
- }
- EXPECT_EQ(12, a.total);
- EXPECT_EQ(-12, b.total);
- }
- TYPED_TEST(ObserverListTest, AddObserverInTheLastObserve) {
- DECLARE_TYPES;
- ObserverListFoo observer_list;
- AddInObserve<ObserverListFoo> a(&observer_list);
- Adder b(-1);
- a.SetToAdd(&b);
- observer_list.AddObserver(&a);
- auto it = observer_list.begin();
- while (it != observer_list.end()) {
- auto& observer = *it;
- // Intentionally increment the iterator before calling Observe(). The
- // ObserverList starts with only one observer, and it == observer_list.end()
- // should be true after the next line.
- ++it;
- // However, the first Observe() call will add a second observer: at this
- // point, it != observer_list.end() should be true, and Observe() should be
- // called on the newly added observer on the next iteration of the loop.
- observer.Observe(10);
- }
- EXPECT_EQ(-10, b.total);
- }
- class MockLogAssertHandler {
- public:
- MOCK_METHOD4(
- HandleLogAssert,
- void(const char*, int, const base::StringPiece, const base::StringPiece));
- };
- #if DCHECK_IS_ON()
- TYPED_TEST(ObserverListTest, NonReentrantObserverList) {
- DECLARE_TYPES;
- using NonReentrantObserverListFoo = typename PickObserverList<
- Foo>::template ObserverListType<Foo, /*check_empty=*/false,
- /*allow_reentrancy=*/false>;
- NonReentrantObserverListFoo non_reentrant_observer_list;
- Adder a(1);
- non_reentrant_observer_list.AddObserver(&a);
- EXPECT_DCHECK_DEATH({
- for (const Foo& observer : non_reentrant_observer_list) {
- for (const Foo& nested_observer : non_reentrant_observer_list) {
- std::ignore = observer;
- std::ignore = nested_observer;
- }
- }
- });
- }
- TYPED_TEST(ObserverListTest, ReentrantObserverList) {
- DECLARE_TYPES;
- using ReentrantObserverListFoo = typename PickObserverList<
- Foo>::template ObserverListType<Foo, /*check_empty=*/false,
- /*allow_reentrancy=*/true>;
- ReentrantObserverListFoo reentrant_observer_list;
- Adder a(1);
- reentrant_observer_list.AddObserver(&a);
- bool passed = false;
- for (const Foo& observer : reentrant_observer_list) {
- for (const Foo& nested_observer : reentrant_observer_list) {
- std::ignore = observer;
- std::ignore = nested_observer;
- passed = true;
- }
- }
- EXPECT_TRUE(passed);
- }
- #endif
- class TestCheckedObserver : public CheckedObserver {
- public:
- explicit TestCheckedObserver(int* count) : count_(count) {}
- TestCheckedObserver(const TestCheckedObserver&) = delete;
- TestCheckedObserver& operator=(const TestCheckedObserver&) = delete;
- void Observe() { ++(*count_); }
- private:
- raw_ptr<int> count_;
- };
- // A second, identical observer, used to test multiple inheritance.
- class TestCheckedObserver2 : public CheckedObserver {
- public:
- explicit TestCheckedObserver2(int* count) : count_(count) {}
- TestCheckedObserver2(const TestCheckedObserver2&) = delete;
- TestCheckedObserver2& operator=(const TestCheckedObserver2&) = delete;
- void Observe() { ++(*count_); }
- private:
- raw_ptr<int> count_;
- };
- using CheckedObserverListTest = ::testing::Test;
- // Test Observers that CHECK() when a UAF might otherwise occur.
- TEST_F(CheckedObserverListTest, CheckedObserver) {
- // See comments below about why this is unique_ptr.
- auto list = std::make_unique<ObserverList<TestCheckedObserver>>();
- int count1 = 0;
- int count2 = 0;
- TestCheckedObserver l1(&count1);
- list->AddObserver(&l1);
- {
- TestCheckedObserver l2(&count2);
- list->AddObserver(&l2);
- for (auto& observer : *list)
- observer.Observe();
- EXPECT_EQ(1, count1);
- EXPECT_EQ(1, count2);
- }
- {
- auto it = list->begin();
- it->Observe();
- // For CheckedObservers, a CHECK() occurs when advancing the iterator. (On
- // calling the observer method would be too late since the pointer would
- // already be null by then).
- EXPECT_CHECK_DEATH(it++);
- // On the non-death fork, no UAF occurs since the deleted observer is never
- // notified, but also the observer list still has |l2| in it. Check that.
- list->RemoveObserver(&l1);
- EXPECT_TRUE(!list->empty());
- // Now (in the non-death fork()) there's a problem. To delete |it|, we need
- // to compact the list, but that needs to iterate, which would CHECK again.
- // We can't remove |l2| (it's null). But we can delete |list|, which makes
- // the weak pointer in the iterator itself null.
- list.reset();
- }
- EXPECT_EQ(2, count1);
- EXPECT_EQ(1, count2);
- }
- class MultiObserver : public TestCheckedObserver,
- public TestCheckedObserver2,
- public AdderT<UncheckedBase> {
- public:
- MultiObserver(int* checked_count, int* two_count)
- : TestCheckedObserver(checked_count),
- TestCheckedObserver2(two_count),
- AdderT(1) {}
- };
- // Test that observers behave as expected when observing multiple interfaces
- // with different traits.
- TEST_F(CheckedObserverListTest, MultiObserver) {
- // Observe two checked observer lists. This is to ensure the WeakPtrFactory
- // in CheckedObserver can correctly service multiple ObserverLists.
- ObserverList<TestCheckedObserver> checked_list;
- ObserverList<TestCheckedObserver2> two_list;
- ObserverList<UncheckedBase>::Unchecked unsafe_list;
- int counts[2] = {};
- auto multi_observer = std::make_unique<MultiObserver>(&counts[0], &counts[1]);
- two_list.AddObserver(multi_observer.get());
- checked_list.AddObserver(multi_observer.get());
- unsafe_list.AddObserver(multi_observer.get());
- auto iterate_over = [](auto* list) {
- for (auto& observer : *list)
- observer.Observe();
- };
- iterate_over(&two_list);
- iterate_over(&checked_list);
- for (auto& observer : unsafe_list)
- observer.Observe(10);
- EXPECT_EQ(10, multi_observer->GetValue());
- for (const auto& count : counts)
- EXPECT_EQ(1, count);
- unsafe_list.RemoveObserver(multi_observer.get()); // Avoid a use-after-free.
- multi_observer.reset();
- EXPECT_CHECK_DEATH(iterate_over(&checked_list));
- for (const auto& count : counts)
- EXPECT_EQ(1, count);
- }
- } // namespace base
|