OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
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 "services/preferences/public/cpp/pref_store_impl.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include "base/macros.h" | |
10 #include "base/memory/ptr_util.h" | |
11 #include "base/message_loop/message_loop.h" | |
12 #include "base/run_loop.h" | |
13 #include "base/values.h" | |
14 #include "components/prefs/value_map_pref_store.h" | |
15 #include "mojo/public/cpp/bindings/binding_set.h" | |
16 #include "services/preferences/public/cpp/pref_store_client.h" | |
17 #include "services/preferences/public/interfaces/preferences.mojom.h" | |
18 #include "testing/gmock/include/gmock/gmock.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 | |
21 using testing::Invoke; | |
22 using testing::WithoutArgs; | |
23 | |
24 namespace prefs { | |
25 namespace { | |
26 | |
27 class PrefStoreObserverMock : public PrefStore::Observer { | |
28 public: | |
29 MOCK_METHOD1(OnPrefValueChanged, void(const std::string&)); | |
30 MOCK_METHOD1(OnInitializationCompleted, void(bool succeeded)); | |
tibell
2017/03/27 03:37:56
Can drop |succeeded| here for consistency with the
Sam McNally
2017/03/27 06:44:40
Done.
| |
31 }; | |
32 | |
33 class MockPrefStore : public ValueMapPrefStore { | |
34 public: | |
35 bool IsInitializationComplete() const override { | |
36 return initialized_ && success_; | |
37 } | |
38 | |
39 void AddObserver(PrefStore::Observer* observer) override { | |
40 observers_.AddObserver(observer); | |
41 } | |
42 | |
43 void RemoveObserver(PrefStore::Observer* observer) override { | |
44 observers_.RemoveObserver(observer); | |
45 } | |
46 | |
47 void CompleteInitialization(bool success) { | |
48 initialized_ = true; | |
49 success_ = success; | |
50 for (auto& observer : observers_) { | |
51 // Some pref stores report completing initialization more than once. Test | |
52 // that additional calls are ignored. | |
53 observer.OnInitializationCompleted(success); | |
54 observer.OnInitializationCompleted(success); | |
55 } | |
56 } | |
57 | |
58 private: | |
59 ~MockPrefStore() override = default; | |
60 | |
61 bool initialized_ = false; | |
62 bool success_ = false; | |
63 base::ObserverList<PrefStore::Observer, true> observers_; | |
64 }; | |
65 | |
66 constexpr char kKey[] = "path.to.key"; | |
67 constexpr char kOtherKey[] = "path.to.other_key"; | |
68 | |
69 class PrefStoreImplTest : public testing::Test { | |
70 public: | |
71 PrefStoreImplTest() = default; | |
72 | |
73 // testing::Test: | |
74 void TearDown() override { | |
75 pref_store_ = nullptr; | |
76 base::RunLoop().RunUntilIdle(); | |
77 pref_store_ptr_.reset(); | |
78 base::RunLoop().RunUntilIdle(); | |
79 impl_.reset(); | |
80 base::RunLoop().RunUntilIdle(); | |
81 } | |
82 | |
83 void CreateImpl(scoped_refptr<PrefStore> backing_pref_store, | |
tibell
2017/03/27 03:37:56
Could this just return the PrefStore instead? Less
Sam McNally
2017/03/27 06:44:40
Different tests use different PrefStores.
| |
84 std::vector<std::string> observed_prefs = {}) { | |
85 impl_ = base::MakeUnique<PrefStoreImpl>( | |
86 std::move(backing_pref_store), mojo::MakeRequest(&pref_store_ptr_)); | |
87 | |
88 if (observed_prefs.empty()) | |
89 observed_prefs.insert(observed_prefs.end(), {kKey, kOtherKey}); | |
90 pref_store_ = CreateConnection(std::move(observed_prefs)); | |
91 } | |
92 | |
93 scoped_refptr<PrefStore> CreateConnection( | |
94 std::vector<std::string> observed_prefs) { | |
95 base::RunLoop run_loop; | |
96 mojom::PrefStoreConnectionPtr connection; | |
97 pref_store_ptr_->AddObserver( | |
98 observed_prefs, | |
99 base::Bind( | |
100 [](mojom::PrefStoreConnectionPtr* output, base::OnceClosure quit, | |
101 mojom::PrefStoreConnectionPtr connection) { | |
102 std::move(quit).Run(); | |
103 *output = std::move(connection); | |
104 }, | |
105 &connection, run_loop.QuitClosure())); | |
106 run_loop.Run(); | |
107 return make_scoped_refptr(new PrefStoreClient(std::move(connection))); | |
108 } | |
109 | |
110 PrefStore* pref_store() { return pref_store_.get(); } | |
111 | |
112 private: | |
113 base::MessageLoop message_loop_; | |
114 | |
115 std::unique_ptr<PrefStoreImpl> impl_; | |
116 mojom::PrefStorePtr pref_store_ptr_; | |
117 | |
118 scoped_refptr<PrefStore> pref_store_; | |
119 | |
120 DISALLOW_COPY_AND_ASSIGN(PrefStoreImplTest); | |
121 }; | |
122 | |
123 TEST_F(PrefStoreImplTest, InitializationSuccess) { | |
124 auto backing_pref_store = make_scoped_refptr(new MockPrefStore()); | |
125 CreateImpl(backing_pref_store); | |
126 EXPECT_FALSE(pref_store()->IsInitializationComplete()); | |
127 | |
128 backing_pref_store->CompleteInitialization(true); | |
129 PrefStoreObserverMock observer; | |
130 pref_store()->AddObserver(&observer); | |
131 base::RunLoop run_loop; | |
132 EXPECT_CALL(observer, OnInitializationCompleted(true)) | |
133 .Times(1) | |
tibell
2017/03/27 03:37:56
Times(1) is the default so you can remove.
Sam McNally
2017/03/27 06:44:40
Done.
| |
134 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); | |
135 run_loop.Run(); | |
136 pref_store()->RemoveObserver(&observer); | |
137 EXPECT_TRUE(pref_store()->IsInitializationComplete()); | |
138 } | |
139 | |
140 TEST_F(PrefStoreImplTest, InitializationFailure) { | |
141 auto backing_pref_store = make_scoped_refptr(new MockPrefStore()); | |
142 CreateImpl(backing_pref_store); | |
143 EXPECT_FALSE(pref_store()->IsInitializationComplete()); | |
144 | |
145 backing_pref_store->CompleteInitialization(false); | |
146 PrefStoreObserverMock observer; | |
147 pref_store()->AddObserver(&observer); | |
148 base::RunLoop run_loop; | |
149 EXPECT_CALL(observer, OnInitializationCompleted(false)) | |
150 .Times(1) | |
tibell
2017/03/27 03:37:56
ditto
Sam McNally
2017/03/27 06:44:41
Done.
| |
151 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); | |
152 run_loop.Run(); | |
153 pref_store()->RemoveObserver(&observer); | |
154 | |
155 // TODO(sammc): Should IsInitializationComplete() return false? | |
156 EXPECT_TRUE(pref_store()->IsInitializationComplete()); | |
157 } | |
158 | |
159 TEST_F(PrefStoreImplTest, InitialValue) { | |
160 auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore()); | |
161 const base::Value value("value"); | |
162 backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0); | |
163 CreateImpl(backing_pref_store); | |
164 ASSERT_TRUE(pref_store()->IsInitializationComplete()); | |
tibell
2017/03/27 03:37:56
Maybe add a TODO here too to check what the backin
Sam McNally
2017/03/27 06:44:41
As discussed, this isn't testing that the presence
| |
165 const base::Value* output = nullptr; | |
166 ASSERT_TRUE(pref_store()->GetValue(kKey, &output)); | |
167 EXPECT_TRUE(value.Equals(output)); | |
168 } | |
169 | |
170 TEST_F(PrefStoreImplTest, InitialValueWithoutPathExpansion) { | |
171 auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore()); | |
172 base::DictionaryValue dict; | |
173 dict.SetStringWithoutPathExpansion(kKey, "value"); | |
174 backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0); | |
175 CreateImpl(backing_pref_store); | |
176 ASSERT_TRUE(pref_store()->IsInitializationComplete()); | |
177 const base::Value* output = nullptr; | |
178 ASSERT_TRUE(pref_store()->GetValue(kKey, &output)); | |
179 EXPECT_TRUE(dict.Equals(output)); | |
180 } | |
181 | |
182 TEST_F(PrefStoreImplTest, WriteObservedByClient) { | |
183 auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore()); | |
184 CreateImpl(backing_pref_store); | |
185 ASSERT_TRUE(pref_store()->IsInitializationComplete()); | |
186 | |
187 const base::Value value("value"); | |
188 backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0); | |
189 | |
190 PrefStoreObserverMock observer; | |
191 pref_store()->AddObserver(&observer); | |
192 base::RunLoop run_loop; | |
193 EXPECT_CALL(observer, OnPrefValueChanged(kKey)) | |
tibell
2017/03/27 03:37:56
Could this be lifted out into a
ExpectPrefChange(
Sam McNally
2017/03/27 06:44:40
Done.
| |
194 .Times(1) | |
tibell
2017/03/27 03:37:56
Remove
Sam McNally
2017/03/27 06:44:40
Done.
| |
195 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); | |
196 run_loop.Run(); | |
197 pref_store()->RemoveObserver(&observer); | |
198 | |
199 const base::Value* output = nullptr; | |
200 ASSERT_TRUE(pref_store()->GetValue(kKey, &output)); | |
201 EXPECT_TRUE(value.Equals(output)); | |
202 } | |
203 | |
204 TEST_F(PrefStoreImplTest, WriteToUnregisteredPrefNotObservedByClient) { | |
205 auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore()); | |
206 CreateImpl(backing_pref_store, {kKey}); | |
207 ASSERT_TRUE(pref_store()->IsInitializationComplete()); | |
208 | |
209 backing_pref_store->SetValue(kOtherKey, base::MakeUnique<base::Value>(123), | |
210 0); | |
211 backing_pref_store->SetValue(kKey, base::MakeUnique<base::Value>("value"), 0); | |
212 | |
213 PrefStoreObserverMock observer; | |
214 pref_store()->AddObserver(&observer); | |
215 base::RunLoop run_loop; | |
216 EXPECT_CALL(observer, OnPrefValueChanged(kOtherKey)).Times(0); | |
217 EXPECT_CALL(observer, OnPrefValueChanged(kKey)) | |
218 .Times(1) | |
tibell
2017/03/27 03:37:56
Remove
Sam McNally
2017/03/27 06:44:41
Done.
| |
219 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); | |
220 run_loop.Run(); | |
221 pref_store()->RemoveObserver(&observer); | |
222 | |
223 EXPECT_FALSE(pref_store()->GetValue(kOtherKey, nullptr)); | |
224 } | |
225 | |
226 TEST_F(PrefStoreImplTest, WriteWithoutPathExpansionObservedByClient) { | |
227 auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore()); | |
228 CreateImpl(backing_pref_store); | |
229 ASSERT_TRUE(pref_store()->IsInitializationComplete()); | |
230 | |
231 base::DictionaryValue dict; | |
232 dict.SetStringWithoutPathExpansion(kKey, "value"); | |
233 backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0); | |
234 | |
235 PrefStoreObserverMock observer; | |
236 pref_store()->AddObserver(&observer); | |
237 base::RunLoop run_loop; | |
238 EXPECT_CALL(observer, OnPrefValueChanged(kKey)) | |
239 .Times(1) | |
tibell
2017/03/27 03:37:56
Remove
Sam McNally
2017/03/27 06:44:40
Done.
| |
240 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); | |
241 run_loop.Run(); | |
242 pref_store()->RemoveObserver(&observer); | |
243 | |
244 const base::Value* output = nullptr; | |
245 ASSERT_TRUE(pref_store()->GetValue(kKey, &output)); | |
246 EXPECT_TRUE(dict.Equals(output)); | |
247 } | |
248 | |
249 TEST_F(PrefStoreImplTest, RemoveObservedByClient) { | |
250 auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore()); | |
251 const base::Value value("value"); | |
252 backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0); | |
253 CreateImpl(backing_pref_store); | |
254 ASSERT_TRUE(pref_store()->IsInitializationComplete()); | |
255 | |
256 const base::Value* output = nullptr; | |
257 ASSERT_TRUE(pref_store()->GetValue(kKey, &output)); | |
258 EXPECT_TRUE(value.Equals(output)); | |
259 backing_pref_store->RemoveValue(kKey, 0); | |
260 | |
261 // This should be a no-op and shouldn't trigger a notification for the other | |
262 // client. | |
263 backing_pref_store->RemoveValue(kKey, 0); | |
264 | |
265 PrefStoreObserverMock observer; | |
266 pref_store()->AddObserver(&observer); | |
267 base::RunLoop run_loop; | |
268 EXPECT_CALL(observer, OnPrefValueChanged(kKey)) | |
269 .Times(1) | |
tibell
2017/03/27 03:37:56
Remove
Sam McNally
2017/03/27 06:44:41
Done.
| |
270 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); | |
271 run_loop.Run(); | |
272 base::RunLoop().RunUntilIdle(); | |
273 pref_store()->RemoveObserver(&observer); | |
274 | |
275 EXPECT_FALSE(pref_store()->GetValue(kKey, &output)); | |
276 } | |
277 | |
278 TEST_F(PrefStoreImplTest, RemoveOfUnregisteredPrefNotObservedByClient) { | |
279 auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore()); | |
280 const base::Value value("value"); | |
281 backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0); | |
282 backing_pref_store->SetValue(kOtherKey, value.CreateDeepCopy(), 0); | |
283 CreateImpl(backing_pref_store, {kKey}); | |
284 ASSERT_TRUE(pref_store()->IsInitializationComplete()); | |
285 | |
286 backing_pref_store->RemoveValue(kOtherKey, 0); | |
287 backing_pref_store->RemoveValue(kKey, 0); | |
288 | |
289 PrefStoreObserverMock observer; | |
290 pref_store()->AddObserver(&observer); | |
291 base::RunLoop run_loop; | |
292 EXPECT_CALL(observer, OnPrefValueChanged(kOtherKey)).Times(0); | |
293 EXPECT_CALL(observer, OnPrefValueChanged(kKey)) | |
294 .Times(1) | |
tibell
2017/03/27 03:37:56
Remove
Sam McNally
2017/03/27 06:44:40
Done.
| |
295 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); | |
296 run_loop.Run(); | |
297 pref_store()->RemoveObserver(&observer); | |
298 } | |
299 | |
300 TEST_F(PrefStoreImplTest, RemoveWithoutPathExpansionObservedByOtherClient) { | |
301 auto backing_pref_store = make_scoped_refptr(new ValueMapPrefStore()); | |
302 base::DictionaryValue dict; | |
303 dict.SetStringWithoutPathExpansion(kKey, "value"); | |
304 backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0); | |
305 CreateImpl(backing_pref_store); | |
306 ASSERT_TRUE(pref_store()->IsInitializationComplete()); | |
307 | |
308 const base::Value* output = nullptr; | |
309 ASSERT_TRUE(pref_store()->GetValue(kKey, &output)); | |
310 EXPECT_TRUE(dict.Equals(output)); | |
311 | |
312 base::Value* mutable_value = nullptr; | |
313 dict.SetStringWithoutPathExpansion(kKey, "value"); | |
314 ASSERT_TRUE(backing_pref_store->GetMutableValue(kKey, &mutable_value)); | |
315 base::DictionaryValue* mutable_dict = nullptr; | |
316 ASSERT_TRUE(mutable_value->GetAsDictionary(&mutable_dict)); | |
317 mutable_dict->RemoveWithoutPathExpansion(kKey, nullptr); | |
318 backing_pref_store->ReportValueChanged(kKey, 0); | |
319 | |
320 PrefStoreObserverMock observer; | |
321 pref_store()->AddObserver(&observer); | |
322 base::RunLoop run_loop; | |
323 EXPECT_CALL(observer, OnPrefValueChanged(kKey)) | |
324 .Times(1) | |
tibell
2017/03/27 03:37:56
Remove
Sam McNally
2017/03/27 06:44:40
Done.
| |
325 .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); }))); | |
326 run_loop.Run(); | |
327 pref_store()->RemoveObserver(&observer); | |
328 | |
329 ASSERT_TRUE(pref_store()->GetValue(kKey, &output)); | |
330 const base::DictionaryValue* dict_value = nullptr; | |
331 ASSERT_TRUE(output->GetAsDictionary(&dict_value)); | |
332 EXPECT_TRUE(dict_value->empty()); | |
333 } | |
334 | |
335 } // namespace | |
336 } // namespace prefs | |
OLD | NEW |