// Copyright 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 <stddef.h>
#include <stdint.h>

#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/bind_test_util.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/country_names.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
#include "components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h"
#include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/browser_sync/abstract_profile_sync_service_test.h"
#include "components/sync/base/model_type.h"
#include "components/sync/driver/data_type_controller.h"
#include "components/sync/driver/data_type_manager_impl.h"
#include "components/sync/driver/profile_sync_service.h"
#include "components/sync/driver/sync_api_component_factory_mock.h"
#include "components/sync/driver/sync_client_mock.h"
#include "components/sync/driver/test_profile_sync_service.h"
#include "components/sync/engine/data_type_debug_info_listener.h"
#include "components/sync/engine/sequenced_model_worker.h"
#include "components/sync/protocol/autofill_specifics.pb.h"
#include "components/sync/syncable/mutable_entry.h"
#include "components/sync/syncable/read_node.h"
#include "components/sync/syncable/read_transaction.h"
#include "components/sync/syncable/syncable_write_transaction.h"
#include "components/sync/syncable/write_node.h"
#include "components/sync/syncable/write_transaction.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "components/version_info/version_info.h"
#include "components/webdata/common/web_database.h"
#include "components/webdata_services/web_data_service_test_util.h"
#include "services/identity/public/cpp/identity_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using autofill::AutofillChange;
using autofill::AutofillChangeList;
using autofill::AutofillKey;
using autofill::AutofillProfile;
using autofill::AutofillProfileChange;
using autofill::AutofillProfileSyncableService;
using autofill::AutofillTable;
using autofill::AutofillWebDataService;
using autofill::NAME_FULL;
using autofill::PersonalDataManager;
using autofill::ServerFieldType;
using base::ASCIIToUTF16;
using base::Time;
using base::TimeDelta;
using base::WaitableEvent;
using syncer::AUTOFILL_PROFILE;
using syncer::BaseNode;
using syncer::syncable::CREATE;
using syncer::syncable::GET_TYPE_ROOT;
using syncer::syncable::MutableEntry;
using syncer::syncable::UNITTEST;
using syncer::syncable::WriterTag;
using syncer::syncable::WriteTransaction;
using testing::_;
using testing::ByMove;
using testing::DoAll;
using testing::ElementsAre;
using testing::Not;
using testing::Return;
using testing::SetArgPointee;

namespace browser_sync {

namespace {

void RegisterAutofillPrefs(user_prefs::PrefRegistrySyncable* registry) {
  registry->RegisterBooleanPref(autofill::prefs::kAutofillCreditCardEnabled,
                                true);
  registry->RegisterBooleanPref(autofill::prefs::kAutofillProfileEnabled, true);
  registry->RegisterBooleanPref(autofill::prefs::kAutofillWalletImportEnabled,
                                true);
  registry->RegisterIntegerPref(autofill::prefs::kAutofillLastVersionDeduped,
                                atoi(version_info::GetVersionNumber().c_str()));
  registry->RegisterIntegerPref(autofill::prefs::kAutofillLastVersionValidated,
                                atoi(version_info::GetVersionNumber().c_str()));
  registry->RegisterBooleanPref(
      autofill::prefs::kAutofillJapanCityFieldMigrated, true);
  registry->RegisterBooleanPref(autofill::prefs::kAutofillOrphanRowsRemoved,
                                true);
  registry->RegisterIntegerPref(
      autofill::prefs::kAutofillLastVersionDisusedAddressesDeleted, 0);
  registry->RegisterIntegerPref(
      autofill::prefs::kAutofillLastVersionDisusedCreditCardsDeleted, 0);
  registry->RegisterStringPref(
      autofill::prefs::kAutofillProfileValidity, "",
      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
}

void RunAndSignal(base::OnceClosure cb, WaitableEvent* event) {
  std::move(cb).Run();
  event->Signal();
}

}  // namespace

class AutofillTableMock : public AutofillTable {
 public:
  AutofillTableMock() {}
  MOCK_METHOD2(RemoveFormElement,
               bool(const base::string16& name,
                    const base::string16& value));  // NOLINT
  MOCK_METHOD4(GetAutofillTimestamps,
               bool(const base::string16& name,  // NOLINT
                    const base::string16& value,
                    Time* date_created,
                    Time* date_last_used));
  MOCK_METHOD1(GetAutofillProfiles,
               bool(std::vector<std::unique_ptr<AutofillProfile>>*));  // NOLINT
  MOCK_METHOD1(UpdateAutofillProfile, bool(const AutofillProfile&));   // NOLINT
  MOCK_METHOD1(AddAutofillProfile, bool(const AutofillProfile&));      // NOLINT
  MOCK_METHOD1(RemoveAutofillProfile, bool(const std::string&));       // NOLINT

