// Copyright 2018 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 "components/password_manager/core/browser/new_password_form_manager.h"

#include <string>
#include <utility>

#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/test_mock_time_task_runner.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_download_manager.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/autofill/core/common/password_form_generation_data.h"
#include "components/autofill/core/common/password_generation_util.h"
#include "components/password_manager/core/browser/fake_form_fetcher.h"
#include "components/password_manager/core/browser/password_form_manager_for_ui.h"
#include "components/password_manager/core/browser/password_manager_util.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/stub_form_saver.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "components/password_manager/core/browser/stub_password_manager_driver.h"
#include "components/password_manager/core/browser/vote_uploads_test_matchers.h"
#include "components/ukm/test_ukm_recorder.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using autofill::AutofillUploadContents;
using autofill::FieldPropertiesFlags;
using autofill::FormData;
using autofill::FormFieldData;
using autofill::FormSignature;
using autofill::FormStructure;
using autofill::PasswordForm;
using autofill::PasswordFormFillData;
using autofill::PasswordFormGenerationData;
using autofill::ServerFieldType;
using base::ASCIIToUTF16;
using base::TestMockTimeTaskRunner;
using testing::_;
using testing::AllOf;
using testing::Contains;
using testing::ElementsAre;
using testing::IsEmpty;
using testing::Mock;
using testing::NiceMock;
using testing::Pointee;
using testing::Return;
using testing::SaveArg;
using testing::SaveArgPointee;
using testing::UnorderedElementsAre;

namespace password_manager {

namespace {

// Indices of username and password fields in the observed form.
const int kUsernameFieldIndex = 1;
const int kPasswordFieldIndex = 2;

MATCHER_P(FormHasUniqueKey, key, "") {
  return ArePasswordFormUniqueKeysEqual(arg, key);
}

class MockPasswordManagerDriver : public StubPasswordManagerDriver {
 public:
  MockPasswordManagerDriver() {}

  ~MockPasswordManagerDriver() override {}

  MOCK_METHOD1(FillPasswordForm, void(const PasswordFormFillData&));
  MOCK_METHOD1(AllowPasswordGenerationForForm, void(const PasswordForm&));
  MOCK_METHOD1(FormEligibleForGenerationFound,
               void(const autofill::PasswordFormGenerationData&));
};

class MockAutofillDownloadManager : public autofill::AutofillDownloadManager {
 public:
  MockAutofillDownloadManager()
      : AutofillDownloadManager(nullptr, &fake_observer) {}

  MOCK_METHOD6(StartUploadRequest,
               bool(const FormStructure&,
                    bool,
                    const autofill::ServerFieldTypeSet&,
                    const std::string&,
                    bool,
                    PrefService*));

 private:
  class StubObserver : public AutofillDownloadManager::Observer {
    void OnLoadedServerPredictions(
        std::string response,
        const std::vector<std::string>& form_signatures) override {}
  };

  StubObserver fake_observer;
  DISALLOW_COPY_AND_ASSIGN(MockAutofillDownloadManager);
};

class MockPasswordManagerClient : public StubPasswordManagerClient {
 public:
  MockPasswordManagerClient() = default;
  ~MockPasswordManagerClient() override = default;

  MOCK_CONST_METHOD0(IsIncognito, bool());

  MOCK_METHOD0(GetAutofillDownloadManager,
               autofill::AutofillDownloadManager*());

  MOCK_METHOD0(UpdateFormManagers, void());

  MOCK_METHOD2(AutofillHttpAuth,
               void(const PasswordForm&, const PasswordFormManagerForUI*));
};

void CheckPendingCredentials(const PasswordForm& expected,
                             const PasswordForm& actual) {
  EXPECT_EQ(expected.signon_realm, actual.signon_realm);
  EXPECT_EQ(expected.origin, actual.origin);
  EXPECT_EQ(expected.action, actual.action);
  EXPECT_EQ(expected.username_value, actual.username_value);
  EXPECT_EQ(expected.password_value, actual.password_value);
  EXPECT_EQ(expected.username_element, actual.username_element);
  EXPECT_EQ(expected.password_element, actual.password_element);
  EXPECT_EQ(expected.blacklisted_by_user, actual.blacklisted_by_user);
  EXPECT_EQ(expected.form_data, actual.form_data);
}

struct ExpectedGenerationUKM {
  base::Optional<int64_t> generation_popup_shown;
  int64_t has_generated_password;
  base::Optional<int64_t> generated_password_modified;
};

// Check that UKM |metric_name| in |entry| is equal to |expected|. |expected| ==
// null means that no metric recording is expected.
void CheckMetric(const int64_t* expected,
                 const ukm::mojom::UkmEntry* entry,
                 const char* metric_name) {
  SCOPED_TRACE(testing::Message("Checking UKM metric ") << metric_name);

  const int64_t* actual =
      ukm::TestUkmRecorder::GetEntryMetric(entry, metric_name);

  ASSERT_EQ(!!expected, !!actual);
  if (expected)
    EXPECT_EQ(*expected, *actual);
}

// Check that |recorder| records metrics |expected_metrics|.
void CheckPasswordGenerationUKM(const ukm::TestAutoSetUkmRecorder& recorder,
                                const ExpectedGenerationUKM& expected_metrics) {
  auto entries =
      recorder.GetEntriesByName(ukm::builders::PasswordForm::kEntryName);
  ASSERT_EQ(1u, entries.size());
  const int64_t* expected_popup_shown = nullptr;
  if (expected_metrics.generation_popup_shown)
    expected_popup_shown = &expected_metrics.generation_popup_shown.value();
  CheckMetric(expected_popup_shown, entries[0],
              ukm::builders::PasswordForm::kGeneration_PopupShownName);

  CheckMetric(&expected_metrics.has_generated_password, entries[0],
              ukm::builders::PasswordForm::kGeneration_GeneratedPasswordName);

  const int64_t* expected_password_modified = nullptr;
  if (expected_metrics.generated_password_modified)
    expected_password_modified =
        &expected_metrics.generated_password_modified.value();
  CheckMetric(
      expected_password_modified, entries[0],
      ukm::builders::PasswordForm::kGeneration_GeneratedPasswordModifiedName);
}

// Create predictions for |form| using field predictions |field_predictions|.
std::map<FormSignature, FormPredictions> CreatePredictions(
    const FormData& form,
    std::vector<std::pair<int, ServerFieldType>> field_predictions) {
  FormPredictions predictions;
  for (const auto& index_prediction : field_predictions) {
    uint32_t renderer_id =
        form.fields[index_prediction.first].unique_renderer_id;
    ServerFieldType server_type = index_prediction.second;
    predictions.push_back({.renderer_id = renderer_id, .type = server_type});
  }
  FormSignature form_signature = CalculateFormSignature(form);
  return {{form_signature, predictions}};
}

class MockFormSaver : public StubFormSaver {
 public:
  MockFormSaver() = default;

  ~MockFormSaver() override = default;

  // FormSaver:
  MOCK_METHOD1(PermanentlyBlacklist, PasswordForm(PasswordStore::FormDigest));
  MOCK_METHOD3(Save,
               void(PasswordForm pending,
                    const std::vector<const PasswordForm*>& matches,
                    const base::string16& old_password));
  MOCK_METHOD3(Update,
               void(PasswordForm pending,
                    const std::vector<const PasswordForm*>& matches,
                    const base::string16& old_password));
  MOCK_METHOD4(UpdateReplace,
               void(PasswordForm pending,
                    const std::vector<const PasswordForm*>& matches,
                    const base::string16& old_password,
                    const PasswordForm& old_unique_key));
  MOCK_METHOD1(Remove, void(const PasswordForm&));

  std::unique_ptr<FormSaver> Clone() override {
    return std::make_unique<MockFormSaver>();
  }

