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 "base/test/gtest_util.h"
11 #include "testing/gtest/include/gtest/gtest.h"
16 class TestSourceObserver {
18 virtual ~TestSourceObserver() = default;
23 void AddObserver(TestSourceObserver* observer);
24 void RemoveObserver(TestSourceObserver* observer);
26 bool HasObserver(TestSourceObserver* observer) const;
27 size_t num_observers() const { return observers_.size(); }
30 std::vector<TestSourceObserver*> observers_;
33 void TestSource::AddObserver(TestSourceObserver* observer) {
34 observers_.push_back(observer);
37 void TestSource::RemoveObserver(TestSourceObserver* observer) {
38 auto it = base::ranges::find(observers_, observer);
39 EXPECT_TRUE(it != observers_.end());
43 bool TestSource::HasObserver(TestSourceObserver* observer) const {
44 return base::Contains(observers_, observer);
47 using TestScopedObservation = ScopedObservation<TestSource, TestSourceObserver>;
51 TEST(ScopedObservationTest, RemovesObservationOnDestruction) {
55 TestSourceObserver o1;
56 TestScopedObservation obs(&o1);
57 EXPECT_EQ(0u, s1.num_observers());
58 EXPECT_FALSE(s1.HasObserver(&o1));
61 EXPECT_EQ(1u, s1.num_observers());
62 EXPECT_TRUE(s1.HasObserver(&o1));
65 // Test that the observation is removed when it goes out of scope.
66 EXPECT_EQ(0u, s1.num_observers());
69 TEST(ScopedObservationTest, Reset) {
71 TestSourceObserver o1;
72 TestScopedObservation obs(&o1);
73 EXPECT_EQ(0u, s1.num_observers());
77 EXPECT_EQ(1u, s1.num_observers());
78 EXPECT_TRUE(s1.HasObserver(&o1));
81 EXPECT_EQ(0u, s1.num_observers());
83 // Safe to call with no observation.
85 EXPECT_EQ(0u, s1.num_observers());
88 TEST(ScopedObservationTest, IsObserving) {
90 TestSourceObserver o1;
91 TestScopedObservation obs(&o1);
92 EXPECT_FALSE(obs.IsObserving());
95 EXPECT_TRUE(obs.IsObserving());
98 EXPECT_FALSE(obs.IsObserving());
101 TEST(ScopedObservationTest, IsObservingSource) {
104 TestSourceObserver o1;
105 TestScopedObservation obs(&o1);
106 EXPECT_FALSE(obs.IsObservingSource(&s1));
107 EXPECT_FALSE(obs.IsObservingSource(&s2));
110 EXPECT_TRUE(obs.IsObservingSource(&s1));
111 EXPECT_FALSE(obs.IsObservingSource(&s2));
114 EXPECT_FALSE(obs.IsObservingSource(&s1));
115 EXPECT_FALSE(obs.IsObservingSource(&s2));
120 // A test source with oddly named Add/Remove functions.
121 class TestSourceWithNonDefaultNames {
123 void AddFoo(TestSourceObserver* observer) { impl_.AddObserver(observer); }
124 void RemoveFoo(TestSourceObserver* observer) {
125 impl_.RemoveObserver(observer);
128 const TestSource& impl() const { return impl_; }
134 using TestScopedObservationWithNonDefaultNames =
135 ScopedObservation<TestSourceWithNonDefaultNames, TestSourceObserver>;
140 struct ScopedObservationTraits<TestSourceWithNonDefaultNames,
141 TestSourceObserver> {
142 static void AddObserver(TestSourceWithNonDefaultNames* source,
143 TestSourceObserver* observer) {
144 source->AddFoo(observer);
146 static void RemoveObserver(TestSourceWithNonDefaultNames* source,
147 TestSourceObserver* observer) {
148 source->RemoveFoo(observer);
152 TEST(ScopedObservationTest, NonDefaultNames) {
153 TestSourceWithNonDefaultNames s1;
154 TestSourceObserver o1;
156 EXPECT_EQ(0u, s1.impl().num_observers());
158 TestScopedObservationWithNonDefaultNames obs(&o1);
160 EXPECT_EQ(1u, s1.impl().num_observers());
161 EXPECT_TRUE(s1.impl().HasObserver(&o1));
164 EXPECT_EQ(0u, s1.impl().num_observers());
169 // A forward-declared test source.
173 class ObservationHolder : public TestSourceObserver {
175 // Declared but not defined since TestSourceFwd is not yet defined.
176 explicit ObservationHolder(TestSourceFwd* source);
179 // ScopedObservation<> is instantiated with a forward-declared parameter.
180 ScopedObservation<TestSourceFwd, TestSourceObserver> obs_{this};
183 // TestSourceFwd gets an actual definition!
184 class TestSourceFwd : public TestSource {};
186 // Calling ScopedObservation::Observe() requires an actual definition rather
187 // than just a forward declaration; make sure it compiles now that there is a
189 ObservationHolder::ObservationHolder(TestSourceFwd* source) {
190 obs_.Observe(source);
195 TEST(ScopedObservationTest, ForwardDeclaredSource) {
197 ASSERT_EQ(s.num_observers(), 0U);
199 ObservationHolder o(&s);
200 ASSERT_EQ(s.num_observers(), 1U);
202 ASSERT_EQ(s.num_observers(), 0U);
207 class TestSourceWithNonDefaultNamesFwd;
209 class ObservationWithNonDefaultNamesHolder : public TestSourceObserver {
211 // Declared but not defined since TestSourceWithNonDefaultNamesFwd is not yet
213 explicit ObservationWithNonDefaultNamesHolder(
214 TestSourceWithNonDefaultNamesFwd* source);
217 // ScopedObservation<> is instantiated with a forward-declared parameter.
218 ScopedObservation<TestSourceWithNonDefaultNamesFwd, TestSourceObserver> obs_{
222 // TestSourceWithNonDefaultNamesFwd gets an actual definition!
223 class TestSourceWithNonDefaultNamesFwd : public TestSourceWithNonDefaultNames {
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.
232 struct ScopedObservationTraits<TestSourceWithNonDefaultNamesFwd,
233 TestSourceObserver> {
234 static void AddObserver(TestSourceWithNonDefaultNamesFwd* source,
235 TestSourceObserver* observer) {
236 source->AddFoo(observer);
238 static void RemoveObserver(TestSourceWithNonDefaultNamesFwd* source,
239 TestSourceObserver* observer) {
240 source->RemoveFoo(observer);
246 // Calling ScopedObservation::Observe() requires an actual definition rather
247 // than just a forward declaration; make sure it compiles now that there is
249 ObservationWithNonDefaultNamesHolder::ObservationWithNonDefaultNamesHolder(
250 TestSourceWithNonDefaultNamesFwd* source) {
251 obs_.Observe(source);
256 TEST(ScopedObservationTest, ForwardDeclaredSourceWithNonDefaultNames) {
257 TestSourceWithNonDefaultNamesFwd s;
258 ASSERT_EQ(s.impl().num_observers(), 0U);
260 ObservationWithNonDefaultNamesHolder o(&s);
261 ASSERT_EQ(s.impl().num_observers(), 1U);
263 ASSERT_EQ(s.impl().num_observers(), 0U);