OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "base/location.h" | |
6 #include "base/message_loop/message_loop.h" | |
7 #include "base/strings/utf_string_conversions.h" | |
8 #include "chrome/browser/webdata/autofill_profile_syncable_service.h" | |
9 #include "components/autofill/core/browser/autofill_profile.h" | |
10 #include "components/autofill/core/browser/webdata/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" | |
17 | |
18 namespace autofill { | |
19 | |
20 using ::testing::_; | |
21 using ::testing::DoAll; | |
22 using ::testing::Eq; | |
23 using ::testing::Return; | |
24 using ::testing::Property; | |
25 using base::ASCIIToUTF16; | |
26 using base::UTF8ToUTF16; | |
27 using content::BrowserThread; | |
28 | |
29 namespace { | |
30 | |
31 // Some guids for testing. | |
32 const char kGuid1[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44B"; | |
33 const char kGuid2[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44C"; | |
34 const char kGuid3[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44D"; | |
35 const char kGuid4[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44E"; | |
36 const char kHttpOrigin[] = "http://www.example.com/"; | |
37 const char kHttpsOrigin[] = "https://www.example.com/"; | |
38 const char kSettingsOrigin[] = "Chrome settings"; | |
39 | |
40 class MockAutofillProfileSyncableService | |
41 : public AutofillProfileSyncableService { | |
42 public: | |
43 MockAutofillProfileSyncableService() {} | |
44 virtual ~MockAutofillProfileSyncableService() {} | |
45 | |
46 using AutofillProfileSyncableService::DataBundle; | |
47 using AutofillProfileSyncableService::set_sync_processor; | |
48 using AutofillProfileSyncableService::CreateData; | |
49 | |
50 MOCK_METHOD1(LoadAutofillData, bool(std::vector<AutofillProfile*>*)); | |
51 MOCK_METHOD1(SaveChangesToWebData, | |
52 bool(const AutofillProfileSyncableService::DataBundle&)); | |
53 }; | |
54 | |
55 ACTION_P(CopyData, data) { | |
56 arg0->resize(data->size()); | |
57 std::copy(data->begin(), data->end(), arg0->begin()); | |
58 } | |
59 | |
60 MATCHER_P(CheckSyncChanges, n_sync_changes_list, "") { | |
61 if (arg.size() != n_sync_changes_list.size()) | |
62 return false; | |
63 syncer::SyncChangeList::const_iterator passed, expected; | |
64 for (passed = arg.begin(), expected = n_sync_changes_list.begin(); | |
65 passed != arg.end() && expected != n_sync_changes_list.end(); | |
66 ++passed, ++expected) { | |
67 DCHECK(passed->IsValid()); | |
68 if (passed->change_type() != expected->change_type()) | |
69 return false; | |
70 if (passed->sync_data().GetSpecifics().SerializeAsString() != | |
71 expected->sync_data().GetSpecifics().SerializeAsString()) { | |
72 return false; | |
73 } | |
74 } | |
75 return true; | |
76 } | |
77 | |
78 MATCHER_P(DataBundleCheck, n_bundle, "") { | |
79 if ((arg.profiles_to_delete.size() != n_bundle.profiles_to_delete.size()) || | |
80 (arg.profiles_to_update.size() != n_bundle.profiles_to_update.size()) || | |
81 (arg.profiles_to_add.size() != n_bundle.profiles_to_add.size())) | |
82 return false; | |
83 for (size_t i = 0; i < arg.profiles_to_delete.size(); ++i) { | |
84 if (arg.profiles_to_delete[i] != n_bundle.profiles_to_delete[i]) | |
85 return false; | |
86 } | |
87 for (size_t i = 0; i < arg.profiles_to_update.size(); ++i) { | |
88 if (*arg.profiles_to_update[i] != *n_bundle.profiles_to_update[i]) | |
89 return false; | |
90 } | |
91 for (size_t i = 0; i < arg.profiles_to_add.size(); ++i) { | |
92 if (*arg.profiles_to_add[i] != *n_bundle.profiles_to_add[i]) | |
93 return false; | |
94 } | |
95 return true; | |
96 } | |
97 | |
98 class MockSyncChangeProcessor : public syncer::SyncChangeProcessor { | |
99 public: | |
100 MockSyncChangeProcessor() {} | |
101 virtual ~MockSyncChangeProcessor() {} | |
102 | |
103 MOCK_METHOD2(ProcessSyncChanges, | |
104 syncer::SyncError(const tracked_objects::Location&, | |
105 const syncer::SyncChangeList&)); | |
106 virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type) | |
107 const OVERRIDE { return syncer::SyncDataList(); } | |
108 }; | |
109 | |
110 class TestSyncChangeProcessor : public syncer::SyncChangeProcessor { | |
111 public: | |
112 TestSyncChangeProcessor() {} | |
113 virtual ~TestSyncChangeProcessor() {} | |
114 | |
115 virtual syncer::SyncError ProcessSyncChanges( | |
116 const tracked_objects::Location& location, | |
117 const syncer::SyncChangeList& changes) OVERRIDE { | |
118 changes_ = changes; | |
119 return syncer::SyncError(); | |
120 } | |
121 | |
122 virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const | |
123 OVERRIDE { | |
124 return syncer::SyncDataList(); | |
125 } | |
126 | |
127 const syncer::SyncChangeList& changes() { return changes_; } | |
128 | |
129 private: | |
130 syncer::SyncChangeList changes_; | |
131 }; | |
132 | |
133 // Returns a profile with all fields set. Contains identical data to the data | |
134 // returned from ConstructCompleteSyncData(). | |
135 scoped_ptr<AutofillProfile> ConstructCompleteProfile() { | |
136 scoped_ptr<AutofillProfile> profile( | |
137 new AutofillProfile(kGuid1, kHttpsOrigin)); | |
138 | |
139 std::vector<base::string16> names; | |
140 names.push_back(ASCIIToUTF16("John K. Doe")); | |
141 names.push_back(ASCIIToUTF16("Jane Luise Smith")); | |
142 profile->SetRawMultiInfo(NAME_FULL, names); | |
143 | |
144 std::vector<base::string16> emails; | |
145 emails.push_back(ASCIIToUTF16("user@example.com")); | |
146 emails.push_back(ASCIIToUTF16("superuser@example.org")); | |
147 profile->SetRawMultiInfo(EMAIL_ADDRESS, emails); | |
148 | |
149 std::vector<base::string16> phones; | |
150 phones.push_back(ASCIIToUTF16("1.800.555.1234")); | |
151 phones.push_back(ASCIIToUTF16("1.866.650.0000")); | |
152 profile->SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, phones); | |
153 | |
154 profile->SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, | |
155 ASCIIToUTF16("123 Fake St.\n" | |
156 "Apt. 42")); | |
157 EXPECT_EQ(ASCIIToUTF16("123 Fake St."), | |
158 profile->GetRawInfo(ADDRESS_HOME_LINE1)); | |
159 EXPECT_EQ(ASCIIToUTF16("Apt. 42"), profile->GetRawInfo(ADDRESS_HOME_LINE2)); | |
160 | |
161 profile->SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Google, Inc.")); | |
162 profile->SetRawInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("Mountain View")); | |
163 profile->SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California")); | |
164 profile->SetRawInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("94043")); | |
165 profile->SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US")); | |
166 profile->SetRawInfo(ADDRESS_HOME_SORTING_CODE, ASCIIToUTF16("CEDEX")); | |
167 profile->SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, | |
168 ASCIIToUTF16("Santa Clara")); | |
169 return profile.Pass(); | |
170 } | |
171 | |
172 // Returns SyncData with all Autofill profile fields set. Contains identical | |
173 // data to the data returned from ConstructCompleteProfile(). | |
174 syncer::SyncData ConstructCompleteSyncData() { | |
175 sync_pb::EntitySpecifics entity_specifics; | |
176 sync_pb::AutofillProfileSpecifics* specifics = | |
177 entity_specifics.mutable_autofill_profile(); | |
178 | |
179 specifics->set_guid(kGuid1); | |
180 specifics->set_origin(kHttpsOrigin); | |
181 | |
182 specifics->add_name_first("John"); | |
183 specifics->add_name_middle("K."); | |
184 specifics->add_name_last("Doe"); | |
185 | |
186 specifics->add_name_first("Jane"); | |
187 specifics->add_name_middle("Luise"); | |
188 specifics->add_name_last("Smith"); | |
189 | |
190 specifics->add_email_address("user@example.com"); | |
191 specifics->add_email_address("superuser@example.org"); | |
192 | |
193 specifics->add_phone_home_whole_number("1.800.555.1234"); | |
194 specifics->add_phone_home_whole_number("1.866.650.0000"); | |
195 | |
196 specifics->set_address_home_line1("123 Fake St."); | |
197 specifics->set_address_home_line2("Apt. 42"); | |
198 specifics->set_address_home_street_address("123 Fake St.\n" | |
199 "Apt. 42"); | |
200 | |
201 specifics->set_company_name("Google, Inc."); | |
202 specifics->set_address_home_city("Mountain View"); | |
203 specifics->set_address_home_state("California"); | |
204 specifics->set_address_home_zip("94043"); | |
205 specifics->set_address_home_country("US"); | |
206 specifics->set_address_home_sorting_code("CEDEX"); | |
207 specifics->set_address_home_dependent_locality("Santa Clara"); | |
208 | |
209 return syncer::SyncData::CreateLocalData(kGuid1, kGuid1, entity_specifics); | |
210 } | |
211 | |
212 } // namespace | |
213 | |
214 class AutofillProfileSyncableServiceTest : public testing::Test { | |
215 public: | |
216 AutofillProfileSyncableServiceTest() | |
217 : ui_thread_(BrowserThread::UI, &message_loop_), | |
218 db_thread_(BrowserThread::DB, &message_loop_) {} | |
219 | |
220 virtual void SetUp() OVERRIDE { | |
221 sync_processor_.reset(new MockSyncChangeProcessor); | |
222 } | |
223 | |
224 // Wrapper around AutofillProfileSyncableService::MergeDataAndStartSyncing() | |
225 // that also verifies expectations. | |
226 void MergeDataAndStartSyncing( | |
227 const std::vector<AutofillProfile*>& profiles_from_web_db, | |
228 const syncer::SyncDataList& data_list, | |
229 const MockAutofillProfileSyncableService::DataBundle& expected_bundle, | |
230 const syncer::SyncChangeList& expected_change_list) { | |
231 EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_)) | |
232 .Times(1) | |
233 .WillOnce(DoAll(CopyData(&profiles_from_web_db), Return(true))); | |
234 EXPECT_CALL(autofill_syncable_service_, | |
235 SaveChangesToWebData(DataBundleCheck(expected_bundle))) | |
236 .Times(1) | |
237 .WillOnce(Return(true)); | |
238 if (expected_change_list.empty()) { | |
239 EXPECT_CALL(*sync_processor_, ProcessSyncChanges(_, _)).Times(0); | |
240 } else { | |
241 ON_CALL(*sync_processor_, ProcessSyncChanges(_, _)) | |
242 .WillByDefault(Return(syncer::SyncError())); | |
243 EXPECT_CALL(*sync_processor_, | |
244 ProcessSyncChanges(_, CheckSyncChanges(expected_change_list))) | |
245 .Times(1) | |
246 .WillOnce(Return(syncer::SyncError())); | |
247 } | |
248 | |
249 // Takes ownership of sync_processor_. | |
250 autofill_syncable_service_.MergeDataAndStartSyncing( | |
251 syncer::AUTOFILL_PROFILE, data_list, | |
252 sync_processor_.PassAs<syncer::SyncChangeProcessor>(), | |
253 scoped_ptr<syncer::SyncErrorFactory>( | |
254 new syncer::SyncErrorFactoryMock())); | |
255 } | |
256 | |
257 protected: | |
258 base::MessageLoop message_loop_; | |
259 content::TestBrowserThread ui_thread_; | |
260 content::TestBrowserThread db_thread_; | |
261 MockAutofillProfileSyncableService autofill_syncable_service_; | |
262 scoped_ptr<MockSyncChangeProcessor> sync_processor_; | |
263 }; | |
264 | |
265 TEST_F(AutofillProfileSyncableServiceTest, MergeDataAndStartSyncing) { | |
266 std::vector<AutofillProfile*> profiles_from_web_db; | |
267 std::string guid_present1 = kGuid1; | |
268 std::string guid_present2 = kGuid2; | |
269 std::string guid_synced1 = kGuid3; | |
270 std::string guid_synced2 = kGuid4; | |
271 std::string origin_present1 = kHttpOrigin; | |
272 std::string origin_present2 = std::string(); | |
273 std::string origin_synced1 = kHttpsOrigin; | |
274 std::string origin_synced2 = kSettingsOrigin; | |
275 | |
276 profiles_from_web_db.push_back( | |
277 new AutofillProfile(guid_present1, origin_present1)); | |
278 profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, UTF8ToUTF16("John")); | |
279 profiles_from_web_db.back()->SetRawInfo(ADDRESS_HOME_LINE1, | |
280 UTF8ToUTF16("1 1st st")); | |
281 profiles_from_web_db.push_back( | |
282 new AutofillProfile(guid_present2, origin_present2)); | |
283 profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, UTF8ToUTF16("Tom")); | |
284 profiles_from_web_db.back()->SetRawInfo(ADDRESS_HOME_LINE1, | |
285 UTF8ToUTF16("2 2nd st")); | |
286 | |
287 syncer::SyncDataList data_list; | |
288 AutofillProfile profile1(guid_synced1, origin_synced1); | |
289 profile1.SetRawInfo(NAME_FIRST, UTF8ToUTF16("Jane")); | |
290 data_list.push_back(autofill_syncable_service_.CreateData(profile1)); | |
291 AutofillProfile profile2(guid_synced2, origin_synced2); | |
292 profile2.SetRawInfo(NAME_FIRST, UTF8ToUTF16("Harry")); | |
293 data_list.push_back(autofill_syncable_service_.CreateData(profile2)); | |
294 // This one will have the name and origin updated. | |
295 AutofillProfile profile3(guid_present2, origin_synced2); | |
296 profile3.SetRawInfo(NAME_FIRST, UTF8ToUTF16("Tom Doe")); | |
297 data_list.push_back(autofill_syncable_service_.CreateData(profile3)); | |
298 | |
299 syncer::SyncChangeList expected_change_list; | |
300 expected_change_list.push_back( | |
301 syncer::SyncChange(FROM_HERE, | |
302 syncer::SyncChange::ACTION_ADD, | |
303 MockAutofillProfileSyncableService::CreateData( | |
304 *profiles_from_web_db.front()))); | |
305 | |
306 MockAutofillProfileSyncableService::DataBundle expected_bundle; | |
307 expected_bundle.profiles_to_add.push_back(&profile1); | |
308 expected_bundle.profiles_to_add.push_back(&profile2); | |
309 expected_bundle.profiles_to_update.push_back(&profile3); | |
310 | |
311 MergeDataAndStartSyncing( | |
312 profiles_from_web_db, data_list, expected_bundle, expected_change_list); | |
313 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); | |
314 } | |
315 | |
316 TEST_F(AutofillProfileSyncableServiceTest, MergeIdenticalProfiles) { | |
317 std::vector<AutofillProfile*> profiles_from_web_db; | |
318 std::string guid_present1 = kGuid1; | |
319 std::string guid_present2 = kGuid2; | |
320 std::string guid_synced1 = kGuid3; | |
321 std::string guid_synced2 = kGuid4; | |
322 std::string origin_present1 = kHttpOrigin; | |
323 std::string origin_present2 = kSettingsOrigin; | |
324 std::string origin_synced1 = kHttpsOrigin; | |
325 std::string origin_synced2 = kHttpsOrigin; | |
326 | |
327 profiles_from_web_db.push_back( | |
328 new AutofillProfile(guid_present1, origin_present1)); | |
329 profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, UTF8ToUTF16("John")); | |
330 profiles_from_web_db.back()->SetRawInfo(ADDRESS_HOME_LINE1, | |
331 UTF8ToUTF16("1 1st st")); | |
332 profiles_from_web_db.push_back( | |
333 new AutofillProfile(guid_present2, origin_present2)); | |
334 profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, UTF8ToUTF16("Tom")); | |
335 profiles_from_web_db.back()->SetRawInfo(ADDRESS_HOME_LINE1, | |
336 UTF8ToUTF16("2 2nd st")); | |
337 | |
338 // The synced profiles are identical to the local ones, except that the guids | |
339 // are different. | |
340 syncer::SyncDataList data_list; | |
341 AutofillProfile profile1(guid_synced1, origin_synced1); | |
342 profile1.SetRawInfo(NAME_FIRST, UTF8ToUTF16("John")); | |
343 profile1.SetRawInfo(ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); | |
344 data_list.push_back(autofill_syncable_service_.CreateData(profile1)); | |
345 AutofillProfile profile2(guid_synced2, origin_synced2); | |
346 profile2.SetRawInfo(NAME_FIRST, UTF8ToUTF16("Tom")); | |
347 profile2.SetRawInfo(ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st")); | |
348 data_list.push_back(autofill_syncable_service_.CreateData(profile2)); | |
349 | |
350 AutofillProfile expected_profile(profile2); | |
351 expected_profile.set_origin(kSettingsOrigin); | |
352 syncer::SyncChangeList expected_change_list; | |
353 expected_change_list.push_back( | |
354 syncer::SyncChange(FROM_HERE, | |
355 syncer::SyncChange::ACTION_UPDATE, | |
356 MockAutofillProfileSyncableService::CreateData( | |
357 expected_profile))); | |
358 | |
359 MockAutofillProfileSyncableService::DataBundle expected_bundle; | |
360 expected_bundle.profiles_to_delete.push_back(guid_present1); | |
361 expected_bundle.profiles_to_delete.push_back(guid_present2); | |
362 expected_bundle.profiles_to_add.push_back(&profile1); | |
363 expected_bundle.profiles_to_add.push_back(&expected_profile); | |
364 | |
365 MergeDataAndStartSyncing( | |
366 profiles_from_web_db, data_list, expected_bundle, expected_change_list); | |
367 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); | |
368 } | |
369 | |
370 TEST_F(AutofillProfileSyncableServiceTest, MergeSimilarProfiles) { | |
371 std::vector<AutofillProfile*> profiles_from_web_db; | |
372 std::string guid_present1 = kGuid1; | |
373 std::string guid_present2 = kGuid2; | |
374 std::string guid_synced1 = kGuid3; | |
375 std::string guid_synced2 = kGuid4; | |
376 std::string origin_present1 = kHttpOrigin; | |
377 std::string origin_present2 = kSettingsOrigin; | |
378 std::string origin_synced1 = kHttpsOrigin; | |
379 std::string origin_synced2 = kHttpsOrigin; | |
380 | |
381 profiles_from_web_db.push_back( | |
382 new AutofillProfile(guid_present1, origin_present1)); | |
383 profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, UTF8ToUTF16("John")); | |
384 profiles_from_web_db.back()->SetRawInfo(ADDRESS_HOME_LINE1, | |
385 UTF8ToUTF16("1 1st st")); | |
386 profiles_from_web_db.push_back( | |
387 new AutofillProfile(guid_present2, origin_present2)); | |
388 profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, UTF8ToUTF16("Tom")); | |
389 profiles_from_web_db.back()->SetRawInfo(ADDRESS_HOME_LINE1, | |
390 UTF8ToUTF16("2 2nd st")); | |
391 | |
392 // The synced profiles are identical to the local ones, except that the guids | |
393 // are different. | |
394 syncer::SyncDataList data_list; | |
395 AutofillProfile profile1(guid_synced1, origin_synced1); | |
396 profile1.SetRawInfo(NAME_FIRST, UTF8ToUTF16("John")); | |
397 profile1.SetRawInfo(ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); | |
398 profile1.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Frobbers, Inc.")); | |
399 data_list.push_back(autofill_syncable_service_.CreateData(profile1)); | |
400 AutofillProfile profile2(guid_synced2, origin_synced2); | |
401 profile2.SetRawInfo(NAME_FIRST, UTF8ToUTF16("Tom")); | |
402 profile2.SetRawInfo(ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st")); | |
403 profile2.SetRawInfo(COMPANY_NAME, UTF8ToUTF16("Fizzbang, LLC.")); | |
404 data_list.push_back(autofill_syncable_service_.CreateData(profile2)); | |
405 | |
406 // The first profile should have its origin updated. | |
407 // The second profile should remain as-is, because an unverified profile | |
408 // should never overwrite a verified one. | |
409 AutofillProfile expected_profile(profile1); | |
410 expected_profile.set_origin(origin_present1); | |
411 syncer::SyncChangeList expected_change_list; | |
412 expected_change_list.push_back( | |
413 syncer::SyncChange(FROM_HERE, | |
414 syncer::SyncChange::ACTION_ADD, | |
415 MockAutofillProfileSyncableService::CreateData( | |
416 *profiles_from_web_db.back()))); | |
417 expected_change_list.push_back( | |
418 syncer::SyncChange(FROM_HERE, | |
419 syncer::SyncChange::ACTION_UPDATE, | |
420 MockAutofillProfileSyncableService::CreateData( | |
421 expected_profile))); | |
422 | |
423 MockAutofillProfileSyncableService::DataBundle expected_bundle; | |
424 expected_bundle.profiles_to_delete.push_back(guid_present1); | |
425 expected_bundle.profiles_to_add.push_back(&expected_profile); | |
426 expected_bundle.profiles_to_add.push_back(&profile2); | |
427 | |
428 MergeDataAndStartSyncing( | |
429 profiles_from_web_db, data_list, expected_bundle, expected_change_list); | |
430 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); | |
431 } | |
432 | |
433 // Ensure that no Sync events are generated to fill in missing origins from Sync | |
434 // with explicitly present empty ones. This ensures that the migration to add | |
435 // origins to profiles does not generate lots of needless Sync updates. | |
436 TEST_F(AutofillProfileSyncableServiceTest, MergeDataEmptyOrigins) { | |
437 std::vector<AutofillProfile*> profiles_from_web_db; | |
438 | |
439 // Create a profile with an empty origin. | |
440 AutofillProfile profile(kGuid1, std::string()); | |
441 profile.SetRawInfo(NAME_FIRST, UTF8ToUTF16("John")); | |
442 profile.SetRawInfo(ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); | |
443 | |
444 profiles_from_web_db.push_back(new AutofillProfile(profile)); | |
445 | |
446 // Create a Sync profile identical to |profile|, except with no origin set. | |
447 sync_pb::EntitySpecifics specifics; | |
448 sync_pb::AutofillProfileSpecifics* autofill_specifics = | |
449 specifics.mutable_autofill_profile(); | |
450 autofill_specifics->set_guid(profile.guid()); | |
451 autofill_specifics->add_name_first("John"); | |
452 autofill_specifics->add_name_middle(std::string()); | |
453 autofill_specifics->add_name_last(std::string()); | |
454 autofill_specifics->add_email_address(std::string()); | |
455 autofill_specifics->add_phone_home_whole_number(std::string()); | |
456 autofill_specifics->set_address_home_line1("1 1st st"); | |
457 EXPECT_FALSE(autofill_specifics->has_origin()); | |
458 | |
459 syncer::SyncDataList data_list; | |
460 data_list.push_back( | |
461 syncer::SyncData::CreateLocalData( | |
462 profile.guid(), profile.guid(), specifics)); | |
463 | |
464 MockAutofillProfileSyncableService::DataBundle expected_bundle; | |
465 syncer::SyncChangeList expected_change_list; | |
466 MergeDataAndStartSyncing( | |
467 profiles_from_web_db, data_list, expected_bundle, expected_change_list); | |
468 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); | |
469 } | |
470 | |
471 TEST_F(AutofillProfileSyncableServiceTest, GetAllSyncData) { | |
472 std::vector<AutofillProfile*> profiles_from_web_db; | |
473 std::string guid_present1 = kGuid1; | |
474 std::string guid_present2 = kGuid2; | |
475 | |
476 profiles_from_web_db.push_back( | |
477 new AutofillProfile(guid_present1, kHttpOrigin)); | |
478 profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, UTF8ToUTF16("John")); | |
479 profiles_from_web_db.push_back( | |
480 new AutofillProfile(guid_present2, kHttpsOrigin)); | |
481 profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, UTF8ToUTF16("Jane")); | |
482 | |
483 syncer::SyncChangeList expected_change_list; | |
484 expected_change_list.push_back( | |
485 syncer::SyncChange(FROM_HERE, | |
486 syncer::SyncChange::ACTION_ADD, | |
487 MockAutofillProfileSyncableService::CreateData( | |
488 *profiles_from_web_db.front()))); | |
489 expected_change_list.push_back( | |
490 syncer::SyncChange(FROM_HERE, | |
491 syncer::SyncChange::ACTION_ADD, | |
492 MockAutofillProfileSyncableService::CreateData( | |
493 *profiles_from_web_db.back()))); | |
494 | |
495 MockAutofillProfileSyncableService::DataBundle expected_bundle; | |
496 syncer::SyncDataList data_list; | |
497 MergeDataAndStartSyncing( | |
498 profiles_from_web_db, data_list, expected_bundle, expected_change_list); | |
499 | |
500 syncer::SyncDataList data = | |
501 autofill_syncable_service_.GetAllSyncData(syncer::AUTOFILL_PROFILE); | |
502 | |
503 ASSERT_EQ(2U, data.size()); | |
504 EXPECT_EQ(guid_present1, data[0].GetSpecifics().autofill_profile().guid()); | |
505 EXPECT_EQ(guid_present2, data[1].GetSpecifics().autofill_profile().guid()); | |
506 EXPECT_EQ(kHttpOrigin, data[0].GetSpecifics().autofill_profile().origin()); | |
507 EXPECT_EQ(kHttpsOrigin, data[1].GetSpecifics().autofill_profile().origin()); | |
508 | |
509 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); | |
510 } | |
511 | |
512 TEST_F(AutofillProfileSyncableServiceTest, ProcessSyncChanges) { | |
513 std::vector<AutofillProfile *> profiles_from_web_db; | |
514 std::string guid_present = kGuid1; | |
515 std::string guid_synced = kGuid2; | |
516 | |
517 syncer::SyncChangeList change_list; | |
518 AutofillProfile profile(guid_synced, kHttpOrigin); | |
519 profile.SetRawInfo(NAME_FIRST, UTF8ToUTF16("Jane")); | |
520 change_list.push_back( | |
521 syncer::SyncChange( | |
522 FROM_HERE, | |
523 syncer::SyncChange::ACTION_ADD, | |
524 MockAutofillProfileSyncableService::CreateData(profile))); | |
525 AutofillProfile empty_profile(guid_present, kHttpsOrigin); | |
526 change_list.push_back( | |
527 syncer::SyncChange( | |
528 FROM_HERE, | |
529 syncer::SyncChange::ACTION_DELETE, | |
530 MockAutofillProfileSyncableService::CreateData(empty_profile))); | |
531 | |
532 MockAutofillProfileSyncableService::DataBundle expected_bundle; | |
533 expected_bundle.profiles_to_delete.push_back(guid_present); | |
534 expected_bundle.profiles_to_add.push_back(&profile); | |
535 | |
536 EXPECT_CALL(autofill_syncable_service_, SaveChangesToWebData( | |
537 DataBundleCheck(expected_bundle))) | |
538 .Times(1) | |
539 .WillOnce(Return(true)); | |
540 | |
541 autofill_syncable_service_.set_sync_processor(sync_processor_.release()); | |
542 syncer::SyncError error = autofill_syncable_service_.ProcessSyncChanges( | |
543 FROM_HERE, change_list); | |
544 | |
545 EXPECT_FALSE(error.IsSet()); | |
546 } | |
547 | |
548 TEST_F(AutofillProfileSyncableServiceTest, AutofillProfileAdded) { | |
549 // Will be owned by the syncable service. Keep a reference available here for | |
550 // verifying test expectations. | |
551 TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor; | |
552 autofill_syncable_service_.set_sync_processor(sync_change_processor); | |
553 | |
554 AutofillProfile profile(kGuid1, kHttpsOrigin); | |
555 profile.SetRawInfo(NAME_FIRST, UTF8ToUTF16("Jane")); | |
556 AutofillProfileChange change(AutofillProfileChange::ADD, kGuid1, &profile); | |
557 autofill_syncable_service_.AutofillProfileChanged(change); | |
558 | |
559 ASSERT_EQ(1U, sync_change_processor->changes().size()); | |
560 syncer::SyncChange result = sync_change_processor->changes()[0]; | |
561 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, result.change_type()); | |
562 | |
563 sync_pb::AutofillProfileSpecifics specifics = | |
564 result.sync_data().GetSpecifics().autofill_profile(); | |
565 EXPECT_EQ(kGuid1, specifics.guid()); | |
566 EXPECT_EQ(kHttpsOrigin, specifics.origin()); | |
567 EXPECT_THAT(specifics.name_first(), testing::ElementsAre("Jane")); | |
568 } | |
569 | |
570 TEST_F(AutofillProfileSyncableServiceTest, AutofillProfileDeleted) { | |
571 // Will be owned by the syncable service. Keep a reference available here for | |
572 // verifying test expectations. | |
573 TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor; | |
574 autofill_syncable_service_.set_sync_processor(sync_change_processor); | |
575 | |
576 AutofillProfileChange change(AutofillProfileChange::REMOVE, kGuid2, NULL); | |
577 autofill_syncable_service_.AutofillProfileChanged(change); | |
578 | |
579 ASSERT_EQ(1U, sync_change_processor->changes().size()); | |
580 syncer::SyncChange result = sync_change_processor->changes()[0]; | |
581 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, result.change_type()); | |
582 sync_pb::AutofillProfileSpecifics specifics = | |
583 result.sync_data().GetSpecifics().autofill_profile(); | |
584 EXPECT_EQ(kGuid2, specifics.guid()); | |
585 } | |
586 | |
587 TEST_F(AutofillProfileSyncableServiceTest, UpdateField) { | |
588 AutofillProfile profile(kGuid1, kSettingsOrigin); | |
589 std::string company1 = "A Company"; | |
590 std::string company2 = "Another Company"; | |
591 profile.SetRawInfo(COMPANY_NAME, UTF8ToUTF16(company1)); | |
592 EXPECT_FALSE(AutofillProfileSyncableService::UpdateField( | |
593 COMPANY_NAME, company1, &profile)); | |
594 EXPECT_EQ(profile.GetRawInfo(COMPANY_NAME), UTF8ToUTF16(company1)); | |
595 EXPECT_TRUE(AutofillProfileSyncableService::UpdateField( | |
596 COMPANY_NAME, company2, &profile)); | |
597 EXPECT_EQ(profile.GetRawInfo(COMPANY_NAME), UTF8ToUTF16(company2)); | |
598 EXPECT_FALSE(AutofillProfileSyncableService::UpdateField( | |
599 COMPANY_NAME, company2, &profile)); | |
600 EXPECT_EQ(profile.GetRawInfo(COMPANY_NAME), UTF8ToUTF16(company2)); | |
601 } | |
602 | |
603 TEST_F(AutofillProfileSyncableServiceTest, UpdateMultivaluedField) { | |
604 AutofillProfile profile(kGuid1, kHttpsOrigin); | |
605 | |
606 std::vector<base::string16> values; | |
607 values.push_back(UTF8ToUTF16("1@1.com")); | |
608 values.push_back(UTF8ToUTF16("2@1.com")); | |
609 profile.SetRawMultiInfo(EMAIL_ADDRESS, values); | |
610 | |
611 ::google::protobuf::RepeatedPtrField<std::string> specifics_fields; | |
612 specifics_fields.AddAllocated(new std::string("2@1.com")); | |
613 specifics_fields.AddAllocated(new std::string("3@1.com")); | |
614 | |
615 EXPECT_TRUE(AutofillProfileSyncableService::UpdateMultivaluedField( | |
616 EMAIL_ADDRESS, specifics_fields, &profile)); | |
617 profile.GetRawMultiInfo(EMAIL_ADDRESS, &values); | |
618 ASSERT_TRUE(values.size() == 2); | |
619 EXPECT_EQ(values[0], UTF8ToUTF16("2@1.com")); | |
620 EXPECT_EQ(values[1], UTF8ToUTF16("3@1.com")); | |
621 | |
622 EXPECT_FALSE(AutofillProfileSyncableService::UpdateMultivaluedField( | |
623 EMAIL_ADDRESS, specifics_fields, &profile)); | |
624 profile.GetRawMultiInfo(EMAIL_ADDRESS, &values); | |
625 ASSERT_EQ(values.size(), 2U); | |
626 EXPECT_EQ(values[0], UTF8ToUTF16("2@1.com")); | |
627 EXPECT_EQ(values[1], UTF8ToUTF16("3@1.com")); | |
628 EXPECT_TRUE(AutofillProfileSyncableService::UpdateMultivaluedField( | |
629 EMAIL_ADDRESS, ::google::protobuf::RepeatedPtrField<std::string>(), | |
630 &profile)); | |
631 profile.GetRawMultiInfo(EMAIL_ADDRESS, &values); | |
632 ASSERT_EQ(values.size(), 1U); // Always have at least an empty string. | |
633 EXPECT_EQ(values[0], UTF8ToUTF16("")); | |
634 } | |
635 | |
636 TEST_F(AutofillProfileSyncableServiceTest, MergeProfile) { | |
637 AutofillProfile profile1(kGuid1, kHttpOrigin); | |
638 profile1.SetRawInfo(ADDRESS_HOME_LINE1, UTF8ToUTF16("111 First St.")); | |
639 | |
640 std::vector<base::string16> values; | |
641 values.push_back(UTF8ToUTF16("1@1.com")); | |
642 values.push_back(UTF8ToUTF16("2@1.com")); | |
643 profile1.SetRawMultiInfo(EMAIL_ADDRESS, values); | |
644 | |
645 AutofillProfile profile2(kGuid2, kHttpsOrigin); | |
646 profile2.SetRawInfo(ADDRESS_HOME_LINE1, UTF8ToUTF16("111 First St.")); | |
647 | |
648 // |values| now is [ "1@1.com", "2@1.com", "3@1.com" ]. | |
649 values.push_back(UTF8ToUTF16("3@1.com")); | |
650 profile2.SetRawMultiInfo(EMAIL_ADDRESS, values); | |
651 | |
652 values.clear(); | |
653 values.push_back(UTF8ToUTF16("John")); | |
654 profile1.SetRawMultiInfo(NAME_FIRST, values); | |
655 values.push_back(UTF8ToUTF16("Jane")); | |
656 profile2.SetRawMultiInfo(NAME_FIRST, values); | |
657 | |
658 values.clear(); | |
659 values.push_back(UTF8ToUTF16("Doe")); | |
660 profile1.SetRawMultiInfo(NAME_LAST, values); | |
661 values.push_back(UTF8ToUTF16("Other")); | |
662 profile2.SetRawMultiInfo(NAME_LAST, values); | |
663 | |
664 values.clear(); | |
665 values.push_back(UTF8ToUTF16("650234567")); | |
666 profile2.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, values); | |
667 | |
668 EXPECT_FALSE(AutofillProfileSyncableService::MergeProfile(profile2, | |
669 &profile1, | |
670 "en-US")); | |
671 | |
672 profile1.GetRawMultiInfo(NAME_FIRST, &values); | |
673 ASSERT_EQ(values.size(), 2U); | |
674 EXPECT_EQ(values[0], UTF8ToUTF16("John")); | |
675 EXPECT_EQ(values[1], UTF8ToUTF16("Jane")); | |
676 | |
677 profile1.GetRawMultiInfo(NAME_LAST, &values); | |
678 ASSERT_EQ(values.size(), 2U); | |
679 EXPECT_EQ(values[0], UTF8ToUTF16("Doe")); | |
680 EXPECT_EQ(values[1], UTF8ToUTF16("Other")); | |
681 | |
682 profile1.GetRawMultiInfo(EMAIL_ADDRESS, &values); | |
683 ASSERT_EQ(values.size(), 3U); | |
684 EXPECT_EQ(values[0], UTF8ToUTF16("1@1.com")); | |
685 EXPECT_EQ(values[1], UTF8ToUTF16("2@1.com")); | |
686 EXPECT_EQ(values[2], UTF8ToUTF16("3@1.com")); | |
687 | |
688 profile1.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values); | |
689 ASSERT_EQ(values.size(), 1U); | |
690 EXPECT_EQ(values[0], UTF8ToUTF16("650234567")); | |
691 | |
692 EXPECT_EQ(profile2.origin(), profile1.origin()); | |
693 | |
694 AutofillProfile profile3(kGuid3, kHttpOrigin); | |
695 profile3.SetRawInfo(ADDRESS_HOME_LINE1, UTF8ToUTF16("111 First St.")); | |
696 | |
697 values.clear(); | |
698 values.push_back(UTF8ToUTF16("Jane")); | |
699 profile3.SetRawMultiInfo(NAME_FIRST, values); | |
700 | |
701 values.clear(); | |
702 values.push_back(UTF8ToUTF16("Doe")); | |
703 profile3.SetRawMultiInfo(NAME_LAST, values); | |
704 | |
705 EXPECT_TRUE(AutofillProfileSyncableService::MergeProfile(profile3, | |
706 &profile1, | |
707 "en-US")); | |
708 | |
709 profile1.GetRawMultiInfo(NAME_FIRST, &values); | |
710 ASSERT_EQ(values.size(), 3U); | |
711 EXPECT_EQ(values[0], UTF8ToUTF16("John")); | |
712 EXPECT_EQ(values[1], UTF8ToUTF16("Jane")); | |
713 EXPECT_EQ(values[2], UTF8ToUTF16("Jane")); | |
714 | |
715 profile1.GetRawMultiInfo(NAME_LAST, &values); | |
716 ASSERT_EQ(values.size(), 3U); | |
717 EXPECT_EQ(values[0], UTF8ToUTF16("Doe")); | |
718 EXPECT_EQ(values[1], UTF8ToUTF16("Other")); | |
719 EXPECT_EQ(values[2], UTF8ToUTF16("Doe")); | |
720 | |
721 // Middle name should have three entries as well. | |
722 profile1.GetRawMultiInfo(NAME_MIDDLE, &values); | |
723 ASSERT_EQ(values.size(), 3U); | |
724 EXPECT_TRUE(values[0].empty()); | |
725 EXPECT_TRUE(values[1].empty()); | |
726 EXPECT_TRUE(values[2].empty()); | |
727 | |
728 profile1.GetRawMultiInfo(EMAIL_ADDRESS, &values); | |
729 ASSERT_EQ(values.size(), 3U); | |
730 EXPECT_EQ(values[0], UTF8ToUTF16("1@1.com")); | |
731 EXPECT_EQ(values[1], UTF8ToUTF16("2@1.com")); | |
732 EXPECT_EQ(values[2], UTF8ToUTF16("3@1.com")); | |
733 | |
734 profile1.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values); | |
735 ASSERT_EQ(values.size(), 1U); | |
736 EXPECT_EQ(values[0], UTF8ToUTF16("650234567")); | |
737 } | |
738 | |
739 // Ensure that all profile fields are able to be synced up from the client to | |
740 // the server. | |
741 TEST_F(AutofillProfileSyncableServiceTest, SyncAllFieldsToServer) { | |
742 std::vector<AutofillProfile*> profiles_from_web_db; | |
743 | |
744 // Create a profile with all fields set. | |
745 profiles_from_web_db.push_back(ConstructCompleteProfile().release()); | |
746 | |
747 // Set up expectations: No changes to the WebDB, and all fields correctly | |
748 // copied to Sync. | |
749 MockAutofillProfileSyncableService::DataBundle expected_bundle; | |
750 syncer::SyncChangeList expected_change_list; | |
751 expected_change_list.push_back( | |
752 syncer::SyncChange(FROM_HERE, | |
753 syncer::SyncChange::ACTION_ADD, | |
754 ConstructCompleteSyncData())); | |
755 | |
756 // Verify the expectations. | |
757 syncer::SyncDataList data_list; | |
758 MergeDataAndStartSyncing( | |
759 profiles_from_web_db, data_list, expected_bundle, expected_change_list); | |
760 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); | |
761 } | |
762 | |
763 // Ensure that all profile fields are able to be synced down from the server to | |
764 // the client. | |
765 TEST_F(AutofillProfileSyncableServiceTest, SyncAllFieldsToClient) { | |
766 // Create a profile with all fields set. | |
767 syncer::SyncDataList data_list; | |
768 data_list.push_back(ConstructCompleteSyncData()); | |
769 | |
770 // Set up expectations: All fields correctly copied to the WebDB, and no | |
771 // changes propagated to Sync. | |
772 syncer::SyncChangeList expected_change_list; | |
773 scoped_ptr<AutofillProfile> expected_profile = ConstructCompleteProfile(); | |
774 MockAutofillProfileSyncableService::DataBundle expected_bundle; | |
775 expected_bundle.profiles_to_add.push_back(expected_profile.get()); | |
776 | |
777 // Verify the expectations. | |
778 std::vector<AutofillProfile*> profiles_from_web_db; | |
779 MergeDataAndStartSyncing( | |
780 profiles_from_web_db, data_list, expected_bundle, expected_change_list); | |
781 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); | |
782 } | |
783 | |
784 // Ensure that the street address field takes precedence over the address line 1 | |
785 // and line 2 fields, even though these are expected to always be in sync in | |
786 // practice. | |
787 TEST_F(AutofillProfileSyncableServiceTest, | |
788 StreetAddressTakesPrecedenceOverAddressLines) { | |
789 // Create a Sync profile with conflicting address data in the street address | |
790 // field vs. the address line 1 and address line 2 fields. | |
791 sync_pb::EntitySpecifics specifics; | |
792 sync_pb::AutofillProfileSpecifics* autofill_specifics = | |
793 specifics.mutable_autofill_profile(); | |
794 autofill_specifics->set_guid(kGuid1); | |
795 autofill_specifics->set_origin(kHttpsOrigin); | |
796 autofill_specifics->add_name_first(std::string()); | |
797 autofill_specifics->add_name_middle(std::string()); | |
798 autofill_specifics->add_name_last(std::string()); | |
799 autofill_specifics->add_email_address(std::string()); | |
800 autofill_specifics->add_phone_home_whole_number(std::string()); | |
801 autofill_specifics->set_address_home_line1("123 Example St."); | |
802 autofill_specifics->set_address_home_line2("Apt. 42"); | |
803 autofill_specifics->set_address_home_street_address("456 El Camino Real\n" | |
804 "Suite #1337"); | |
805 | |
806 syncer::SyncDataList data_list; | |
807 data_list.push_back( | |
808 syncer::SyncData::CreateLocalData(kGuid1, kGuid1, specifics)); | |
809 | |
810 // Set up expectations: Full street address takes precedence over address | |
811 // lines. | |
812 syncer::SyncChangeList expected_change_list; | |
813 AutofillProfile expected_profile(kGuid1, kHttpsOrigin); | |
814 expected_profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, | |
815 ASCIIToUTF16("456 El Camino Real\n" | |
816 "Suite #1337")); | |
817 EXPECT_EQ(ASCIIToUTF16("456 El Camino Real"), | |
818 expected_profile.GetRawInfo(ADDRESS_HOME_LINE1)); | |
819 EXPECT_EQ(ASCIIToUTF16("Suite #1337"), | |
820 expected_profile.GetRawInfo(ADDRESS_HOME_LINE2)); | |
821 MockAutofillProfileSyncableService::DataBundle expected_bundle; | |
822 expected_bundle.profiles_to_add.push_back(&expected_profile); | |
823 | |
824 // Verify the expectations. | |
825 std::vector<AutofillProfile*> profiles_from_web_db; | |
826 MergeDataAndStartSyncing( | |
827 profiles_from_web_db, data_list, expected_bundle, expected_change_list); | |
828 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); | |
829 } | |
830 | |
831 // Ensure that no Sync events are generated to fill in missing street address | |
832 // fields from Sync with explicitly present ones identical to the data stored in | |
833 // the line1 and line2 fields. This ensures that the migration to add the | |
834 // street address field to profiles does not generate lots of needless Sync | |
835 // updates. | |
836 TEST_F(AutofillProfileSyncableServiceTest, MergeDataEmptyStreetAddress) { | |
837 std::vector<AutofillProfile*> profiles_from_web_db; | |
838 | |
839 // Create a profile with the street address set. | |
840 AutofillProfile profile(kGuid1, kHttpsOrigin); | |
841 profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, | |
842 ASCIIToUTF16("123 Example St.\n" | |
843 "Apt. 42")); | |
844 EXPECT_EQ(ASCIIToUTF16("123 Example St."), | |
845 profile.GetRawInfo(ADDRESS_HOME_LINE1)); | |
846 EXPECT_EQ(ASCIIToUTF16("Apt. 42"), profile.GetRawInfo(ADDRESS_HOME_LINE2)); | |
847 | |
848 profiles_from_web_db.push_back(new AutofillProfile(profile)); | |
849 | |
850 // Create a Sync profile identical to |profile|, except without street address | |
851 // explicitly set. | |
852 sync_pb::EntitySpecifics specifics; | |
853 sync_pb::AutofillProfileSpecifics* autofill_specifics = | |
854 specifics.mutable_autofill_profile(); | |
855 autofill_specifics->set_guid(profile.guid()); | |
856 autofill_specifics->set_origin(profile.origin()); | |
857 autofill_specifics->add_name_first(std::string()); | |
858 autofill_specifics->add_name_middle(std::string()); | |
859 autofill_specifics->add_name_last(std::string()); | |
860 autofill_specifics->add_email_address(std::string()); | |
861 autofill_specifics->add_phone_home_whole_number(std::string()); | |
862 autofill_specifics->set_address_home_line1("123 Example St."); | |
863 autofill_specifics->set_address_home_line2("Apt. 42"); | |
864 EXPECT_FALSE(autofill_specifics->has_address_home_street_address()); | |
865 | |
866 syncer::SyncDataList data_list; | |
867 data_list.push_back( | |
868 syncer::SyncData::CreateLocalData( | |
869 profile.guid(), profile.guid(), specifics)); | |
870 | |
871 MockAutofillProfileSyncableService::DataBundle expected_bundle; | |
872 syncer::SyncChangeList expected_change_list; | |
873 MergeDataAndStartSyncing( | |
874 profiles_from_web_db, data_list, expected_bundle, expected_change_list); | |
875 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); | |
876 } | |
877 | |
878 } // namespace autofill | |
OLD | NEW |