  // Convenience downcasting method.
  static MockFormSaver& Get(NewPasswordFormManager* form_manager) {
    return *static_cast<MockFormSaver*>(form_manager->form_saver());
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(MockFormSaver);
};

// TODO(https://crbug.com/831123): Test sending metrics.
// TODO(https://crbug.com/831123): Test create pending credentials when
// generation happened.
// TODO(https://crbug.com/831123): Test create pending credentials with
// Credential API.
class NewPasswordFormManagerTest : public testing::Test {
 public:
  NewPasswordFormManagerTest() : task_runner_(new TestMockTimeTaskRunner) {
    GURL origin = GURL("https://accounts.google.com/a/ServiceLoginAuth");
    GURL action = GURL("https://accounts.google.com/a/ServiceLogin");
    GURL psl_origin = GURL("https://myaccounts.google.com/a/ServiceLoginAuth");
    GURL psl_action = GURL("https://myaccounts.google.com/a/ServiceLogin");

    observed_form_.url = origin;
    observed_form_.action = action;
    observed_form_.name = ASCIIToUTF16("sign-in");
    observed_form_.unique_renderer_id = 1;
    observed_form_.is_form_tag = true;

    observed_form_only_password_fields_ = observed_form_;

    FormFieldData field;
    field.name = ASCIIToUTF16("firstname");
    field.id_attribute = field.name;
    field.name_attribute = field.name;
    field.form_control_type = "text";
    field.unique_renderer_id = 1;
    observed_form_.fields.push_back(field);

    field.name = ASCIIToUTF16("username");
    field.id_attribute = field.name;
    field.name_attribute = field.name;
    field.form_control_type = "text";
    field.unique_renderer_id = 2;
    observed_form_.fields.push_back(field);

    field.name = ASCIIToUTF16("password");
    field.id_attribute = field.name;
    field.name_attribute = field.name;
    field.form_control_type = "password";
    field.unique_renderer_id = 3;
    observed_form_.fields.push_back(field);
    observed_form_only_password_fields_.fields.push_back(field);

    field.name = ASCIIToUTF16("password2");
    field.id_attribute = field.name;
    field.name_attribute = field.name;
    field.form_control_type = "password";
    field.unique_renderer_id = 5;
    observed_form_only_password_fields_.fields.push_back(field);

// On iOS the unique_id member uniquely addresses this field in the DOM.
// This is an ephemeral value which is not guaranteed to be stable across
// page loads. It serves to allow a given field to be found during the
// current navigation.
// TODO(crbug.com/896689): Expand the logic/application of this to other
// platforms and/or merge this concept with |unique_renderer_id|.
#if defined(OS_IOS)
    for (auto& f : observed_form_.fields) {
      f.unique_id = f.id_attribute;
    }
    for (auto& f : observed_form_only_password_fields_.fields) {
      f.unique_id = f.id_attribute;
    }
#endif

    submitted_form_ = observed_form_;
    submitted_form_.fields[kUsernameFieldIndex].value = ASCIIToUTF16("user1");
    submitted_form_.fields[kPasswordFieldIndex].value = ASCIIToUTF16("secret1");

    saved_match_.origin = origin;
    saved_match_.action = action;
    saved_match_.signon_realm = "https://accounts.google.com/";
    saved_match_.preferred = true;
    saved_match_.username_value = ASCIIToUTF16("test@gmail.com");
    saved_match_.username_element = ASCIIToUTF16("field1");
    saved_match_.password_value = ASCIIToUTF16("test1");
    saved_match_.password_element = ASCIIToUTF16("field2");
    saved_match_.is_public_suffix_match = false;
    saved_match_.scheme = PasswordForm::Scheme::kHtml;

    psl_saved_match_ = saved_match_;
    psl_saved_match_.origin = psl_origin;
    psl_saved_match_.action = psl_action;
    psl_saved_match_.signon_realm = "https://myaccounts.google.com/";
    psl_saved_match_.is_public_suffix_match = true;

    parsed_observed_form_ = saved_match_;
    parsed_observed_form_.form_data = observed_form_;
    parsed_observed_form_.username_element =
        observed_form_.fields[kUsernameFieldIndex].name;
    parsed_observed_form_.password_element =
        observed_form_.fields[kPasswordFieldIndex].name;

    parsed_submitted_form_ = parsed_observed_form_;
    parsed_submitted_form_.form_data = submitted_form_;
    parsed_submitted_form_.username_value =
        submitted_form_.fields[kUsernameFieldIndex].value;
    parsed_submitted_form_.password_value =
        submitted_form_.fields[kPasswordFieldIndex].value;

    blacklisted_match_ = saved_match_;
    blacklisted_match_.blacklisted_by_user = true;

    EXPECT_CALL(client_, GetAutofillDownloadManager())
        .WillRepeatedly(testing::Return(&mock_autofill_download_manager_));
    ON_CALL(mock_autofill_download_manager_,
            StartUploadRequest(_, _, _, _, _, _))
        .WillByDefault(testing::Return(true));

    CreateFormManager(observed_form_);
  }

 protected:
  MockAutofillDownloadManager mock_autofill_download_manager_;
  FormData observed_form_;
  FormData submitted_form_;
  FormData observed_form_only_password_fields_;
  PasswordForm saved_match_;
  PasswordForm psl_saved_match_;
  PasswordForm blacklisted_match_;
  PasswordForm parsed_observed_form_;
  PasswordForm parsed_submitted_form_;
  MockPasswordManagerClient client_;
  MockPasswordManagerDriver driver_;
  scoped_refptr<TestMockTimeTaskRunner> task_runner_;

  // Define |fetcher_| before |form_manager_|, because the former needs to
  // outlive the latter.
  std::unique_ptr<FakeFormFetcher> fetcher_;
  std::unique_ptr<NewPasswordFormManager> form_manager_;

  // Creates NewPasswordFormManager and sets it to |form_manager_|. Along the
  // way a new |fetcher_| is created.
  void CreateFormManager(const FormData& observed_form) {
    fetcher_.reset(new FakeFormFetcher());
    fetcher_->Fetch();
    form_manager_.reset(new NewPasswordFormManager(
        &client_, driver_.AsWeakPtr(), observed_form, fetcher_.get(),
        std::make_unique<NiceMock<MockFormSaver>>(), nullptr));
  }

  // Creates NewPasswordFormManager and sets it to |form_manager_| for
  // |base_auth_observed_form|. Along the way a new |fetcher_| is created.
  void CreateFormManagerForNonWebForm(
      const PasswordForm& base_auth_observed_form) {
    fetcher_.reset(new FakeFormFetcher());
    fetcher_->Fetch();
    form_manager_.reset(new NewPasswordFormManager(
        &client_, PasswordStore::FormDigest(base_auth_observed_form),
        fetcher_.get(), std::make_unique<NiceMock<MockFormSaver>>()));
  }

  void SetNonFederatedAndNotifyFetchCompleted(
      const std::vector<const autofill::PasswordForm*>& non_federated) {
    fetcher_->SetNonFederated(non_federated);
    fetcher_->NotifyFetchCompleted();
  }
};

TEST_F(NewPasswordFormManagerTest, DoesManage) {
  EXPECT_TRUE(form_manager_->DoesManage(observed_form_, &driver_));
  // Forms on other drivers are not considered managed.
  EXPECT_FALSE(form_manager_->DoesManage(observed_form_, nullptr));
  FormData another_form = observed_form_;
  another_form.is_form_tag = false;
  EXPECT_FALSE(form_manager_->DoesManage(another_form, &driver_));

  // On non-iOS platforms unique_renderer_id is the form identifier.
  another_form = observed_form_;
  another_form.unique_renderer_id = observed_form_.unique_renderer_id + 1;
#if defined(OS_IOS)
  EXPECT_TRUE(form_manager_->DoesManage(another_form, &driver_));
#else
  EXPECT_FALSE(form_manager_->DoesManage(another_form, &driver_));
#endif

  // On iOS platforms form name is the form identifier.
  another_form = observed_form_;
  another_form.name = observed_form_.name + ASCIIToUTF16("1");
#if defined(OS_IOS)
  EXPECT_FALSE(form_manager_->DoesManage(another_form, &driver_));
#else
  EXPECT_TRUE(form_manager_->DoesManage(another_form, &driver_));
#endif
}

TEST_F(NewPasswordFormManagerTest, DoesManageNoFormTag) {
  observed_form_.is_form_tag = false;
  CreateFormManager(observed_form_);

  FormData another_form = observed_form_;
  // Simulate that new input was added by JavaScript.
  another_form.fields.push_back(FormFieldData());
  EXPECT_TRUE(form_manager_->DoesManage(another_form, &driver_));
  // Forms on other drivers are not considered managed.
  EXPECT_FALSE(form_manager_->DoesManage(another_form, nullptr));
}

TEST_F(NewPasswordFormManagerTest, Autofill) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());

  CreateFormManager(observed_form_);
  EXPECT_CALL(driver_, FormEligibleForGenerationFound(_)).Times(0);
  PasswordFormFillData fill_data;
  EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
  CreateFormManager(observed_form_);
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  task_runner_->FastForwardUntilNoTasksRemain();

  EXPECT_EQ(observed_form_.url, fill_data.origin);
  EXPECT_FALSE(fill_data.wait_for_username);
  EXPECT_EQ(observed_form_.fields[1].name, fill_data.username_field.name);
  EXPECT_EQ(saved_match_.username_value, fill_data.username_field.value);
  EXPECT_EQ(observed_form_.fields[2].name, fill_data.password_field.name);
  EXPECT_EQ(saved_match_.password_value, fill_data.password_field.value);
}

TEST_F(NewPasswordFormManagerTest, AutofillNotMoreThan5Times) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());

  EXPECT_CALL(driver_, FillPasswordForm(_));
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  task_runner_->FastForwardUntilNoTasksRemain();
  Mock::VerifyAndClearExpectations(&driver_);

  for (size_t i = 0; i < NewPasswordFormManager::kMaxTimesAutofill - 1; ++i) {
    EXPECT_CALL(driver_, FillPasswordForm(_));
    form_manager_->Fill();
    Mock::VerifyAndClearExpectations(&driver_);
  }

  EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
  form_manager_->Fill();
}

// NewPasswordFormManager should always send fill data to renderer, even for
// sign-up forms (no "current-password" field, i.e., no password field to fill
// into). However, for sign-up forms, no particular password field should be
// identified for filling. That way, Chrome won't disturb the user by filling
// the sign-up form, but will be able to offer a manual fallback for filling if
// the form was misclassified.
TEST_F(NewPasswordFormManagerTest, AutofillSignUpForm) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  // Make |observed_form_| to be sign-up form.
  observed_form_.fields.back().autocomplete_attribute = "new-password";

  PasswordFormFillData fill_data;
  EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));

  PasswordFormGenerationData generation_data;
  EXPECT_CALL(driver_, FormEligibleForGenerationFound(_))
      .WillOnce(SaveArg<0>(&generation_data));

  CreateFormManager(observed_form_);
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  task_runner_->FastForwardUntilNoTasksRemain();
  constexpr uint32_t kNoID = FormFieldData::kNotSetFormControlRendererId;
  EXPECT_EQ(kNoID, fill_data.password_field.unique_renderer_id);
  EXPECT_EQ(saved_match_.password_value, fill_data.password_field.value);
#if defined(OS_IOS)
  EXPECT_EQ(ASCIIToUTF16("sign-in"), generation_data.form_name);
  EXPECT_EQ(ASCIIToUTF16("password"), generation_data.new_password_element);
  EXPECT_EQ(base::string16(), generation_data.confirmation_password_element);
#else
  EXPECT_EQ(observed_form_.fields.back().unique_renderer_id,
            generation_data.new_password_renderer_id);
  EXPECT_EQ(kNoID, generation_data.confirmation_password_renderer_id);
#endif
}

// Check that generation signal is sent the the renderer when new password
// fields are marked with autocomplete attribute.
TEST_F(NewPasswordFormManagerTest, GenerationOnNewAndConfirmPasswordFields) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  // Make |observed_form_| to be sign-up form.
  observed_form_.fields.back().autocomplete_attribute = "new-password";
  const uint32_t new_password_render_id =
      observed_form_.fields.back().unique_renderer_id;
  // Add a confirmation field.
  FormFieldData field;
  const uint32_t confirm_password_render_id = new_password_render_id + 1;
  field.unique_renderer_id = confirm_password_render_id;
  field.form_control_type = "password";
  field.autocomplete_attribute = "new-password";
  observed_form_.fields.push_back(field);

  PasswordFormGenerationData generation_data;
  EXPECT_CALL(driver_, FormEligibleForGenerationFound(_))
      .WillOnce(SaveArg<0>(&generation_data));

  CreateFormManager(observed_form_);
  fetcher_->NotifyFetchCompleted();

  task_runner_->FastForwardUntilNoTasksRemain();
