1 // Copyright (c) 2012 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/location.h"
6 #include "base/message_loop.h"
7 #include "base/utf_string_conversions.h"
8 #include "chrome/browser/webdata/autofill_profile_syncable_service.h"
9 #include "components/autofill/browser/autofill_profile.h"
10 #include "components/webdata/autofill/autofill_change.h"
11 #include "content/public/test/test_browser_thread.h"
12 #include "sync/api/sync_error_factory.h"
13 #include "sync/api/sync_error_factory_mock.h"
14 #include "sync/protocol/sync.pb.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
19 using ::testing::DoAll
;
21 using ::testing::Return
;
22 using ::testing::Property
;
23 using content::BrowserThread
;
24 class AutofillProfile
;
26 // Some guids for testing.
27 std::string kGuid1
= "EDC609ED-7EEE-4F27-B00C-423242A9C44B";
28 std::string kGuid2
= "EDC609ED-7EEE-4F27-B00C-423242A9C44C";
29 std::string kGuid3
= "EDC609ED-7EEE-4F27-B00C-423242A9C44D";
30 std::string kGuid4
= "EDC609ED-7EEE-4F27-B00C-423242A9C44E";
32 class MockAutofillProfileSyncableService
33 : public AutofillProfileSyncableService
{
35 MockAutofillProfileSyncableService() {
37 virtual ~MockAutofillProfileSyncableService() {}
39 MOCK_METHOD1(LoadAutofillData
, bool(std::vector
<AutofillProfile
*>*));
40 MOCK_METHOD1(SaveChangesToWebData
,
41 bool(const AutofillProfileSyncableService::DataBundle
&));
44 ACTION_P(CopyData
, data
) {
45 arg0
->resize(data
->size());
46 std::copy(data
->begin(), data
->end(), arg0
->begin());
49 MATCHER_P(CheckSyncChanges
, n_sync_changes_list
, "") {
50 if (arg
.size() != n_sync_changes_list
.size())
52 syncer::SyncChangeList::const_iterator passed
, expected
;
53 for (passed
= arg
.begin(), expected
= n_sync_changes_list
.begin();
54 passed
!= arg
.end() && expected
!= n_sync_changes_list
.end();
55 ++passed
, ++expected
) {
56 DCHECK(passed
->IsValid());
57 if (passed
->change_type() != expected
->change_type())
59 if (passed
->sync_data().GetSpecifics().autofill_profile().guid() !=
60 expected
->sync_data().GetSpecifics().autofill_profile().guid()) {
67 MATCHER_P(DataBundleCheck
, n_bundle
, "") {
68 if ((arg
.profiles_to_delete
.size() != n_bundle
.profiles_to_delete
.size()) ||
69 (arg
.profiles_to_update
.size() != n_bundle
.profiles_to_update
.size()) ||
70 (arg
.profiles_to_add
.size() != n_bundle
.profiles_to_add
.size())) {
73 for (size_t i
= 0; i
< arg
.profiles_to_delete
.size(); ++i
) {
74 if (arg
.profiles_to_delete
[i
] != n_bundle
.profiles_to_delete
[i
])
77 for (size_t i
= 0; i
< arg
.profiles_to_update
.size(); ++i
) {
78 if (arg
.profiles_to_update
[i
]->guid() !=
79 n_bundle
.profiles_to_update
[i
]->guid()) {
83 for (size_t i
= 0; i
< arg
.profiles_to_add
.size(); ++i
) {
84 if (arg
.profiles_to_add
[i
]->Compare(*n_bundle
.profiles_to_add
[i
]))
90 class MockSyncChangeProcessor
: public syncer::SyncChangeProcessor
{
92 MockSyncChangeProcessor() {}
93 virtual ~MockSyncChangeProcessor() {}
95 MOCK_METHOD2(ProcessSyncChanges
,
96 syncer::SyncError(const tracked_objects::Location
&,
97 const syncer::SyncChangeList
&));
100 class AutofillProfileSyncableServiceTest
: public testing::Test
{
102 AutofillProfileSyncableServiceTest()
103 : ui_thread_(BrowserThread::UI
, &message_loop_
),
104 db_thread_(BrowserThread::DB
, &message_loop_
) {}
106 virtual void SetUp() OVERRIDE
{
107 sync_processor_
.reset(new MockSyncChangeProcessor
);
111 MessageLoop message_loop_
;
112 content::TestBrowserThread ui_thread_
;
113 content::TestBrowserThread db_thread_
;
114 MockAutofillProfileSyncableService autofill_syncable_service_
;
115 scoped_ptr
<MockSyncChangeProcessor
> sync_processor_
;
118 TEST_F(AutofillProfileSyncableServiceTest
, MergeDataAndStartSyncing
) {
119 std::vector
<AutofillProfile
*> profiles_from_web_db
;
120 std::string guid_present1
= kGuid1
;
121 std::string guid_present2
= kGuid2
;
122 std::string guid_synced1
= kGuid3
;
123 std::string guid_synced2
= kGuid4
;
125 profiles_from_web_db
.push_back(new AutofillProfile(guid_present1
));
126 profiles_from_web_db
.back()->SetRawInfo(NAME_FIRST
, UTF8ToUTF16("John"));
127 profiles_from_web_db
.back()->SetRawInfo(ADDRESS_HOME_LINE1
,
128 UTF8ToUTF16("1 1st st"));
129 profiles_from_web_db
.push_back(new AutofillProfile(guid_present2
));
130 profiles_from_web_db
.back()->SetRawInfo(NAME_FIRST
, UTF8ToUTF16("Tom"));
131 profiles_from_web_db
.back()->SetRawInfo(ADDRESS_HOME_LINE1
,
132 UTF8ToUTF16("2 2nd st"));
134 syncer::SyncDataList data_list
;
135 AutofillProfile
profile1(guid_synced1
);
136 profile1
.SetRawInfo(NAME_FIRST
, UTF8ToUTF16("Jane"));
137 data_list
.push_back(autofill_syncable_service_
.CreateData(profile1
));
138 AutofillProfile
profile2(guid_synced2
);
139 profile2
.SetRawInfo(NAME_FIRST
, UTF8ToUTF16("Harry"));
140 data_list
.push_back(autofill_syncable_service_
.CreateData(profile2
));
141 // This one will have the name updated.
142 AutofillProfile
profile3(guid_present2
);
143 profile3
.SetRawInfo(NAME_FIRST
, UTF8ToUTF16("Tom Doe"));
144 data_list
.push_back(autofill_syncable_service_
.CreateData(profile3
));
146 syncer::SyncChangeList expected_change_list
;
147 expected_change_list
.push_back(
148 syncer::SyncChange(FROM_HERE
,
149 syncer::SyncChange::ACTION_ADD
,
150 AutofillProfileSyncableService::CreateData(
151 (*profiles_from_web_db
.front()))));
153 AutofillProfileSyncableService::DataBundle expected_bundle
;
154 expected_bundle
.profiles_to_add
.push_back(&profile1
);
155 expected_bundle
.profiles_to_add
.push_back(&profile2
);
156 expected_bundle
.profiles_to_update
.push_back(&profile3
);
158 EXPECT_CALL(autofill_syncable_service_
, LoadAutofillData(_
))
160 .WillOnce(DoAll(CopyData(&profiles_from_web_db
), Return(true)));
161 EXPECT_CALL(autofill_syncable_service_
,
162 SaveChangesToWebData(DataBundleCheck(expected_bundle
)))
164 .WillOnce(Return(true));
165 ON_CALL(*sync_processor_
, ProcessSyncChanges(_
, _
))
166 .WillByDefault(Return(syncer::SyncError()));
167 EXPECT_CALL(*sync_processor_
,
168 ProcessSyncChanges(_
, CheckSyncChanges(expected_change_list
)))
170 .WillOnce(Return(syncer::SyncError()));
172 // Takes ownership of sync_processor_.
173 autofill_syncable_service_
.MergeDataAndStartSyncing(
174 syncer::AUTOFILL_PROFILE
, data_list
,
175 sync_processor_
.PassAs
<syncer::SyncChangeProcessor
>(),
176 scoped_ptr
<syncer::SyncErrorFactory
>(new syncer::SyncErrorFactoryMock()));
177 autofill_syncable_service_
.StopSyncing(syncer::AUTOFILL_PROFILE
);
180 TEST_F(AutofillProfileSyncableServiceTest
, GetAllSyncData
) {
181 std::vector
<AutofillProfile
*> profiles_from_web_db
;
182 std::string guid_present1
= kGuid1
;
183 std::string guid_present2
= kGuid2
;
185 profiles_from_web_db
.push_back(new AutofillProfile(guid_present1
));
186 profiles_from_web_db
.back()->SetRawInfo(NAME_FIRST
, UTF8ToUTF16("John"));
187 profiles_from_web_db
.push_back(new AutofillProfile(guid_present2
));
188 profiles_from_web_db
.back()->SetRawInfo(NAME_FIRST
, UTF8ToUTF16("Jane"));
190 EXPECT_CALL(autofill_syncable_service_
, LoadAutofillData(_
))
192 .WillOnce(DoAll(CopyData(&profiles_from_web_db
), Return(true)));
193 EXPECT_CALL(autofill_syncable_service_
, SaveChangesToWebData(_
))
195 .WillOnce(Return(true));
196 ON_CALL(*sync_processor_
, ProcessSyncChanges(_
, _
))
197 .WillByDefault(Return(syncer::SyncError()));
198 EXPECT_CALL(*sync_processor_
,
201 Property(&syncer::SyncChangeList::size
, Eq(2U))))
203 .WillOnce(Return(syncer::SyncError()));
205 syncer::SyncDataList data_list
;
206 // Takes ownership of sync_processor_.
207 autofill_syncable_service_
.MergeDataAndStartSyncing(
208 syncer::AUTOFILL_PROFILE
, data_list
,
209 sync_processor_
.PassAs
<syncer::SyncChangeProcessor
>(),
210 scoped_ptr
<syncer::SyncErrorFactory
>(new syncer::SyncErrorFactoryMock()));
212 syncer::SyncDataList data
=
213 autofill_syncable_service_
.GetAllSyncData(syncer::AUTOFILL_PROFILE
);
215 EXPECT_EQ(2U, data
.size());
216 EXPECT_EQ(guid_present1
, data
.front().GetSpecifics()
217 .autofill_profile().guid());
218 EXPECT_EQ(guid_present2
, data
.back().GetSpecifics()
219 .autofill_profile().guid());
222 TEST_F(AutofillProfileSyncableServiceTest
, ProcessSyncChanges
) {
223 std::vector
<AutofillProfile
*> profiles_from_web_db
;
224 std::string guid_present
= kGuid1
;
225 std::string guid_synced
= kGuid2
;
227 syncer::SyncChangeList change_list
;
228 AutofillProfile
profile(guid_synced
);
229 profile
.SetRawInfo(NAME_FIRST
, UTF8ToUTF16("Jane"));
230 change_list
.push_back(
231 syncer::SyncChange(FROM_HERE
,
232 syncer::SyncChange::ACTION_ADD
,
233 AutofillProfileSyncableService::CreateData(profile
)));
234 AutofillProfile
empty_profile(guid_present
);
235 change_list
.push_back(
238 syncer::SyncChange::ACTION_DELETE
,
239 AutofillProfileSyncableService::CreateData(empty_profile
)));
241 AutofillProfileSyncableService::DataBundle expected_bundle
;
242 expected_bundle
.profiles_to_delete
.push_back(guid_present
);
243 expected_bundle
.profiles_to_add
.push_back(&profile
);
245 EXPECT_CALL(autofill_syncable_service_
, SaveChangesToWebData(
246 DataBundleCheck(expected_bundle
)))
248 .WillOnce(Return(true));
250 autofill_syncable_service_
.set_sync_processor(sync_processor_
.release());
251 syncer::SyncError error
= autofill_syncable_service_
.ProcessSyncChanges(
252 FROM_HERE
, change_list
);
254 EXPECT_FALSE(error
.IsSet());
257 TEST_F(AutofillProfileSyncableServiceTest
, ActOnChange
) {
258 AutofillProfile
profile(kGuid1
);
259 profile
.SetRawInfo(NAME_FIRST
, UTF8ToUTF16("Jane"));
260 AutofillProfileChange
change1(AutofillProfileChange::ADD
, kGuid1
, &profile
);
261 AutofillProfileChange
change2(AutofillProfileChange::REMOVE
, kGuid2
, NULL
);
262 ON_CALL(*sync_processor_
, ProcessSyncChanges(_
, _
))
264 Return(syncer::SyncError(FROM_HERE
, std::string("an error"),
265 syncer::AUTOFILL_PROFILE
)));
266 EXPECT_CALL(*sync_processor_
, ProcessSyncChanges(_
, _
)).Times(2);
268 autofill_syncable_service_
.set_sync_processor(sync_processor_
.release());
269 autofill_syncable_service_
.ActOnChange(change1
);
270 autofill_syncable_service_
.ActOnChange(change2
);
273 TEST_F(AutofillProfileSyncableServiceTest
, UpdateField
) {
274 AutofillProfile
profile(kGuid1
);
275 std::string company1
= "A Company";
276 std::string company2
= "Another Company";
277 profile
.SetRawInfo(COMPANY_NAME
, UTF8ToUTF16(company1
));
278 EXPECT_FALSE(AutofillProfileSyncableService::UpdateField(
279 COMPANY_NAME
, company1
, &profile
));
280 EXPECT_EQ(profile
.GetRawInfo(COMPANY_NAME
), UTF8ToUTF16(company1
));
281 EXPECT_TRUE(AutofillProfileSyncableService::UpdateField(
282 COMPANY_NAME
, company2
, &profile
));
283 EXPECT_EQ(profile
.GetRawInfo(COMPANY_NAME
), UTF8ToUTF16(company2
));
284 EXPECT_FALSE(AutofillProfileSyncableService::UpdateField(
285 COMPANY_NAME
, company2
, &profile
));
286 EXPECT_EQ(profile
.GetRawInfo(COMPANY_NAME
), UTF8ToUTF16(company2
));
289 TEST_F(AutofillProfileSyncableServiceTest
, UpdateMultivaluedField
) {
290 AutofillProfile
profile(kGuid1
);
292 std::vector
<string16
> values
;
293 values
.push_back(UTF8ToUTF16("1@1.com"));
294 values
.push_back(UTF8ToUTF16("2@1.com"));
295 profile
.SetRawMultiInfo(EMAIL_ADDRESS
, values
);
297 ::google::protobuf::RepeatedPtrField
<std::string
> specifics_fields
;
298 specifics_fields
.AddAllocated(new std::string("2@1.com"));
299 specifics_fields
.AddAllocated(new std::string("3@1.com"));
301 EXPECT_TRUE(AutofillProfileSyncableService::UpdateMultivaluedField(
302 EMAIL_ADDRESS
, specifics_fields
, &profile
));
303 profile
.GetRawMultiInfo(EMAIL_ADDRESS
, &values
);
304 ASSERT_TRUE(values
.size() == 2);
305 EXPECT_EQ(values
[0], UTF8ToUTF16("2@1.com"));
306 EXPECT_EQ(values
[1], UTF8ToUTF16("3@1.com"));
308 EXPECT_FALSE(AutofillProfileSyncableService::UpdateMultivaluedField(
309 EMAIL_ADDRESS
, specifics_fields
, &profile
));
310 profile
.GetRawMultiInfo(EMAIL_ADDRESS
, &values
);
311 ASSERT_EQ(values
.size(), 2U);
312 EXPECT_EQ(values
[0], UTF8ToUTF16("2@1.com"));
313 EXPECT_EQ(values
[1], UTF8ToUTF16("3@1.com"));
314 EXPECT_TRUE(AutofillProfileSyncableService::UpdateMultivaluedField(
315 EMAIL_ADDRESS
, ::google::protobuf::RepeatedPtrField
<std::string
>(),
317 profile
.GetRawMultiInfo(EMAIL_ADDRESS
, &values
);
318 ASSERT_EQ(values
.size(), 1U); // Always have at least an empty string.
319 EXPECT_EQ(values
[0], UTF8ToUTF16(""));
322 TEST_F(AutofillProfileSyncableServiceTest
, MergeProfile
) {
323 AutofillProfile
profile1(kGuid1
);
324 profile1
.SetRawInfo(ADDRESS_HOME_LINE1
, UTF8ToUTF16("111 First St."));
326 std::vector
<string16
> values
;
327 values
.push_back(UTF8ToUTF16("1@1.com"));
328 values
.push_back(UTF8ToUTF16("2@1.com"));
329 profile1
.SetRawMultiInfo(EMAIL_ADDRESS
, values
);
331 AutofillProfile
profile2(kGuid2
);
332 profile2
.SetRawInfo(ADDRESS_HOME_LINE1
, UTF8ToUTF16("111 First St."));
334 // |values| now is [ "1@1.com", "2@1.com", "3@1.com" ].
335 values
.push_back(UTF8ToUTF16("3@1.com"));
336 profile2
.SetRawMultiInfo(EMAIL_ADDRESS
, values
);
339 values
.push_back(UTF8ToUTF16("John"));
340 profile1
.SetRawMultiInfo(NAME_FIRST
, values
);
341 values
.push_back(UTF8ToUTF16("Jane"));
342 profile2
.SetRawMultiInfo(NAME_FIRST
, values
);
345 values
.push_back(UTF8ToUTF16("Doe"));
346 profile1
.SetRawMultiInfo(NAME_LAST
, values
);
347 values
.push_back(UTF8ToUTF16("Other"));
348 profile2
.SetRawMultiInfo(NAME_LAST
, values
);
351 values
.push_back(UTF8ToUTF16("650234567"));
352 profile2
.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER
, values
);
354 EXPECT_FALSE(AutofillProfileSyncableService::MergeProfile(profile2
,
357 profile1
.GetRawMultiInfo(NAME_FIRST
, &values
);
358 ASSERT_EQ(values
.size(), 2U);
359 EXPECT_EQ(values
[0], UTF8ToUTF16("John"));
360 EXPECT_EQ(values
[1], UTF8ToUTF16("Jane"));
362 profile1
.GetRawMultiInfo(NAME_LAST
, &values
);
363 ASSERT_EQ(values
.size(), 2U);
364 EXPECT_EQ(values
[0], UTF8ToUTF16("Doe"));
365 EXPECT_EQ(values
[1], UTF8ToUTF16("Other"));
367 profile1
.GetRawMultiInfo(EMAIL_ADDRESS
, &values
);
368 ASSERT_EQ(values
.size(), 3U);
369 EXPECT_EQ(values
[0], UTF8ToUTF16("1@1.com"));
370 EXPECT_EQ(values
[1], UTF8ToUTF16("2@1.com"));
371 EXPECT_EQ(values
[2], UTF8ToUTF16("3@1.com"));
373 profile1
.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER
, &values
);
374 ASSERT_EQ(values
.size(), 1U);
375 EXPECT_EQ(values
[0], UTF8ToUTF16("650234567"));
377 AutofillProfile
profile3(kGuid3
);
378 profile3
.SetRawInfo(ADDRESS_HOME_LINE1
, UTF8ToUTF16("111 First St."));
381 values
.push_back(UTF8ToUTF16("Jane"));
382 profile3
.SetRawMultiInfo(NAME_FIRST
, values
);
385 values
.push_back(UTF8ToUTF16("Doe"));
386 profile3
.SetRawMultiInfo(NAME_LAST
, values
);
388 EXPECT_TRUE(AutofillProfileSyncableService::MergeProfile(profile3
,
391 profile1
.GetRawMultiInfo(NAME_FIRST
, &values
);
392 ASSERT_EQ(values
.size(), 3U);
393 EXPECT_EQ(values
[0], UTF8ToUTF16("John"));
394 EXPECT_EQ(values
[1], UTF8ToUTF16("Jane"));
395 EXPECT_EQ(values
[2], UTF8ToUTF16("Jane"));
397 profile1
.GetRawMultiInfo(NAME_LAST
, &values
);
398 ASSERT_EQ(values
.size(), 3U);
399 EXPECT_EQ(values
[0], UTF8ToUTF16("Doe"));
400 EXPECT_EQ(values
[1], UTF8ToUTF16("Other"));
401 EXPECT_EQ(values
[2], UTF8ToUTF16("Doe"));
403 // Middle name should have three entries as well.
404 profile1
.GetRawMultiInfo(NAME_MIDDLE
, &values
);
405 ASSERT_EQ(values
.size(), 3U);
406 EXPECT_TRUE(values
[0].empty());
407 EXPECT_TRUE(values
[1].empty());
408 EXPECT_TRUE(values
[2].empty());
410 profile1
.GetRawMultiInfo(EMAIL_ADDRESS
, &values
);
411 ASSERT_EQ(values
.size(), 3U);
412 EXPECT_EQ(values
[0], UTF8ToUTF16("1@1.com"));
413 EXPECT_EQ(values
[1], UTF8ToUTF16("2@1.com"));
414 EXPECT_EQ(values
[2], UTF8ToUTF16("3@1.com"));
416 profile1
.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER
, &values
);
417 ASSERT_EQ(values
.size(), 1U);
418 EXPECT_EQ(values
[0], UTF8ToUTF16("650234567"));