blob: b73f2fc1c5f565553ef3fa8c803bdda8c4cf2db1 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2020 The Chromium Authors
Sigurdur Asgeirsson1a164fd2020-11-05 20:13:172// 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
Peter Kasting025a94252025-01-29 21:28:377#include <algorithm>
8
Jan Wilken Dörrieb5a41c32020-12-09 18:55:479#include "base/containers/contains.h"
Ali Hijazie63cbaf62023-12-20 19:29:3510#include "base/memory/raw_ptr.h"
Andrew Rayskiy3cf073392022-11-11 00:31:4911#include "base/scoped_observation_traits.h"
Sigurdur Asgeirsson1a164fd2020-11-05 20:13:1712#include "base/test/gtest_util.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15namespace base {
16namespace {
17
18class TestSourceObserver {};
19
20class TestSource {
21 public:
22 void AddObserver(TestSourceObserver* observer);
23 void RemoveObserver(TestSourceObserver* observer);
24
25 bool HasObserver(TestSourceObserver* observer) const;
26 size_t num_observers() const { return observers_.size(); }
27
28 private:
Ali Hijazie63cbaf62023-12-20 19:29:3529 std::vector<raw_ptr<TestSourceObserver, VectorExperimental>> observers_;
Sigurdur Asgeirsson1a164fd2020-11-05 20:13:1730};
31
32void TestSource::AddObserver(TestSourceObserver* observer) {
33 observers_.push_back(observer);
34}
35
36void TestSource::RemoveObserver(TestSourceObserver* observer) {
Peter Kasting025a94252025-01-29 21:28:3737 auto it = std::ranges::find(observers_, observer);
Sigurdur Asgeirsson1a164fd2020-11-05 20:13:1738 ASSERT_TRUE(it != observers_.end());
39 observers_.erase(it);
40}
41
42bool TestSource::HasObserver(TestSourceObserver* observer) const {
43 return base::Contains(observers_, observer);
44}
45
46using TestScopedMultiSourceObservation =
47 ScopedMultiSourceObservation<TestSource, TestSourceObserver>;
48
49class ScopedMultiSourceObservationTest : public testing::Test {
50 public:
51 TestSource* s1() { return &s1_; }
52 TestSource* s2() { return &s2_; }
53 TestSourceObserver* o1() { return &o1_; }
54
55 private:
56 TestSource s1_;
57 TestSource s2_;
58 TestSourceObserver o1_;
59};
60
61} // namespace
62
63TEST_F(ScopedMultiSourceObservationTest, RemovesSourcesOnDestruction) {
64 {
65 TestScopedMultiSourceObservation obs(o1());
66 EXPECT_EQ(0u, s1()->num_observers());
67 EXPECT_FALSE(s1()->HasObserver(o1()));
68
69 obs.AddObservation(s1());
70 EXPECT_EQ(1u, s1()->num_observers());
71 EXPECT_TRUE(s1()->HasObserver(o1()));
72
73 obs.AddObservation(s2());
74 EXPECT_EQ(1u, s2()->num_observers());
75 EXPECT_TRUE(s2()->HasObserver(o1()));
76 }
77
78 // Test that all observations are removed when it goes out of scope.
79 EXPECT_EQ(0u, s1()->num_observers());
80 EXPECT_EQ(0u, s2()->num_observers());
81}
82
83TEST_F(ScopedMultiSourceObservationTest, RemoveObservation) {
84 TestScopedMultiSourceObservation obs(o1());
85 EXPECT_EQ(0u, s1()->num_observers());
86 EXPECT_FALSE(s1()->HasObserver(o1()));
87 EXPECT_EQ(0u, s2()->num_observers());
88 EXPECT_FALSE(s2()->HasObserver(o1()));
89
90 obs.AddObservation(s1());
91 EXPECT_EQ(1u, s1()->num_observers());
92 EXPECT_TRUE(s1()->HasObserver(o1()));
93
94 obs.AddObservation(s2());
95 EXPECT_EQ(1u, s2()->num_observers());
96 EXPECT_TRUE(s2()->HasObserver(o1()));
97
98 obs.RemoveObservation(s1());
99 EXPECT_EQ(0u, s1()->num_observers());
100 EXPECT_FALSE(s1()->HasObserver(o1()));
101 EXPECT_EQ(1u, s2()->num_observers());
102 EXPECT_TRUE(s2()->HasObserver(o1()));
103
104 obs.RemoveObservation(s2());
105 EXPECT_EQ(0u, s1()->num_observers());
106 EXPECT_FALSE(s1()->HasObserver(o1()));
107 EXPECT_EQ(0u, s2()->num_observers());
108 EXPECT_FALSE(s2()->HasObserver(o1()));
109}
110
111TEST_F(ScopedMultiSourceObservationTest, RemoveAllObservations) {
112 TestScopedMultiSourceObservation obs(o1());
113 EXPECT_EQ(0u, s1()->num_observers());
114 EXPECT_FALSE(s1()->HasObserver(o1()));
115 EXPECT_EQ(0u, s2()->num_observers());
116 EXPECT_FALSE(s2()->HasObserver(o1()));
117
118 obs.AddObservation(s1());
119 obs.AddObservation(s2());
120 EXPECT_EQ(1u, s1()->num_observers());
121 EXPECT_TRUE(s1()->HasObserver(o1()));
122 EXPECT_EQ(1u, s2()->num_observers());
123 EXPECT_TRUE(s2()->HasObserver(o1()));
124
125 obs.RemoveAllObservations();
126 EXPECT_EQ(0u, s1()->num_observers());
127 EXPECT_FALSE(s1()->HasObserver(o1()));
128 EXPECT_EQ(0u, s2()->num_observers());
129 EXPECT_FALSE(s2()->HasObserver(o1()));
130}
131
132TEST_F(ScopedMultiSourceObservationTest, IsObservingSource) {
133 TestScopedMultiSourceObservation obs(o1());
134 EXPECT_FALSE(obs.IsObservingSource(s1()));
135 EXPECT_FALSE(obs.IsObservingSource(s2()));
136
137 obs.AddObservation(s1());
138 EXPECT_TRUE(obs.IsObservingSource(s1()));
139 EXPECT_FALSE(obs.IsObservingSource(s2()));
140
141 obs.AddObservation(s2());
142 EXPECT_TRUE(obs.IsObservingSource(s1()));
143 EXPECT_TRUE(obs.IsObservingSource(s2()));
144
145 obs.RemoveObservation(s1());
146 EXPECT_FALSE(obs.IsObservingSource(s1()));
147 EXPECT_TRUE(obs.IsObservingSource(s2()));
148}
149
150TEST_F(ScopedMultiSourceObservationTest, IsObservingAnySource) {
151 TestScopedMultiSourceObservation obs(o1());
152 EXPECT_FALSE(obs.IsObservingAnySource());
153
154 obs.AddObservation(s1());
155 EXPECT_TRUE(obs.IsObservingAnySource());
156
157 obs.AddObservation(s2());
158 EXPECT_TRUE(obs.IsObservingAnySource());
159
160 obs.RemoveAllObservations();
161 EXPECT_FALSE(obs.IsObservingAnySource());
162}
163
164TEST_F(ScopedMultiSourceObservationTest, GetSourcesCount) {
165 TestScopedMultiSourceObservation obs(o1());
166 EXPECT_EQ(0u, obs.GetSourcesCount());
167
168 obs.AddObservation(s1());
169 EXPECT_EQ(1u, obs.GetSourcesCount());
170
171 obs.AddObservation(s2());
172 EXPECT_EQ(2u, obs.GetSourcesCount());
173
174 obs.RemoveAllObservations();
175 EXPECT_EQ(0u, obs.GetSourcesCount());
176}
177
178namespace {
179
180// A test source with oddly named Add/Remove functions.
181class TestSourceWithNonDefaultNames {
182 public:
183 void AddFoo(TestSourceObserver* observer) { impl_.AddObserver(observer); }
184 void RemoveFoo(TestSourceObserver* observer) {
185 impl_.RemoveObserver(observer);
186 }
187
188 const TestSource& impl() const { return impl_; }
189
190 private:
191 TestSource impl_;
192};
193
194using TestScopedMultiSourceObservationWithNonDefaultNames =
195 ScopedMultiSourceObservation<TestSourceWithNonDefaultNames,
Andrew Rayskiy3cf073392022-11-11 00:31:49196 TestSourceObserver>;
Sigurdur Asgeirsson1a164fd2020-11-05 20:13:17197
198} // namespace
199
Andrew Rayskiy3cf073392022-11-11 00:31:49200template <>
201struct ScopedObservationTraits<TestSourceWithNonDefaultNames,
202 TestSourceObserver> {
203 static void AddObserver(TestSourceWithNonDefaultNames* source,
204 TestSourceObserver* observer) {
205 source->AddFoo(observer);
206 }
207 static void RemoveObserver(TestSourceWithNonDefaultNames* source,
208 TestSourceObserver* observer) {
209 source->RemoveFoo(observer);
210 }
211};
212
Sigurdur Asgeirsson1a164fd2020-11-05 20:13:17213TEST_F(ScopedMultiSourceObservationTest, NonDefaultNames) {
214 TestSourceWithNonDefaultNames nds1;
215
216 EXPECT_EQ(0u, nds1.impl().num_observers());
217 {
218 TestScopedMultiSourceObservationWithNonDefaultNames obs(o1());
219 obs.AddObservation(&nds1);
220 EXPECT_EQ(1u, nds1.impl().num_observers());
221 EXPECT_TRUE(nds1.impl().HasObserver(o1()));
222 }
223
224 EXPECT_EQ(0u, nds1.impl().num_observers());
225}
226
227} // namespace base