#if defined(OS_IOS)
  EXPECT_EQ(ASCIIToUTF16("sign-in"), generation_data.form_name);
  EXPECT_EQ(ASCIIToUTF16("password"), generation_data.new_password_element);
  EXPECT_EQ(base::string16(), generation_data.confirmation_password_element);
#else
  EXPECT_EQ(new_password_render_id, generation_data.new_password_renderer_id);
  EXPECT_EQ(confirm_password_render_id,
            generation_data.confirmation_password_renderer_id);
#endif
}

TEST_F(NewPasswordFormManagerTest, AutofillWithBlacklistedMatch) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  PasswordFormFillData fill_data;
  EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
  fetcher_->SetNonFederated({&saved_match_});
  fetcher_->SetBlacklisted({&blacklisted_match_});
  fetcher_->NotifyFetchCompleted();

  task_runner_->FastForwardUntilNoTasksRemain();

  EXPECT_EQ(observed_form_.url, fill_data.origin);
  EXPECT_EQ(saved_match_.username_value, fill_data.username_field.value);
  EXPECT_EQ(saved_match_.password_value, fill_data.password_field.value);
}

TEST_F(NewPasswordFormManagerTest, SetSubmitted) {
  EXPECT_FALSE(form_manager_->is_submitted());
  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form_, &driver_, false));
  EXPECT_TRUE(form_manager_->is_submitted());

  FormData another_form = submitted_form_;
  another_form.name += ASCIIToUTF16("1");
#if !defined(OS_IOS)
  // |another_form| is managed because the same |unique_renderer_id| as
  // |observed_form_|.
  EXPECT_TRUE(form_manager_->ProvisionallySave(another_form, &driver_, false));
  EXPECT_TRUE(form_manager_->is_submitted());
#endif
}

TEST_F(NewPasswordFormManagerTest, SetSubmittedMultipleTimes) {
  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form_, &driver_, false));
  EXPECT_TRUE(form_manager_->is_submitted());

  // Make the submitted form to be invalid password form.
  submitted_form_.fields.clear();

  // Expect that |form_manager_| is still in submitted state because the first
  // time the submited form was valid.
  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form_, &driver_, false));
  EXPECT_TRUE(form_manager_->is_submitted());
  EXPECT_TRUE(form_manager_->GetSubmittedForm());
}

// Tests that when NewPasswordFormManager receives saved matches it waits for
// server predictions and fills on receving them.
TEST_F(NewPasswordFormManagerTest, ServerPredictionsWithinDelay) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());

  // Expects no filling on save matches receiving.
  EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});
  Mock::VerifyAndClearExpectations(&driver_);

  std::map<FormSignature, FormPredictions> predictions = CreatePredictions(
      observed_form_, {std::make_pair(2, autofill::PASSWORD)});

  // Expect filling without delay on receiving server predictions.
  EXPECT_CALL(driver_, FillPasswordForm(_)).Times(1);
  form_manager_->ProcessServerPredictions(predictions);
  Mock::VerifyAndClearExpectations(&driver_);

  // Expect no filling on receving predictions again.
  EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
  form_manager_->ProcessServerPredictions(predictions);
}

// Tests that NewPasswordFormManager fills after some delay even without
// server predictions.
TEST_F(NewPasswordFormManagerTest, ServerPredictionsAfterDelay) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());

  EXPECT_CALL(driver_, FillPasswordForm(_)).Times(1);
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});
  // Expect filling after passing filling delay.

  // Simulate passing filling delay.
  task_runner_->FastForwardUntilNoTasksRemain();
  Mock::VerifyAndClearExpectations(&driver_);

  std::map<FormSignature, FormPredictions> predictions = CreatePredictions(
      observed_form_, {std::make_pair(2, autofill::PASSWORD)});

  // Expect filling on receiving server predictions because it was less than
  // kMaxTimesAutofill attempts to fill.
  EXPECT_CALL(driver_, FillPasswordForm(_)).Times(1);
  form_manager_->ProcessServerPredictions(predictions);
  task_runner_->FastForwardUntilNoTasksRemain();
}

// Tests that filling happens immediately if server predictions are received
// before saved matches.
TEST_F(NewPasswordFormManagerTest, ServerPredictionsBeforeFetcher) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  // Expect no filling after receiving saved matches from |fetcher_|, since
  // |form_manager| is waiting for server-side predictions.
  EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
  CreateFormManager(observed_form_);

  std::map<FormSignature, FormPredictions> predictions = CreatePredictions(
      observed_form_, {std::make_pair(2, autofill::PASSWORD)});
  form_manager_->ProcessServerPredictions(predictions);
  Mock::VerifyAndClearExpectations(&driver_);

  // Expect filling without delay on receiving server predictions.
  EXPECT_CALL(driver_, FillPasswordForm(_)).Times(1);
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});
}

// Tests creating pending credentials when the password store is empty.
TEST_F(NewPasswordFormManagerTest, CreatePendingCredentialsEmptyStore) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  fetcher_->NotifyFetchCompleted();

  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form_, &driver_, false));
  CheckPendingCredentials(parsed_submitted_form_,
                          form_manager_->GetPendingCredentials());
  EXPECT_EQ(UserAction::kOverrideUsernameAndPassword,
            form_manager_->GetMetricsRecorder()->GetUserAction());
}

// Tests creating pending credentials when new credentials are submitted and the
// store has another credentials saved.
TEST_F(NewPasswordFormManagerTest, CreatePendingCredentialsNewCredentials) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form_, &driver_, false));
  CheckPendingCredentials(parsed_submitted_form_,
                          form_manager_->GetPendingCredentials());
  EXPECT_EQ(UserAction::kOverrideUsernameAndPassword,
            form_manager_->GetMetricsRecorder()->GetUserAction());
}

// Tests that when submitted credentials are equal to already saved one then
// pending credentials equal to saved match.
TEST_F(NewPasswordFormManagerTest, CreatePendingCredentialsAlreadySaved) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  submitted_form_.fields[kUsernameFieldIndex].value =
      saved_match_.username_value;
  submitted_form_.fields[kPasswordFieldIndex].value =
      saved_match_.password_value;

  // Tests that depending on whether we fill on page load or account select that
  // correct user action is recorded. Fill on account select is simulated by
  // pretending we are in incognito mode.
  for (bool is_incognito : {false, true}) {
    EXPECT_CALL(client_, IsIncognito).WillOnce(Return(is_incognito));
    form_manager_->Fill();
    EXPECT_TRUE(
        form_manager_->ProvisionallySave(submitted_form_, &driver_, false));
    CheckPendingCredentials(/* expected */ saved_match_,
                            form_manager_->GetPendingCredentials());
    EXPECT_EQ(is_incognito ? UserAction::kChoose : UserAction::kNone,
              form_manager_->GetMetricsRecorder()->GetUserAction());
  }
}

// Tests that when submitted credentials are equal to already saved PSL
// credentials.
TEST_F(NewPasswordFormManagerTest, CreatePendingCredentialsPSLMatchSaved) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  PasswordForm expected = saved_match_;

  saved_match_.origin = GURL("https://m.accounts.google.com/auth");
  saved_match_.signon_realm = "https://m.accounts.google.com/";
  saved_match_.is_public_suffix_match = true;

  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  submitted_form_.fields[kUsernameFieldIndex].value =
      saved_match_.username_value;
  submitted_form_.fields[kPasswordFieldIndex].value =
      saved_match_.password_value;

  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form_, &driver_, false));
  CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
  EXPECT_EQ(UserAction::kChoosePslMatch,
            form_manager_->GetMetricsRecorder()->GetUserAction());
}

// Tests creating pending credentials when new credentials are different only in
// password with already saved one.
TEST_F(NewPasswordFormManagerTest, CreatePendingCredentialsPasswordOverriden) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  PasswordForm expected = saved_match_;
  expected.password_value += ASCIIToUTF16("1");

  submitted_form_.fields[kUsernameFieldIndex].value =
      saved_match_.username_value;
  submitted_form_.fields[kPasswordFieldIndex].value = expected.password_value;
  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form_, &driver_, false));
  CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
  EXPECT_EQ(UserAction::kOverridePassword,
            form_manager_->GetMetricsRecorder()->GetUserAction());
}

// Tests that when submitted credentials are equal to already saved one then
// pending credentials equal to saved match.
TEST_F(NewPasswordFormManagerTest, CreatePendingCredentialsUpdate) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  FormData submitted_form = observed_form_only_password_fields_;
  submitted_form.fields[0].value = ASCIIToUTF16("strongpassword");
  submitted_form.fields[1].value = ASCIIToUTF16("verystrongpassword");

  PasswordForm expected = saved_match_;
  expected.password_value = ASCIIToUTF16("verystrongpassword");

  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form, &driver_, false));
  CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
  EXPECT_EQ(UserAction::kOverridePassword,
            form_manager_->GetMetricsRecorder()->GetUserAction());
}

// Tests creating pending credentials when a change password form is submitted
// and there are multipe saved forms.
TEST_F(NewPasswordFormManagerTest,
       CreatePendingCredentialsUpdateMultipleSaved) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  PasswordForm another_saved_match = saved_match_;
  another_saved_match.username_value += ASCIIToUTF16("1");
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_, &another_saved_match});

  FormData submitted_form = observed_form_only_password_fields_;
  submitted_form.fields[0].value = ASCIIToUTF16("strongpassword");
  submitted_form.fields[1].value = ASCIIToUTF16("verystrongpassword");

  PasswordForm expected = saved_match_;
  expected.password_value = ASCIIToUTF16("verystrongpassword");

  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form, &driver_, false));
  CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
}

