// Copyright (c) 2011 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/utf_string_conversions.h" #include "chrome/browser/autofill/autofill_profile.h" #include "chrome/browser/sync/internal_api/read_node_mock.h" #include "chrome/browser/sync/internal_api/syncapi_mock.h" #include "chrome/browser/sync/syncable/syncable.h" #include "chrome/browser/sync/syncable/syncable_mock.h" #include "chrome/browser/webdata/autofill_profile_syncable_service.h" #include "content/browser/browser_thread.h" #include "chrome/browser/webdata/autofill_change.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; class AutofillProfile; class MockAutofillProfileSyncableService : public AutofillProfileSyncableService { public: MockAutofillProfileSyncableService() { } virtual ~MockAutofillProfileSyncableService() {} MOCK_METHOD1(LoadAutofillData, bool(std::vector*)); MOCK_METHOD1(SaveChangesToWebData, bool(const AutofillProfileSyncableService::DataBundle&)); // Helper for tests that do not need to setup service completely through the // MergeDataAndStartSyncing(). class AutoSetSyncProcessor { public: AutoSetSyncProcessor(MockAutofillProfileSyncableService* service, SyncChangeProcessor* sync_processor) : service_(service) { service->set_sync_processor(sync_processor); } ~AutoSetSyncProcessor() { service_->set_sync_processor(NULL); } MockAutofillProfileSyncableService* service_; }; }; 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; 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().GetExtension( sync_pb::autofill_profile).guid() != expected->sync_data().GetSpecifics().GetExtension( sync_pb::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]->guid() != n_bundle.profiles_to_update[i]->guid()) { return false; } } for (size_t i = 0; i < arg.profiles_to_add.size(); ++i) { if (arg.profiles_to_add[i]->Compare(*n_bundle.profiles_to_add[i])) return false; } return true; } class MockSyncChangeProcessor : public SyncChangeProcessor { public: MockSyncChangeProcessor() {} virtual ~MockSyncChangeProcessor() {} MOCK_METHOD2(ProcessSyncChanges, SyncError(const tracked_objects::Location&, const SyncChangeList&)); }; class AutofillProfileSyncableServiceTest : public testing::Test { public: AutofillProfileSyncableServiceTest() : db_thread_(BrowserThread::DB, &message_loop_) {} protected: MessageLoop message_loop_; BrowserThread db_thread_; MockAutofillProfileSyncableService autofill_syncable_service_; MockSyncChangeProcessor sync_processor_; }; TEST_F(AutofillProfileSyncableServiceTest, MergeDataAndStartSyncing) { std::vector profiles_from_web_db; std::string guid_present1 = "EDC609ED-7EEE-4F27-B00C-423242A9C44B"; std::string guid_present2 = "EDC609ED-7EEE-4F27-B00C-423242A9C44C"; std::string guid_synced1 = "EDC609ED-7EEE-4F27-B00C-423242A9C44D"; std::string guid_synced2 = "EDC609ED-7EEE-4F27-B00C-423242A9C44E"; profiles_from_web_db.push_back(new AutofillProfile(guid_present1)); profiles_from_web_db.back()->SetInfo(NAME_FIRST, UTF8ToUTF16("John")); profiles_from_web_db.push_back(new AutofillProfile(guid_present2)); profiles_from_web_db.back()->SetInfo(NAME_FIRST, UTF8ToUTF16("Tom")); SyncDataList data_list; AutofillProfile profile1(guid_synced1); profile1.SetInfo(NAME_FIRST, UTF8ToUTF16("Jane")); data_list.push_back(autofill_syncable_service_.CreateData(profile1)); AutofillProfile profile2(guid_synced2); profile2.SetInfo(NAME_FIRST, UTF8ToUTF16("Harry")); data_list.push_back(autofill_syncable_service_.CreateData(profile2)); // This one will have the name updated. AutofillProfile profile3(guid_present2); profile3.SetInfo(NAME_FIRST, UTF8ToUTF16("Tom Doe")); data_list.push_back(autofill_syncable_service_.CreateData(profile3)); SyncChangeList expected_change_list; expected_change_list.push_back( SyncChange(SyncChange::ACTION_ADD, AutofillProfileSyncableService::CreateData( (*profiles_from_web_db.front())))); AutofillProfileSyncableService::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); 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(SyncError())); EXPECT_CALL(sync_processor_, ProcessSyncChanges(_, CheckSyncChanges(expected_change_list))) .Times(1) .WillOnce(Return(SyncError())); autofill_syncable_service_.MergeDataAndStartSyncing( syncable::AUTOFILL_PROFILE, data_list, &sync_processor_); autofill_syncable_service_.StopSyncing(syncable::AUTOFILL_PROFILE); } TEST_F(AutofillProfileSyncableServiceTest, GetAllSyncData) { std::vector profiles_from_web_db; std::string guid_present1 = "EDC609ED-7EEE-4F27-B00C-423242A9C44B"; std::string guid_present2 = "EDC609ED-7EEE-4F27-B00C-423242A9C44C"; profiles_from_web_db.push_back(new AutofillProfile(guid_present1)); profiles_from_web_db.back()->SetInfo(NAME_FIRST, UTF8ToUTF16("John")); profiles_from_web_db.push_back(new AutofillProfile(guid_present2)); profiles_from_web_db.back()->SetInfo(NAME_FIRST, UTF8ToUTF16("Jane")); EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_)) .Times(1) .WillOnce(DoAll(CopyData(&profiles_from_web_db), Return(true))); EXPECT_CALL(autofill_syncable_service_, SaveChangesToWebData(_)) .Times(1) .WillOnce(Return(true)); ON_CALL(sync_processor_, ProcessSyncChanges(_, _)) .WillByDefault(Return(SyncError())); EXPECT_CALL(sync_processor_, ProcessSyncChanges(_, Property(&SyncChangeList::size, Eq(2U)))) .Times(1) .WillOnce(Return(SyncError())); SyncDataList data_list; autofill_syncable_service_.MergeDataAndStartSyncing( syncable::AUTOFILL_PROFILE, data_list, &sync_processor_); SyncDataList data = autofill_syncable_service_.GetAllSyncData(syncable::AUTOFILL_PROFILE); EXPECT_EQ(2U, data.size()); EXPECT_EQ(guid_present1, data.front().GetSpecifics() .GetExtension(sync_pb::autofill_profile).guid()); EXPECT_EQ(guid_present2, data.back().GetSpecifics() .GetExtension(sync_pb::autofill_profile).guid()); } TEST_F(AutofillProfileSyncableServiceTest, ProcessSyncChanges) { std::vector profiles_from_web_db; std::string guid_present = "EDC609ED-7EEE-4F27-B00C-423242A9C44B"; std::string guid_synced = "EDC609ED-7EEE-4F27-B00C-423242A9C44C"; SyncChangeList change_list; AutofillProfile profile(guid_synced); profile.SetInfo(NAME_FIRST, UTF8ToUTF16("Jane")); change_list.push_back( SyncChange(SyncChange::ACTION_ADD, AutofillProfileSyncableService::CreateData(profile))); AutofillProfile empty_profile(guid_present); change_list.push_back( SyncChange(SyncChange::ACTION_DELETE, AutofillProfileSyncableService::CreateData(empty_profile))); AutofillProfileSyncableService::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)); MockAutofillProfileSyncableService::AutoSetSyncProcessor temp( &autofill_syncable_service_, &sync_processor_); SyncError error = autofill_syncable_service_.ProcessSyncChanges( FROM_HERE, change_list); EXPECT_FALSE(error.IsSet()); } TEST_F(AutofillProfileSyncableServiceTest, ActOnChange) { std::string guid1 = "EDC609ED-7EEE-4F27-B00C-423242A9C44B"; std::string guid2 = "EDC609ED-7EEE-4F27-B00C-423242A9C44C"; AutofillProfile profile(guid1); profile.SetInfo(NAME_FIRST, UTF8ToUTF16("Jane")); AutofillProfileChange change1(AutofillProfileChange::ADD, guid1, &profile); AutofillProfileChange change2(AutofillProfileChange::REMOVE, guid2, NULL); ON_CALL(sync_processor_, ProcessSyncChanges(_, _)) .WillByDefault(Return(SyncError(FROM_HERE, std::string("an error"), syncable::AUTOFILL_PROFILE))); MockAutofillProfileSyncableService::AutoSetSyncProcessor temp( &autofill_syncable_service_, &sync_processor_); autofill_syncable_service_.ActOnChange(change1); autofill_syncable_service_.ActOnChange(change2); }