  // TODO(crbug.com/904390): Remove when the investigation is over.
  MOCK_CONST_METHOD1(
      GetServerProfiles,
      bool(std::vector<std::unique_ptr<AutofillProfile>>*));  // NOLINT
};

MATCHER_P(MatchProfiles, profile, "") {
  return (profile.Compare(arg) == 0);
}

ACTION_P(LoadAutofillProfiles, datafunc) {
  std::vector<std::unique_ptr<AutofillProfile>> profiles =
      std::move(datafunc());
  arg0->swap(profiles);
}

class WebDatabaseFake : public WebDatabase {
 public:
  explicit WebDatabaseFake(AutofillTable* autofill_table) {
    AddTable(autofill_table);
  }
};

class FakeAutofillBackend : public autofill::AutofillWebDataBackend {
 public:
  FakeAutofillBackend(
      WebDatabase* web_database,
      const base::RepeatingClosure& on_changed,
      const base::RepeatingCallback<void(syncer::ModelType)>& on_sync_started,
      const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner)
      : web_database_(web_database),
        on_changed_(on_changed),
        on_sync_started_(on_sync_started),
        ui_task_runner_(ui_task_runner) {}

  ~FakeAutofillBackend() override {}
  WebDatabase* GetDatabase() override { return web_database_; }
  void AddObserver(
      autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override {
  }
  void RemoveObserver(
      autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override {
  }
  void CommitChanges() override {}
  void RemoveExpiredFormElements() override {}

  void NotifyOfAutofillProfileChanged(
      const autofill::AutofillProfileChange& change) override {}
  void NotifyOfCreditCardChanged(
      const autofill::CreditCardChange& change) override {}
  void NotifyOfMultipleAutofillChanges() override {
    DCHECK(!ui_task_runner_->RunsTasksInCurrentSequence());
    ui_task_runner_->PostTask(FROM_HERE, on_changed_);
  }
  void NotifyThatSyncHasStarted(syncer::ModelType model_type) override {
    DCHECK(!ui_task_runner_->RunsTasksInCurrentSequence());
    ui_task_runner_->PostTask(FROM_HERE,
                              base::BindOnce(on_sync_started_, model_type));
  }

 private:
  WebDatabase* web_database_;
  base::RepeatingClosure on_changed_;
  base::RepeatingCallback<void(syncer::ModelType)> on_sync_started_;
  const scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
};

class ProfileSyncServiceAutofillTest;

class TokenWebDataServiceFake : public TokenWebData {
 public:
  TokenWebDataServiceFake(
      const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
      const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner)
      : TokenWebData(ui_task_runner, db_task_runner) {}

  bool IsDatabaseLoaded() override { return true; }

  AutofillWebDataService::Handle GetAllTokens(
      WebDataServiceConsumer* consumer) override {
    // TODO(tim): It would be nice if WebDataService was injected on
    // construction of ProfileOAuth2TokenService rather than fetched by
    // Initialize so that this isn't necessary (we could pass a null service).
    // We currently do return it via EXPECT_CALLs, but without depending on
    // order-of-initialization (which seems way more fragile) we can't tell
    // which component is asking at what time, and some components in these
    // Autofill tests require a WebDataService.
    return 0;
  }

 private:
  ~TokenWebDataServiceFake() override {}

  DISALLOW_COPY_AND_ASSIGN(TokenWebDataServiceFake);
};

class WebDataServiceFake : public AutofillWebDataService {
 public:
  WebDataServiceFake(
      const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
      const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner)
      : AutofillWebDataService(ui_task_runner, db_task_runner),
        web_database_(nullptr),
        autofill_profile_syncable_service_(nullptr),
        syncable_service_created_or_destroyed_(
            base::WaitableEvent::ResetPolicy::AUTOMATIC,
            base::WaitableEvent::InitialState::NOT_SIGNALED),
        db_task_runner_(db_task_runner),
        ui_task_runner_(ui_task_runner) {}

  void SetDatabase(WebDatabase* web_database) { web_database_ = web_database; }

  void StartSyncableService() {
    // The |autofill_profile_syncable_service_| must be constructed on the DB
    // sequence.
    const base::RepeatingClosure& on_changed_callback = base::BindRepeating(
        &WebDataServiceFake::NotifyAutofillMultipleChangedOnUISequence,
        AsWeakPtr());
    const base::RepeatingCallback<void(syncer::ModelType)>&
        on_sync_started_callback = base::BindRepeating(
            &WebDataServiceFake::NotifySyncStartedOnUISequence, AsWeakPtr());

    db_task_runner_->PostTask(
        FROM_HERE, base::BindOnce(&WebDataServiceFake::CreateSyncableService,
                                  base::Unretained(this), on_changed_callback,
                                  std::move(on_sync_started_callback)));
    syncable_service_created_or_destroyed_.Wait();
  }

  void ShutdownSyncableService() {
    // The |autofill_profile_syncable_service_| must be destructed on the DB
    // sequence.
    db_task_runner_->PostTask(
        FROM_HERE, base::BindOnce(&WebDataServiceFake::DestroySyncableService,
                                  base::Unretained(this)));
    syncable_service_created_or_destroyed_.Wait();
  }

  bool IsDatabaseLoaded() override { return true; }

  WebDatabase* GetDatabase() override { return web_database_; }

  void OnAutofillProfileChanged(const AutofillProfileChange& changes) {
    WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
                        base::WaitableEvent::InitialState::NOT_SIGNALED);

    base::OnceClosure notify_cb = base::BindOnce(
        &AutofillProfileSyncableService::AutofillProfileChanged,
        base::Unretained(autofill_profile_syncable_service_), changes);
    db_task_runner_->PostTask(
        FROM_HERE, base::BindOnce(&RunAndSignal, std::move(notify_cb), &event));
    event.Wait();
  }

 private:
  ~WebDataServiceFake() override {}

  void CreateSyncableService(
      const base::RepeatingClosure& on_changed_callback,
      const base::RepeatingCallback<void(syncer::ModelType)>& on_sync_started) {
    ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence());
    // These services are deleted in DestroySyncableService().
    backend_ = std::make_unique<FakeAutofillBackend>(
        GetDatabase(), on_changed_callback, on_sync_started,
        ui_task_runner_.get());
    AutofillProfileSyncableService::CreateForWebDataServiceAndBackend(
        this, backend_.get(), "en-US");

    autofill_profile_syncable_service_ =
        AutofillProfileSyncableService::FromWebDataService(this);

    syncable_service_created_or_destroyed_.Signal();
  }