// Tests creating pending credentials when the password field has an empty name.
TEST_F(NewPasswordFormManagerTest, CreatePendingCredentialsEmptyName) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  fetcher_->NotifyFetchCompleted();

  FormData anonymous_signup = observed_form_;
  // There is an anonymous password field.
  anonymous_signup.fields[2].name.clear();
  anonymous_signup.fields[2].value = ASCIIToUTF16("a password");
  // Mark the password field as new-password.
  std::map<FormSignature, FormPredictions> predictions = CreatePredictions(
      observed_form_, {std::make_pair(2, autofill::ACCOUNT_CREATION_PASSWORD)});

  form_manager_->ProcessServerPredictions(predictions);

  EXPECT_TRUE(
      form_manager_->ProvisionallySave(anonymous_signup, &driver_, false));
  EXPECT_EQ(ASCIIToUTF16("a password"),
            form_manager_->GetPendingCredentials().password_value);
}

// Tests that there is no crash even when the observed form is a not password
// form and the submitted form is password form.
TEST_F(NewPasswordFormManagerTest, NoCrashOnNonPasswordForm) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  FormData form_without_password_fields = observed_form_;
  // Remove the password field.
  form_without_password_fields.fields.resize(kPasswordFieldIndex);
  CreateFormManager(form_without_password_fields);
  fetcher_->NotifyFetchCompleted();

  FormData submitted_form = observed_form_;
  submitted_form.fields[kUsernameFieldIndex].value = ASCIIToUTF16("username");
  submitted_form.fields[kPasswordFieldIndex].value = ASCIIToUTF16("password");

  // Expect no crash.
  form_manager_->ProvisionallySave(submitted_form, &driver_, false);
}

TEST_F(NewPasswordFormManagerTest, IsEqualToSubmittedForm) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  fetcher_->NotifyFetchCompleted();

  FormData submitted_form = observed_form_;
  submitted_form.fields[kUsernameFieldIndex].value =
      saved_match_.username_value;
  submitted_form.fields[kPasswordFieldIndex].value =
      saved_match_.password_value;

  // No submitted form yet.
  EXPECT_FALSE(form_manager_->IsEqualToSubmittedForm(submitted_form));

  ASSERT_TRUE(
      form_manager_->ProvisionallySave(submitted_form, &driver_, false));

  observed_form_.unique_renderer_id += 10;
  observed_form_.fields.clear();

  EXPECT_TRUE(form_manager_->IsEqualToSubmittedForm(observed_form_));

  observed_form_.action = GURL("https://example.com");
  EXPECT_FALSE(form_manager_->IsEqualToSubmittedForm(observed_form_));
}

// Tests that when credentials with a new username (i.e. not saved yet) is
// successfully submitted, then they are saved correctly.
TEST_F(NewPasswordFormManagerTest, SaveNewCredentials) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  ukm::TestAutoSetUkmRecorder test_ukm_recorder;
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  FormData submitted_form = observed_form_;
  base::string16 new_username = saved_match_.username_value + ASCIIToUTF16("1");
  base::string16 new_password = saved_match_.password_value + ASCIIToUTF16("1");
  submitted_form.fields[kUsernameFieldIndex].value = new_username;
  submitted_form.fields[kPasswordFieldIndex].value = new_password;

  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form, &driver_, false));
  EXPECT_TRUE(form_manager_->IsNewLogin());

  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
  PasswordForm saved_form;
  std::vector<const PasswordForm*> best_matches;
  EXPECT_CALL(form_saver, Save(_, _, _))
      .WillOnce(DoAll(SaveArg<0>(&saved_form), SaveArg<1>(&best_matches)));
  EXPECT_CALL(client_, UpdateFormManagers());

  form_manager_->Save();

  std::string expected_signon_realm = submitted_form.url.GetOrigin().spec();
  EXPECT_EQ(submitted_form.url, saved_form.origin);
  EXPECT_EQ(expected_signon_realm, saved_form.signon_realm);
  EXPECT_EQ(new_username, saved_form.username_value);
  EXPECT_EQ(new_password, saved_form.password_value);
  EXPECT_TRUE(saved_form.preferred);

  EXPECT_EQ(submitted_form.fields[kUsernameFieldIndex].name,
            saved_form.username_element);
  EXPECT_EQ(submitted_form.fields[kPasswordFieldIndex].name,
            saved_form.password_element);
  EXPECT_EQ(std::vector<const PasswordForm*>{&saved_match_}, best_matches);

  // Check UKM metrics.
  form_manager_.reset();
  ExpectedGenerationUKM expected_metrics = {
      {} /* shown manually */,
      0 /* password generated */,
      {} /* generated password is not modified */};

  CheckPasswordGenerationUKM(test_ukm_recorder, expected_metrics);
}

// Check that if there is saved PSL matched credentials with the same
// username/password as in submitted form, then the saved form is the same
// already saved only with origin and signon_realm from the submitted form.
TEST_F(NewPasswordFormManagerTest, SavePSLToAlreadySaved) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  SetNonFederatedAndNotifyFetchCompleted({&psl_saved_match_});

  FormData submitted_form = observed_form_;
  // Change
  submitted_form.fields[kUsernameFieldIndex].value =
      psl_saved_match_.username_value;
  submitted_form.fields[kPasswordFieldIndex].value =
      psl_saved_match_.password_value;

  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form, &driver_, false));
  EXPECT_TRUE(form_manager_->IsNewLogin());
  EXPECT_TRUE(form_manager_->IsPendingCredentialsPublicSuffixMatch());

  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
  PasswordForm saved_form;
  std::vector<const PasswordForm*> best_matches;
  EXPECT_CALL(form_saver, Save(_, _, _))
      .WillOnce(DoAll(SaveArg<0>(&saved_form), SaveArg<1>(&best_matches)));

  form_manager_->Save();

  EXPECT_EQ(submitted_form.url, saved_form.origin);
  EXPECT_EQ(GetSignonRealm(submitted_form.url), saved_form.signon_realm);
  EXPECT_EQ(saved_form.username_value, psl_saved_match_.username_value);
  EXPECT_EQ(saved_form.password_value, psl_saved_match_.password_value);
  EXPECT_EQ(saved_form.username_element, psl_saved_match_.username_element);
  EXPECT_EQ(saved_form.password_element, psl_saved_match_.password_element);

  EXPECT_TRUE(saved_form.preferred);

  EXPECT_EQ(std::vector<const PasswordForm*>{&psl_saved_match_}, best_matches);
}

// Tests that when credentials with already saved username but with a new
// password are submitted, then the saved password is updated.
TEST_F(NewPasswordFormManagerTest, OverridePassword) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  FormData submitted_form = observed_form_;
  base::string16 username = saved_match_.username_value;
  base::string16 new_password = saved_match_.password_value + ASCIIToUTF16("1");
  submitted_form.fields[kUsernameFieldIndex].value = username;
  submitted_form.fields[kPasswordFieldIndex].value = new_password;

  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form, &driver_, false));
  EXPECT_FALSE(form_manager_->IsNewLogin());
  EXPECT_TRUE(form_manager_->IsPasswordUpdate());

  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
  PasswordForm updated_form;
  EXPECT_CALL(form_saver, Update(_, ElementsAre(Pointee(saved_match_)),
                                 saved_match_.password_value))
      .WillOnce(SaveArg<0>(&updated_form));

  form_manager_->Save();

  EXPECT_TRUE(ArePasswordFormUniqueKeysEqual(saved_match_, updated_form));
  EXPECT_TRUE(updated_form.preferred);
  EXPECT_EQ(new_password, updated_form.password_value);
}

// Tests that when the user changes password on a change password form then the
// saved password is updated.
TEST_F(NewPasswordFormManagerTest, UpdatePasswordOnChangePasswordForm) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  CreateFormManager(observed_form_only_password_fields_);
  PasswordForm not_best_saved_match = saved_match_;
  not_best_saved_match.preferred = false;
  PasswordForm saved_match_another_username = saved_match_;
  saved_match_another_username.username_value += ASCIIToUTF16("1");

  SetNonFederatedAndNotifyFetchCompleted(
      {&saved_match_, &not_best_saved_match, &saved_match_another_username});

  FormData submitted_form = observed_form_only_password_fields_;
  submitted_form.fields[0].value = saved_match_.password_value;
  base::string16 new_password = saved_match_.password_value + ASCIIToUTF16("1");
  submitted_form.fields[1].value = new_password;

  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form, &driver_, false));
  EXPECT_FALSE(form_manager_->IsNewLogin());
  EXPECT_TRUE(form_manager_->IsPasswordUpdate());

  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
  PasswordForm updated_form;
  EXPECT_CALL(form_saver,
              Update(_,
                     UnorderedElementsAre(
                         Pointee(saved_match_), Pointee(not_best_saved_match),
                         Pointee(saved_match_another_username)),
                     saved_match_.password_value))
      .WillOnce(SaveArg<0>(&updated_form));

  form_manager_->Save();

  EXPECT_TRUE(ArePasswordFormUniqueKeysEqual(saved_match_, updated_form));
  EXPECT_TRUE(updated_form.preferred);
  EXPECT_EQ(new_password, updated_form.password_value);
}

TEST_F(NewPasswordFormManagerTest, VotesUploadingOnPasswordUpdate) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());

  for (auto expected_vote :
       {autofill::NEW_PASSWORD, autofill::PROBABLY_NEW_PASSWORD,
        autofill::NOT_NEW_PASSWORD}) {
    SCOPED_TRACE(testing::Message("expected_vote=") << expected_vote);
    CreateFormManager(observed_form_only_password_fields_);
    SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

    FormData submitted_form = observed_form_only_password_fields_;
    submitted_form.fields[0].value = saved_match_.password_value;
    auto new_password = saved_match_.password_value + ASCIIToUTF16("1");
    submitted_form.fields[1].value = new_password;

    EXPECT_TRUE(
        form_manager_->ProvisionallySave(submitted_form, &driver_, false));

    std::map<base::string16, autofill::ServerFieldType> expected_types;
    expected_types[ASCIIToUTF16("password")] = autofill::PASSWORD;
    expected_types[ASCIIToUTF16("password2")] = expected_vote;

    testing::InSequence in_sequence;
    EXPECT_CALL(mock_autofill_download_manager_,
                StartUploadRequest(UploadedAutofillTypesAre(expected_types),
                                   false, _, _, true, nullptr));
    if (expected_vote == autofill::NEW_PASSWORD) {
      // An unrelated |FIRST_USE| vote.
      EXPECT_CALL(mock_autofill_download_manager_,
                  StartUploadRequest(_, _, _, _, _, _));
    }

    if (expected_vote == autofill::NEW_PASSWORD)
      form_manager_->Save();
    else if (expected_vote == autofill::PROBABLY_NEW_PASSWORD)
      form_manager_->OnNoInteraction(true /* is_update */);
    else
      form_manager_->OnNopeUpdateClicked();
    Mock::VerifyAndClearExpectations(&mock_autofill_download_manager_);
  }
}

