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 using ::testing::_; 19 using ::testing::DoAll; 20 using ::testing::Eq; 21 using ::testing::Return; 22 using ::testing::Property; 23 using autofill::AutofillProfile; 24 using autofill::AutofillProfileChange; 25 using content::BrowserThread; 26 27 // Some guids for testing. 28 const char kGuid1[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44B"; 29 const char kGuid2[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44C"; 30 const char kGuid3[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44D"; 31 const char kGuid4[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44E"; 32 const char kHttpOrigin[] = "http://www.example.com/"; 33 const char kHttpsOrigin[] = "https://www.example.com/"; 34 const char kSettingsOrigin[] = "Chrome settings"; 35 36 class MockAutofillProfileSyncableService 37 : public AutofillProfileSyncableService { 38 public: 39 MockAutofillProfileSyncableService() {} 40 virtual ~MockAutofillProfileSyncableService() {} 41 42 using AutofillProfileSyncableService::DataBundle; 43 using AutofillProfileSyncableService::set_sync_processor; 44 using AutofillProfileSyncableService::CreateData; 45 46 MOCK_METHOD1(LoadAutofillData, bool(std::vector<AutofillProfile*>*)); 47 MOCK_METHOD1(SaveChangesToWebData, 48 bool(const AutofillProfileSyncableService::DataBundle&)); 49 }; 50 51 ACTION_P(CopyData, data) { 52 arg0->resize(data->size()); 53 std::copy(data->begin(), data->end(), arg0->begin()); 54 } 55 56 MATCHER_P(CheckSyncChanges, n_sync_changes_list, "") { 57 if (arg.size() != n_sync_changes_list.size()) 58 return false; 59 syncer::SyncChangeList::const_iterator passed, expected; 60 for (passed = arg.begin(), expected = n_sync_changes_list.begin(); 61 passed != arg.end() && expected != n_sync_changes_list.end(); 62 ++passed, ++expected) { 63 DCHECK(passed->IsValid()); 64 if (passed->change_type() != expected->change_type()) 65 return false; 66 if (passed->sync_data().GetSpecifics().autofill_profile().guid() != 67 expected->sync_data().GetSpecifics().autofill_profile().guid()) { 68 return false; 69 } 70 } 71 return true; 72 } 73 74 MATCHER_P(DataBundleCheck, n_bundle, "") { 75 if ((arg.profiles_to_delete.size() != n_bundle.profiles_to_delete.size()) || 76 (arg.profiles_to_update.size() != n_bundle.profiles_to_update.size()) || 77 (arg.profiles_to_add.size() != n_bundle.profiles_to_add.size())) 78 return false; 79 for (size_t i = 0; i < arg.profiles_to_delete.size(); ++i) { 80 if (arg.profiles_to_delete[i] != n_bundle.profiles_to_delete[i]) 81 return false; 82 } 83 for (size_t i = 0; i < arg.profiles_to_update.size(); ++i) { 84 if (*arg.profiles_to_update[i] != *n_bundle.profiles_to_update[i]) 85 return false; 86 } 87 for (size_t i = 0; i < arg.profiles_to_add.size(); ++i) { 88 if (*arg.profiles_to_add[i] != *n_bundle.profiles_to_add[i]) 89 return false; 90 } 91 return true; 92 } 93 94 class MockSyncChangeProcessor : public syncer::SyncChangeProcessor { 95 public: 96 MockSyncChangeProcessor() {} 97 virtual ~MockSyncChangeProcessor() {} 98 99 MOCK_METHOD2(ProcessSyncChanges, 100 syncer::SyncError(const tracked_objects::Location&, 101 const syncer::SyncChangeList&)); 102 }; 103 104 class TestSyncChangeProcessor : public syncer::SyncChangeProcessor { 105 public: 106 TestSyncChangeProcessor() {} 107 virtual ~TestSyncChangeProcessor() {} 108 109 virtual syncer::SyncError ProcessSyncChanges( 110 const tracked_objects::Location& location, 111 const syncer::SyncChangeList& changes) OVERRIDE { 112 changes_ = changes; 113 return syncer::SyncError(); 114 } 115 116 const syncer::SyncChangeList& changes() { return changes_; } 117 118 private: 119 syncer::SyncChangeList changes_; 120 }; 121 122 class AutofillProfileSyncableServiceTest : public testing::Test { 123 public: 124 AutofillProfileSyncableServiceTest() 125 : ui_thread_(BrowserThread::UI, &message_loop_), 126 db_thread_(BrowserThread::DB, &message_loop_) {} 127 128 virtual void SetUp() OVERRIDE { 129 sync_processor_.reset(new MockSyncChangeProcessor); 130 } 131 132 // Wrapper around AutofillProfileSyncableService::MergeDataAndStartSyncing() 133 // that also verifies expectations. 134 void MergeDataAndStartSyncing( 135 const std::vector<AutofillProfile*>& profiles_from_web_db, 136 const syncer::SyncDataList& data_list, 137 const MockAutofillProfileSyncableService::DataBundle& expected_bundle, 138 const syncer::SyncChangeList& expected_change_list) { 139 EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_)) 140 .Times(1) 141 .WillOnce(DoAll(CopyData(&profiles_from_web_db), Return(true))); 142 EXPECT_CALL(autofill_syncable_service_, 143 SaveChangesToWebData(DataBundleCheck(expected_bundle))) 144 .Times(1) 145 .WillOnce(Return(true)); 146 ON_CALL(*sync_processor_, ProcessSyncChanges(_, _)) 147 .WillByDefault(Return(syncer::SyncError())); 148 EXPECT_CALL(*sync_processor_, 149 ProcessSyncChanges(_, CheckSyncChanges(expected_change_list))) 150 .Times(1) 151 .WillOnce(Return(syncer::SyncError())); 152 153 // Takes ownership of sync_processor_. 154 autofill_syncable_service_.MergeDataAndStartSyncing( 155 syncer::AUTOFILL_PROFILE, data_list, 156 sync_processor_.PassAs<syncer::SyncChangeProcessor>(), 157 scoped_ptr<syncer::SyncErrorFactory>( 158 new syncer::SyncErrorFactoryMock())); 159 } 160 161 protected: 162 base::MessageLoop message_loop_; 163 content::TestBrowserThread ui_thread_; 164 content::TestBrowserThread db_thread_; 165 MockAutofillProfileSyncableService autofill_syncable_service_; 166 scoped_ptr<MockSyncChangeProcessor> sync_processor_; 167 }; 168 169 TEST_F(AutofillProfileSyncableServiceTest, MergeDataAndStartSyncing) { 170 std::vector<AutofillProfile*> profiles_from_web_db; 171 std::string guid_present1 = kGuid1; 172 std::string guid_present2 = kGuid2; 173 std::string guid_synced1 = kGuid3; 174 std::string guid_synced2 = kGuid4; 175 std::string origin_present1 = kHttpOrigin; 176 std::string origin_present2 = std::string(); 177 std::string origin_synced1 = kHttpsOrigin; 178 std::string origin_synced2 = kSettingsOrigin; 179 180 profiles_from_web_db.push_back( 181 new AutofillProfile(guid_present1, origin_present1)); 182 profiles_from_web_db.back()->SetRawInfo( 183 autofill::NAME_FIRST, UTF8ToUTF16("John")); 184 profiles_from_web_db.back()->SetRawInfo( 185 autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); 186 profiles_from_web_db.push_back( 187 new AutofillProfile(guid_present2, origin_present2)); 188 profiles_from_web_db.back()->SetRawInfo( 189 autofill::NAME_FIRST, UTF8ToUTF16("Tom")); 190 profiles_from_web_db.back()->SetRawInfo( 191 autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st")); 192 193 syncer::SyncDataList data_list; 194 AutofillProfile profile1(guid_synced1, origin_synced1); 195 profile1.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Jane")); 196 data_list.push_back(autofill_syncable_service_.CreateData(profile1)); 197 AutofillProfile profile2(guid_synced2, origin_synced2); 198 profile2.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Harry")); 199 data_list.push_back(autofill_syncable_service_.CreateData(profile2)); 200 // This one will have the name and origin updated. 201 AutofillProfile profile3(guid_present2, origin_synced2); 202 profile3.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Tom Doe")); 203 data_list.push_back(autofill_syncable_service_.CreateData(profile3)); 204 205 syncer::SyncChangeList expected_change_list; 206 expected_change_list.push_back( 207 syncer::SyncChange(FROM_HERE, 208 syncer::SyncChange::ACTION_ADD, 209 MockAutofillProfileSyncableService::CreateData( 210 *profiles_from_web_db.front()))); 211 212 MockAutofillProfileSyncableService::DataBundle expected_bundle; 213 expected_bundle.profiles_to_add.push_back(&profile1); 214 expected_bundle.profiles_to_add.push_back(&profile2); 215 expected_bundle.profiles_to_update.push_back(&profile3); 216 217 MergeDataAndStartSyncing( 218 profiles_from_web_db, data_list, expected_bundle, expected_change_list); 219 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); 220 } 221 222 TEST_F(AutofillProfileSyncableServiceTest, MergeIdenticalProfiles) { 223 std::vector<AutofillProfile*> profiles_from_web_db; 224 std::string guid_present1 = kGuid1; 225 std::string guid_present2 = kGuid2; 226 std::string guid_synced1 = kGuid3; 227 std::string guid_synced2 = kGuid4; 228 std::string origin_present1 = kHttpOrigin; 229 std::string origin_present2 = kSettingsOrigin; 230 std::string origin_synced1 = kHttpsOrigin; 231 std::string origin_synced2 = kHttpsOrigin; 232 233 profiles_from_web_db.push_back( 234 new AutofillProfile(guid_present1, origin_present1)); 235 profiles_from_web_db.back()->SetRawInfo( 236 autofill::NAME_FIRST, UTF8ToUTF16("John")); 237 profiles_from_web_db.back()->SetRawInfo( 238 autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); 239 profiles_from_web_db.push_back( 240 new AutofillProfile(guid_present2, origin_present2)); 241 profiles_from_web_db.back()->SetRawInfo( 242 autofill::NAME_FIRST, UTF8ToUTF16("Tom")); 243 profiles_from_web_db.back()->SetRawInfo( 244 autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st")); 245 246 // The synced profiles are identical to the local ones, except that the guids 247 // are different. 248 syncer::SyncDataList data_list; 249 AutofillProfile profile1(guid_synced1, origin_synced1); 250 profile1.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("John")); 251 profile1.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); 252 data_list.push_back(autofill_syncable_service_.CreateData(profile1)); 253 AutofillProfile profile2(guid_synced2, origin_synced2); 254 profile2.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Tom")); 255 profile2.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st")); 256 data_list.push_back(autofill_syncable_service_.CreateData(profile2)); 257 258 AutofillProfile expected_profile(profile2); 259 expected_profile.set_origin(kSettingsOrigin); 260 syncer::SyncChangeList expected_change_list; 261 expected_change_list.push_back( 262 syncer::SyncChange(FROM_HERE, 263 syncer::SyncChange::ACTION_UPDATE, 264 MockAutofillProfileSyncableService::CreateData( 265 expected_profile))); 266 267 MockAutofillProfileSyncableService::DataBundle expected_bundle; 268 expected_bundle.profiles_to_delete.push_back(guid_present1); 269 expected_bundle.profiles_to_delete.push_back(guid_present2); 270 expected_bundle.profiles_to_add.push_back(&profile1); 271 expected_bundle.profiles_to_add.push_back(&expected_profile); 272 273 MergeDataAndStartSyncing( 274 profiles_from_web_db, data_list, expected_bundle, expected_change_list); 275 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); 276 } 277 278 TEST_F(AutofillProfileSyncableServiceTest, MergeSimilarProfiles) { 279 std::vector<AutofillProfile*> profiles_from_web_db; 280 std::string guid_present1 = kGuid1; 281 std::string guid_present2 = kGuid2; 282 std::string guid_synced1 = kGuid3; 283 std::string guid_synced2 = kGuid4; 284 std::string origin_present1 = kHttpOrigin; 285 std::string origin_present2 = kSettingsOrigin; 286 std::string origin_synced1 = kHttpsOrigin; 287 std::string origin_synced2 = kHttpsOrigin; 288 289 profiles_from_web_db.push_back( 290 new AutofillProfile(guid_present1, origin_present1)); 291 profiles_from_web_db.back()->SetRawInfo( 292 autofill::NAME_FIRST, UTF8ToUTF16("John")); 293 profiles_from_web_db.back()->SetRawInfo( 294 autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); 295 profiles_from_web_db.push_back( 296 new AutofillProfile(guid_present2, origin_present2)); 297 profiles_from_web_db.back()->SetRawInfo( 298 autofill::NAME_FIRST, UTF8ToUTF16("Tom")); 299 profiles_from_web_db.back()->SetRawInfo( 300 autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st")); 301 302 // The synced profiles are identical to the local ones, except that the guids 303 // are different. 304 syncer::SyncDataList data_list; 305 AutofillProfile profile1(guid_synced1, origin_synced1); 306 profile1.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("John")); 307 profile1.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); 308 profile1.SetRawInfo(autofill::COMPANY_NAME, UTF8ToUTF16("Frobbers, Inc.")); 309 data_list.push_back(autofill_syncable_service_.CreateData(profile1)); 310 AutofillProfile profile2(guid_synced2, origin_synced2); 311 profile2.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Tom")); 312 profile2.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st")); 313 profile2.SetRawInfo(autofill::COMPANY_NAME, UTF8ToUTF16("Fizzbang, LLC.")); 314 data_list.push_back(autofill_syncable_service_.CreateData(profile2)); 315 316 // The first profile should have its origin updated. 317 // The second profile should remain as-is, because an unverified profile 318 // should never overwrite a verified one. 319 AutofillProfile expected_profile(profile1); 320 expected_profile.set_origin(origin_present1); 321 syncer::SyncChangeList expected_change_list; 322 expected_change_list.push_back( 323 syncer::SyncChange(FROM_HERE, 324 syncer::SyncChange::ACTION_ADD, 325 MockAutofillProfileSyncableService::CreateData( 326 *profiles_from_web_db.back()))); 327 expected_change_list.push_back( 328 syncer::SyncChange(FROM_HERE, 329 syncer::SyncChange::ACTION_UPDATE, 330 MockAutofillProfileSyncableService::CreateData( 331 expected_profile))); 332 333 MockAutofillProfileSyncableService::DataBundle expected_bundle; 334 expected_bundle.profiles_to_delete.push_back(guid_present1); 335 expected_bundle.profiles_to_add.push_back(&expected_profile); 336 expected_bundle.profiles_to_add.push_back(&profile2); 337 338 MergeDataAndStartSyncing( 339 profiles_from_web_db, data_list, expected_bundle, expected_change_list); 340 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); 341 } 342 343 // Ensure that no Sync events are generated to fill in missing origins from Sync 344 // with explicitly present empty ones. This ensures that the migration to add 345 // origins to profiles does not generate lots of needless Sync updates. 346 TEST_F(AutofillProfileSyncableServiceTest, MergeDataEmptyOrigins) { 347 std::vector<AutofillProfile*> profiles_from_web_db; 348 349 // Create a profile with an empty origin. 350 AutofillProfile profile(kGuid1, std::string()); 351 profile.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("John")); 352 profile.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); 353 354 profiles_from_web_db.push_back(new AutofillProfile(profile)); 355 356 // Create a Sync profile identical to |profile|, except with no origin set. 357 sync_pb::EntitySpecifics specifics; 358 sync_pb::AutofillProfileSpecifics* autofill_specifics = 359 specifics.mutable_autofill_profile(); 360 autofill_specifics->set_guid(profile.guid()); 361 autofill_specifics->add_name_first("John"); 362 autofill_specifics->add_name_middle(std::string()); 363 autofill_specifics->add_name_last(std::string()); 364 autofill_specifics->add_email_address(std::string()); 365 autofill_specifics->add_phone_home_whole_number(std::string()); 366 autofill_specifics->set_address_home_line1("1 1st st"); 367 EXPECT_FALSE(autofill_specifics->has_origin()); 368 369 syncer::SyncDataList data_list; 370 data_list.push_back( 371 syncer::SyncData::CreateLocalData( 372 profile.guid(), profile.guid(), specifics)); 373 374 MockAutofillProfileSyncableService::DataBundle expected_bundle; 375 EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_)) 376 .Times(1) 377 .WillOnce(DoAll(CopyData(&profiles_from_web_db), Return(true))); 378 EXPECT_CALL(autofill_syncable_service_, 379 SaveChangesToWebData(DataBundleCheck(expected_bundle))) 380 .Times(1) 381 .WillOnce(Return(true)); 382 EXPECT_CALL(*sync_processor_, ProcessSyncChanges(_, _)).Times(0); 383 384 // Takes ownership of sync_processor_. 385 autofill_syncable_service_.MergeDataAndStartSyncing( 386 syncer::AUTOFILL_PROFILE, data_list, 387 sync_processor_.PassAs<syncer::SyncChangeProcessor>(), 388 scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); 389 390 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); 391 } 392 393 TEST_F(AutofillProfileSyncableServiceTest, GetAllSyncData) { 394 std::vector<AutofillProfile*> profiles_from_web_db; 395 std::string guid_present1 = kGuid1; 396 std::string guid_present2 = kGuid2; 397 398 profiles_from_web_db.push_back( 399 new AutofillProfile(guid_present1, kHttpOrigin)); 400 profiles_from_web_db.back()->SetRawInfo( 401 autofill::NAME_FIRST, UTF8ToUTF16("John")); 402 profiles_from_web_db.push_back( 403 new AutofillProfile(guid_present2, kHttpsOrigin)); 404 profiles_from_web_db.back()->SetRawInfo( 405 autofill::NAME_FIRST, UTF8ToUTF16("Jane")); 406 407 syncer::SyncChangeList expected_change_list; 408 expected_change_list.push_back( 409 syncer::SyncChange(FROM_HERE, 410 syncer::SyncChange::ACTION_ADD, 411 MockAutofillProfileSyncableService::CreateData( 412 *profiles_from_web_db.front()))); 413 expected_change_list.push_back( 414 syncer::SyncChange(FROM_HERE, 415 syncer::SyncChange::ACTION_ADD, 416 MockAutofillProfileSyncableService::CreateData( 417 *profiles_from_web_db.back()))); 418 419 MockAutofillProfileSyncableService::DataBundle expected_bundle; 420 syncer::SyncDataList data_list; 421 MergeDataAndStartSyncing( 422 profiles_from_web_db, data_list, expected_bundle, expected_change_list); 423 424 syncer::SyncDataList data = 425 autofill_syncable_service_.GetAllSyncData(syncer::AUTOFILL_PROFILE); 426 427 ASSERT_EQ(2U, data.size()); 428 EXPECT_EQ(guid_present1, data[0].GetSpecifics().autofill_profile().guid()); 429 EXPECT_EQ(guid_present2, data[1].GetSpecifics().autofill_profile().guid()); 430 EXPECT_EQ(kHttpOrigin, data[0].GetSpecifics().autofill_profile().origin()); 431 EXPECT_EQ(kHttpsOrigin, data[1].GetSpecifics().autofill_profile().origin()); 432 433 autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); 434 } 435 436 TEST_F(AutofillProfileSyncableServiceTest, ProcessSyncChanges) { 437 std::vector<AutofillProfile *> profiles_from_web_db; 438 std::string guid_present = kGuid1; 439 std::string guid_synced = kGuid2; 440 441 syncer::SyncChangeList change_list; 442 AutofillProfile profile(guid_synced, kHttpOrigin); 443 profile.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Jane")); 444 change_list.push_back( 445 syncer::SyncChange( 446 FROM_HERE, 447 syncer::SyncChange::ACTION_ADD, 448 MockAutofillProfileSyncableService::CreateData(profile))); 449 AutofillProfile empty_profile(guid_present, kHttpsOrigin); 450 change_list.push_back( 451 syncer::SyncChange( 452 FROM_HERE, 453 syncer::SyncChange::ACTION_DELETE, 454 MockAutofillProfileSyncableService::CreateData(empty_profile))); 455 456 MockAutofillProfileSyncableService::DataBundle expected_bundle; 457 expected_bundle.profiles_to_delete.push_back(guid_present); 458 expected_bundle.profiles_to_add.push_back(&profile); 459 460 EXPECT_CALL(autofill_syncable_service_, SaveChangesToWebData( 461 DataBundleCheck(expected_bundle))) 462 .Times(1) 463 .WillOnce(Return(true)); 464 465 autofill_syncable_service_.set_sync_processor(sync_processor_.release()); 466 syncer::SyncError error = autofill_syncable_service_.ProcessSyncChanges( 467 FROM_HERE, change_list); 468 469 EXPECT_FALSE(error.IsSet()); 470 } 471 472 TEST_F(AutofillProfileSyncableServiceTest, AutofillProfileAdded) { 473 // Will be owned by the syncable service. Keep a reference available here for 474 // verifying test expectations. 475 TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor; 476 autofill_syncable_service_.set_sync_processor(sync_change_processor); 477 478 AutofillProfile profile(kGuid1, kHttpsOrigin); 479 profile.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Jane")); 480 AutofillProfileChange change(AutofillProfileChange::ADD, kGuid1, &profile); 481 autofill_syncable_service_.AutofillProfileChanged(change); 482 483 ASSERT_EQ(1U, sync_change_processor->changes().size()); 484 syncer::SyncChange result = sync_change_processor->changes()[0]; 485 EXPECT_EQ(syncer::SyncChange::ACTION_ADD, result.change_type()); 486 487 sync_pb::AutofillProfileSpecifics specifics = 488 result.sync_data().GetSpecifics().autofill_profile(); 489 EXPECT_EQ(kGuid1, specifics.guid()); 490 EXPECT_EQ(kHttpsOrigin, specifics.origin()); 491 EXPECT_THAT(specifics.name_first(), testing::ElementsAre("Jane")); 492 } 493 494 TEST_F(AutofillProfileSyncableServiceTest, AutofillProfileDeleted) { 495 // Will be owned by the syncable service. Keep a reference available here for 496 // verifying test expectations. 497 TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor; 498 autofill_syncable_service_.set_sync_processor(sync_change_processor); 499 500 AutofillProfileChange change(AutofillProfileChange::REMOVE, kGuid2, NULL); 501 autofill_syncable_service_.AutofillProfileChanged(change); 502 503 ASSERT_EQ(1U, sync_change_processor->changes().size()); 504 syncer::SyncChange result = sync_change_processor->changes()[0]; 505 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, result.change_type()); 506 sync_pb::AutofillProfileSpecifics specifics = 507 result.sync_data().GetSpecifics().autofill_profile(); 508 EXPECT_EQ(kGuid2, specifics.guid()); 509 } 510 511 TEST_F(AutofillProfileSyncableServiceTest, UpdateField) { 512 AutofillProfile profile(kGuid1, kSettingsOrigin); 513 std::string company1 = "A Company"; 514 std::string company2 = "Another Company"; 515 profile.SetRawInfo(autofill::COMPANY_NAME, UTF8ToUTF16(company1)); 516 EXPECT_FALSE(AutofillProfileSyncableService::UpdateField( 517 autofill::COMPANY_NAME, company1, &profile)); 518 EXPECT_EQ(profile.GetRawInfo(autofill::COMPANY_NAME), UTF8ToUTF16(company1)); 519 EXPECT_TRUE(AutofillProfileSyncableService::UpdateField( 520 autofill::COMPANY_NAME, company2, &profile)); 521 EXPECT_EQ(profile.GetRawInfo(autofill::COMPANY_NAME), UTF8ToUTF16(company2)); 522 EXPECT_FALSE(AutofillProfileSyncableService::UpdateField( 523 autofill::COMPANY_NAME, company2, &profile)); 524 EXPECT_EQ(profile.GetRawInfo(autofill::COMPANY_NAME), UTF8ToUTF16(company2)); 525 } 526 527 TEST_F(AutofillProfileSyncableServiceTest, UpdateMultivaluedField) { 528 AutofillProfile profile(kGuid1, kHttpsOrigin); 529 530 std::vector<string16> values; 531 values.push_back(UTF8ToUTF16("1 (at) 1.com")); 532 values.push_back(UTF8ToUTF16("2 (at) 1.com")); 533 profile.SetRawMultiInfo(autofill::EMAIL_ADDRESS, values); 534 535 ::google::protobuf::RepeatedPtrField<std::string> specifics_fields; 536 specifics_fields.AddAllocated(new std::string("2 (at) 1.com")); 537 specifics_fields.AddAllocated(new std::string("3 (at) 1.com")); 538 539 EXPECT_TRUE(AutofillProfileSyncableService::UpdateMultivaluedField( 540 autofill::EMAIL_ADDRESS, specifics_fields, &profile)); 541 profile.GetRawMultiInfo(autofill::EMAIL_ADDRESS, &values); 542 ASSERT_TRUE(values.size() == 2); 543 EXPECT_EQ(values[0], UTF8ToUTF16("2 (at) 1.com")); 544 EXPECT_EQ(values[1], UTF8ToUTF16("3 (at) 1.com")); 545 546 EXPECT_FALSE(AutofillProfileSyncableService::UpdateMultivaluedField( 547 autofill::EMAIL_ADDRESS, specifics_fields, &profile)); 548 profile.GetRawMultiInfo(autofill::EMAIL_ADDRESS, &values); 549 ASSERT_EQ(values.size(), 2U); 550 EXPECT_EQ(values[0], UTF8ToUTF16("2 (at) 1.com")); 551 EXPECT_EQ(values[1], UTF8ToUTF16("3 (at) 1.com")); 552 EXPECT_TRUE(AutofillProfileSyncableService::UpdateMultivaluedField( 553 autofill::EMAIL_ADDRESS, 554 ::google::protobuf::RepeatedPtrField<std::string>(), 555 &profile)); 556 profile.GetRawMultiInfo(autofill::EMAIL_ADDRESS, &values); 557 ASSERT_EQ(values.size(), 1U); // Always have at least an empty string. 558 EXPECT_EQ(values[0], UTF8ToUTF16("")); 559 } 560 561 TEST_F(AutofillProfileSyncableServiceTest, MergeProfile) { 562 AutofillProfile profile1(kGuid1, kHttpOrigin); 563 profile1.SetRawInfo( 564 autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("111 First St.")); 565 566 std::vector<string16> values; 567 values.push_back(UTF8ToUTF16("1 (at) 1.com")); 568 values.push_back(UTF8ToUTF16("2 (at) 1.com")); 569 profile1.SetRawMultiInfo(autofill::EMAIL_ADDRESS, values); 570 571 AutofillProfile profile2(kGuid2, kHttpsOrigin); 572 profile2.SetRawInfo( 573 autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("111 First St.")); 574 575 // |values| now is [ "1 (at) 1.com", "2 (at) 1.com", "3 (at) 1.com" ]. 576 values.push_back(UTF8ToUTF16("3 (at) 1.com")); 577 profile2.SetRawMultiInfo(autofill::EMAIL_ADDRESS, values); 578 579 values.clear(); 580 values.push_back(UTF8ToUTF16("John")); 581 profile1.SetRawMultiInfo(autofill::NAME_FIRST, values); 582 values.push_back(UTF8ToUTF16("Jane")); 583 profile2.SetRawMultiInfo(autofill::NAME_FIRST, values); 584 585 values.clear(); 586 values.push_back(UTF8ToUTF16("Doe")); 587 profile1.SetRawMultiInfo(autofill::NAME_LAST, values); 588 values.push_back(UTF8ToUTF16("Other")); 589 profile2.SetRawMultiInfo(autofill::NAME_LAST, values); 590 591 values.clear(); 592 values.push_back(UTF8ToUTF16("650234567")); 593 profile2.SetRawMultiInfo(autofill::PHONE_HOME_WHOLE_NUMBER, values); 594 595 EXPECT_FALSE(AutofillProfileSyncableService::MergeProfile(profile2, 596 &profile1, 597 "en-US")); 598 599 profile1.GetRawMultiInfo(autofill::NAME_FIRST, &values); 600 ASSERT_EQ(values.size(), 2U); 601 EXPECT_EQ(values[0], UTF8ToUTF16("John")); 602 EXPECT_EQ(values[1], UTF8ToUTF16("Jane")); 603 604 profile1.GetRawMultiInfo(autofill::NAME_LAST, &values); 605 ASSERT_EQ(values.size(), 2U); 606 EXPECT_EQ(values[0], UTF8ToUTF16("Doe")); 607 EXPECT_EQ(values[1], UTF8ToUTF16("Other")); 608 609 profile1.GetRawMultiInfo(autofill::EMAIL_ADDRESS, &values); 610 ASSERT_EQ(values.size(), 3U); 611 EXPECT_EQ(values[0], UTF8ToUTF16("1 (at) 1.com")); 612 EXPECT_EQ(values[1], UTF8ToUTF16("2 (at) 1.com")); 613 EXPECT_EQ(values[2], UTF8ToUTF16("3 (at) 1.com")); 614 615 profile1.GetRawMultiInfo(autofill::PHONE_HOME_WHOLE_NUMBER, &values); 616 ASSERT_EQ(values.size(), 1U); 617 EXPECT_EQ(values[0], UTF8ToUTF16("650234567")); 618 619 EXPECT_EQ(profile2.origin(), profile1.origin()); 620 621 AutofillProfile profile3(kGuid3, kHttpOrigin); 622 profile3.SetRawInfo( 623 autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("111 First St.")); 624 625 values.clear(); 626 values.push_back(UTF8ToUTF16("Jane")); 627 profile3.SetRawMultiInfo(autofill::NAME_FIRST, values); 628 629 values.clear(); 630 values.push_back(UTF8ToUTF16("Doe")); 631 profile3.SetRawMultiInfo(autofill::NAME_LAST, values); 632 633 EXPECT_TRUE(AutofillProfileSyncableService::MergeProfile(profile3, 634 &profile1, 635 "en-US")); 636 637 profile1.GetRawMultiInfo(autofill::NAME_FIRST, &values); 638 ASSERT_EQ(values.size(), 3U); 639 EXPECT_EQ(values[0], UTF8ToUTF16("John")); 640 EXPECT_EQ(values[1], UTF8ToUTF16("Jane")); 641 EXPECT_EQ(values[2], UTF8ToUTF16("Jane")); 642 643 profile1.GetRawMultiInfo(autofill::NAME_LAST, &values); 644 ASSERT_EQ(values.size(), 3U); 645 EXPECT_EQ(values[0], UTF8ToUTF16("Doe")); 646 EXPECT_EQ(values[1], UTF8ToUTF16("Other")); 647 EXPECT_EQ(values[2], UTF8ToUTF16("Doe")); 648 649 // Middle name should have three entries as well. 650 profile1.GetRawMultiInfo(autofill::NAME_MIDDLE, &values); 651 ASSERT_EQ(values.size(), 3U); 652 EXPECT_TRUE(values[0].empty()); 653 EXPECT_TRUE(values[1].empty()); 654 EXPECT_TRUE(values[2].empty()); 655 656 profile1.GetRawMultiInfo(autofill::EMAIL_ADDRESS, &values); 657 ASSERT_EQ(values.size(), 3U); 658 EXPECT_EQ(values[0], UTF8ToUTF16("1 (at) 1.com")); 659 EXPECT_EQ(values[1], UTF8ToUTF16("2 (at) 1.com")); 660 EXPECT_EQ(values[2], UTF8ToUTF16("3 (at) 1.com")); 661 662 profile1.GetRawMultiInfo(autofill::PHONE_HOME_WHOLE_NUMBER, &values); 663 ASSERT_EQ(values.size(), 1U); 664 EXPECT_EQ(values[0], UTF8ToUTF16("650234567")); 665 } 666