• 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_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  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<TestSourceObserver*> 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     EXPECT_EQ(0u, s1.num_observers());
58     EXPECT_FALSE(s1.HasObserver(&o1));
59 
60     obs.Observe(&s1);
61     EXPECT_EQ(1u, s1.num_observers());
62     EXPECT_TRUE(s1.HasObserver(&o1));
63   }
64 
65   // Test that the observation is removed when it goes out of scope.
66   EXPECT_EQ(0u, s1.num_observers());
67 }
68 
TEST(ScopedObservationTest,Reset)69 TEST(ScopedObservationTest, Reset) {
70   TestSource s1;
71   TestSourceObserver o1;
72   TestScopedObservation obs(&o1);
73   EXPECT_EQ(0u, s1.num_observers());
74   obs.Reset();
75 
76   obs.Observe(&s1);
77   EXPECT_EQ(1u, s1.num_observers());
78   EXPECT_TRUE(s1.HasObserver(&o1));
79 
80   obs.Reset();
81   EXPECT_EQ(0u, s1.num_observers());
82 
83   // Safe to call with no observation.
84   obs.Reset();
85   EXPECT_EQ(0u, s1.num_observers());
86 }
87 
TEST(ScopedObservationTest,IsObserving)88 TEST(ScopedObservationTest, IsObserving) {
89   TestSource s1;
90   TestSourceObserver o1;
91   TestScopedObservation obs(&o1);
92   EXPECT_FALSE(obs.IsObserving());
93 
94   obs.Observe(&s1);
95   EXPECT_TRUE(obs.IsObserving());
96 
97   obs.Reset();
98   EXPECT_FALSE(obs.IsObserving());
99 }
100 
TEST(ScopedObservationTest,IsObservingSource)101 TEST(ScopedObservationTest, IsObservingSource) {
102   TestSource s1;
103   TestSource s2;
104   TestSourceObserver o1;
105   TestScopedObservation obs(&o1);
106   EXPECT_FALSE(obs.IsObservingSource(&s1));
107   EXPECT_FALSE(obs.IsObservingSource(&s2));
108 
109   obs.Observe(&s1);
110   EXPECT_TRUE(obs.IsObservingSource(&s1));
111   EXPECT_FALSE(obs.IsObservingSource(&s2));
112 
113   obs.Reset();
114   EXPECT_FALSE(obs.IsObservingSource(&s1));
115   EXPECT_FALSE(obs.IsObservingSource(&s2));
116 }
117 
118 namespace {
119 
120 // A test source with oddly named Add/Remove functions.
121 class TestSourceWithNonDefaultNames {
122  public:
AddFoo(TestSourceObserver * observer)123   void AddFoo(TestSourceObserver* observer) { impl_.AddObserver(observer); }
RemoveFoo(TestSourceObserver * observer)124   void RemoveFoo(TestSourceObserver* observer) {
125     impl_.RemoveObserver(observer);
126   }
127 
impl() const128   const TestSource& impl() const { return impl_; }
129 
130  private:
131   TestSource impl_;
132 };
133 
134 using TestScopedObservationWithNonDefaultNames =
135     ScopedObservation<TestSourceWithNonDefaultNames, TestSourceObserver>;
136 
137 }  // namespace
138 
139 template <>
140 struct ScopedObservationTraits<TestSourceWithNonDefaultNames,
141                                TestSourceObserver> {
AddObserverbase::ScopedObservationTraits142   static void AddObserver(TestSourceWithNonDefaultNames* source,
143                           TestSourceObserver* observer) {
144     source->AddFoo(observer);
145   }
RemoveObserverbase::ScopedObservationTraits146   static void RemoveObserver(TestSourceWithNonDefaultNames* source,
147                              TestSourceObserver* observer) {
148     source->RemoveFoo(observer);
149   }
150 };
151 
TEST(ScopedObservationTest,NonDefaultNames)152 TEST(ScopedObservationTest, NonDefaultNames) {
153   TestSourceWithNonDefaultNames s1;
154   TestSourceObserver o1;
155 
156   EXPECT_EQ(0u, s1.impl().num_observers());
157   {
158     TestScopedObservationWithNonDefaultNames obs(&o1);
159     obs.Observe(&s1);
160     EXPECT_EQ(1u, s1.impl().num_observers());
161     EXPECT_TRUE(s1.impl().HasObserver(&o1));
162   }
163 
164   EXPECT_EQ(0u, s1.impl().num_observers());
165 }
166 
167 namespace {
168 
169 // A forward-declared test source.
170 
171 class TestSourceFwd;
172 
173 class ObservationHolder : public TestSourceObserver {
174  public:
175   // Declared but not defined since TestSourceFwd is not yet defined.
176   explicit ObservationHolder(TestSourceFwd* source);
177 
178  private:
179   // ScopedObservation<> is instantiated with a forward-declared parameter.
180   ScopedObservation<TestSourceFwd, TestSourceObserver> obs_{this};
181 };
182 
183 // TestSourceFwd gets an actual definition!
184 class TestSourceFwd : public TestSource {};
185 
186 // Calling ScopedObservation::Observe() requires an actual definition rather
187 // than just a forward declaration; make sure it compiles now that there is a
188 // definition.
ObservationHolder(TestSourceFwd * source)189 ObservationHolder::ObservationHolder(TestSourceFwd* source) {
190   obs_.Observe(source);
191 }
192 
193 }  // namespace
194 
TEST(ScopedObservationTest,ForwardDeclaredSource)195 TEST(ScopedObservationTest, ForwardDeclaredSource) {
196   TestSourceFwd s;
197   ASSERT_EQ(s.num_observers(), 0U);
198   {
199     ObservationHolder o(&s);
200     ASSERT_EQ(s.num_observers(), 1U);
201   }
202   ASSERT_EQ(s.num_observers(), 0U);
203 }
204 
205 namespace {
206 
207 class TestSourceWithNonDefaultNamesFwd;
208 
209 class ObservationWithNonDefaultNamesHolder : public TestSourceObserver {
210  public:
211   // Declared but not defined since TestSourceWithNonDefaultNamesFwd is not yet
212   // defined.
213   explicit ObservationWithNonDefaultNamesHolder(
214       TestSourceWithNonDefaultNamesFwd* source);
215 
216  private:
217   // ScopedObservation<> is instantiated with a forward-declared parameter.
218   ScopedObservation<TestSourceWithNonDefaultNamesFwd, TestSourceObserver> obs_{
219       this};
220 };
221 
222 // TestSourceWithNonDefaultNamesFwd gets an actual definition!
223 class TestSourceWithNonDefaultNamesFwd : public TestSourceWithNonDefaultNames {
224 };
225 
226 }  // namespace
227 
228 // Now we define the corresponding traits. ScopedObservationTraits
229 // specializations must be defined in base::, since that is where the primary
230 // template definition lives.
231 template <>
232 struct ScopedObservationTraits<TestSourceWithNonDefaultNamesFwd,
233                                TestSourceObserver> {
AddObserverbase::ScopedObservationTraits234   static void AddObserver(TestSourceWithNonDefaultNamesFwd* source,
235                           TestSourceObserver* observer) {
236     source->AddFoo(observer);
237   }
RemoveObserverbase::ScopedObservationTraits238   static void RemoveObserver(TestSourceWithNonDefaultNamesFwd* source,
239                              TestSourceObserver* observer) {
240     source->RemoveFoo(observer);
241   }
242 };
243 
244 namespace {
245 
246 // Calling ScopedObservation::Observe() requires an actual definition rather
247 // than just a forward declaration; make sure it compiles now that there is
248 // a definition.
ObservationWithNonDefaultNamesHolder(TestSourceWithNonDefaultNamesFwd * source)249 ObservationWithNonDefaultNamesHolder::ObservationWithNonDefaultNamesHolder(
250     TestSourceWithNonDefaultNamesFwd* source) {
251   obs_.Observe(source);
252 }
253 
254 }  // namespace
255 
TEST(ScopedObservationTest,ForwardDeclaredSourceWithNonDefaultNames)256 TEST(ScopedObservationTest, ForwardDeclaredSourceWithNonDefaultNames) {
257   TestSourceWithNonDefaultNamesFwd s;
258   ASSERT_EQ(s.impl().num_observers(), 0U);
259   {
260     ObservationWithNonDefaultNamesHolder o(&s);
261     ASSERT_EQ(s.impl().num_observers(), 1U);
262   }
263   ASSERT_EQ(s.impl().num_observers(), 0U);
264 }
265 
266 }  // namespace base
267