TEST_F(NewPasswordFormManagerTest, UpdateUsernameEmptyStore) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  fetcher_->NotifyFetchCompleted();

  form_manager_->ProvisionallySave(submitted_form_, &driver_, false);

  base::string16 new_username =
      parsed_submitted_form_.username_value + ASCIIToUTF16("1");
  PasswordForm expected = parsed_submitted_form_;
  expected.username_value = new_username;
  expected.username_element.clear();

  form_manager_->UpdateUsername(new_username);

  CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
  EXPECT_TRUE(form_manager_->IsNewLogin());
}

TEST_F(NewPasswordFormManagerTest, UpdateUsernameToAnotherFieldValue) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  fetcher_->NotifyFetchCompleted();

  base::string16 user_chosen_username = ASCIIToUTF16("user_chosen_username");
  base::string16 automatically_chosen_username =
      ASCIIToUTF16("automatically_chosen_username");
  submitted_form_.fields[0].value = user_chosen_username;
  submitted_form_.fields[1].value = automatically_chosen_username;
  form_manager_->ProvisionallySave(submitted_form_, &driver_, false);

  EXPECT_EQ(automatically_chosen_username,
            form_manager_->GetPendingCredentials().username_value);

  form_manager_->UpdateUsername(user_chosen_username);

  EXPECT_EQ(user_chosen_username,
            form_manager_->GetPendingCredentials().username_value);

  FieldTypeMap expected_types = {
      {ASCIIToUTF16("firstname"), autofill::USERNAME},
      {ASCIIToUTF16("password"), autofill::PASSWORD}};
  VoteTypeMap expected_vote_types = {
      {ASCIIToUTF16("firstname"),
       AutofillUploadContents::Field::USERNAME_EDITED}};
  EXPECT_CALL(
      mock_autofill_download_manager_,
      StartUploadRequest(
          AllOf(UploadedAutofillTypesAre(expected_types),
                HasGenerationVote(false), VoteTypesAre(expected_vote_types)),
          _, Contains(autofill::USERNAME), _, _, nullptr));
  form_manager_->Save();
}

TEST_F(NewPasswordFormManagerTest, UpdateUsernameToAlreadyExisting) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  form_manager_->ProvisionallySave(submitted_form_, &driver_, false);

  base::string16 new_username = saved_match_.username_value;
  base::string16 expected_password = parsed_submitted_form_.password_value;
  PasswordForm expected = saved_match_;
  expected.password_value = expected_password;

  form_manager_->UpdateUsername(new_username);

  CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
  EXPECT_FALSE(form_manager_->IsNewLogin());
  EXPECT_TRUE(form_manager_->IsPasswordUpdate());
}

TEST_F(NewPasswordFormManagerTest, UpdatePasswordValueEmptyStore) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  fetcher_->NotifyFetchCompleted();

  form_manager_->ProvisionallySave(submitted_form_, &driver_, false);

  base::string16 new_password =
      parsed_submitted_form_.password_value + ASCIIToUTF16("1");
  PasswordForm expected = parsed_submitted_form_;
  expected.password_value = new_password;
  expected.password_element.clear();

  form_manager_->UpdatePasswordValue(new_password);

  CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
  EXPECT_TRUE(form_manager_->IsNewLogin());

  // TODO(https://crbug.com/928690): implement not sending incorrect votes and
  // check that StartUploadRequest is not called.
  EXPECT_CALL(mock_autofill_download_manager_,
              StartUploadRequest(_, _, _, _, _, _))
      .Times(1);
  form_manager_->Save();
}

TEST_F(NewPasswordFormManagerTest, UpdatePasswordValueToAlreadyExisting) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  // Emulate submitting form with known username and different password.
  submitted_form_.fields[kUsernameFieldIndex].value =
      saved_match_.username_value;
  form_manager_->ProvisionallySave(submitted_form_, &driver_, false);

  // The user changes password to already saved one.
  base::string16 password = saved_match_.password_value;
  form_manager_->UpdatePasswordValue(password);

  CheckPendingCredentials(saved_match_, form_manager_->GetPendingCredentials());
  EXPECT_FALSE(form_manager_->IsNewLogin());
  EXPECT_FALSE(form_manager_->IsPasswordUpdate());
}

TEST_F(NewPasswordFormManagerTest, UpdatePasswordValueMultiplePasswordFields) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  FormData form = observed_form_only_password_fields_;

  CreateFormManager(form);
  fetcher_->NotifyFetchCompleted();
  base::string16 password = ASCIIToUTF16("password1");
  base::string16 pin = ASCIIToUTF16("pin");
  form.fields[0].value = password;
  form.fields[1].value = pin;
  form_manager_->ProvisionallySave(form, &driver_, false);

  // Check that a second password field is chosen for saving.
  EXPECT_EQ(pin, form_manager_->GetPendingCredentials().password_value);

  PasswordForm expected = form_manager_->GetPendingCredentials();
  expected.password_value = password;
  expected.password_element = form.fields[0].name;

  // Simulate that the user updates value to save for the first password field.
  form_manager_->UpdatePasswordValue(password);

  // Check that newly created pending credentials are correct.
  CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
  EXPECT_TRUE(form_manager_->IsNewLogin());

  // Check that a vote is sent for the field with the value which is chosen by
  // the user.
  std::map<base::string16, ServerFieldType> expected_types;
  expected_types[expected.password_element] = autofill::PASSWORD;

  EXPECT_CALL(mock_autofill_download_manager_,
              StartUploadRequest(UploadedAutofillTypesAre(expected_types),
                                 false, _, _, true, nullptr));

  // Check that the password which was chosen by the user is saved.
  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
  PasswordForm saved_form;
  EXPECT_CALL(form_saver, Save(_, _, _)).WillOnce(SaveArg<0>(&saved_form));

  form_manager_->Save();
  CheckPendingCredentials(expected, saved_form);
}

TEST_F(NewPasswordFormManagerTest, PermanentlyBlacklist) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  fetcher_->NotifyFetchCompleted();

  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());

  PasswordForm actual_blacklisted_form =
      password_manager_util::MakeNormalizedBlacklistedForm(
          PasswordStore::FormDigest(observed_form_));
  EXPECT_CALL(form_saver,
              PermanentlyBlacklist(PasswordStore::FormDigest(observed_form_)))
      .WillOnce(Return(actual_blacklisted_form));

  form_manager_->PermanentlyBlacklist();
  EXPECT_THAT(form_manager_->GetBlacklistedMatches(),
              ElementsAre(Pointee(actual_blacklisted_form)));
}

TEST_F(NewPasswordFormManagerTest, Clone) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  fetcher_->NotifyFetchCompleted();

  // Provisionally save in order to create pending credentials.
  ASSERT_TRUE(
      form_manager_->ProvisionallySave(submitted_form_, &driver_, false));

  std::unique_ptr<NewPasswordFormManager> cloned_manager =
      form_manager_->Clone();

  EXPECT_TRUE(cloned_manager->DoesManage(observed_form_, nullptr));
  EXPECT_TRUE(cloned_manager->GetFormFetcher());
  // Check that |form_fetcher| was cloned.
  EXPECT_NE(form_manager_->GetFormFetcher(), cloned_manager->GetFormFetcher());

  EXPECT_EQ(form_manager_->metrics_recorder(),
            cloned_manager->metrics_recorder());

  EXPECT_EQ(form_manager_->GetPendingCredentials(),
            cloned_manager->GetPendingCredentials());
  ASSERT_TRUE(cloned_manager->GetSubmittedForm());
  EXPECT_EQ(*form_manager_->GetSubmittedForm(),
            *cloned_manager->GetSubmittedForm());
  EXPECT_TRUE(cloned_manager->is_submitted());
}

// Extracts the information whether parsing was successful from a metric
// specified by |metric_name| stored in |entry|. The metric name should be one
// of ukm::builders::PasswordForm::kReadonlyWhenSavingName and
// ukm::builders::PasswordForm::kReadonlyWhenFillingName.
bool ParsingSuccessReported(const ukm::mojom::UkmEntry* entry,
                            base::StringPiece metric_name) {
  const int64_t* value =
      ukm::TestUkmRecorder::GetEntryMetric(entry, metric_name);
  EXPECT_TRUE(value);
  // Ideally, an ASSERT_TRUE above would prevent the test suite from crashing on
  // dereferencing |value| below. But ASSERT_* is not available in non-void
  // returning functions, so the null value is handled explicitly.
  if (!value)
    return false;  // Value does not matter, the test already failed.
  return 1 == (1 & *value);
}

// Test that an attempt to log to ReadonlyWhenFilling UKM is made when filling.
TEST_F(NewPasswordFormManagerTest, RecordReadonlyWhenFilling) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  ukm::TestAutoSetUkmRecorder test_ukm_recorder;
  EXPECT_CALL(driver_, FillPasswordForm(_));
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  task_runner_->FastForwardUntilNoTasksRemain();

  // Destroy the form manager to destroy the UKM recorder it owns. The recorder
  // only records metrics in its destructor.
  form_manager_.reset();

  auto entries = test_ukm_recorder.GetEntriesByName(
      ukm::builders::PasswordForm::kEntryName);
  ASSERT_EQ(1u, entries.size());

  EXPECT_TRUE(ParsingSuccessReported(
      entries[0], ukm::builders::PasswordForm::kReadonlyWhenFillingName));
}