  void DestroySyncableService() {
    ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence());
    autofill_profile_syncable_service_ = nullptr;
    backend_.reset();
    syncable_service_created_or_destroyed_.Signal();
  }

  WebDatabase* web_database_;
  AutofillProfileSyncableService* autofill_profile_syncable_service_;
  std::unique_ptr<autofill::AutofillWebDataBackend> backend_;

  WaitableEvent syncable_service_created_or_destroyed_;

  const scoped_refptr<base::SingleThreadTaskRunner> db_task_runner_;
  const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;

  DISALLOW_COPY_AND_ASSIGN(WebDataServiceFake);
};

ACTION_P(ReturnNewDataTypeManagerWithDebugListener, debug_listener) {
  return std::make_unique<syncer::DataTypeManagerImpl>(arg0, debug_listener,
                                                       arg2, arg3, arg4, arg5);
}

class MockPersonalDataManager : public PersonalDataManager {
 public:
  MockPersonalDataManager() : PersonalDataManager("en-US") {}
  MOCK_CONST_METHOD0(IsDataLoaded, bool());
  MOCK_METHOD0(LoadProfiles, void());
  MOCK_METHOD0(LoadCreditCards, void());
  MOCK_METHOD0(LoadPaymentsCustomerData, void());
  MOCK_METHOD0(Refresh, void());
};

class AddAutofillProfileHelper;

class ProfileSyncServiceAutofillTest
    : public AbstractProfileSyncServiceTest,
      public syncer::DataTypeDebugInfoListener {
 public:
  // DataTypeDebugInfoListener implementation.
  void OnDataTypeConfigureComplete(
      const std::vector<syncer::DataTypeConfigurationStats>&
          configuration_stats) override {
    for (const syncer::DataTypeConfigurationStats& stat : configuration_stats) {
      if (stat.model_type == syncer::AUTOFILL_PROFILE) {
        association_stats_ = stat.association_stats;
        return;
      }
    }
    ASSERT_TRUE(false) << "Autofill profile type did not get configured!";
  }

 protected:
  ProfileSyncServiceAutofillTest() : debug_ptr_factory_(this) {
    autofill::CountryNames::SetLocaleString("en-US");
    RegisterAutofillPrefs(
        profile_sync_service_bundle()->pref_service()->registry());

    data_type_thread()->Start();

    web_database_ = std::make_unique<WebDatabaseFake>(&autofill_table_);
    web_data_wrapper_ = std::make_unique<MockWebDataServiceWrapper>(
        new WebDataServiceFake(base::ThreadTaskRunnerHandle::Get(),
                               data_type_thread()->task_runner()),
        new TokenWebDataServiceFake(base::ThreadTaskRunnerHandle::Get(),
                                    data_type_thread()->task_runner()));
    web_data_service_ = static_cast<WebDataServiceFake*>(
        web_data_wrapper_->GetProfileAutofillWebData().get());
    web_data_service_->SetDatabase(web_database_.get());

    personal_data_manager_ = std::make_unique<MockPersonalDataManager>();

    EXPECT_CALL(personal_data_manager(), LoadProfiles());
    EXPECT_CALL(personal_data_manager(), LoadCreditCards());
    EXPECT_CALL(personal_data_manager(), LoadPaymentsCustomerData());

    personal_data_manager_->Init(web_data_service_,
                                 /*account_database=*/nullptr,
                                 profile_sync_service_bundle()->pref_service(),
                                 /*identity_manager=*/nullptr,
                                 /*client_profile_validator=*/nullptr,
                                 /*history_service=*/nullptr,
                                 /*is_off_the_record=*/false);

    web_data_service_->StartSyncableService();
  }

  ~ProfileSyncServiceAutofillTest() override {
    web_data_service_->ShutdownOnUISequence();
    web_data_service_->ShutdownSyncableService();
    web_data_wrapper_->Shutdown();
    web_data_service_ = nullptr;
    web_data_wrapper_.reset();
    web_database_.reset();
    // Shut down the service explicitly before some data members from this
    // test it needs will be deleted.
    sync_service()->Shutdown();
  }

  int GetSyncCount() {
    syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
    syncer::ReadNode node(&trans);
    if (node.InitTypeRoot(AUTOFILL_PROFILE) != BaseNode::INIT_OK)
      return 0;
    return node.GetTotalNodeCount() - 1;
  }

  void StartAutofillProfileSyncService(base::OnceClosure callback) {
    profile_sync_service_bundle()
        ->identity_test_env()
        ->MakePrimaryAccountAvailable("test_user@gmail.com");

    std::unique_ptr<syncer::SyncClientMock> sync_client =
        profile_sync_service_bundle()->CreateSyncClientMock();
    syncer::SyncClientMock* sync_client_copy = sync_client.get();
    CreateSyncService(std::move(sync_client), std::move(callback));

    syncer::DataTypeController::TypeVector controllers;
    controllers.push_back(std::make_unique<AutofillProfileDataTypeController>(
        data_type_thread()->task_runner(), /*dump_stack=*/base::DoNothing(),
        sync_service(), sync_client_copy,
        base::BindLambdaForTesting([&]() -> autofill::PersonalDataManager* {
          return personal_data_manager_.get();
        }),
        web_data_service_));

    ON_CALL(*sync_client_copy, GetSyncableServiceForType(AUTOFILL_PROFILE))
        .WillByDefault(testing::Invoke([=](syncer::ModelType) {
          return AutofillProfileSyncableService::FromWebDataService(
                     web_data_service_.get())
              ->AsWeakPtr();
        }));
    ON_CALL(*sync_client_copy, CreateDataTypeControllers(_))
        .WillByDefault(Return(ByMove(std::move(controllers))));
    ON_CALL(*sync_client_copy, CreateModelWorkerForGroup(syncer::GROUP_DB))
        .WillByDefault(
            Return(base::MakeRefCounted<syncer::SequencedModelWorker>(
                data_type_thread()->task_runner(), syncer::GROUP_DB)));

    ON_CALL(*profile_sync_service_bundle()->component_factory(),
            CreateDataTypeManager(_, _, _, _, _, _))
        .WillByDefault(ReturnNewDataTypeManagerWithDebugListener(
            syncer::MakeWeakHandle(debug_ptr_factory_.GetWeakPtr())));

    EXPECT_CALL(personal_data_manager(), IsDataLoaded())
        .WillRepeatedly(Return(true));

    sync_service()->Initialize();
    base::RunLoop().Run();

    // It's possible this test triggered an unrecoverable error, in which case
    // we can't get the sync count.
    if (sync_service()->IsSyncFeatureActive()) {
      EXPECT_EQ(GetSyncCount(),
                association_stats_.num_sync_items_after_association);
    }
    EXPECT_EQ(association_stats_.num_sync_items_after_association,
              association_stats_.num_sync_items_before_association +
                  association_stats_.num_sync_items_added -
                  association_stats_.num_sync_items_deleted);
  }

  bool AddAutofillSyncNode(const AutofillProfile& profile) {
    syncer::WriteTransaction trans(FROM_HERE, sync_service()->GetUserShare());
    syncer::WriteNode node(&trans);
    std::string tag = profile.guid();
    syncer::WriteNode::InitUniqueByCreationResult result =
        node.InitUniqueByCreation(AUTOFILL_PROFILE, tag);
    if (result != syncer::WriteNode::INIT_SUCCESS)
      return false;

    sync_pb::EntitySpecifics specifics;
    AutofillProfileSyncableService::WriteAutofillProfile(profile, &specifics);
    node.SetEntitySpecifics(specifics);
    return true;
  }

  bool GetAutofillProfilesFromSyncDBUnderProfileNode(
      std::vector<AutofillProfile>* profiles) {
    syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
    syncer::ReadNode autofill_root(&trans);
    if (autofill_root.InitTypeRoot(AUTOFILL_PROFILE) != BaseNode::INIT_OK) {
      return false;
    }

    int64_t child_id = autofill_root.GetFirstChildId();
    while (child_id != syncer::kInvalidId) {
      syncer::ReadNode child_node(&trans);
      if (child_node.InitByIdLookup(child_id) != BaseNode::INIT_OK)
        return false;

      const sync_pb::AutofillProfileSpecifics& autofill(
          child_node.GetEntitySpecifics().autofill_profile());
      AutofillProfile p;
      p.set_guid(autofill.guid());
      AutofillProfileSyncableService::OverwriteProfileWithServerData(autofill,
                                                                     &p);
      profiles->push_back(p);
      child_id = child_node.GetSuccessorId();
    }
    return true;
  }

  void SetIdleChangeProcessorExpectations() {
    EXPECT_CALL(autofill_table_, RemoveFormElement(_, _)).Times(0);
    EXPECT_CALL(autofill_table_, GetAutofillTimestamps(_, _, _, _)).Times(0);
  }

  AutofillTableMock& autofill_table() { return autofill_table_; }

  MockPersonalDataManager& personal_data_manager() {
    return *personal_data_manager_;
  }

  WebDataServiceFake* web_data_service() { return web_data_service_.get(); }

 private:
  friend class AddAutofillProfileHelper;

  AutofillTableMock autofill_table_;
  std::unique_ptr<WebDatabaseFake> web_database_;
  std::unique_ptr<MockWebDataServiceWrapper> web_data_wrapper_;
  scoped_refptr<WebDataServiceFake> web_data_service_;
  std::unique_ptr<MockPersonalDataManager> personal_data_manager_;
  syncer::DataTypeAssociationStats association_stats_;
  base::WeakPtrFactory<DataTypeDebugInfoListener> debug_ptr_factory_;

  DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceAutofillTest);
};

