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.
5 #include "base/scoped_observation.h"
7 #include "base/containers/contains.h"
8 #include "base/ranges/algorithm.h"
9 #include "base/scoped_observation_traits.h"
10 #include "testing/gtest/include/gtest/gtest.h"
15 class TestSourceObserver {
17 virtual ~TestSourceObserver() = default;
22 void AddObserver(TestSourceObserver* observer);
23 void RemoveObserver(TestSourceObserver* observer);
25 bool HasObserver(TestSourceObserver* observer) const;
26 size_t num_observers() const { return observers_.size(); }
29 std::vector<TestSourceObserver*> observers_;
32 void TestSource::AddObserver(TestSourceObserver* observer) {
33 observers_.push_back(observer);
36 void TestSource::RemoveObserver(TestSourceObserver* observer) {
37 auto it = base::ranges::find(observers_, observer);
38 EXPECT_TRUE(it != observers_.end());
42 bool TestSource::HasObserver(TestSourceObserver* observer) const {
43 return base::Contains(observers_, observer);
46 using TestScopedObservation = ScopedObservation<TestSource, TestSourceObserver>;
50 TEST(ScopedObservationTest, RemovesObservationOnDestruction) {
54 TestSourceObserver o1;
55 TestScopedObservation obs(&o1);
56 const TestScopedObservation& cobs = obs;
57 EXPECT_EQ(0u, s1.num_observers());
58 EXPECT_FALSE(s1.HasObserver(&o1));
59 EXPECT_EQ(obs.GetSource(), nullptr);
60 EXPECT_EQ(cobs.GetSource(), nullptr);
63 EXPECT_EQ(1u, s1.num_observers());
64 EXPECT_TRUE(s1.HasObserver(&o1));
65 TestSource* const got_source = obs.GetSource();
66 EXPECT_EQ(got_source, &s1);
67 EXPECT_EQ(cobs.GetSource(), &s1);
70 // Test that the observation is removed when it goes out of scope.
71 EXPECT_EQ(0u, s1.num_observers());
74 TEST(ScopedObservationTest, Reset) {
76 TestSourceObserver o1;
77 TestScopedObservation obs(&o1);
78 const TestScopedObservation& cobs = obs;
79 EXPECT_EQ(0u, s1.num_observers());
80 EXPECT_EQ(obs.GetSource(), nullptr);
81 EXPECT_EQ(cobs.GetSource(), nullptr);
83 EXPECT_EQ(obs.GetSource(), nullptr);
84 EXPECT_EQ(cobs.GetSource(), nullptr);
87 EXPECT_EQ(1u, s1.num_observers());
88 EXPECT_TRUE(s1.HasObserver(&o1));
89 EXPECT_EQ(obs.GetSource(), &s1);
90 EXPECT_EQ(cobs.GetSource(), &s1);
93 EXPECT_EQ(0u, s1.num_observers());
94 EXPECT_EQ(obs.GetSource(), nullptr);
95 EXPECT_EQ(cobs.GetSource(), nullptr);
97 // Safe to call with no observation.
99 EXPECT_EQ(0u, s1.num_observers());
100 EXPECT_EQ(obs.GetSource(), nullptr);
101 EXPECT_EQ(cobs.GetSource(), nullptr);
104 TEST(ScopedObservationTest, IsObserving) {
106 TestSourceObserver o1;
107 TestScopedObservation obs(&o1);
108 const TestScopedObservation& cobs = obs;
109 EXPECT_FALSE(cobs.IsObserving());
110 EXPECT_EQ(obs.GetSource(), nullptr);
111 EXPECT_EQ(cobs.GetSource(), nullptr);
114 EXPECT_TRUE(cobs.IsObserving());
115 EXPECT_EQ(obs.GetSource(), &s1);
116 EXPECT_EQ(cobs.GetSource(), &s1);
119 EXPECT_FALSE(cobs.IsObserving());
120 EXPECT_EQ(obs.GetSource(), nullptr);
121 EXPECT_EQ(cobs.GetSource(), nullptr);
124 TEST(ScopedObservationTest, IsObservingSource) {
127 TestSourceObserver o1;
128 TestScopedObservation obs(&o1);
129 const TestScopedObservation& cobs = obs;
130 EXPECT_FALSE(cobs.IsObservingSource(&s1));
131 EXPECT_FALSE(cobs.IsObservingSource(&s2));
132 EXPECT_EQ(obs.GetSource(), nullptr);
133 EXPECT_EQ(cobs.GetSource(), nullptr);
136 EXPECT_TRUE(cobs.IsObservingSource(&s1));
137 EXPECT_FALSE(cobs.IsObservingSource(&s2));
138 EXPECT_EQ(obs.GetSource(), &s1);
139 EXPECT_EQ(cobs.GetSource(), &s1);
142 EXPECT_FALSE(cobs.IsObservingSource(&s1));
143 EXPECT_FALSE(cobs.IsObservingSource(&s2));
144 EXPECT_EQ(obs.GetSource(), nullptr);
145 EXPECT_EQ(cobs.GetSource(), nullptr);
150 // A test source with oddly named Add/Remove functions.
151 class TestSourceWithNonDefaultNames {
153 void AddFoo(TestSourceObserver* observer) { impl_.AddObserver(observer); }
154 void RemoveFoo(TestSourceObserver* observer) {
155 impl_.RemoveObserver(observer);
158 const TestSource& impl() const { return impl_; }
164 using TestScopedObservationWithNonDefaultNames =
165 ScopedObservation<TestSourceWithNonDefaultNames, TestSourceObserver>;
170 struct ScopedObservationTraits<TestSourceWithNonDefaultNames,
171 TestSourceObserver> {
172 static void AddObserver(TestSourceWithNonDefaultNames* source,
173 TestSourceObserver* observer) {
174 source->AddFoo(observer);
176 static void RemoveObserver(TestSourceWithNonDefaultNames* source,
177 TestSourceObserver* observer) {
178 source->RemoveFoo(observer);
182 TEST(ScopedObservationTest, NonDefaultNames) {
183 TestSourceWithNonDefaultNames s1;
184 TestSourceObserver o1;
186 EXPECT_EQ(0u, s1.impl().num_observers());
188 TestScopedObservationWithNonDefaultNames obs(&o1);
190 EXPECT_EQ(1u, s1.impl().num_observers());
191 EXPECT_TRUE(s1.impl().HasObserver(&o1));
194 EXPECT_EQ(0u, s1.impl().num_observers());
199 // A forward-declared test source.
203 class ObservationHolder : public TestSourceObserver {
205 // Declared but not defined since TestSourceFwd is not yet defined.
206 explicit ObservationHolder(TestSourceFwd* source);
209 // ScopedObservation<> is instantiated with a forward-declared parameter.
210 ScopedObservation<TestSourceFwd, TestSourceObserver> obs_{this};
213 // TestSourceFwd gets an actual definition!
214 class TestSourceFwd : public TestSource {};
216 // Calling ScopedObservation::Observe() requires an actual definition rather
217 // than just a forward declaration; make sure it compiles now that there is a
219 ObservationHolder::ObservationHolder(TestSourceFwd* source) {
220 obs_.Observe(source);
225 TEST(ScopedObservationTest, ForwardDeclaredSource) {
227 ASSERT_EQ(s.num_observers(), 0U);
229 ObservationHolder o(&s);
230 ASSERT_EQ(s.num_observers(), 1U);
232 ASSERT_EQ(s.num_observers(), 0U);
237 class TestSourceWithNonDefaultNamesFwd;
239 class ObservationWithNonDefaultNamesHolder : public TestSourceObserver {
241 // Declared but not defined since TestSourceWithNonDefaultNamesFwd is not yet
243 explicit ObservationWithNonDefaultNamesHolder(
244 TestSourceWithNonDefaultNamesFwd* source);
247 // ScopedObservation<> is instantiated with a forward-declared parameter.
248 ScopedObservation<TestSourceWithNonDefaultNamesFwd, TestSourceObserver> obs_{
252 // TestSourceWithNonDefaultNamesFwd gets an actual definition!
253 class TestSourceWithNonDefaultNamesFwd : public TestSourceWithNonDefaultNames {
258 // Now we define the corresponding traits. ScopedObservationTraits
259 // specializations must be defined in base::, since that is where the primary
260 // template definition lives.
262 struct ScopedObservationTraits<TestSourceWithNonDefaultNamesFwd,
263 TestSourceObserver> {
264 static void AddObserver(TestSourceWithNonDefaultNamesFwd* source,
265 TestSourceObserver* observer) {
266 source->AddFoo(observer);
268 static void RemoveObserver(TestSourceWithNonDefaultNamesFwd* source,
269 TestSourceObserver* observer) {
270 source->RemoveFoo(observer);
276 // Calling ScopedObservation::Observe() requires an actual definition rather
277 // than just a forward declaration; make sure it compiles now that there is
279 ObservationWithNonDefaultNamesHolder::ObservationWithNonDefaultNamesHolder(
280 TestSourceWithNonDefaultNamesFwd* source) {
281 obs_.Observe(source);
286 TEST(ScopedObservationTest, ForwardDeclaredSourceWithNonDefaultNames) {
287 TestSourceWithNonDefaultNamesFwd s;
288 ASSERT_EQ(s.impl().num_observers(), 0U);
290 ObservationWithNonDefaultNamesHolder o(&s);
291 ASSERT_EQ(s.impl().num_observers(), 1U);
293 ASSERT_EQ(s.impl().num_observers(), 0U);