// Test that an attempt to log to ReadonlyWhenFilling UKM is made when filling,
// even when the parsing itself is unsuccessful.
TEST_F(NewPasswordFormManagerTest, RecordReadonlyWhenFilling_ParsingFailed) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());

  FormData malformed_form = observed_form_;
  malformed_form.fields.clear();
  CreateFormManager(malformed_form);
  // Only create the recorder after the current form manager is created,
  // otherwise the destruction of the previous one will add unwanted UKM entries
  // in it.
  ukm::TestAutoSetUkmRecorder test_ukm_recorder;
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  task_runner_->FastForwardUntilNoTasksRemain();

  // Destroy the form manager to destroy the UKM recorder it owns. The recorder
  // only records metrics in its destructor.
  form_manager_.reset();

  auto entries = test_ukm_recorder.GetEntriesByName(
      ukm::builders::PasswordForm::kEntryName);
  ASSERT_EQ(1u, entries.size());

  EXPECT_FALSE(ParsingSuccessReported(
      entries[0], ukm::builders::PasswordForm::kReadonlyWhenFillingName));
}

// Test that an attempt to log to ReadonlyWhenSaving UKM is made when creating
// pending credentials.
TEST_F(NewPasswordFormManagerTest, RecordReadonlyWhenSaving) {
  // The scoped context is needed for the UKM recorder.
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  ukm::TestAutoSetUkmRecorder test_ukm_recorder;
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form_, &driver_, false));

  // Destroy the form manager to destroy the UKM recorder it owns. The recorder
  // only records metrics in its destructor.
  form_manager_.reset();

  auto entries = test_ukm_recorder.GetEntriesByName(
      ukm::builders::PasswordForm::kEntryName);
  ASSERT_EQ(1u, entries.size());

  EXPECT_TRUE(ParsingSuccessReported(
      entries[0], ukm::builders::PasswordForm::kReadonlyWhenSavingName));
}

// Test that an attempt to log to ReadonlyWhenSaving UKM is made when creating
// pending credentials, even when their parsing itself is unsuccessful.
TEST_F(NewPasswordFormManagerTest, RecordReadonlyWhenSaving_ParsingFailed) {
  // The scoped context is needed for the UKM recorder.
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  ukm::TestAutoSetUkmRecorder test_ukm_recorder;
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  FormData malformed_form = submitted_form_;
  malformed_form.fields.clear();
  EXPECT_FALSE(
      form_manager_->ProvisionallySave(malformed_form, &driver_, false));

  // Destroy the form manager to destroy the UKM recorder it owns. The recorder
  // only records metrics in its destructor.
  form_manager_.reset();

  auto entries = test_ukm_recorder.GetEntriesByName(
      ukm::builders::PasswordForm::kEntryName);
  ASSERT_EQ(1u, entries.size());

  EXPECT_FALSE(ParsingSuccessReported(
      entries[0], ukm::builders::PasswordForm::kReadonlyWhenSavingName));
}

TEST_F(NewPasswordFormManagerTest, PresaveGeneratedPasswordEmptyStore) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  ukm::TestAutoSetUkmRecorder test_ukm_recorder;
  fetcher_->NotifyFetchCompleted();

  EXPECT_FALSE(form_manager_->HasGeneratedPassword());

  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());

  form_manager_->SetGenerationPopupWasShown(
      true /* generation_popup_was_shown */, false /* is_manual_generation */);

  // Check that the generated password is presaved.
  PasswordForm saved_form;
  EXPECT_CALL(form_saver, Save(_, IsEmpty(), base::string16()))
      .WillOnce(SaveArg<0>(&saved_form));

  PasswordForm form_with_generated_password = parsed_submitted_form_;
  FormData& form_data = form_with_generated_password.form_data;
  form_manager_->PresaveGeneratedPassword(form_with_generated_password);

  EXPECT_TRUE(form_manager_->HasGeneratedPassword());
  EXPECT_EQ(saved_form.username_value,
            form_data.fields[kUsernameFieldIndex].value);
  EXPECT_EQ(saved_form.password_value,
            form_data.fields[kPasswordFieldIndex].value);

  Mock::VerifyAndClearExpectations(&form_saver);

  // Check that when the generated password is edited, then it's presaved.
  form_with_generated_password.password_value += ASCIIToUTF16("1");
  form_data.fields[kPasswordFieldIndex].value =
      form_with_generated_password.password_value;
  EXPECT_CALL(form_saver,
              UpdateReplace(_, IsEmpty(), ASCIIToUTF16(""),
                            FormHasUniqueKey(form_with_generated_password)))
      .WillOnce(SaveArg<0>(&saved_form));

  form_manager_->PresaveGeneratedPassword(form_with_generated_password);

  EXPECT_TRUE(form_manager_->HasGeneratedPassword());
  EXPECT_EQ(saved_form.username_value,
            form_data.fields[kUsernameFieldIndex].value);
  EXPECT_EQ(saved_form.password_value,
            form_with_generated_password.password_value);

  Mock::VerifyAndClearExpectations(&form_saver);

  // Check UKM metrics.
  form_manager_.reset();
  ExpectedGenerationUKM expected_metrics = {
      base::make_optional(1u) /* shown automatically */,
      1 /* password generated */,
      base::make_optional(1u) /* password modified */};

  CheckPasswordGenerationUKM(test_ukm_recorder, expected_metrics);
}

TEST_F(NewPasswordFormManagerTest, PresaveGenerated_ModifiedUsername) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  ukm::TestAutoSetUkmRecorder test_ukm_recorder;
  fetcher_->NotifyFetchCompleted();

  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());

  form_manager_->SetGenerationPopupWasShown(
      true /* generation_popup_was_shown */, false /* is_manual_generation */);

  // Check that the generated password is presaved.
  PasswordForm saved_form;
  EXPECT_CALL(form_saver, Save(_, _, _)).WillOnce(SaveArg<0>(&saved_form));
  PasswordForm form_with_generated_password = parsed_submitted_form_;
  FormData& form_data = form_with_generated_password.form_data;
  form_manager_->PresaveGeneratedPassword(form_with_generated_password);
  Mock::VerifyAndClearExpectations(&form_saver);

  // Check that when the username is edited, then it's presaved.
  form_with_generated_password.username_value += ASCIIToUTF16("1");
  form_data.fields[kUsernameFieldIndex].value =
      form_with_generated_password.username_value;

  EXPECT_CALL(form_saver, UpdateReplace(_, IsEmpty(), ASCIIToUTF16(""),
                                        FormHasUniqueKey(saved_form)))
      .WillOnce(SaveArg<0>(&saved_form));
  form_manager_->PresaveGeneratedPassword(form_with_generated_password);

  EXPECT_TRUE(form_manager_->HasGeneratedPassword());
  EXPECT_EQ(saved_form.username_value,
            form_with_generated_password.username_value);
  EXPECT_EQ(saved_form.password_value,
            form_with_generated_password.password_value);

  // Check UKM metrics.
  form_manager_.reset();
  ExpectedGenerationUKM expected_metrics = {
      base::make_optional(1u) /* shown automatically */,
      1 /* password generated */,
      base::make_optional(0u) /* password modified */};

  CheckPasswordGenerationUKM(test_ukm_recorder, expected_metrics);
}

TEST_F(NewPasswordFormManagerTest, GeneratedPasswordWhichIsNotInFormData) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  fetcher_->NotifyFetchCompleted();
  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());

  // Create a password form such that |form_data| do not contain the generated
  // password.
  PasswordForm form_with_generated_password;
  form_with_generated_password.form_data = submitted_form_;
  const base::string16 generated_password = ASCIIToUTF16("gen_pw");
  // |password_value| should contain the generated password.
  form_with_generated_password.password_value = generated_password;

  // Check that the generated password is presaved.
  PasswordForm saved_form;
  EXPECT_CALL(form_saver, Save(_, _, _)).WillOnce(SaveArg<0>(&saved_form));

  form_manager_->PresaveGeneratedPassword(form_with_generated_password);
  EXPECT_EQ(submitted_form_.fields[kUsernameFieldIndex].value,
            saved_form.username_value);
  EXPECT_EQ(generated_password, saved_form.password_value);
  EXPECT_TRUE(form_manager_->HasGeneratedPassword());

  // Check that the generated password is saved.
  EXPECT_CALL(form_saver, UpdateReplace(_, IsEmpty(), ASCIIToUTF16(""),
                                        FormHasUniqueKey(saved_form)))
      .WillOnce(SaveArg<0>(&saved_form));
  EXPECT_CALL(client_, UpdateFormManagers());

  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form_, &driver_, false));
  form_manager_->Save();

  EXPECT_EQ(submitted_form_.fields[kUsernameFieldIndex].value,
            saved_form.username_value);
  EXPECT_EQ(generated_password, saved_form.password_value);
}

TEST_F(NewPasswordFormManagerTest, PresaveGenerationWhenParsingFails) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  fetcher_->NotifyFetchCompleted();
  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());

  // Create a password form with empty |form_data|. On this form the form parser
  // should fail.
  PasswordForm form_with_empty_form_data;
  const base::string16 generated_password = ASCIIToUTF16("gen_pw");
  form_with_empty_form_data.password_value = generated_password;

  // Check that nevertheless the generated password is presaved.
  PasswordForm saved_form;
  EXPECT_CALL(form_saver, Save(_, IsEmpty(), base::string16()))
      .WillOnce(SaveArg<0>(&saved_form));
  form_manager_->PresaveGeneratedPassword(form_with_empty_form_data);
  EXPECT_EQ(generated_password, saved_form.password_value);
}

TEST_F(NewPasswordFormManagerTest, PasswordNoLongerGenerated) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  ukm::TestAutoSetUkmRecorder test_ukm_recorder;
  fetcher_->NotifyFetchCompleted();

  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
  form_manager_->SetGenerationPopupWasShown(
      true /* generation_popup_was_shown */, true /* is_manual_generation */);

  EXPECT_CALL(form_saver, Save(_, _, _));

  PasswordForm form = parsed_submitted_form_;
  form_manager_->PresaveGeneratedPassword(form);
  Mock::VerifyAndClearExpectations(&form_saver);

  EXPECT_TRUE(form_manager_->HasGeneratedPassword());

  // Check when the user removes the generated password on the page, it is
  // removed from the store.
  EXPECT_CALL(form_saver, Remove(_));
  form_manager_->PasswordNoLongerGenerated();

  EXPECT_FALSE(form_manager_->HasGeneratedPassword());

  // Check UKM metrics.
  form_manager_.reset();
  ExpectedGenerationUKM expected_metrics = {
      base::make_optional(2u) /* shown manually */,
      0 /* password generated */,
      {} /* generated password is not modified */};

  CheckPasswordGenerationUKM(test_ukm_recorder, expected_metrics);
}

