xref: /aosp_15_r20/external/cronet/base/scoped_observation_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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_observation.h"
6 
7 #include "base/containers/contains.h"
8 #include "base/memory/raw_ptr.h"
9 #include "base/ranges/algorithm.h"
10 #include "base/scoped_observation_traits.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 
13 namespace base {
14 namespace {
15 
16 class TestSourceObserver {
17  public:
18   virtual ~TestSourceObserver() = default;
19 };
20 
21 class TestSource {
22  public:
23   void AddObserver(TestSourceObserver* observer);
24   void RemoveObserver(TestSourceObserver* observer);
25 
26   bool HasObserver(TestSourceObserver* observer) const;
num_observers() const27   size_t num_observers() const { return observers_.size(); }
28 
29  private:
30   std::vector<raw_ptr<TestSourceObserver, VectorExperimental>> observers_;
31 };
32 
AddObserver(TestSourceObserver * observer)33 void TestSource::AddObserver(TestSourceObserver* observer) {
34   observers_.push_back(observer);
35 }
36 
RemoveObserver(TestSourceObserver * observer)37 void TestSource::RemoveObserver(TestSourceObserver* observer) {
38   auto it = base::ranges::find(observers_, observer);
39   EXPECT_TRUE(it != observers_.end());
40   observers_.erase(it);
41 }
42 
HasObserver(TestSourceObserver * observer) const43 bool TestSource::HasObserver(TestSourceObserver* observer) const {
44   return base::Contains(observers_, observer);
45 }
46 
47 using TestScopedObservation = ScopedObservation<TestSource, TestSourceObserver>;
48 
49 }  // namespace
50 
TEST(ScopedObservationTest,RemovesObservationOnDestruction)51 TEST(ScopedObservationTest, RemovesObservationOnDestruction) {
52   TestSource s1;
53 
54   {
55     TestSourceObserver o1;
56     TestScopedObservation obs(&o1);
57     const TestScopedObservation& cobs = obs;
58     EXPECT_EQ(0u, s1.num_observers());
59     EXPECT_FALSE(s1.HasObserver(&o1));
60     EXPECT_EQ(obs.GetSource(), nullptr);
61     EXPECT_EQ(cobs.GetSource(), nullptr);
62 
63     obs.Observe(&s1);
64     EXPECT_EQ(1u, s1.num_observers());
65     EXPECT_TRUE(s1.HasObserver(&o1));
66     TestSource* const got_source = obs.GetSource();
67     EXPECT_EQ(got_source, &s1);
68     EXPECT_EQ(cobs.GetSource(), &s1);
69   }
70 
71   // Test that the observation is removed when it goes out of scope.
72   EXPECT_EQ(0u, s1.num_observers());
73 }
74 
TEST(ScopedObservationTest,Reset)75 TEST(ScopedObservationTest, Reset) {
76   TestSource s1;
77   TestSourceObserver o1;
78   TestScopedObservation obs(&o1);
79   const TestScopedObservation& cobs = obs;
80   EXPECT_EQ(0u, s1.num_observers());
81   EXPECT_EQ(obs.GetSource(), nullptr);
82   EXPECT_EQ(cobs.GetSource(), nullptr);
83   obs.Reset();
84   EXPECT_EQ(obs.GetSource(), nullptr);
85   EXPECT_EQ(cobs.GetSource(), nullptr);
86 
87   obs.Observe(&s1);
88   EXPECT_EQ(1u, s1.num_observers());
89   EXPECT_TRUE(s1.HasObserver(&o1));
90   EXPECT_EQ(obs.GetSource(), &s1);
91   EXPECT_EQ(cobs.GetSource(), &s1);
92 
93   obs.Reset();
94   EXPECT_EQ(0u, s1.num_observers());
95   EXPECT_EQ(obs.GetSource(), nullptr);
96   EXPECT_EQ(cobs.GetSource(), nullptr);
97 
98   // Safe to call with no observation.
99   obs.Reset();
100   EXPECT_EQ(0u, s1.num_observers());
101   EXPECT_EQ(obs.GetSource(), nullptr);
102   EXPECT_EQ(cobs.GetSource(), nullptr);
103 }
104 
TEST(ScopedObservationTest,IsObserving)105 TEST(ScopedObservationTest, IsObserving) {
106   TestSource s1;
107   TestSourceObserver o1;
108   TestScopedObservation obs(&o1);
109   const TestScopedObservation& cobs = obs;
110   EXPECT_FALSE(cobs.IsObserving());
111   EXPECT_EQ(obs.GetSource(), nullptr);
112   EXPECT_EQ(cobs.GetSource(), nullptr);
113 
114   obs.Observe(&s1);
115   EXPECT_TRUE(cobs.IsObserving());
116   EXPECT_EQ(obs.GetSource(), &s1);
117   EXPECT_EQ(cobs.GetSource(), &s1);
118 
119   obs.Reset();
120   EXPECT_FALSE(cobs.IsObserving());
121   EXPECT_EQ(obs.GetSource(), nullptr);
122   EXPECT_EQ(cobs.GetSource(), nullptr);
123 }
124 
TEST(ScopedObservationTest,IsObservingSource)125 TEST(ScopedObservationTest, IsObservingSource) {
126   TestSource s1;
127   TestSource s2;
128   TestSourceObserver o1;
129   TestScopedObservation obs(&o1);
130   const TestScopedObservation& cobs = obs;
131   EXPECT_FALSE(cobs.IsObservingSource(&s1));
132   EXPECT_FALSE(cobs.IsObservingSource(&s2));
133   EXPECT_EQ(obs.GetSource(), nullptr);
134   EXPECT_EQ(cobs.GetSource(), nullptr);
135 
136   obs.Observe(&s1);
137   EXPECT_TRUE(cobs.IsObservingSource(&s1));
138   EXPECT_FALSE(cobs.IsObservingSource(&s2));
139   EXPECT_EQ(obs.GetSource(), &s1);
140   EXPECT_EQ(cobs.GetSource(), &s1);
141 
142   obs.Reset();
143   EXPECT_FALSE(cobs.IsObservingSource(&s1));
144   EXPECT_FALSE(cobs.IsObservingSource(&s2));
145   EXPECT_EQ(obs.GetSource(), nullptr);
146   EXPECT_EQ(cobs.GetSource(), nullptr);
147 }
148 
149 namespace {
150 
151 // A test source with oddly named Add/Remove functions.
152 class TestSourceWithNonDefaultNames {
153  public:
AddFoo(TestSourceObserver * observer)154   void AddFoo(TestSourceObserver* observer) { impl_.AddObserver(observer); }
RemoveFoo(TestSourceObserver * observer)155   void RemoveFoo(TestSourceObserver* observer) {
156     impl_.RemoveObserver(observer);
157   }
158 
impl() const159   const TestSource& impl() const { return impl_; }
160 
161  private:
162   TestSource impl_;
163 };
164 
165 using TestScopedObservationWithNonDefaultNames =
166     ScopedObservation<TestSourceWithNonDefaultNames, TestSourceObserver>;
167 
168 }  // namespace
169 
170 template <>
171 struct ScopedObservationTraits<TestSourceWithNonDefaultNames,
172                                TestSourceObserver> {
AddObserverbase::ScopedObservationTraits173   static void AddObserver(TestSourceWithNonDefaultNames* source,
174                           TestSourceObserver* observer) {
175     source->AddFoo(observer);
176   }
RemoveObserverbase::ScopedObservationTraits177   static void RemoveObserver(TestSourceWithNonDefaultNames* source,
178                              TestSourceObserver* observer) {
179     source->RemoveFoo(observer);
180   }
181 };
182 
TEST(ScopedObservationTest,NonDefaultNames)183 TEST(ScopedObservationTest, NonDefaultNames) {
184   TestSourceWithNonDefaultNames s1;
185   TestSourceObserver o1;
186 
187   EXPECT_EQ(0u, s1.impl().num_observers());
188   {
189     TestScopedObservationWithNonDefaultNames obs(&o1);
190     obs.Observe(&s1);
191     EXPECT_EQ(1u, s1.impl().num_observers());
192     EXPECT_TRUE(s1.impl().HasObserver(&o1));
193   }
194 
195   EXPECT_EQ(0u, s1.impl().num_observers());
196 }
197 
198 namespace {
199 
200 // A forward-declared test source.
201 
202 class TestSourceFwd;
203 
204 class ObservationHolder : public TestSourceObserver {
205  public:
206   // Declared but not defined since TestSourceFwd is not yet defined.
207   explicit ObservationHolder(TestSourceFwd* source);
208 
209  private:
210   // ScopedObservation<> is instantiated with a forward-declared parameter.
211   ScopedObservation<TestSourceFwd, TestSourceObserver> obs_{this};
212 };
213 
214 // TestSourceFwd gets an actual definition!
215 class TestSourceFwd : public TestSource {};
216 
217 // Calling ScopedObservation::Observe() requires an actual definition rather
218 // than just a forward declaration; make sure it compiles now that there is a
219 // definition.
ObservationHolder(TestSourceFwd * source)220 ObservationHolder::ObservationHolder(TestSourceFwd* source) {
221   obs_.Observe(source);
222 }
223 
224 }  // namespace
225 
TEST(ScopedObservationTest,ForwardDeclaredSource)226 TEST(ScopedObservationTest, ForwardDeclaredSource) {
227   TestSourceFwd s;
228   ASSERT_EQ(s.num_observers(), 0U);
229   {
230     ObservationHolder o(&s);
231     ASSERT_EQ(s.num_observers(), 1U);
232   }
233   ASSERT_EQ(s.num_observers(), 0U);
234 }
235 
236 namespace {
237 
238 class TestSourceWithNonDefaultNamesFwd;
239 
240 class ObservationWithNonDefaultNamesHolder : public TestSourceObserver {
241  public:
242   // Declared but not defined since TestSourceWithNonDefaultNamesFwd is not yet
243   // defined.
244   explicit ObservationWithNonDefaultNamesHolder(
245       TestSourceWithNonDefaultNamesFwd* source);
246 
247  private:
248   // ScopedObservation<> is instantiated with a forward-declared parameter.
249   ScopedObservation<TestSourceWithNonDefaultNamesFwd, TestSourceObserver> obs_{
250       this};
251 };
252 
253 // TestSourceWithNonDefaultNamesFwd gets an actual definition!
254 class TestSourceWithNonDefaultNamesFwd : public TestSourceWithNonDefaultNames {
255 };
256 
257 }  // namespace
258 
259 // Now we define the corresponding traits. ScopedObservationTraits
260 // specializations must be defined in base::, since that is where the primary
261 // template definition lives.
262 template <>
263 struct ScopedObservationTraits<TestSourceWithNonDefaultNamesFwd,
264                                TestSourceObserver> {
AddObserverbase::ScopedObservationTraits265   static void AddObserver(TestSourceWithNonDefaultNamesFwd* source,
266                           TestSourceObserver* observer) {
267     source->AddFoo(observer);
268   }
RemoveObserverbase::ScopedObservationTraits269   static void RemoveObserver(TestSourceWithNonDefaultNamesFwd* source,
270                              TestSourceObserver* observer) {
271     source->RemoveFoo(observer);
272   }
273 };
274 
275 namespace {
276 
277 // Calling ScopedObservation::Observe() requires an actual definition rather
278 // than just a forward declaration; make sure it compiles now that there is
279 // a definition.
ObservationWithNonDefaultNamesHolder(TestSourceWithNonDefaultNamesFwd * source)280 ObservationWithNonDefaultNamesHolder::ObservationWithNonDefaultNamesHolder(
281     TestSourceWithNonDefaultNamesFwd* source) {
282   obs_.Observe(source);
283 }
284 
285 }  // namespace
286 
TEST(ScopedObservationTest,ForwardDeclaredSourceWithNonDefaultNames)287 TEST(ScopedObservationTest, ForwardDeclaredSourceWithNonDefaultNames) {
288   TestSourceWithNonDefaultNamesFwd s;
289   ASSERT_EQ(s.impl().num_observers(), 0U);
290   {
291     ObservationWithNonDefaultNamesHolder o(&s);
292     ASSERT_EQ(s.impl().num_observers(), 1U);
293   }
294   ASSERT_EQ(s.impl().num_observers(), 0U);
295 }
296 
297 }  // namespace base
298