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 "base/macros.h"
6 #include "base/memory/ref_counted.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/prefs/scoped_user_pref_update.h"
9 #include "base/values.h"
10 #include "components/syncable_prefs/pref_model_associator.h"
11 #include "components/syncable_prefs/pref_model_associator_client.h"
12 #include "components/syncable_prefs/pref_service_mock_factory.h"
13 #include "components/syncable_prefs/pref_service_syncable.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 namespace syncable_prefs
{
20 const char kStringPrefName
[] = "pref.string";
21 const char kListPrefName
[] = "pref.list";
22 const char kDictionaryPrefName
[] = "pref.dictionary";
24 class TestPrefModelAssociatorClient
: public PrefModelAssociatorClient
{
26 TestPrefModelAssociatorClient() {}
27 ~TestPrefModelAssociatorClient() override
{}
29 // PrefModelAssociatorClient implementation.
30 bool IsMergeableListPreference(const std::string
& pref_name
) const override
{
31 return pref_name
== kListPrefName
;
34 bool IsMergeableDictionaryPreference(
35 const std::string
& pref_name
) const override
{
36 return pref_name
== kDictionaryPrefName
;
39 bool IsMigratedPreference(const std::string
& new_pref_name
,
40 std::string
* old_pref_name
) const override
{
44 bool IsOldMigratedPreference(const std::string
& old_pref_name
,
45 std::string
* new_pref_name
) const override
{
50 DISALLOW_COPY_AND_ASSIGN(TestPrefModelAssociatorClient
);
53 class AbstractPreferenceMergeTest
: public testing::Test
{
55 AbstractPreferenceMergeTest() {
56 PrefServiceMockFactory factory
;
57 factory
.SetPrefModelAssociatorClient(&client_
);
58 scoped_refptr
<user_prefs::PrefRegistrySyncable
> pref_registry(
59 new user_prefs::PrefRegistrySyncable
);
60 pref_registry
->RegisterStringPref(
63 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF
);
64 pref_registry
->RegisterListPref(
66 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF
);
67 pref_registry
->RegisterDictionaryPref(
69 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF
);
70 pref_service_
= factory
.CreateSyncable(pref_registry
.get());
71 pref_sync_service_
= static_cast<PrefModelAssociator
*>(
72 pref_service_
->GetSyncableService(syncer::PREFERENCES
));
75 void SetContentPattern(base::DictionaryValue
* patterns_dict
,
76 const std::string
& expression
,
78 base::DictionaryValue
* expression_dict
;
80 patterns_dict
->GetDictionaryWithoutPathExpansion(expression
,
83 expression_dict
= new base::DictionaryValue
;
84 patterns_dict
->SetWithoutPathExpansion(expression
, expression_dict
);
86 expression_dict
->SetWithoutPathExpansion(
87 "setting", new base::FundamentalValue(setting
));
90 void SetPrefToEmpty(const std::string
& pref_name
) {
91 scoped_ptr
<base::Value
> empty_value
;
92 const PrefService::Preference
* pref
=
93 pref_service_
->FindPreference(pref_name
.c_str());
95 base::Value::Type type
= pref
->GetType();
96 if (type
== base::Value::TYPE_DICTIONARY
)
97 empty_value
.reset(new base::DictionaryValue
);
98 else if (type
== base::Value::TYPE_LIST
)
99 empty_value
.reset(new base::ListValue
);
102 pref_service_
->Set(pref_name
.c_str(), *empty_value
);
105 TestPrefModelAssociatorClient client_
;
106 scoped_ptr
<PrefServiceSyncable
> pref_service_
;
107 PrefModelAssociator
* pref_sync_service_
;
110 class ListPreferenceMergeTest
: public AbstractPreferenceMergeTest
{
112 ListPreferenceMergeTest()
113 : server_url0_("http://example.com/server0"),
114 server_url1_("http://example.com/server1"),
115 local_url0_("http://example.com/local0"),
116 local_url1_("http://example.com/local1") {
117 server_url_list_
.Append(new base::StringValue(server_url0_
));
118 server_url_list_
.Append(new base::StringValue(server_url1_
));
121 std::string server_url0_
;
122 std::string server_url1_
;
123 std::string local_url0_
;
124 std::string local_url1_
;
125 base::ListValue server_url_list_
;
128 TEST_F(ListPreferenceMergeTest
, NotListOrDictionary
) {
129 pref_service_
->SetString(kStringPrefName
, local_url0_
);
130 const PrefService::Preference
* pref
=
131 pref_service_
->FindPreference(kStringPrefName
);
132 scoped_ptr
<base::Value
> server_value(new base::StringValue(server_url0_
));
133 scoped_ptr
<base::Value
> merged_value(
134 pref_sync_service_
->MergePreference(pref
->name(),
137 EXPECT_TRUE(merged_value
->Equals(server_value
.get()));
140 TEST_F(ListPreferenceMergeTest
, LocalEmpty
) {
141 SetPrefToEmpty(kListPrefName
);
142 const PrefService::Preference
* pref
=
143 pref_service_
->FindPreference(kListPrefName
);
144 scoped_ptr
<base::Value
> merged_value(
145 pref_sync_service_
->MergePreference(pref
->name(),
148 EXPECT_TRUE(merged_value
->Equals(&server_url_list_
));
151 TEST_F(ListPreferenceMergeTest
, ServerNull
) {
152 scoped_ptr
<base::Value
> null_value
= base::Value::CreateNullValue();
154 ListPrefUpdate
update(pref_service_
.get(), kListPrefName
);
155 base::ListValue
* local_list_value
= update
.Get();
156 local_list_value
->Append(new base::StringValue(local_url0_
));
159 const PrefService::Preference
* pref
=
160 pref_service_
->FindPreference(kListPrefName
);
161 scoped_ptr
<base::Value
> merged_value(
162 pref_sync_service_
->MergePreference(pref
->name(),
165 const base::ListValue
* local_list_value
=
166 pref_service_
->GetList(kListPrefName
);
167 EXPECT_TRUE(merged_value
->Equals(local_list_value
));
170 TEST_F(ListPreferenceMergeTest
, ServerEmpty
) {
171 scoped_ptr
<base::Value
> empty_value(new base::ListValue
);
173 ListPrefUpdate
update(pref_service_
.get(), kListPrefName
);
174 base::ListValue
* local_list_value
= update
.Get();
175 local_list_value
->Append(new base::StringValue(local_url0_
));
178 const PrefService::Preference
* pref
=
179 pref_service_
->FindPreference(kListPrefName
);
180 scoped_ptr
<base::Value
> merged_value(
181 pref_sync_service_
->MergePreference(pref
->name(),
184 const base::ListValue
* local_list_value
=
185 pref_service_
->GetList(kListPrefName
);
186 EXPECT_TRUE(merged_value
->Equals(local_list_value
));
189 TEST_F(ListPreferenceMergeTest
, Merge
) {
191 ListPrefUpdate
update(pref_service_
.get(), kListPrefName
);
192 base::ListValue
* local_list_value
= update
.Get();
193 local_list_value
->Append(new base::StringValue(local_url0_
));
194 local_list_value
->Append(new base::StringValue(local_url1_
));
197 const PrefService::Preference
* pref
=
198 pref_service_
->FindPreference(kListPrefName
);
199 scoped_ptr
<base::Value
> merged_value(
200 pref_sync_service_
->MergePreference(pref
->name(),
204 base::ListValue expected
;
205 expected
.Append(new base::StringValue(server_url0_
));
206 expected
.Append(new base::StringValue(server_url1_
));
207 expected
.Append(new base::StringValue(local_url0_
));
208 expected
.Append(new base::StringValue(local_url1_
));
209 EXPECT_TRUE(merged_value
->Equals(&expected
));
212 TEST_F(ListPreferenceMergeTest
, Duplicates
) {
214 ListPrefUpdate
update(pref_service_
.get(), kListPrefName
);
215 base::ListValue
* local_list_value
= update
.Get();
216 local_list_value
->Append(new base::StringValue(local_url0_
));
217 local_list_value
->Append(new base::StringValue(server_url0_
));
218 local_list_value
->Append(new base::StringValue(server_url1_
));
221 const PrefService::Preference
* pref
=
222 pref_service_
->FindPreference(kListPrefName
);
223 scoped_ptr
<base::Value
> merged_value(
224 pref_sync_service_
->MergePreference(pref
->name(),
228 base::ListValue expected
;
229 expected
.Append(new base::StringValue(server_url0_
));
230 expected
.Append(new base::StringValue(server_url1_
));
231 expected
.Append(new base::StringValue(local_url0_
));
232 EXPECT_TRUE(merged_value
->Equals(&expected
));
235 TEST_F(ListPreferenceMergeTest
, Equals
) {
237 ListPrefUpdate
update(pref_service_
.get(), kListPrefName
);
238 base::ListValue
* local_list_value
= update
.Get();
239 local_list_value
->Append(new base::StringValue(server_url0_
));
240 local_list_value
->Append(new base::StringValue(server_url1_
));
243 scoped_ptr
<base::Value
> original(server_url_list_
.DeepCopy());
244 const PrefService::Preference
* pref
=
245 pref_service_
->FindPreference(kListPrefName
);
246 scoped_ptr
<base::Value
> merged_value(
247 pref_sync_service_
->MergePreference(pref
->name(),
250 EXPECT_TRUE(merged_value
->Equals(original
.get()));
253 class DictionaryPreferenceMergeTest
: public AbstractPreferenceMergeTest
{
255 DictionaryPreferenceMergeTest()
256 : expression0_("expression0"),
257 expression1_("expression1"),
258 expression2_("expression2"),
259 expression3_("expression3"),
260 expression4_("expression4") {
261 SetContentPattern(&server_patterns_
, expression0_
, 1);
262 SetContentPattern(&server_patterns_
, expression1_
, 2);
263 SetContentPattern(&server_patterns_
, expression2_
, 1);
266 std::string expression0_
;
267 std::string expression1_
;
268 std::string expression2_
;
269 std::string expression3_
;
270 std::string expression4_
;
271 base::DictionaryValue server_patterns_
;
274 TEST_F(DictionaryPreferenceMergeTest
, LocalEmpty
) {
275 SetPrefToEmpty(kDictionaryPrefName
);
276 const PrefService::Preference
* pref
=
277 pref_service_
->FindPreference(kDictionaryPrefName
);
278 scoped_ptr
<base::Value
> merged_value(
279 pref_sync_service_
->MergePreference(pref
->name(),
282 EXPECT_TRUE(merged_value
->Equals(&server_patterns_
));
285 TEST_F(DictionaryPreferenceMergeTest
, ServerNull
) {
286 scoped_ptr
<base::Value
> null_value
= base::Value::CreateNullValue();
288 DictionaryPrefUpdate
update(pref_service_
.get(), kDictionaryPrefName
);
289 base::DictionaryValue
* local_dict_value
= update
.Get();
290 SetContentPattern(local_dict_value
, expression3_
, 1);
293 const PrefService::Preference
* pref
=
294 pref_service_
->FindPreference(kDictionaryPrefName
);
295 scoped_ptr
<base::Value
> merged_value(
296 pref_sync_service_
->MergePreference(pref
->name(),
299 const base::DictionaryValue
* local_dict_value
=
300 pref_service_
->GetDictionary(kDictionaryPrefName
);
301 EXPECT_TRUE(merged_value
->Equals(local_dict_value
));
304 TEST_F(DictionaryPreferenceMergeTest
, ServerEmpty
) {
305 scoped_ptr
<base::Value
> empty_value(new base::DictionaryValue
);
307 DictionaryPrefUpdate
update(pref_service_
.get(), kDictionaryPrefName
);
308 base::DictionaryValue
* local_dict_value
= update
.Get();
309 SetContentPattern(local_dict_value
, expression3_
, 1);
312 const PrefService::Preference
* pref
=
313 pref_service_
->FindPreference(kDictionaryPrefName
);
314 scoped_ptr
<base::Value
> merged_value(
315 pref_sync_service_
->MergePreference(pref
->name(),
318 const base::DictionaryValue
* local_dict_value
=
319 pref_service_
->GetDictionary(kDictionaryPrefName
);
320 EXPECT_TRUE(merged_value
->Equals(local_dict_value
));
323 TEST_F(DictionaryPreferenceMergeTest
, MergeNoConflicts
) {
325 DictionaryPrefUpdate
update(pref_service_
.get(), kDictionaryPrefName
);
326 base::DictionaryValue
* local_dict_value
= update
.Get();
327 SetContentPattern(local_dict_value
, expression3_
, 1);
330 scoped_ptr
<base::Value
> merged_value(pref_sync_service_
->MergePreference(
332 *pref_service_
->FindPreference(kDictionaryPrefName
)->GetValue(),
335 base::DictionaryValue expected
;
336 SetContentPattern(&expected
, expression0_
, 1);
337 SetContentPattern(&expected
, expression1_
, 2);
338 SetContentPattern(&expected
, expression2_
, 1);
339 SetContentPattern(&expected
, expression3_
, 1);
340 EXPECT_TRUE(merged_value
->Equals(&expected
));
343 TEST_F(DictionaryPreferenceMergeTest
, MergeConflicts
) {
345 DictionaryPrefUpdate
update(pref_service_
.get(), kDictionaryPrefName
);
346 base::DictionaryValue
* local_dict_value
= update
.Get();
347 SetContentPattern(local_dict_value
, expression0_
, 2);
348 SetContentPattern(local_dict_value
, expression2_
, 1);
349 SetContentPattern(local_dict_value
, expression3_
, 1);
350 SetContentPattern(local_dict_value
, expression4_
, 2);
353 scoped_ptr
<base::Value
> merged_value(pref_sync_service_
->MergePreference(
355 *pref_service_
->FindPreference(kDictionaryPrefName
)->GetValue(),
358 base::DictionaryValue expected
;
359 SetContentPattern(&expected
, expression0_
, 1);
360 SetContentPattern(&expected
, expression1_
, 2);
361 SetContentPattern(&expected
, expression2_
, 1);
362 SetContentPattern(&expected
, expression3_
, 1);
363 SetContentPattern(&expected
, expression4_
, 2);
364 EXPECT_TRUE(merged_value
->Equals(&expected
));
367 TEST_F(DictionaryPreferenceMergeTest
, MergeValueToDictionary
) {
368 base::DictionaryValue local_dict_value
;
369 local_dict_value
.SetInteger("key", 0);
371 base::DictionaryValue server_dict_value
;
372 server_dict_value
.SetInteger("key.subkey", 0);
374 scoped_ptr
<base::Value
> merged_value(pref_sync_service_
->MergePreference(
379 EXPECT_TRUE(merged_value
->Equals(&server_dict_value
));
382 TEST_F(DictionaryPreferenceMergeTest
, Equal
) {
384 DictionaryPrefUpdate
update(pref_service_
.get(), kDictionaryPrefName
);
385 base::DictionaryValue
* local_dict_value
= update
.Get();
386 SetContentPattern(local_dict_value
, expression0_
, 1);
387 SetContentPattern(local_dict_value
, expression1_
, 2);
388 SetContentPattern(local_dict_value
, expression2_
, 1);
391 scoped_ptr
<base::Value
> merged_value(pref_sync_service_
->MergePreference(
393 *pref_service_
->FindPreference(kDictionaryPrefName
)->GetValue(),
395 EXPECT_TRUE(merged_value
->Equals(&server_patterns_
));
398 TEST_F(DictionaryPreferenceMergeTest
, ConflictButServerWins
) {
400 DictionaryPrefUpdate
update(pref_service_
.get(), kDictionaryPrefName
);
401 base::DictionaryValue
* local_dict_value
= update
.Get();
402 SetContentPattern(local_dict_value
, expression0_
, 2);
403 SetContentPattern(local_dict_value
, expression1_
, 2);
404 SetContentPattern(local_dict_value
, expression2_
, 1);
407 scoped_ptr
<base::Value
> merged_value(pref_sync_service_
->MergePreference(
409 *pref_service_
->FindPreference(kDictionaryPrefName
)->GetValue(),
411 EXPECT_TRUE(merged_value
->Equals(&server_patterns_
));
414 class IndividualPreferenceMergeTest
: public AbstractPreferenceMergeTest
{
416 IndividualPreferenceMergeTest()
417 : url0_("http://example.com/server0"),
418 url1_("http://example.com/server1"),
419 expression0_("expression0"),
420 expression1_("expression1") {
421 server_url_list_
.Append(new base::StringValue(url0_
));
422 SetContentPattern(&server_patterns_
, expression0_
, 1);
425 bool MergeListPreference(const char* pref
) {
427 ListPrefUpdate
update(pref_service_
.get(), pref
);
428 base::ListValue
* local_list_value
= update
.Get();
429 local_list_value
->Append(new base::StringValue(url1_
));
432 scoped_ptr
<base::Value
> merged_value(pref_sync_service_
->MergePreference(
434 *pref_service_
->GetUserPrefValue(pref
),
437 base::ListValue expected
;
438 expected
.Append(new base::StringValue(url0_
));
439 expected
.Append(new base::StringValue(url1_
));
440 return merged_value
->Equals(&expected
);
443 bool MergeDictionaryPreference(const char* pref
) {
445 DictionaryPrefUpdate
update(pref_service_
.get(), pref
);
446 base::DictionaryValue
* local_dict_value
= update
.Get();
447 SetContentPattern(local_dict_value
, expression1_
, 1);
450 scoped_ptr
<base::Value
> merged_value(pref_sync_service_
->MergePreference(
452 *pref_service_
->GetUserPrefValue(pref
),
455 base::DictionaryValue expected
;
456 SetContentPattern(&expected
, expression0_
, 1);
457 SetContentPattern(&expected
, expression1_
, 1);
458 return merged_value
->Equals(&expected
);
463 std::string expression0_
;
464 std::string expression1_
;
465 std::string content_type0_
;
466 base::ListValue server_url_list_
;
467 base::DictionaryValue server_patterns_
;
470 TEST_F(IndividualPreferenceMergeTest
, ListPreference
) {
471 EXPECT_TRUE(MergeListPreference(kListPrefName
));
476 } // namespace syncable_prefs