TEST_F(NewPasswordFormManagerTest, PresaveGeneratedPasswordExistingCredential) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  ukm::TestAutoSetUkmRecorder test_ukm_recorder;
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());

  form_manager_->SetGenerationPopupWasShown(
      true /* generation_popup_was_shown */, false /* is_manual_generation */);

  // Check that the generated password is presaved.
  PasswordForm saved_form;
  EXPECT_CALL(form_saver, Save(_, _, _)).WillOnce(SaveArg<0>(&saved_form));

  PasswordForm form_with_generated_password = parsed_submitted_form_;
  FormData& form_data = form_with_generated_password.form_data;

  // Check that the generated password is saved with the empty username when
  // there is already a saved credetial with the same username.
  form_data.fields[kUsernameFieldIndex].value = saved_match_.username_value;
  form_manager_->PresaveGeneratedPassword(form_with_generated_password);

  EXPECT_TRUE(form_manager_->HasGeneratedPassword());
  EXPECT_TRUE(saved_form.username_value.empty());
  EXPECT_EQ(form_with_generated_password.password_value,
            saved_form.password_value);
}

TEST_F(NewPasswordFormManagerTest, UserEventsForGeneration) {
  using GeneratedPasswordStatus =
      PasswordFormMetricsRecorder::GeneratedPasswordStatus;

  PasswordForm submitted_form(parsed_observed_form_);
  submitted_form.form_data = submitted_form_;
  FormData& form_data = submitted_form.form_data;

  {  // User accepts a generated password.
    base::HistogramTester histogram_tester;
    CreateFormManager(observed_form_);
    form_manager_->PresaveGeneratedPassword(submitted_form);
    form_manager_.reset();
    histogram_tester.ExpectUniqueSample(
        "PasswordGeneration.UserDecision",
        GeneratedPasswordStatus::kPasswordAccepted, 1);
  }

  {  // User edits the generated password.
    base::HistogramTester histogram_tester;
    CreateFormManager(observed_form_);
    form_manager_->PresaveGeneratedPassword(submitted_form);
    form_data.fields[kPasswordFieldIndex].value += ASCIIToUTF16("1");
    submitted_form.password_value = form_data.fields[kPasswordFieldIndex].value;
    form_manager_->PresaveGeneratedPassword(submitted_form);
    form_manager_.reset();
    histogram_tester.ExpectUniqueSample(
        "PasswordGeneration.UserDecision",
        GeneratedPasswordStatus::kPasswordEdited, 1);
  }

  {  // User clears the generated password.
    base::HistogramTester histogram_tester;
    CreateFormManager(observed_form_);
    form_manager_->PresaveGeneratedPassword(submitted_form);
    form_data.fields[kPasswordFieldIndex].value += ASCIIToUTF16("2");
    submitted_form.password_value = form_data.fields[kPasswordFieldIndex].value;
    form_manager_->PresaveGeneratedPassword(submitted_form);
    form_manager_->PasswordNoLongerGenerated();
    form_manager_.reset();
    histogram_tester.ExpectUniqueSample(
        "PasswordGeneration.UserDecision",
        GeneratedPasswordStatus::kPasswordDeleted, 1);
  }
}

TEST_F(NewPasswordFormManagerTest, FillForm) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());

  for (bool observed_form_changed : {false, true}) {
    SCOPED_TRACE(testing::Message("observed_form_changed=")
                 << observed_form_changed);
    CreateFormManager(observed_form_);
    EXPECT_CALL(driver_, FillPasswordForm(_));
    SetNonFederatedAndNotifyFetchCompleted({&saved_match_});
    task_runner_->FastForwardUntilNoTasksRemain();
    Mock::VerifyAndClearExpectations(&driver_);

    FormData form = observed_form_;

    if (observed_form_changed) {
      form.fields[kUsernameFieldIndex].unique_renderer_id += 1000;
      form.fields[kUsernameFieldIndex].name += ASCIIToUTF16("1");
      form.fields[kUsernameFieldIndex].id_attribute += ASCIIToUTF16("1");
#if defined(OS_IOS)
      form.fields[kUsernameFieldIndex].unique_id += ASCIIToUTF16("1");
#endif
      form.fields[kPasswordFieldIndex].unique_renderer_id += 1000;
    }

    PasswordFormFillData fill_data;
    EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
    form_manager_->FillForm(form);

    EXPECT_EQ(form.fields[kUsernameFieldIndex].name,
              fill_data.username_field.name);
    EXPECT_EQ(form.fields[kUsernameFieldIndex].unique_renderer_id,
              fill_data.username_field.unique_renderer_id);
    EXPECT_EQ(saved_match_.username_value, fill_data.username_field.value);
    EXPECT_EQ(form.fields[kPasswordFieldIndex].name,
              fill_data.password_field.name);
    EXPECT_EQ(form.fields[kPasswordFieldIndex].unique_renderer_id,
              fill_data.password_field.unique_renderer_id);
    EXPECT_EQ(saved_match_.password_value, fill_data.password_field.value);

    base::HistogramTester histogram_tester;
    form_manager_.reset();
    uint32_t expected_differences_mask = 0;
    if (observed_form_changed)
      expected_differences_mask = 2;  // renderer_id changes.
    histogram_tester.ExpectUniqueSample("PasswordManager.DynamicFormChanges",
                                        expected_differences_mask, 1);
  }
}

TEST_F(NewPasswordFormManagerTest, FillFormWaitForServerPredictions) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  FormData changed_form = observed_form_;

  changed_form.fields[kUsernameFieldIndex].unique_renderer_id += 1000;
  changed_form.fields[kPasswordFieldIndex].unique_renderer_id += 1000;

  // Check that no filling until server predicions or filling timeout
  // expiration.
  EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
  form_manager_->FillForm(changed_form);
  Mock::VerifyAndClearExpectations(&driver_);

  // Check that the changed form is filled after the filling timeout expires.

  PasswordFormFillData fill_data;
  EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));

  task_runner_->FastForwardUntilNoTasksRemain();
  EXPECT_EQ(changed_form.fields[kUsernameFieldIndex].unique_renderer_id,
            fill_data.username_field.unique_renderer_id);
  EXPECT_EQ(changed_form.fields[kPasswordFieldIndex].unique_renderer_id,
            fill_data.password_field.unique_renderer_id);

  base::HistogramTester histogram_tester;
  form_manager_.reset();
  uint32_t expected_differences_mask = 2;  // renderer_id changes.
  histogram_tester.ExpectUniqueSample("PasswordManager.DynamicFormChanges",
                                      expected_differences_mask, 1);
}

TEST_F(NewPasswordFormManagerTest, Update) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());

  PasswordForm not_best_saved_match = saved_match_;
  not_best_saved_match.preferred = false;
  PasswordForm saved_match_another_username = saved_match_;
  saved_match_another_username.username_value += ASCIIToUTF16("1");
  SetNonFederatedAndNotifyFetchCompleted(
      {&saved_match_, &saved_match_another_username});

  FormData submitted_form = observed_form_;
  base::string16 username = saved_match_.username_value;
  base::string16 new_password = saved_match_.password_value + ASCIIToUTF16("1");
  submitted_form.fields[kUsernameFieldIndex].value = username;
  submitted_form.fields[kPasswordFieldIndex].value = new_password;

  EXPECT_TRUE(
      form_manager_->ProvisionallySave(submitted_form, &driver_, false));

  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
  PasswordForm updated_form;
  EXPECT_CALL(form_saver, Update(_,
                                 UnorderedElementsAre(
                                     Pointee(saved_match_),
                                     Pointee(saved_match_another_username)),
                                 saved_match_.password_value))
      .WillOnce(SaveArg<0>(&updated_form));
  EXPECT_CALL(client_, UpdateFormManagers());

  form_manager_->Update(saved_match_);

  EXPECT_TRUE(ArePasswordFormUniqueKeysEqual(saved_match_, updated_form));
  EXPECT_TRUE(updated_form.preferred);
  EXPECT_EQ(new_password, updated_form.password_value);
}

// TODO(https://crbug.com/918846): implement FillingAssistance metric on iOS.
#if defined(OS_IOS)
#define MAYBE_FillingAssistanceMetric DISABLED_FillingAssistanceMetric
#else
#define MAYBE_FillingAssistanceMetric FillingAssistanceMetric
#endif
TEST_F(NewPasswordFormManagerTest, MAYBE_FillingAssistanceMetric) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  SetNonFederatedAndNotifyFetchCompleted({&saved_match_});

  // Simulate that the user fills the saved credentials manually.
  submitted_form_.fields[kUsernameFieldIndex].value =
      saved_match_.username_value;
  submitted_form_.fields[kUsernameFieldIndex].properties_mask =
      FieldPropertiesFlags::AUTOFILLED_ON_USER_TRIGGER;
  submitted_form_.fields[kPasswordFieldIndex].value =
      saved_match_.password_value;
  submitted_form_.fields[kPasswordFieldIndex].properties_mask =
      FieldPropertiesFlags::AUTOFILLED_ON_USER_TRIGGER;

  base::HistogramTester histogram_tester;
  //  Simulate successful submission.
  form_manager_->ProvisionallySave(submitted_form_, &driver_, false);
  form_manager_->GetMetricsRecorder()->LogSubmitPassed();

  form_manager_.reset();
  histogram_tester.ExpectUniqueSample(
      "PasswordManager.FillingAssistance",
      PasswordFormMetricsRecorder::FillingAssistance::kManual, 1);
}

TEST_F(NewPasswordFormManagerTest, PasswordRevealedVote) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());

  for (bool password_revealed : {false, true}) {
    SCOPED_TRACE(testing::Message("password_revealed=") << password_revealed);
    CreateFormManager(observed_form_);
    fetcher_->NotifyFetchCompleted();

    EXPECT_TRUE(
        form_manager_->ProvisionallySave(submitted_form_, &driver_, false));

    if (password_revealed)
      form_manager_->OnPasswordsRevealed();

    EXPECT_CALL(mock_autofill_download_manager_,
                StartUploadRequest(PasswordsWereRevealed(password_revealed),
                                   false, _, _, true, nullptr));
    form_manager_->Save();
    Mock::VerifyAndClearExpectations(&mock_autofill_download_manager_);
  }
}

