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