class AddAutofillProfileHelper {
 public:
  AddAutofillProfileHelper(ProfileSyncServiceAutofillTest* test,
                           const std::vector<AutofillProfile>& entries)
      : callback_(base::BindOnce(&AddAutofillProfileHelper::AddAutofillCallback,
                                 base::Unretained(this),
                                 test,
                                 entries)),
        success_(false) {}

  base::OnceClosure callback() { return std::move(callback_); }
  bool success() { return success_; }

 private:
  void AddAutofillCallback(ProfileSyncServiceAutofillTest* test,
                           const std::vector<AutofillProfile>& entries) {
    if (!test->CreateRoot(AUTOFILL_PROFILE))
      return;

    for (size_t i = 0; i < entries.size(); ++i) {
      if (!test->AddAutofillSyncNode(entries[i]))
        return;
    }
    success_ = true;
  }

  base::OnceClosure callback_;
  bool success_;
};

TEST_F(ProfileSyncServiceAutofillTest, HasProfileEmptySync) {
  std::vector<std::unique_ptr<AutofillProfile>> profiles;
  std::vector<AutofillProfile> expected_profiles;
  std::unique_ptr<AutofillProfile> profile0 =
      std::make_unique<AutofillProfile>();
  autofill::test::SetProfileInfoWithGuid(
      profile0.get(), "54B3F9AA-335E-4F71-A27D-719C41564230", "Billing",
      "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
      "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
  expected_profiles.push_back(*profile0);
  profiles.push_back(std::move(profile0));
  auto profile_returner = [&profiles]() { return std::move(profiles); };
  EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
      .WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
  EXPECT_CALL(personal_data_manager(), Refresh());
  SetIdleChangeProcessorExpectations();
  CreateRootHelper create_root(this, AUTOFILL_PROFILE);
  StartAutofillProfileSyncService(create_root.callback());
  ASSERT_TRUE(create_root.success());
  std::vector<AutofillProfile> sync_profiles;
  ASSERT_TRUE(GetAutofillProfilesFromSyncDBUnderProfileNode(&sync_profiles));
  EXPECT_EQ(1U, sync_profiles.size());
  EXPECT_EQ(0, expected_profiles[0].Compare(sync_profiles[0]));
}

TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncMergeProfile) {
  AutofillProfile sync_profile;
  autofill::test::SetProfileInfoWithGuid(
      &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
      "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
      "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");

  std::unique_ptr<AutofillProfile> native_profile =
      std::make_unique<AutofillProfile>();
  autofill::test::SetProfileInfoWithGuid(
      native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
      "Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
      "Orlando", "FL", "32801", "US", "19482937549");

  std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
  native_profiles.push_back(std::move(native_profile));
  auto profile_returner = [&native_profiles]() {
    return std::move(native_profiles);
  };
  EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
      .WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));

  std::vector<AutofillProfile> sync_profiles;
  sync_profiles.push_back(sync_profile);
  AddAutofillProfileHelper add_autofill(this, sync_profiles);

  EXPECT_CALL(autofill_table(),
              UpdateAutofillProfile(MatchProfiles(sync_profile)))
      .WillOnce(Return(true));
  EXPECT_CALL(personal_data_manager(), Refresh());
  StartAutofillProfileSyncService(add_autofill.callback());
  ASSERT_TRUE(add_autofill.success());

  std::vector<AutofillProfile> new_sync_profiles;
  ASSERT_TRUE(
      GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
  ASSERT_EQ(1U, new_sync_profiles.size());
  EXPECT_EQ(0, sync_profile.Compare(new_sync_profiles[0]));
}