TEST_F(NewPasswordFormManagerTest, GenerationUploadOnNoInteraction) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());

  for (bool generation_popup_shown : {false, true}) {
    SCOPED_TRACE(testing::Message("generation_popup_shown=")
                 << generation_popup_shown);
    CreateFormManager(observed_form_);
    fetcher_->NotifyFetchCompleted();

    if (generation_popup_shown) {
      form_manager_->SetGenerationElement(ASCIIToUTF16("password"));
      form_manager_->SetGenerationPopupWasShown(
          true /*generation_popup_was_shown*/, false /*is_manual_generation*/);
    }
    EXPECT_TRUE(
        form_manager_->ProvisionallySave(submitted_form_, &driver_, false));

    EXPECT_CALL(
        mock_autofill_download_manager_,
        StartUploadRequest(HasGenerationVote(true), false, _, _, true, nullptr))
        .Times(generation_popup_shown ? 1 : 0);
    form_manager_->OnNoInteraction(false /*is_update */);
    Mock::VerifyAndClearExpectations(&mock_autofill_download_manager_);
  }
}

TEST_F(NewPasswordFormManagerTest, GenerationUploadOnNeverClicked) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());

  for (bool generation_popup_shown : {false, true}) {
    SCOPED_TRACE(testing::Message("generation_popup_shown=")
                 << generation_popup_shown);
    CreateFormManager(observed_form_);
    fetcher_->NotifyFetchCompleted();

    if (generation_popup_shown) {
      form_manager_->SetGenerationElement(ASCIIToUTF16("password"));
      form_manager_->SetGenerationPopupWasShown(
          true /*generation_popup_was_shown*/, false /*is_manual_generation*/);
    }
    EXPECT_TRUE(
        form_manager_->ProvisionallySave(submitted_form_, &driver_, false));

    EXPECT_CALL(
        mock_autofill_download_manager_,
        StartUploadRequest(HasGenerationVote(true), false, _, _, true, nullptr))
        .Times(generation_popup_shown ? 1 : 0);
    form_manager_->OnNeverClicked();
    Mock::VerifyAndClearExpectations(&mock_autofill_download_manager_);
  }
}

TEST_F(NewPasswordFormManagerTest, SaveHttpAuthNoHttpAuthStored) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());

  for (bool html_credentials_saved : {false, true}) {
    SCOPED_TRACE(testing::Message("html_credentials_saved=")
                 << html_credentials_saved);
    PasswordForm http_auth_form = parsed_observed_form_;
    http_auth_form.scheme = PasswordForm::Scheme::kBasic;

    // Check that no filling because no http auth credentials are stored.
    EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
    EXPECT_CALL(client_, AutofillHttpAuth(_, _)).Times(0);

    CreateFormManagerForNonWebForm(http_auth_form);
    MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());

    std::vector<const PasswordForm*> saved_matches;
    if (html_credentials_saved)
      saved_matches.push_back(&saved_match_);
    SetNonFederatedAndNotifyFetchCompleted(saved_matches);

    base::string16 username = ASCIIToUTF16("user1");
    base::string16 password = ASCIIToUTF16("pass1");
    http_auth_form.username_value = username;
    http_auth_form.password_value = password;

    // Check that submitted credentials are saved.
    ASSERT_TRUE(form_manager_->ProvisionallySaveHttpAuthForm(http_auth_form));
    EXPECT_TRUE(form_manager_->IsNewLogin());

    PasswordForm saved_form;
    EXPECT_CALL(form_saver, Save(_, _, _)).WillOnce(SaveArg<0>(&saved_form));
    form_manager_->Save();

    EXPECT_EQ(http_auth_form.signon_realm, saved_form.signon_realm);
    EXPECT_EQ(username, saved_form.username_value);
    EXPECT_EQ(password, saved_form.password_value);
  }
}

TEST_F(NewPasswordFormManagerTest, HTTPAuthAlreadySaved) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  PasswordForm http_auth_form = parsed_observed_form_;
  http_auth_form.scheme = PasswordForm::Scheme::kBasic;

  CreateFormManagerForNonWebForm(http_auth_form);

  const base::string16 username = ASCIIToUTF16("user1");
  const base::string16 password = ASCIIToUTF16("pass1");
  http_auth_form.username_value = username;
  http_auth_form.password_value = password;
  EXPECT_CALL(client_, AutofillHttpAuth(http_auth_form, _)).Times(1);
  SetNonFederatedAndNotifyFetchCompleted({&http_auth_form});

  // Check that if known credentials are submitted, then |form_manager_| is not
  // in state new login nor password overridden.
  ASSERT_TRUE(form_manager_->ProvisionallySaveHttpAuthForm(http_auth_form));
  EXPECT_FALSE(form_manager_->IsNewLogin());
  EXPECT_FALSE(form_manager_->IsPasswordUpdate());
}

TEST_F(NewPasswordFormManagerTest, HTTPAuthPasswordOverridden) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  PasswordForm http_auth_form = parsed_observed_form_;
  http_auth_form.scheme = PasswordForm::Scheme::kBasic;

  CreateFormManagerForNonWebForm(http_auth_form);
  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());

  PasswordForm saved_http_auth_form = http_auth_form;
  const base::string16 username = ASCIIToUTF16("user1");
  const base::string16 password = ASCIIToUTF16("pass1");
  saved_http_auth_form.username_value = username;
  saved_http_auth_form.password_value = password;
  EXPECT_CALL(client_, AutofillHttpAuth(saved_http_auth_form, _)).Times(1);
  SetNonFederatedAndNotifyFetchCompleted({&saved_http_auth_form});

  // Check that if new password is submitted, then |form_manager_| is in state
  // password overridden.
  PasswordForm submitted_http_auth_form = saved_http_auth_form;
  base::string16 new_password = password + ASCIIToUTF16("1");
  submitted_http_auth_form.password_value = new_password;
  ASSERT_TRUE(
      form_manager_->ProvisionallySaveHttpAuthForm(submitted_http_auth_form));
  EXPECT_FALSE(form_manager_->IsNewLogin());
  EXPECT_TRUE(form_manager_->IsPasswordUpdate());

  // Check that the password is updated in the stored credential.
  PasswordForm updated_form;
  EXPECT_CALL(form_saver,
              Update(_, ElementsAre(Pointee(saved_http_auth_form)), password))
      .WillOnce(SaveArg<0>(&updated_form));

  form_manager_->Save();

  EXPECT_TRUE(
      ArePasswordFormUniqueKeysEqual(saved_http_auth_form, updated_form));
  EXPECT_EQ(new_password, updated_form.password_value);
}

TEST_F(NewPasswordFormManagerTest, BlacklistHttpAuthCredentials) {
  PasswordForm http_auth_form = parsed_observed_form_;
  http_auth_form.signon_realm += "my-auth-realm";
  http_auth_form.scheme = PasswordForm::Scheme::kBasic;

  CreateFormManagerForNonWebForm(http_auth_form);
  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());

  // Simulate that the user submits http auth credentials.
  http_auth_form.username_value = ASCIIToUTF16("user1");
  http_auth_form.password_value = ASCIIToUTF16("pass1");
  ASSERT_TRUE(form_manager_->ProvisionallySaveHttpAuthForm(http_auth_form));

  // Simulate that the user clicks never.
  PasswordForm blacklisted_form;
  EXPECT_CALL(form_saver,
              PermanentlyBlacklist(PasswordStore::FormDigest(http_auth_form)));
  form_manager_->OnNeverClicked();
}

#if defined(OS_IOS)
TEST_F(NewPasswordFormManagerTest, iOSPresavedGeneratedPassword) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  fetcher_->NotifyFetchCompleted();
  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());

  FormData form_to_presave = observed_form_;
  const base::string16 typed_username = ASCIIToUTF16("user1");
  FormFieldData& username_field = form_to_presave.fields[kUsernameFieldIndex];
  FormFieldData& password_field = form_to_presave.fields[kPasswordFieldIndex];
  username_field.value = typed_username;
  password_field.value = ASCIIToUTF16("not_password");
  // Use |generated_password| different from value in field to test that the
  // generated password is saved.
  const base::string16 generated_password = ASCIIToUTF16("gen_pw");
  // Use different |unique_id| and |name| to test that |unique_id| is taken.
  password_field.unique_id = password_field.name + ASCIIToUTF16("1");
  const base::string16 generation_element = password_field.unique_id;

  PasswordForm saved_form;
  EXPECT_CALL(form_saver, Save(_, IsEmpty(), base::string16()))
      .WillOnce(SaveArg<0>(&saved_form));
  form_manager_->PresaveGeneratedPassword(
      &driver_, form_to_presave, generated_password, generation_element);
  EXPECT_EQ(generated_password, saved_form.password_value);

  Mock::VerifyAndClearExpectations(&form_saver);

  const base::string16 changed_password =
      generated_password + ASCIIToUTF16("1");
  EXPECT_CALL(form_saver, UpdateReplace(_, _, base::string16(), _))
      .WillOnce(SaveArg<0>(&saved_form));

  form_manager_->UpdateGeneratedPasswordOnUserInput(
      form_to_presave.name, generation_element, changed_password);
  EXPECT_EQ(username_field.value, saved_form.username_value);
  EXPECT_EQ(changed_password, saved_form.password_value);
}

TEST_F(NewPasswordFormManagerTest, UpdateGeneratedPasswordBeforePresaving) {
  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
  fetcher_->NotifyFetchCompleted();
  MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());

  FormData form_to_presave = observed_form_;
  const base::string16 generation_element =
      form_to_presave.fields[kPasswordFieldIndex].unique_id;
  const base::string16 generation_field_value = ASCIIToUTF16("some_password");

  // Check that nothing is saved on changing password, in case when there was no
  // pre-saving.
  EXPECT_CALL(form_saver, Save(_, _, _)).Times(0);
  form_manager_->UpdateGeneratedPasswordOnUserInput(
      form_to_presave.name, generation_element, generation_field_value);
}

#endif  // defined(OS_IOS)

}  // namespace

}  // namespace password_manager
