• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/scoped_multi_source_observation.h"
6 
7 #include "base/containers/contains.h"
8 #include "base/ranges/algorithm.h"
9 #include "base/scoped_observation_traits.h"
10 #include "base/test/gtest_util.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 
13 namespace base {
14 namespace {
15 
16 class TestSourceObserver {};
17 
18 class TestSource {
19  public:
20   void AddObserver(TestSourceObserver* observer);
21   void RemoveObserver(TestSourceObserver* observer);
22 
23   bool HasObserver(TestSourceObserver* observer) const;
num_observers() const24   size_t num_observers() const { return observers_.size(); }
25 
26  private:
27   std::vector<TestSourceObserver*> observers_;
28 };
29 
AddObserver(TestSourceObserver * observer)30 void TestSource::AddObserver(TestSourceObserver* observer) {
31   observers_.push_back(observer);
32 }
33 
RemoveObserver(TestSourceObserver * observer)34 void TestSource::RemoveObserver(TestSourceObserver* observer) {
35   auto it = base::ranges::find(observers_, observer);
36   ASSERT_TRUE(it != observers_.end());
37   observers_.erase(it);
38 }
39 
HasObserver(TestSourceObserver * observer) const40 bool TestSource::HasObserver(TestSourceObserver* observer) const {
41   return base::Contains(observers_, observer);
42 }
43 
44 using TestScopedMultiSourceObservation =
45     ScopedMultiSourceObservation<TestSource, TestSourceObserver>;
46 
47 class ScopedMultiSourceObservationTest : public testing::Test {
48  public:
s1()49   TestSource* s1() { return &s1_; }
s2()50   TestSource* s2() { return &s2_; }
o1()51   TestSourceObserver* o1() { return &o1_; }
52 
53  private:
54   TestSource s1_;
55   TestSource s2_;
56   TestSourceObserver o1_;
57 };
58 
59 }  // namespace
60 
TEST_F(ScopedMultiSourceObservationTest,RemovesSourcesOnDestruction)61 TEST_F(ScopedMultiSourceObservationTest, RemovesSourcesOnDestruction) {
62   {
63     TestScopedMultiSourceObservation obs(o1());
64     EXPECT_EQ(0u, s1()->num_observers());
65     EXPECT_FALSE(s1()->HasObserver(o1()));
66 
67     obs.AddObservation(s1());
68     EXPECT_EQ(1u, s1()->num_observers());
69     EXPECT_TRUE(s1()->HasObserver(o1()));
70 
71     obs.AddObservation(s2());
72     EXPECT_EQ(1u, s2()->num_observers());
73     EXPECT_TRUE(s2()->HasObserver(o1()));
74   }
75 
76   // Test that all observations are removed when it goes out of scope.
77   EXPECT_EQ(0u, s1()->num_observers());
78   EXPECT_EQ(0u, s2()->num_observers());
79 }
80 
TEST_F(ScopedMultiSourceObservationTest,RemoveObservation)81 TEST_F(ScopedMultiSourceObservationTest, RemoveObservation) {
82   TestScopedMultiSourceObservation obs(o1());
83   EXPECT_EQ(0u, s1()->num_observers());
84   EXPECT_FALSE(s1()->HasObserver(o1()));
85   EXPECT_EQ(0u, s2()->num_observers());
86   EXPECT_FALSE(s2()->HasObserver(o1()));
87 
88   obs.AddObservation(s1());
89   EXPECT_EQ(1u, s1()->num_observers());
90   EXPECT_TRUE(s1()->HasObserver(o1()));
91 
92   obs.AddObservation(s2());
93   EXPECT_EQ(1u, s2()->num_observers());
94   EXPECT_TRUE(s2()->HasObserver(o1()));
95 
96   obs.RemoveObservation(s1());
97   EXPECT_EQ(0u, s1()->num_observers());
98   EXPECT_FALSE(s1()->HasObserver(o1()));
99   EXPECT_EQ(1u, s2()->num_observers());
100   EXPECT_TRUE(s2()->HasObserver(o1()));
101 
102   obs.RemoveObservation(s2());
103   EXPECT_EQ(0u, s1()->num_observers());
104   EXPECT_FALSE(s1()->HasObserver(o1()));
105   EXPECT_EQ(0u, s2()->num_observers());
106   EXPECT_FALSE(s2()->HasObserver(o1()));
107 }
108 
TEST_F(ScopedMultiSourceObservationTest,RemoveAllObservations)109 TEST_F(ScopedMultiSourceObservationTest, RemoveAllObservations) {
110   TestScopedMultiSourceObservation obs(o1());
111   EXPECT_EQ(0u, s1()->num_observers());
112   EXPECT_FALSE(s1()->HasObserver(o1()));
113   EXPECT_EQ(0u, s2()->num_observers());
114   EXPECT_FALSE(s2()->HasObserver(o1()));
115 
116   obs.AddObservation(s1());
117   obs.AddObservation(s2());
118   EXPECT_EQ(1u, s1()->num_observers());
119   EXPECT_TRUE(s1()->HasObserver(o1()));
120   EXPECT_EQ(1u, s2()->num_observers());
121   EXPECT_TRUE(s2()->HasObserver(o1()));
122 
123   obs.RemoveAllObservations();
124   EXPECT_EQ(0u, s1()->num_observers());
125   EXPECT_FALSE(s1()->HasObserver(o1()));
126   EXPECT_EQ(0u, s2()->num_observers());
127   EXPECT_FALSE(s2()->HasObserver(o1()));
128 }
129 
TEST_F(ScopedMultiSourceObservationTest,IsObservingSource)130 TEST_F(ScopedMultiSourceObservationTest, IsObservingSource) {
131   TestScopedMultiSourceObservation obs(o1());
132   EXPECT_FALSE(obs.IsObservingSource(s1()));
133   EXPECT_FALSE(obs.IsObservingSource(s2()));
134 
135   obs.AddObservation(s1());
136   EXPECT_TRUE(obs.IsObservingSource(s1()));
137   EXPECT_FALSE(obs.IsObservingSource(s2()));
138 
139   obs.AddObservation(s2());
140   EXPECT_TRUE(obs.IsObservingSource(s1()));
141   EXPECT_TRUE(obs.IsObservingSource(s2()));
142 
143   obs.RemoveObservation(s1());
144   EXPECT_FALSE(obs.IsObservingSource(s1()));
145   EXPECT_TRUE(obs.IsObservingSource(s2()));
146 }
147 
TEST_F(ScopedMultiSourceObservationTest,IsObservingAnySource)148 TEST_F(ScopedMultiSourceObservationTest, IsObservingAnySource) {
149   TestScopedMultiSourceObservation obs(o1());
150   EXPECT_FALSE(obs.IsObservingAnySource());
151 
152   obs.AddObservation(s1());
153   EXPECT_TRUE(obs.IsObservingAnySource());
154 
155   obs.AddObservation(s2());
156   EXPECT_TRUE(obs.IsObservingAnySource());
157 
158   obs.RemoveAllObservations();
159   EXPECT_FALSE(obs.IsObservingAnySource());
160 }
161 
TEST_F(ScopedMultiSourceObservationTest,GetSourcesCount)162 TEST_F(ScopedMultiSourceObservationTest, GetSourcesCount) {
163   TestScopedMultiSourceObservation obs(o1());
164   EXPECT_EQ(0u, obs.GetSourcesCount());
165 
166   obs.AddObservation(s1());
167   EXPECT_EQ(1u, obs.GetSourcesCount());
168 
169   obs.AddObservation(s2());
170   EXPECT_EQ(2u, obs.GetSourcesCount());
171 
172   obs.RemoveAllObservations();
173   EXPECT_EQ(0u, obs.GetSourcesCount());
174 }
175 
176 namespace {
177 
178 // A test source with oddly named Add/Remove functions.
179 class TestSourceWithNonDefaultNames {
180  public:
AddFoo(TestSourceObserver * observer)181   void AddFoo(TestSourceObserver* observer) { impl_.AddObserver(observer); }
RemoveFoo(TestSourceObserver * observer)182   void RemoveFoo(TestSourceObserver* observer) {
183     impl_.RemoveObserver(observer);
184   }
185 
impl() const186   const TestSource& impl() const { return impl_; }
187 
188  private:
189   TestSource impl_;
190 };
191 
192 using TestScopedMultiSourceObservationWithNonDefaultNames =
193     ScopedMultiSourceObservation<TestSourceWithNonDefaultNames,
194                                  TestSourceObserver>;
195 
196 }  // namespace
197 
198 template <>
199 struct ScopedObservationTraits<TestSourceWithNonDefaultNames,
200                                TestSourceObserver> {
AddObserverbase::ScopedObservationTraits201   static void AddObserver(TestSourceWithNonDefaultNames* source,
202                           TestSourceObserver* observer) {
203     source->AddFoo(observer);
204   }
RemoveObserverbase::ScopedObservationTraits205   static void RemoveObserver(TestSourceWithNonDefaultNames* source,
206                              TestSourceObserver* observer) {
207     source->RemoveFoo(observer);
208   }
209 };
210 
TEST_F(ScopedMultiSourceObservationTest,NonDefaultNames)211 TEST_F(ScopedMultiSourceObservationTest, NonDefaultNames) {
212   TestSourceWithNonDefaultNames nds1;
213 
214   EXPECT_EQ(0u, nds1.impl().num_observers());
215   {
216     TestScopedMultiSourceObservationWithNonDefaultNames obs(o1());
217     obs.AddObservation(&nds1);
218     EXPECT_EQ(1u, nds1.impl().num_observers());
219     EXPECT_TRUE(nds1.impl().HasObserver(o1()));
220   }
221 
222   EXPECT_EQ(0u, nds1.impl().num_observers());
223 }
224 
225 }  // namespace base
226