// Tests that a sync with a new native profile that matches a more recent new
// sync profile but with less information results in the native profile being
// deleted and replaced by the sync profile with merged usage stats.
TEST_F(
    ProfileSyncServiceAutofillTest,
    HasNativeHasSyncMergeSimilarProfileCombine_SyncHasMoreInfoAndMoreRecent) {
  // Create two almost identical profiles. The GUIDs are different and the
  // native profile has no value for company name.
  AutofillProfile sync_profile;
  autofill::test::SetProfileInfoWithGuid(
      &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
      "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
      "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
  sync_profile.set_use_date(base::Time::FromTimeT(4321));

  std::unique_ptr<AutofillProfile> native_profile =
      std::make_unique<AutofillProfile>();
  autofill::test::SetProfileInfoWithGuid(
      native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
      "Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
      "Hollywood", "CA", "91601", "US", "12345678910");
  native_profile->set_use_date(base::Time::FromTimeT(1234));

  AutofillProfile expected_profile(sync_profile);
  expected_profile.SetRawInfo(NAME_FULL,
                              ASCIIToUTF16("Billing Mitchell Morrison"));
  expected_profile.set_use_count(1);

  std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
  native_profiles.push_back(std::move(native_profile));
  auto profile_returner = [&native_profiles]() {
    return std::move(native_profiles);
  };
  EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
      .WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
  EXPECT_CALL(autofill_table(),
              AddAutofillProfile(MatchProfiles(expected_profile)))
      .WillOnce(Return(true));
  EXPECT_CALL(autofill_table(),
              RemoveAutofillProfile("23355099-1170-4B71-8ED4-144470CC9EBF"))
      .WillOnce(Return(true));
  std::vector<AutofillProfile> sync_profiles;
  sync_profiles.push_back(sync_profile);
  AddAutofillProfileHelper add_autofill(this, sync_profiles);

  EXPECT_CALL(personal_data_manager(), Refresh());
  // Adds all entries in |sync_profiles| to sync.
  StartAutofillProfileSyncService(add_autofill.callback());
  ASSERT_TRUE(add_autofill.success());

  std::vector<AutofillProfile> new_sync_profiles;
  ASSERT_TRUE(
      GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
  ASSERT_EQ(1U, new_sync_profiles.size());
  // Check that key fields are the same.
  EXPECT_TRUE(new_sync_profiles[0].IsSubsetOf(sync_profile, "en-US"));
  // Make sure the additional information from the sync profile was kept.
  EXPECT_EQ(ASCIIToUTF16("Fox"),
            new_sync_profiles[0].GetRawInfo(ServerFieldType::COMPANY_NAME));
  // Check that the latest use date is saved.
  EXPECT_EQ(base::Time::FromTimeT(4321), new_sync_profiles[0].use_date());
  // Check that the use counts were added (default value is 1).
  EXPECT_EQ(1U, new_sync_profiles[0].use_count());
}

// Tests that a sync with a new native profile that matches an older new sync
// profile but with less information results in the native profile being deleted
// and replaced by the sync profile with merged usage stats.
TEST_F(ProfileSyncServiceAutofillTest,
       HasNativeHasSyncMergeSimilarProfileCombine_SyncHasMoreInfoAndOlder) {
  // Create two almost identical profiles. The GUIDs are different and the
  // native profile has no value for company name.
  AutofillProfile sync_profile;
  autofill::test::SetProfileInfoWithGuid(
      &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
      "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
      "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
  sync_profile.set_use_date(base::Time::FromTimeT(1234));

  std::unique_ptr<AutofillProfile> native_profile =
      std::make_unique<AutofillProfile>();
  autofill::test::SetProfileInfoWithGuid(
      native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
      "Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
      "Hollywood", "CA", "91601", "US", "12345678910");
  native_profile->set_use_date(base::Time::FromTimeT(4321));

  AutofillProfile expected_profile(sync_profile);
  expected_profile.SetRawInfo(NAME_FULL,
                              ASCIIToUTF16("Billing Mitchell Morrison"));
  expected_profile.set_use_count(1);
  expected_profile.set_use_date(native_profile->use_date());

  std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
  native_profiles.push_back(std::move(native_profile));
  auto profile_returner = [&native_profiles]() {
    return std::move(native_profiles);
  };
  EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
      .WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
  EXPECT_CALL(autofill_table(),
              AddAutofillProfile(MatchProfiles(expected_profile)))
      .WillOnce(Return(true));
  EXPECT_CALL(autofill_table(),
              RemoveAutofillProfile("23355099-1170-4B71-8ED4-144470CC9EBF"))
      .WillOnce(Return(true));
  std::vector<AutofillProfile> sync_profiles;
  sync_profiles.push_back(sync_profile);
  AddAutofillProfileHelper add_autofill(this, sync_profiles);

  EXPECT_CALL(personal_data_manager(), Refresh());
  // Adds all entries in |sync_profiles| to sync.
  StartAutofillProfileSyncService(add_autofill.callback());
  ASSERT_TRUE(add_autofill.success());

  std::vector<AutofillProfile> new_sync_profiles;
  ASSERT_TRUE(
      GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
  ASSERT_EQ(1U, new_sync_profiles.size());
  // Check that key fields are the same.
  EXPECT_TRUE(new_sync_profiles[0].IsSubsetOf(sync_profile, "en-US"));
  // Make sure the additional information from the sync profile was kept.
  EXPECT_EQ(ASCIIToUTF16("Fox"),
            new_sync_profiles[0].GetRawInfo(ServerFieldType::COMPANY_NAME));
  // Check that the latest use date is saved.
  EXPECT_EQ(base::Time::FromTimeT(4321), new_sync_profiles[0].use_date());
  // Check that the use counts were added (default value is 1).
  EXPECT_EQ(1U, new_sync_profiles[0].use_count());
}

// Tests that a sync with a new native profile that matches an a new sync
// profile but with more information results in the native profile being deleted
// and replaced by the sync profile with the native profiles additional
// information merged in. The merge should happen even if the sync profile is
// more recent.
TEST_F(ProfileSyncServiceAutofillTest,
       HasNativeHasSyncMergeSimilarProfileCombine_NativeHasMoreInfo) {
  // Create two almost identical profiles. The GUIDs are different and the
  // sync profile has no value for company name.
  AutofillProfile sync_profile;
  autofill::test::SetProfileInfoWithGuid(
      &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
      "Mitchell", "Morrison", "johnwayne@me.xyz", "", "123 Zoo St.", "unit 5",
      "Hollywood", "CA", "91601", "US", "12345678910");
  sync_profile.set_use_date(base::Time::FromTimeT(4321));

  std::unique_ptr<AutofillProfile> native_profile =
      std::make_unique<AutofillProfile>();
  autofill::test::SetProfileInfoWithGuid(
      native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
      "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
      "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
  native_profile->set_use_date(base::Time::FromTimeT(1234));

  AutofillProfile expected_profile(*native_profile);
  expected_profile.SetRawInfo(NAME_FULL,
                              ASCIIToUTF16("Billing Mitchell Morrison"));
  expected_profile.set_use_date(sync_profile.use_date());
  expected_profile.set_use_count(1);

  std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
  native_profiles.push_back(std::move(native_profile));
  auto profile_returner = [&native_profiles]() {
    return std::move(native_profiles);
  };
  EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
      .WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
  EXPECT_CALL(autofill_table(),
              AddAutofillProfile(MatchProfiles(expected_profile)))
      .WillOnce(Return(true));
  EXPECT_CALL(autofill_table(),
              RemoveAutofillProfile("23355099-1170-4B71-8ED4-144470CC9EBF"))
      .WillOnce(Return(true));
  std::vector<AutofillProfile> sync_profiles;
  sync_profiles.push_back(sync_profile);
  AddAutofillProfileHelper add_autofill(this, sync_profiles);

  EXPECT_CALL(personal_data_manager(), Refresh());
  // Adds all entries in |sync_profiles| to sync.
  StartAutofillProfileSyncService(add_autofill.callback());
  ASSERT_TRUE(add_autofill.success());

  std::vector<AutofillProfile> new_sync_profiles;
  ASSERT_TRUE(
      GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
  ASSERT_EQ(1U, new_sync_profiles.size());
  // Check that key fields are the same.
  EXPECT_TRUE(new_sync_profiles[0].IsSubsetOf(expected_profile, "en-US"));
  // Make sure the additional information of the native profile was saved into
  // the sync profile.
  EXPECT_EQ(ASCIIToUTF16("Fox"),
            new_sync_profiles[0].GetRawInfo(ServerFieldType::COMPANY_NAME));
  // Check that the latest use date is saved.
  EXPECT_EQ(base::Time::FromTimeT(4321), new_sync_profiles[0].use_date());
  // Check that the use counts were added (default value is 1).
  EXPECT_EQ(1U, new_sync_profiles[0].use_count());
}

// Tests that a sync with a new native profile that differ only by name a new
// sync profile results in keeping both profiles.
TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSync_DifferentPrimaryInfo) {
  AutofillProfile sync_profile;
  autofill::test::SetProfileInfoWithGuid(
      &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
      "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
      "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
  sync_profile.set_use_date(base::Time::FromTimeT(4321));

  std::unique_ptr<AutofillProfile> native_profile =
      std::make_unique<AutofillProfile>();
  autofill::test::SetProfileInfoWithGuid(
      native_profile.get(), "23355099-1170-4B71-8ED4-144470CC9EBF", "Billing",
      "John", "Smith", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
      "Hollywood", "CA", "91601", "US", "12345678910");
  native_profile->set_use_date(base::Time::FromTimeT(1234));

  std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
  native_profiles.push_back(std::move(native_profile));
  auto profile_returner = [&native_profiles]() {
    return std::move(native_profiles);
  };
  EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
      .WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));
  EXPECT_CALL(autofill_table(), AddAutofillProfile(MatchProfiles(sync_profile)))
      .WillOnce(Return(true));
  std::vector<AutofillProfile> sync_profiles;
  sync_profiles.push_back(sync_profile);
  AddAutofillProfileHelper add_autofill(this, sync_profiles);

  EXPECT_CALL(personal_data_manager(), Refresh());
  // Adds all entries in |sync_profiles| to sync.
  StartAutofillProfileSyncService(add_autofill.callback());
  ASSERT_TRUE(add_autofill.success());

  std::vector<AutofillProfile> new_sync_profiles;
  ASSERT_TRUE(
      GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
  // The two profiles should be kept.
  ASSERT_EQ(2U, new_sync_profiles.size());
}

// Tests that a new native profile that is the same as a new sync profile except
// with different GUIDs results in the native profile being deleted and replaced
// by the sync profile.
TEST_F(ProfileSyncServiceAutofillTest, MergeProfileWithDifferentGuid) {
  AutofillProfile sync_profile;

  autofill::test::SetProfileInfoWithGuid(
      &sync_profile, "23355099-1170-4B71-8ED4-144470CC9EBE", "Billing",
      "Mitchell", "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.",
      "unit 5", "Hollywood", "CA", "91601", "US", "12345678910");
  sync_profile.set_use_count(20);
  sync_profile.set_use_date(base::Time::FromTimeT(1234));

  std::string native_guid = "EDC609ED-7EEE-4F27-B00C-423242A9C44B";
  std::unique_ptr<AutofillProfile> native_profile =
      std::make_unique<AutofillProfile>();
  autofill::test::SetProfileInfoWithGuid(
      native_profile.get(), native_guid.c_str(), "Billing", "Mitchell",
      "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
      "Hollywood", "CA", "91601", "US", "12345678910");
  native_profile->set_use_count(5);
  native_profile->set_use_date(base::Time::FromTimeT(4321));

  std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
  native_profiles.push_back(std::move(native_profile));
  auto profile_returner = [&native_profiles]() {
    return std::move(native_profiles);
  };
  EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
      .WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));

  std::vector<AutofillProfile> sync_profiles;
  sync_profiles.push_back(sync_profile);
  AddAutofillProfileHelper add_autofill(this, sync_profiles);

  EXPECT_CALL(autofill_table(), AddAutofillProfile(_)).WillOnce(Return(true));
  EXPECT_CALL(autofill_table(), RemoveAutofillProfile(native_guid))
      .WillOnce(Return(true));
  EXPECT_CALL(personal_data_manager(), Refresh());
  StartAutofillProfileSyncService(add_autofill.callback());
  ASSERT_TRUE(add_autofill.success());

  std::vector<AutofillProfile> new_sync_profiles;
  ASSERT_TRUE(
      GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
  // Check that the profiles were merged.
  ASSERT_EQ(1U, new_sync_profiles.size());
  EXPECT_EQ(0, sync_profile.Compare(new_sync_profiles[0]));
  // Check that the sync guid was kept.
  EXPECT_EQ(sync_profile.guid(), new_sync_profiles[0].guid());
  // Check that the sync profile use count was kept.
  EXPECT_EQ(20U, new_sync_profiles[0].use_count());
  // Check that the sync profile use date was kept.
  EXPECT_EQ(base::Time::FromTimeT(1234), new_sync_profiles[0].use_date());
}

TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeAddProfile) {
  EXPECT_CALL(autofill_table(), GetAutofillProfiles(_)).WillOnce(Return(true));
  EXPECT_CALL(personal_data_manager(), Refresh());
  SetIdleChangeProcessorExpectations();
  CreateRootHelper create_root(this, AUTOFILL_PROFILE);
  StartAutofillProfileSyncService(create_root.callback());
  ASSERT_TRUE(create_root.success());

  AutofillProfile added_profile;
  autofill::test::SetProfileInfoWithGuid(
      &added_profile, "D6ADA912-D374-4C0A-917D-F5C8EBE43011", "Josephine",
      "Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
      "Orlando", "FL", "32801", "US", "19482937549");

  // TODO(crbug.com/904390): Remove when the investigation is over. This call is
  // needed in the AutofillProfileChanged() callback.
  EXPECT_CALL(autofill_table(), GetServerProfiles(_)).WillOnce(Return(true));

  AutofillProfileChange change(AutofillProfileChange::ADD, added_profile.guid(),
                               &added_profile);
  web_data_service()->OnAutofillProfileChanged(change);

  std::vector<AutofillProfile> new_sync_profiles;
  ASSERT_TRUE(
      GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
  ASSERT_EQ(1U, new_sync_profiles.size());
  EXPECT_EQ(0, added_profile.Compare(new_sync_profiles[0]));
}

TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeRemoveProfile) {
  AutofillProfile sync_profile;
  autofill::test::SetProfileInfoWithGuid(
      &sync_profile, "3BA5FA1B-1EC4-4BB3-9B57-EC92BE3C1A09", "Josephine",
      "Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
      "Orlando", "FL", "32801", "US", "19482937549");
  std::unique_ptr<AutofillProfile> native_profile =
      std::make_unique<AutofillProfile>();
  autofill::test::SetProfileInfoWithGuid(
      native_profile.get(), "3BA5FA1B-1EC4-4BB3-9B57-EC92BE3C1A09", "Josephine",
      "Alicia", "Saenz", "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
      "Orlando", "FL", "32801", "US", "19482937549");

  std::vector<std::unique_ptr<AutofillProfile>> native_profiles;
  native_profiles.push_back(std::move(native_profile));
  auto profile_returner = [&native_profiles]() {
    return std::move(native_profiles);
  };
  EXPECT_CALL(autofill_table(), GetAutofillProfiles(_))
      .WillOnce(DoAll(LoadAutofillProfiles(profile_returner), Return(true)));

  std::vector<AutofillProfile> sync_profiles;
  sync_profiles.push_back(sync_profile);
  AddAutofillProfileHelper add_autofill(this, sync_profiles);
  EXPECT_CALL(personal_data_manager(), Refresh());
  StartAutofillProfileSyncService(add_autofill.callback());
  ASSERT_TRUE(add_autofill.success());

  AutofillProfileChange change(AutofillProfileChange::REMOVE,
                               sync_profile.guid(), nullptr);
  web_data_service()->OnAutofillProfileChanged(change);

  std::vector<AutofillProfile> new_sync_profiles;
  ASSERT_TRUE(
      GetAutofillProfilesFromSyncDBUnderProfileNode(&new_sync_profiles));
  ASSERT_EQ(0U, new_sync_profiles.size());
}

}  // namespace browser_sync
