1 // Copyright (c) 2011 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.
5 #include "components/sync_preferences/pref_model_associator.h"
9 #include "base/macros.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/values.h"
13 #include "components/prefs/scoped_user_pref_update.h"
14 #include "components/prefs/testing_pref_store.h"
15 #include "components/sync_preferences/pref_model_associator_client.h"
16 #include "components/sync_preferences/pref_service_mock_factory.h"
17 #include "components/sync_preferences/pref_service_syncable.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 namespace sync_preferences {
24 const char kStringPrefName[] = "pref.string";
25 const char kListPrefName[] = "pref.list";
26 const char kDictionaryPrefName[] = "pref.dictionary";
27 const char kCustomMergePrefName[] = "pref.custom";
29 class TestPrefModelAssociatorClient : public PrefModelAssociatorClient {
31 TestPrefModelAssociatorClient() {}
32 ~TestPrefModelAssociatorClient() override {}
34 // PrefModelAssociatorClient implementation.
35 bool IsMergeableListPreference(const std::string& pref_name) const override {
36 return pref_name == kListPrefName;
39 bool IsMergeableDictionaryPreference(
40 const std::string& pref_name) const override {
41 return pref_name == kDictionaryPrefName;
44 std::unique_ptr<base::Value> MaybeMergePreferenceValues(
45 const std::string& pref_name,
46 const base::Value& local_value,
47 const base::Value& server_value) const override {
48 if (pref_name == kCustomMergePrefName) {
49 return base::WrapUnique(local_value.DeepCopy());
55 DISALLOW_COPY_AND_ASSIGN(TestPrefModelAssociatorClient);
58 class AbstractPreferenceMergeTest : public testing::Test {
60 AbstractPreferenceMergeTest()
61 : user_prefs_(base::MakeRefCounted<TestingPrefStore>()) {
62 PrefServiceMockFactory factory;
63 factory.SetPrefModelAssociatorClient(&client_);
64 factory.set_user_prefs(user_prefs_);
65 scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry(
66 new user_prefs::PrefRegistrySyncable);
67 pref_registry->RegisterStringPref(
68 kStringPrefName, std::string(),
69 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
70 pref_registry->RegisterListPref(
71 kListPrefName, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
72 pref_registry->RegisterDictionaryPref(
73 kDictionaryPrefName, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
74 pref_service_ = factory.CreateSyncable(pref_registry.get());
75 pref_registry->RegisterStringPref(
76 kCustomMergePrefName, std::string(),
77 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
78 pref_sync_service_ = static_cast<PrefModelAssociator*>(
79 pref_service_->GetSyncableService(syncer::PREFERENCES));
82 void SetContentPattern(base::Value* patterns_dict,
83 const std::string& expression,
85 base::Value* expression_dict =
86 patterns_dict->FindKeyOfType(expression, base::Value::Type::DICTIONARY);
87 if (!expression_dict) {
88 expression_dict = patterns_dict->SetKey(
89 expression, base::Value(base::Value::Type::DICTIONARY));
91 expression_dict->SetKey("setting", base::Value(setting));
94 void SetPrefToEmpty(const std::string& pref_name) {
95 std::unique_ptr<base::Value> empty_value;
96 const PrefService::Preference* pref =
97 pref_service_->FindPreference(pref_name.c_str());
99 base::Value::Type type = pref->GetType();
100 if (type == base::Value::Type::DICTIONARY)
101 empty_value.reset(new base::DictionaryValue);
102 else if (type == base::Value::Type::LIST)
103 empty_value.reset(new base::ListValue);
106 pref_service_->Set(pref_name.c_str(), *empty_value);
109 TestPrefModelAssociatorClient client_;
110 scoped_refptr<TestingPrefStore> user_prefs_;
111 std::unique_ptr<PrefServiceSyncable> pref_service_;
112 PrefModelAssociator* pref_sync_service_;
115 using CustomPreferenceMergeTest = AbstractPreferenceMergeTest;
117 TEST_F(CustomPreferenceMergeTest, ClientMergesCustomPreference) {
118 pref_service_->SetString(kCustomMergePrefName, "local");
119 const PrefService::Preference* pref =
120 pref_service_->FindPreference(kCustomMergePrefName);
121 std::unique_ptr<base::Value> local_value =
122 base::WrapUnique(pref->GetValue()->DeepCopy());
123 std::unique_ptr<base::Value> server_value(new base::Value("server"));
124 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
125 pref->name(), *pref->GetValue(), *server_value));
126 // TestPrefModelAssociatorClient should have chosen local value instead of the
127 // default server value.
128 EXPECT_TRUE(merged_value->Equals(local_value.get()));
131 class ListPreferenceMergeTest : public AbstractPreferenceMergeTest {
133 ListPreferenceMergeTest()
134 : server_url0_("http://example.com/server0"),
135 server_url1_("http://example.com/server1"),
136 local_url0_("http://example.com/local0"),
137 local_url1_("http://example.com/local1") {
138 server_url_list_.AppendString(server_url0_);
139 server_url_list_.AppendString(server_url1_);
142 std::string server_url0_;
143 std::string server_url1_;
144 std::string local_url0_;
145 std::string local_url1_;
146 base::ListValue server_url_list_;
149 TEST_F(ListPreferenceMergeTest, NotListOrDictionary) {
150 pref_service_->SetString(kStringPrefName, local_url0_);
151 const PrefService::Preference* pref =
152 pref_service_->FindPreference(kStringPrefName);
153 std::unique_ptr<base::Value> server_value(new base::Value(server_url0_));
154 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
155 pref->name(), *pref->GetValue(), *server_value));
156 EXPECT_TRUE(merged_value->Equals(server_value.get()));
159 TEST_F(ListPreferenceMergeTest, LocalEmpty) {
160 SetPrefToEmpty(kListPrefName);
161 const PrefService::Preference* pref =
162 pref_service_->FindPreference(kListPrefName);
163 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
164 pref->name(), *pref->GetValue(), server_url_list_));
165 EXPECT_TRUE(merged_value->Equals(&server_url_list_));
168 TEST_F(ListPreferenceMergeTest, ServerNull) {
169 auto null_value = std::make_unique<base::Value>();
171 ListPrefUpdate update(pref_service_.get(), kListPrefName);
172 base::ListValue* local_list_value = update.Get();
173 local_list_value->AppendString(local_url0_);
176 const PrefService::Preference* pref =
177 pref_service_->FindPreference(kListPrefName);
178 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
179 pref->name(), *pref->GetValue(), *null_value));
180 const base::ListValue* local_list_value =
181 pref_service_->GetList(kListPrefName);
182 EXPECT_TRUE(merged_value->Equals(local_list_value));
185 TEST_F(ListPreferenceMergeTest, ServerEmpty) {
186 std::unique_ptr<base::Value> empty_value(new base::ListValue);
188 ListPrefUpdate update(pref_service_.get(), kListPrefName);
189 base::ListValue* local_list_value = update.Get();
190 local_list_value->AppendString(local_url0_);
193 const PrefService::Preference* pref =
194 pref_service_->FindPreference(kListPrefName);
195 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
196 pref->name(), *pref->GetValue(), *empty_value));
197 const base::ListValue* local_list_value =
198 pref_service_->GetList(kListPrefName);
199 EXPECT_TRUE(merged_value->Equals(local_list_value));
202 TEST_F(ListPreferenceMergeTest, Merge) {
204 ListPrefUpdate update(pref_service_.get(), kListPrefName);
205 base::ListValue* local_list_value = update.Get();
206 local_list_value->AppendString(local_url0_);
207 local_list_value->AppendString(local_url1_);
210 const PrefService::Preference* pref =
211 pref_service_->FindPreference(kListPrefName);
212 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
213 pref->name(), *pref->GetValue(), server_url_list_));
215 base::ListValue expected;
216 expected.AppendString(server_url0_);
217 expected.AppendString(server_url1_);
218 expected.AppendString(local_url0_);
219 expected.AppendString(local_url1_);
220 EXPECT_TRUE(merged_value->Equals(&expected));
223 TEST_F(ListPreferenceMergeTest, Duplicates) {
225 ListPrefUpdate update(pref_service_.get(), kListPrefName);
226 base::ListValue* local_list_value = update.Get();
227 local_list_value->AppendString(local_url0_);
228 local_list_value->AppendString(server_url0_);
229 local_list_value->AppendString(server_url1_);
232 const PrefService::Preference* pref =
233 pref_service_->FindPreference(kListPrefName);
234 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
235 pref->name(), *pref->GetValue(), server_url_list_));
237 base::ListValue expected;
238 expected.AppendString(server_url0_);
239 expected.AppendString(server_url1_);
240 expected.AppendString(local_url0_);
241 EXPECT_TRUE(merged_value->Equals(&expected));
244 TEST_F(ListPreferenceMergeTest, Equals) {
246 ListPrefUpdate update(pref_service_.get(), kListPrefName);
247 base::ListValue* local_list_value = update.Get();
248 local_list_value->AppendString(server_url0_);
249 local_list_value->AppendString(server_url1_);
252 std::unique_ptr<base::Value> original(server_url_list_.DeepCopy());
253 const PrefService::Preference* pref =
254 pref_service_->FindPreference(kListPrefName);
255 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
256 pref->name(), *pref->GetValue(), server_url_list_));
257 EXPECT_TRUE(merged_value->Equals(original.get()));
260 class DictionaryPreferenceMergeTest : public AbstractPreferenceMergeTest {
262 DictionaryPreferenceMergeTest()
263 : expression0_("expression0"),
264 expression1_("expression1"),
265 expression2_("expression2"),
266 expression3_("expression3"),
267 expression4_("expression4") {
268 SetContentPattern(&server_patterns_, expression0_, 1);
269 SetContentPattern(&server_patterns_, expression1_, 2);
270 SetContentPattern(&server_patterns_, expression2_, 1);
273 std::string expression0_;
274 std::string expression1_;
275 std::string expression2_;
276 std::string expression3_;
277 std::string expression4_;
278 base::DictionaryValue server_patterns_;
281 TEST_F(DictionaryPreferenceMergeTest, LocalEmpty) {
282 SetPrefToEmpty(kDictionaryPrefName);
283 const PrefService::Preference* pref =
284 pref_service_->FindPreference(kDictionaryPrefName);
285 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
286 pref->name(), *pref->GetValue(), server_patterns_));
287 EXPECT_TRUE(merged_value->Equals(&server_patterns_));
290 TEST_F(DictionaryPreferenceMergeTest, ServerNull) {
291 auto null_value = std::make_unique<base::Value>();
293 DictionaryPrefUpdate update(pref_service_.get(), kDictionaryPrefName);
294 base::DictionaryValue* local_dict_value = update.Get();
295 SetContentPattern(local_dict_value, expression3_, 1);
298 const PrefService::Preference* pref =
299 pref_service_->FindPreference(kDictionaryPrefName);
300 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
301 pref->name(), *pref->GetValue(), *null_value));
302 const base::DictionaryValue* local_dict_value =
303 pref_service_->GetDictionary(kDictionaryPrefName);
304 EXPECT_TRUE(merged_value->Equals(local_dict_value));
307 TEST_F(DictionaryPreferenceMergeTest, ServerEmpty) {
308 std::unique_ptr<base::Value> empty_value(new base::DictionaryValue);
310 DictionaryPrefUpdate update(pref_service_.get(), kDictionaryPrefName);
311 base::DictionaryValue* local_dict_value = update.Get();
312 SetContentPattern(local_dict_value, expression3_, 1);
315 const PrefService::Preference* pref =
316 pref_service_->FindPreference(kDictionaryPrefName);
317 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
318 pref->name(), *pref->GetValue(), *empty_value));
319 const base::DictionaryValue* local_dict_value =
320 pref_service_->GetDictionary(kDictionaryPrefName);
321 EXPECT_TRUE(merged_value->Equals(local_dict_value));
324 TEST_F(DictionaryPreferenceMergeTest, MergeNoConflicts) {
326 DictionaryPrefUpdate update(pref_service_.get(), kDictionaryPrefName);
327 base::DictionaryValue* local_dict_value = update.Get();
328 SetContentPattern(local_dict_value, expression3_, 1);
331 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
333 *pref_service_->FindPreference(kDictionaryPrefName)->GetValue(),
336 base::DictionaryValue expected;
337 SetContentPattern(&expected, expression0_, 1);
338 SetContentPattern(&expected, expression1_, 2);
339 SetContentPattern(&expected, expression2_, 1);
340 SetContentPattern(&expected, expression3_, 1);
341 EXPECT_TRUE(merged_value->Equals(&expected));
344 TEST_F(DictionaryPreferenceMergeTest, MergeConflicts) {
346 DictionaryPrefUpdate update(pref_service_.get(), kDictionaryPrefName);
347 base::DictionaryValue* local_dict_value = update.Get();
348 SetContentPattern(local_dict_value, expression0_, 2);
349 SetContentPattern(local_dict_value, expression2_, 1);
350 SetContentPattern(local_dict_value, expression3_, 1);
351 SetContentPattern(local_dict_value, expression4_, 2);
354 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
356 *pref_service_->FindPreference(kDictionaryPrefName)->GetValue(),
359 base::DictionaryValue expected;
360 SetContentPattern(&expected, expression0_, 1);
361 SetContentPattern(&expected, expression1_, 2);
362 SetContentPattern(&expected, expression2_, 1);
363 SetContentPattern(&expected, expression3_, 1);
364 SetContentPattern(&expected, expression4_, 2);
365 EXPECT_TRUE(merged_value->Equals(&expected));
368 TEST_F(DictionaryPreferenceMergeTest, MergeValueToDictionary) {
369 base::DictionaryValue local_dict_value;
370 local_dict_value.SetInteger("key", 0);
372 base::DictionaryValue server_dict_value;
373 server_dict_value.SetInteger("key.subkey", 0);
375 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
376 kDictionaryPrefName, local_dict_value, server_dict_value));
378 EXPECT_TRUE(merged_value->Equals(&server_dict_value));
381 TEST_F(DictionaryPreferenceMergeTest, Equal) {
383 DictionaryPrefUpdate update(pref_service_.get(), kDictionaryPrefName);
384 base::DictionaryValue* local_dict_value = update.Get();
385 SetContentPattern(local_dict_value, expression0_, 1);
386 SetContentPattern(local_dict_value, expression1_, 2);
387 SetContentPattern(local_dict_value, expression2_, 1);
390 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
392 *pref_service_->FindPreference(kDictionaryPrefName)->GetValue(),
394 EXPECT_TRUE(merged_value->Equals(&server_patterns_));
397 TEST_F(DictionaryPreferenceMergeTest, ConflictButServerWins) {
399 DictionaryPrefUpdate update(pref_service_.get(), kDictionaryPrefName);
400 base::DictionaryValue* local_dict_value = update.Get();
401 SetContentPattern(local_dict_value, expression0_, 2);
402 SetContentPattern(local_dict_value, expression1_, 2);
403 SetContentPattern(local_dict_value, expression2_, 1);
406 std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
408 *pref_service_->FindPreference(kDictionaryPrefName)->GetValue(),
410 EXPECT_TRUE(merged_value->Equals(&server_patterns_));
413 class IndividualPreferenceMergeTest : public AbstractPreferenceMergeTest {
415 IndividualPreferenceMergeTest()
416 : url0_("http://example.com/server0"),
417 url1_("http://example.com/server1"),
418 expression0_("expression0"),
419 expression1_("expression1") {
420 server_url_list_.AppendString(url0_);
421 SetContentPattern(&server_patterns_, expression0_, 1);
424 bool MergeListPreference(const char* pref) {
426 ListPrefUpdate update(pref_service_.get(), pref);
427 base::ListValue* local_list_value = update.Get();
428 local_list_value->AppendString(url1_);
431 std::unique_ptr<base::Value> merged_value(
432 pref_sync_service_->MergePreference(
433 pref, *pref_service_->GetUserPrefValue(pref), server_url_list_));
435 base::ListValue expected;
436 expected.AppendString(url0_);
437 expected.AppendString(url1_);
438 return merged_value->Equals(&expected);
441 bool MergeDictionaryPreference(const char* pref) {
443 DictionaryPrefUpdate update(pref_service_.get(), pref);
444 base::DictionaryValue* local_dict_value = update.Get();
445 SetContentPattern(local_dict_value, expression1_, 1);
448 std::unique_ptr<base::Value> merged_value(
449 pref_sync_service_->MergePreference(
450 pref, *pref_service_->GetUserPrefValue(pref), server_patterns_));
452 base::DictionaryValue expected;
453 SetContentPattern(&expected, expression0_, 1);
454 SetContentPattern(&expected, expression1_, 1);
455 return merged_value->Equals(&expected);
460 std::string expression0_;
461 std::string expression1_;
462 std::string content_type0_;
463 base::ListValue server_url_list_;
464 base::DictionaryValue server_patterns_;
467 TEST_F(IndividualPreferenceMergeTest, ListPreference) {
468 EXPECT_TRUE(MergeListPreference(kListPrefName));
473 } // namespace sync_preferences