| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/location.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/browser/webdata/autofill_profile_syncable_service.h" |
| #include "components/autofill/core/browser/autofill_profile.h" |
| #include "components/autofill/core/browser/webdata/autofill_change.h" |
| #include "content/public/test/test_browser_thread.h" |
| #include "sync/api/sync_error_factory.h" |
| #include "sync/api/sync_error_factory_mock.h" |
| #include "sync/protocol/sync.pb.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ::testing::_; |
| using ::testing::DoAll; |
| using ::testing::Eq; |
| using ::testing::Return; |
| using ::testing::Property; |
| using autofill::AutofillProfile; |
| using autofill::AutofillProfileChange; |
| using content::BrowserThread; |
| |
| // Some guids for testing. |
| const char kGuid1[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44B"; |
| const char kGuid2[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44C"; |
| const char kGuid3[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44D"; |
| const char kGuid4[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44E"; |
| const char kHttpOrigin[] = "http://www.example.com/"; |
| const char kHttpsOrigin[] = "https://www.example.com/"; |
| const char kSettingsOrigin[] = "Chrome settings"; |
| |
| class MockAutofillProfileSyncableService |
| : public AutofillProfileSyncableService { |
| public: |
| MockAutofillProfileSyncableService() {} |
| virtual ~MockAutofillProfileSyncableService() {} |
| |
| using AutofillProfileSyncableService::DataBundle; |
| using AutofillProfileSyncableService::set_sync_processor; |
| using AutofillProfileSyncableService::CreateData; |
| |
| MOCK_METHOD1(LoadAutofillData, bool(std::vector<AutofillProfile*>*)); |
| MOCK_METHOD1(SaveChangesToWebData, |
| bool(const AutofillProfileSyncableService::DataBundle&)); |
| }; |
| |
| ACTION_P(CopyData, data) { |
| arg0->resize(data->size()); |
| std::copy(data->begin(), data->end(), arg0->begin()); |
| } |
| |
| MATCHER_P(CheckSyncChanges, n_sync_changes_list, "") { |
| if (arg.size() != n_sync_changes_list.size()) |
| return false; |
| syncer::SyncChangeList::const_iterator passed, expected; |
| for (passed = arg.begin(), expected = n_sync_changes_list.begin(); |
| passed != arg.end() && expected != n_sync_changes_list.end(); |
| ++passed, ++expected) { |
| DCHECK(passed->IsValid()); |
| if (passed->change_type() != expected->change_type()) |
| return false; |
| if (passed->sync_data().GetSpecifics().autofill_profile().guid() != |
| expected->sync_data().GetSpecifics().autofill_profile().guid()) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| MATCHER_P(DataBundleCheck, n_bundle, "") { |
| if ((arg.profiles_to_delete.size() != n_bundle.profiles_to_delete.size()) || |
| (arg.profiles_to_update.size() != n_bundle.profiles_to_update.size()) || |
| (arg.profiles_to_add.size() != n_bundle.profiles_to_add.size())) |
| return false; |
| for (size_t i = 0; i < arg.profiles_to_delete.size(); ++i) { |
| if (arg.profiles_to_delete[i] != n_bundle.profiles_to_delete[i]) |
| return false; |
| } |
| for (size_t i = 0; i < arg.profiles_to_update.size(); ++i) { |
| if (*arg.profiles_to_update[i] != *n_bundle.profiles_to_update[i]) |
| return false; |
| } |
| for (size_t i = 0; i < arg.profiles_to_add.size(); ++i) { |
| if (*arg.profiles_to_add[i] != *n_bundle.profiles_to_add[i]) |
| return false; |
| } |
| return true; |
| } |
| |
| class MockSyncChangeProcessor : public syncer::SyncChangeProcessor { |
| public: |
| MockSyncChangeProcessor() {} |
| virtual ~MockSyncChangeProcessor() {} |
| |
| MOCK_METHOD2(ProcessSyncChanges, |
| syncer::SyncError(const tracked_objects::Location&, |
| const syncer::SyncChangeList&)); |
| }; |
| |
| class TestSyncChangeProcessor : public syncer::SyncChangeProcessor { |
| public: |
| TestSyncChangeProcessor() {} |
| virtual ~TestSyncChangeProcessor() {} |
| |
| virtual syncer::SyncError ProcessSyncChanges( |
| const tracked_objects::Location& location, |
| const syncer::SyncChangeList& changes) OVERRIDE { |
| changes_ = changes; |
| return syncer::SyncError(); |
| } |
| |
| const syncer::SyncChangeList& changes() { return changes_; } |
| |
| private: |
| syncer::SyncChangeList changes_; |
| }; |
| |
| class AutofillProfileSyncableServiceTest : public testing::Test { |
| public: |
| AutofillProfileSyncableServiceTest() |
| : ui_thread_(BrowserThread::UI, &message_loop_), |
| db_thread_(BrowserThread::DB, &message_loop_) {} |
| |
| virtual void SetUp() OVERRIDE { |
| sync_processor_.reset(new MockSyncChangeProcessor); |
| } |
| |
| // Wrapper around AutofillProfileSyncableService::MergeDataAndStartSyncing() |
| // that also verifies expectations. |
| void MergeDataAndStartSyncing( |
| const std::vector<AutofillProfile*>& profiles_from_web_db, |
| const syncer::SyncDataList& data_list, |
| const MockAutofillProfileSyncableService::DataBundle& expected_bundle, |
| const syncer::SyncChangeList& expected_change_list) { |
| EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_)) |
| .Times(1) |
| .WillOnce(DoAll(CopyData(&profiles_from_web_db), Return(true))); |
| EXPECT_CALL(autofill_syncable_service_, |
| SaveChangesToWebData(DataBundleCheck(expected_bundle))) |
| .Times(1) |
| .WillOnce(Return(true)); |
| ON_CALL(*sync_processor_, ProcessSyncChanges(_, _)) |
| .WillByDefault(Return(syncer::SyncError())); |
| EXPECT_CALL(*sync_processor_, |
| ProcessSyncChanges(_, CheckSyncChanges(expected_change_list))) |
| .Times(1) |
| .WillOnce(Return(syncer::SyncError())); |
| |
| // Takes ownership of sync_processor_. |
| autofill_syncable_service_.MergeDataAndStartSyncing( |
| syncer::AUTOFILL_PROFILE, data_list, |
| sync_processor_.PassAs<syncer::SyncChangeProcessor>(), |
| scoped_ptr<syncer::SyncErrorFactory>( |
| new syncer::SyncErrorFactoryMock())); |
| } |
| |
| protected: |
| base::MessageLoop message_loop_; |
| content::TestBrowserThread ui_thread_; |
| content::TestBrowserThread db_thread_; |
| MockAutofillProfileSyncableService autofill_syncable_service_; |
| scoped_ptr<MockSyncChangeProcessor> sync_processor_; |
| }; |
| |
| TEST_F(AutofillProfileSyncableServiceTest, MergeDataAndStartSyncing) { |
| std::vector<AutofillProfile*> profiles_from_web_db; |
| std::string guid_present1 = kGuid1; |
| std::string guid_present2 = kGuid2; |
| std::string guid_synced1 = kGuid3; |
| std::string guid_synced2 = kGuid4; |
| std::string origin_present1 = kHttpOrigin; |
| std::string origin_present2 = std::string(); |
| std::string origin_synced1 = kHttpsOrigin; |
| std::string origin_synced2 = kSettingsOrigin; |
| |
| profiles_from_web_db.push_back( |
| new AutofillProfile(guid_present1, origin_present1)); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::NAME_FIRST, UTF8ToUTF16("John")); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); |
| profiles_from_web_db.push_back( |
| new AutofillProfile(guid_present2, origin_present2)); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::NAME_FIRST, UTF8ToUTF16("Tom")); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st")); |
| |
| syncer::SyncDataList data_list; |
| AutofillProfile profile1(guid_synced1, origin_synced1); |
| profile1.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Jane")); |
| data_list.push_back(autofill_syncable_service_.CreateData(profile1)); |
| AutofillProfile profile2(guid_synced2, origin_synced2); |
| profile2.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Harry")); |
| data_list.push_back(autofill_syncable_service_.CreateData(profile2)); |
| // This one will have the name and origin updated. |
| AutofillProfile profile3(guid_present2, origin_synced2); |
| profile3.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Tom Doe")); |
| data_list.push_back(autofill_syncable_service_.CreateData(profile3)); |
| |
| syncer::SyncChangeList expected_change_list; |
| expected_change_list.push_back( |
| syncer::SyncChange(FROM_HERE, |
| syncer::SyncChange::ACTION_ADD, |
| MockAutofillProfileSyncableService::CreateData( |
| *profiles_from_web_db.front()))); |
| |
| MockAutofillProfileSyncableService::DataBundle expected_bundle; |
| expected_bundle.profiles_to_add.push_back(&profile1); |
| expected_bundle.profiles_to_add.push_back(&profile2); |
| expected_bundle.profiles_to_update.push_back(&profile3); |
| |
| MergeDataAndStartSyncing( |
| profiles_from_web_db, data_list, expected_bundle, expected_change_list); |
| autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); |
| } |
| |
| TEST_F(AutofillProfileSyncableServiceTest, MergeIdenticalProfiles) { |
| std::vector<AutofillProfile*> profiles_from_web_db; |
| std::string guid_present1 = kGuid1; |
| std::string guid_present2 = kGuid2; |
| std::string guid_synced1 = kGuid3; |
| std::string guid_synced2 = kGuid4; |
| std::string origin_present1 = kHttpOrigin; |
| std::string origin_present2 = kSettingsOrigin; |
| std::string origin_synced1 = kHttpsOrigin; |
| std::string origin_synced2 = kHttpsOrigin; |
| |
| profiles_from_web_db.push_back( |
| new AutofillProfile(guid_present1, origin_present1)); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::NAME_FIRST, UTF8ToUTF16("John")); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); |
| profiles_from_web_db.push_back( |
| new AutofillProfile(guid_present2, origin_present2)); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::NAME_FIRST, UTF8ToUTF16("Tom")); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st")); |
| |
| // The synced profiles are identical to the local ones, except that the guids |
| // are different. |
| syncer::SyncDataList data_list; |
| AutofillProfile profile1(guid_synced1, origin_synced1); |
| profile1.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("John")); |
| profile1.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); |
| data_list.push_back(autofill_syncable_service_.CreateData(profile1)); |
| AutofillProfile profile2(guid_synced2, origin_synced2); |
| profile2.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Tom")); |
| profile2.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st")); |
| data_list.push_back(autofill_syncable_service_.CreateData(profile2)); |
| |
| AutofillProfile expected_profile(profile2); |
| expected_profile.set_origin(kSettingsOrigin); |
| syncer::SyncChangeList expected_change_list; |
| expected_change_list.push_back( |
| syncer::SyncChange(FROM_HERE, |
| syncer::SyncChange::ACTION_UPDATE, |
| MockAutofillProfileSyncableService::CreateData( |
| expected_profile))); |
| |
| MockAutofillProfileSyncableService::DataBundle expected_bundle; |
| expected_bundle.profiles_to_delete.push_back(guid_present1); |
| expected_bundle.profiles_to_delete.push_back(guid_present2); |
| expected_bundle.profiles_to_add.push_back(&profile1); |
| expected_bundle.profiles_to_add.push_back(&expected_profile); |
| |
| MergeDataAndStartSyncing( |
| profiles_from_web_db, data_list, expected_bundle, expected_change_list); |
| autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); |
| } |
| |
| TEST_F(AutofillProfileSyncableServiceTest, MergeSimilarProfiles) { |
| std::vector<AutofillProfile*> profiles_from_web_db; |
| std::string guid_present1 = kGuid1; |
| std::string guid_present2 = kGuid2; |
| std::string guid_synced1 = kGuid3; |
| std::string guid_synced2 = kGuid4; |
| std::string origin_present1 = kHttpOrigin; |
| std::string origin_present2 = kSettingsOrigin; |
| std::string origin_synced1 = kHttpsOrigin; |
| std::string origin_synced2 = kHttpsOrigin; |
| |
| profiles_from_web_db.push_back( |
| new AutofillProfile(guid_present1, origin_present1)); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::NAME_FIRST, UTF8ToUTF16("John")); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); |
| profiles_from_web_db.push_back( |
| new AutofillProfile(guid_present2, origin_present2)); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::NAME_FIRST, UTF8ToUTF16("Tom")); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st")); |
| |
| // The synced profiles are identical to the local ones, except that the guids |
| // are different. |
| syncer::SyncDataList data_list; |
| AutofillProfile profile1(guid_synced1, origin_synced1); |
| profile1.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("John")); |
| profile1.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); |
| profile1.SetRawInfo(autofill::COMPANY_NAME, UTF8ToUTF16("Frobbers, Inc.")); |
| data_list.push_back(autofill_syncable_service_.CreateData(profile1)); |
| AutofillProfile profile2(guid_synced2, origin_synced2); |
| profile2.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Tom")); |
| profile2.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("2 2nd st")); |
| profile2.SetRawInfo(autofill::COMPANY_NAME, UTF8ToUTF16("Fizzbang, LLC.")); |
| data_list.push_back(autofill_syncable_service_.CreateData(profile2)); |
| |
| // The first profile should have its origin updated. |
| // The second profile should remain as-is, because an unverified profile |
| // should never overwrite a verified one. |
| AutofillProfile expected_profile(profile1); |
| expected_profile.set_origin(origin_present1); |
| syncer::SyncChangeList expected_change_list; |
| expected_change_list.push_back( |
| syncer::SyncChange(FROM_HERE, |
| syncer::SyncChange::ACTION_ADD, |
| MockAutofillProfileSyncableService::CreateData( |
| *profiles_from_web_db.back()))); |
| expected_change_list.push_back( |
| syncer::SyncChange(FROM_HERE, |
| syncer::SyncChange::ACTION_UPDATE, |
| MockAutofillProfileSyncableService::CreateData( |
| expected_profile))); |
| |
| MockAutofillProfileSyncableService::DataBundle expected_bundle; |
| expected_bundle.profiles_to_delete.push_back(guid_present1); |
| expected_bundle.profiles_to_add.push_back(&expected_profile); |
| expected_bundle.profiles_to_add.push_back(&profile2); |
| |
| MergeDataAndStartSyncing( |
| profiles_from_web_db, data_list, expected_bundle, expected_change_list); |
| autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); |
| } |
| |
| // Ensure that no Sync events are generated to fill in missing origins from Sync |
| // with explicitly present empty ones. This ensures that the migration to add |
| // origins to profiles does not generate lots of needless Sync updates. |
| TEST_F(AutofillProfileSyncableServiceTest, MergeDataEmptyOrigins) { |
| std::vector<AutofillProfile*> profiles_from_web_db; |
| |
| // Create a profile with an empty origin. |
| AutofillProfile profile(kGuid1, std::string()); |
| profile.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("John")); |
| profile.SetRawInfo(autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("1 1st st")); |
| |
| profiles_from_web_db.push_back(new AutofillProfile(profile)); |
| |
| // Create a Sync profile identical to |profile|, except with no origin set. |
| sync_pb::EntitySpecifics specifics; |
| sync_pb::AutofillProfileSpecifics* autofill_specifics = |
| specifics.mutable_autofill_profile(); |
| autofill_specifics->set_guid(profile.guid()); |
| autofill_specifics->add_name_first("John"); |
| autofill_specifics->add_name_middle(std::string()); |
| autofill_specifics->add_name_last(std::string()); |
| autofill_specifics->add_email_address(std::string()); |
| autofill_specifics->add_phone_home_whole_number(std::string()); |
| autofill_specifics->set_address_home_line1("1 1st st"); |
| EXPECT_FALSE(autofill_specifics->has_origin()); |
| |
| syncer::SyncDataList data_list; |
| data_list.push_back( |
| syncer::SyncData::CreateLocalData( |
| profile.guid(), profile.guid(), specifics)); |
| |
| MockAutofillProfileSyncableService::DataBundle expected_bundle; |
| EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_)) |
| .Times(1) |
| .WillOnce(DoAll(CopyData(&profiles_from_web_db), Return(true))); |
| EXPECT_CALL(autofill_syncable_service_, |
| SaveChangesToWebData(DataBundleCheck(expected_bundle))) |
| .Times(1) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*sync_processor_, ProcessSyncChanges(_, _)).Times(0); |
| |
| // Takes ownership of sync_processor_. |
| autofill_syncable_service_.MergeDataAndStartSyncing( |
| syncer::AUTOFILL_PROFILE, data_list, |
| sync_processor_.PassAs<syncer::SyncChangeProcessor>(), |
| scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock())); |
| |
| autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); |
| } |
| |
| TEST_F(AutofillProfileSyncableServiceTest, GetAllSyncData) { |
| std::vector<AutofillProfile*> profiles_from_web_db; |
| std::string guid_present1 = kGuid1; |
| std::string guid_present2 = kGuid2; |
| |
| profiles_from_web_db.push_back( |
| new AutofillProfile(guid_present1, kHttpOrigin)); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::NAME_FIRST, UTF8ToUTF16("John")); |
| profiles_from_web_db.push_back( |
| new AutofillProfile(guid_present2, kHttpsOrigin)); |
| profiles_from_web_db.back()->SetRawInfo( |
| autofill::NAME_FIRST, UTF8ToUTF16("Jane")); |
| |
| syncer::SyncChangeList expected_change_list; |
| expected_change_list.push_back( |
| syncer::SyncChange(FROM_HERE, |
| syncer::SyncChange::ACTION_ADD, |
| MockAutofillProfileSyncableService::CreateData( |
| *profiles_from_web_db.front()))); |
| expected_change_list.push_back( |
| syncer::SyncChange(FROM_HERE, |
| syncer::SyncChange::ACTION_ADD, |
| MockAutofillProfileSyncableService::CreateData( |
| *profiles_from_web_db.back()))); |
| |
| MockAutofillProfileSyncableService::DataBundle expected_bundle; |
| syncer::SyncDataList data_list; |
| MergeDataAndStartSyncing( |
| profiles_from_web_db, data_list, expected_bundle, expected_change_list); |
| |
| syncer::SyncDataList data = |
| autofill_syncable_service_.GetAllSyncData(syncer::AUTOFILL_PROFILE); |
| |
| ASSERT_EQ(2U, data.size()); |
| EXPECT_EQ(guid_present1, data[0].GetSpecifics().autofill_profile().guid()); |
| EXPECT_EQ(guid_present2, data[1].GetSpecifics().autofill_profile().guid()); |
| EXPECT_EQ(kHttpOrigin, data[0].GetSpecifics().autofill_profile().origin()); |
| EXPECT_EQ(kHttpsOrigin, data[1].GetSpecifics().autofill_profile().origin()); |
| |
| autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE); |
| } |
| |
| TEST_F(AutofillProfileSyncableServiceTest, ProcessSyncChanges) { |
| std::vector<AutofillProfile *> profiles_from_web_db; |
| std::string guid_present = kGuid1; |
| std::string guid_synced = kGuid2; |
| |
| syncer::SyncChangeList change_list; |
| AutofillProfile profile(guid_synced, kHttpOrigin); |
| profile.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Jane")); |
| change_list.push_back( |
| syncer::SyncChange( |
| FROM_HERE, |
| syncer::SyncChange::ACTION_ADD, |
| MockAutofillProfileSyncableService::CreateData(profile))); |
| AutofillProfile empty_profile(guid_present, kHttpsOrigin); |
| change_list.push_back( |
| syncer::SyncChange( |
| FROM_HERE, |
| syncer::SyncChange::ACTION_DELETE, |
| MockAutofillProfileSyncableService::CreateData(empty_profile))); |
| |
| MockAutofillProfileSyncableService::DataBundle expected_bundle; |
| expected_bundle.profiles_to_delete.push_back(guid_present); |
| expected_bundle.profiles_to_add.push_back(&profile); |
| |
| EXPECT_CALL(autofill_syncable_service_, SaveChangesToWebData( |
| DataBundleCheck(expected_bundle))) |
| .Times(1) |
| .WillOnce(Return(true)); |
| |
| autofill_syncable_service_.set_sync_processor(sync_processor_.release()); |
| syncer::SyncError error = autofill_syncable_service_.ProcessSyncChanges( |
| FROM_HERE, change_list); |
| |
| EXPECT_FALSE(error.IsSet()); |
| } |
| |
| TEST_F(AutofillProfileSyncableServiceTest, AutofillProfileAdded) { |
| // Will be owned by the syncable service. Keep a reference available here for |
| // verifying test expectations. |
| TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor; |
| autofill_syncable_service_.set_sync_processor(sync_change_processor); |
| |
| AutofillProfile profile(kGuid1, kHttpsOrigin); |
| profile.SetRawInfo(autofill::NAME_FIRST, UTF8ToUTF16("Jane")); |
| AutofillProfileChange change(AutofillProfileChange::ADD, kGuid1, &profile); |
| autofill_syncable_service_.AutofillProfileChanged(change); |
| |
| ASSERT_EQ(1U, sync_change_processor->changes().size()); |
| syncer::SyncChange result = sync_change_processor->changes()[0]; |
| EXPECT_EQ(syncer::SyncChange::ACTION_ADD, result.change_type()); |
| |
| sync_pb::AutofillProfileSpecifics specifics = |
| result.sync_data().GetSpecifics().autofill_profile(); |
| EXPECT_EQ(kGuid1, specifics.guid()); |
| EXPECT_EQ(kHttpsOrigin, specifics.origin()); |
| EXPECT_THAT(specifics.name_first(), testing::ElementsAre("Jane")); |
| } |
| |
| TEST_F(AutofillProfileSyncableServiceTest, AutofillProfileDeleted) { |
| // Will be owned by the syncable service. Keep a reference available here for |
| // verifying test expectations. |
| TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor; |
| autofill_syncable_service_.set_sync_processor(sync_change_processor); |
| |
| AutofillProfileChange change(AutofillProfileChange::REMOVE, kGuid2, NULL); |
| autofill_syncable_service_.AutofillProfileChanged(change); |
| |
| ASSERT_EQ(1U, sync_change_processor->changes().size()); |
| syncer::SyncChange result = sync_change_processor->changes()[0]; |
| EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, result.change_type()); |
| sync_pb::AutofillProfileSpecifics specifics = |
| result.sync_data().GetSpecifics().autofill_profile(); |
| EXPECT_EQ(kGuid2, specifics.guid()); |
| } |
| |
| TEST_F(AutofillProfileSyncableServiceTest, UpdateField) { |
| AutofillProfile profile(kGuid1, kSettingsOrigin); |
| std::string company1 = "A Company"; |
| std::string company2 = "Another Company"; |
| profile.SetRawInfo(autofill::COMPANY_NAME, UTF8ToUTF16(company1)); |
| EXPECT_FALSE(AutofillProfileSyncableService::UpdateField( |
| autofill::COMPANY_NAME, company1, &profile)); |
| EXPECT_EQ(profile.GetRawInfo(autofill::COMPANY_NAME), UTF8ToUTF16(company1)); |
| EXPECT_TRUE(AutofillProfileSyncableService::UpdateField( |
| autofill::COMPANY_NAME, company2, &profile)); |
| EXPECT_EQ(profile.GetRawInfo(autofill::COMPANY_NAME), UTF8ToUTF16(company2)); |
| EXPECT_FALSE(AutofillProfileSyncableService::UpdateField( |
| autofill::COMPANY_NAME, company2, &profile)); |
| EXPECT_EQ(profile.GetRawInfo(autofill::COMPANY_NAME), UTF8ToUTF16(company2)); |
| } |
| |
| TEST_F(AutofillProfileSyncableServiceTest, UpdateMultivaluedField) { |
| AutofillProfile profile(kGuid1, kHttpsOrigin); |
| |
| std::vector<string16> values; |
| values.push_back(UTF8ToUTF16("1@1.com")); |
| values.push_back(UTF8ToUTF16("2@1.com")); |
| profile.SetRawMultiInfo(autofill::EMAIL_ADDRESS, values); |
| |
| ::google::protobuf::RepeatedPtrField<std::string> specifics_fields; |
| specifics_fields.AddAllocated(new std::string("2@1.com")); |
| specifics_fields.AddAllocated(new std::string("3@1.com")); |
| |
| EXPECT_TRUE(AutofillProfileSyncableService::UpdateMultivaluedField( |
| autofill::EMAIL_ADDRESS, specifics_fields, &profile)); |
| profile.GetRawMultiInfo(autofill::EMAIL_ADDRESS, &values); |
| ASSERT_TRUE(values.size() == 2); |
| EXPECT_EQ(values[0], UTF8ToUTF16("2@1.com")); |
| EXPECT_EQ(values[1], UTF8ToUTF16("3@1.com")); |
| |
| EXPECT_FALSE(AutofillProfileSyncableService::UpdateMultivaluedField( |
| autofill::EMAIL_ADDRESS, specifics_fields, &profile)); |
| profile.GetRawMultiInfo(autofill::EMAIL_ADDRESS, &values); |
| ASSERT_EQ(values.size(), 2U); |
| EXPECT_EQ(values[0], UTF8ToUTF16("2@1.com")); |
| EXPECT_EQ(values[1], UTF8ToUTF16("3@1.com")); |
| EXPECT_TRUE(AutofillProfileSyncableService::UpdateMultivaluedField( |
| autofill::EMAIL_ADDRESS, |
| ::google::protobuf::RepeatedPtrField<std::string>(), |
| &profile)); |
| profile.GetRawMultiInfo(autofill::EMAIL_ADDRESS, &values); |
| ASSERT_EQ(values.size(), 1U); // Always have at least an empty string. |
| EXPECT_EQ(values[0], UTF8ToUTF16("")); |
| } |
| |
| TEST_F(AutofillProfileSyncableServiceTest, MergeProfile) { |
| AutofillProfile profile1(kGuid1, kHttpOrigin); |
| profile1.SetRawInfo( |
| autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("111 First St.")); |
| |
| std::vector<string16> values; |
| values.push_back(UTF8ToUTF16("1@1.com")); |
| values.push_back(UTF8ToUTF16("2@1.com")); |
| profile1.SetRawMultiInfo(autofill::EMAIL_ADDRESS, values); |
| |
| AutofillProfile profile2(kGuid2, kHttpsOrigin); |
| profile2.SetRawInfo( |
| autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("111 First St.")); |
| |
| // |values| now is [ "1@1.com", "2@1.com", "3@1.com" ]. |
| values.push_back(UTF8ToUTF16("3@1.com")); |
| profile2.SetRawMultiInfo(autofill::EMAIL_ADDRESS, values); |
| |
| values.clear(); |
| values.push_back(UTF8ToUTF16("John")); |
| profile1.SetRawMultiInfo(autofill::NAME_FIRST, values); |
| values.push_back(UTF8ToUTF16("Jane")); |
| profile2.SetRawMultiInfo(autofill::NAME_FIRST, values); |
| |
| values.clear(); |
| values.push_back(UTF8ToUTF16("Doe")); |
| profile1.SetRawMultiInfo(autofill::NAME_LAST, values); |
| values.push_back(UTF8ToUTF16("Other")); |
| profile2.SetRawMultiInfo(autofill::NAME_LAST, values); |
| |
| values.clear(); |
| values.push_back(UTF8ToUTF16("650234567")); |
| profile2.SetRawMultiInfo(autofill::PHONE_HOME_WHOLE_NUMBER, values); |
| |
| EXPECT_FALSE(AutofillProfileSyncableService::MergeProfile(profile2, |
| &profile1, |
| "en-US")); |
| |
| profile1.GetRawMultiInfo(autofill::NAME_FIRST, &values); |
| ASSERT_EQ(values.size(), 2U); |
| EXPECT_EQ(values[0], UTF8ToUTF16("John")); |
| EXPECT_EQ(values[1], UTF8ToUTF16("Jane")); |
| |
| profile1.GetRawMultiInfo(autofill::NAME_LAST, &values); |
| ASSERT_EQ(values.size(), 2U); |
| EXPECT_EQ(values[0], UTF8ToUTF16("Doe")); |
| EXPECT_EQ(values[1], UTF8ToUTF16("Other")); |
| |
| profile1.GetRawMultiInfo(autofill::EMAIL_ADDRESS, &values); |
| ASSERT_EQ(values.size(), 3U); |
| EXPECT_EQ(values[0], UTF8ToUTF16("1@1.com")); |
| EXPECT_EQ(values[1], UTF8ToUTF16("2@1.com")); |
| EXPECT_EQ(values[2], UTF8ToUTF16("3@1.com")); |
| |
| profile1.GetRawMultiInfo(autofill::PHONE_HOME_WHOLE_NUMBER, &values); |
| ASSERT_EQ(values.size(), 1U); |
| EXPECT_EQ(values[0], UTF8ToUTF16("650234567")); |
| |
| EXPECT_EQ(profile2.origin(), profile1.origin()); |
| |
| AutofillProfile profile3(kGuid3, kHttpOrigin); |
| profile3.SetRawInfo( |
| autofill::ADDRESS_HOME_LINE1, UTF8ToUTF16("111 First St.")); |
| |
| values.clear(); |
| values.push_back(UTF8ToUTF16("Jane")); |
| profile3.SetRawMultiInfo(autofill::NAME_FIRST, values); |
| |
| values.clear(); |
| values.push_back(UTF8ToUTF16("Doe")); |
| profile3.SetRawMultiInfo(autofill::NAME_LAST, values); |
| |
| EXPECT_TRUE(AutofillProfileSyncableService::MergeProfile(profile3, |
| &profile1, |
| "en-US")); |
| |
| profile1.GetRawMultiInfo(autofill::NAME_FIRST, &values); |
| ASSERT_EQ(values.size(), 3U); |
| EXPECT_EQ(values[0], UTF8ToUTF16("John")); |
| EXPECT_EQ(values[1], UTF8ToUTF16("Jane")); |
| EXPECT_EQ(values[2], UTF8ToUTF16("Jane")); |
| |
| profile1.GetRawMultiInfo(autofill::NAME_LAST, &values); |
| ASSERT_EQ(values.size(), 3U); |
| EXPECT_EQ(values[0], UTF8ToUTF16("Doe")); |
| EXPECT_EQ(values[1], UTF8ToUTF16("Other")); |
| EXPECT_EQ(values[2], UTF8ToUTF16("Doe")); |
| |
| // Middle name should have three entries as well. |
| profile1.GetRawMultiInfo(autofill::NAME_MIDDLE, &values); |
| ASSERT_EQ(values.size(), 3U); |
| EXPECT_TRUE(values[0].empty()); |
| EXPECT_TRUE(values[1].empty()); |
| EXPECT_TRUE(values[2].empty()); |
| |
| profile1.GetRawMultiInfo(autofill::EMAIL_ADDRESS, &values); |
| ASSERT_EQ(values.size(), 3U); |
| EXPECT_EQ(values[0], UTF8ToUTF16("1@1.com")); |
| EXPECT_EQ(values[1], UTF8ToUTF16("2@1.com")); |
| EXPECT_EQ(values[2], UTF8ToUTF16("3@1.com")); |
| |
| profile1.GetRawMultiInfo(autofill::PHONE_HOME_WHOLE_NUMBER, &values); |
| ASSERT_EQ(values.size(), 1U); |
| EXPECT_EQ(values[0], UTF8ToUTF16("650234567")); |
| } |