chromium/chrome/browser/password_manager/android/password_generation_controller_impl_unittest.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/password_manager/android/password_generation_controller_impl.h"

#include <map>
#include <memory>
#include <utility>

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/keyboard_accessory/android/accessory_sheet_enums.h"
#include "chrome/browser/keyboard_accessory/test_utils/android/mock_manual_filling_controller.h"
#include "chrome/browser/password_manager/chrome_password_manager_client.h"
#include "chrome/browser/touch_to_fill/password_manager/password_generation/android/fake_touch_to_fill_password_generation_bridge.h"
#include "chrome/browser/touch_to_fill/password_manager/password_generation/android/mock_touch_to_fill_password_generation_bridge.h"
#include "chrome/browser/touch_to_fill/password_manager/password_generation/android/touch_to_fill_password_generation_controller.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/autofill/core/common/password_generation_util.h"
#include "components/password_manager/content/browser/content_password_manager_driver.h"
#include "components/password_manager/core/browser/password_autofill_manager.h"
#include "components/password_manager/core/browser/password_generation_frame_helper.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_store/mock_password_store_interface.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/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "content/public/browser/web_contents.h"
#include "testing/gmock/include/gmock/gmock.h"

using autofill::password_generation::PasswordGenerationType;
using password_manager::metrics_util::GenerationDialogChoice;

namespace {
using autofill::FooterCommand;
using autofill::mojom::FocusedFieldType;
using autofill::password_generation::PasswordGenerationUIData;
using base::ASCIIToUTF16;
using password_manager::ContentPasswordManagerDriver;
using password_manager::MockPasswordStoreInterface;
using password_manager::PasswordForm;
using testing::_;
using testing::AtMost;
using testing::ByMove;
using testing::Eq;
using testing::Mock;
using testing::NiceMock;
using testing::Return;
using testing::StrictMock;
using ShouldShowAction = ManualFillingController::ShouldShowAction;
using TouchToFillOutcome =
    password_manager::metrics_util::TouchToFillPasswordGenerationTriggerOutcome;

const char kTouchToFillTriggerOutcomeHistogramName[] =
    "PasswordManager.TouchToFill.PasswordGeneration.TriggerOutcome";

class TestPasswordManagerClient
    : public password_manager::StubPasswordManagerClient {
 public:
  TestPasswordManagerClient();
  ~TestPasswordManagerClient() override;

  password_manager::PasswordStoreInterface* GetProfilePasswordStore()
      const override;

  MOCK_METHOD((const password_manager::PasswordManager*),
              GetPasswordManager,
              (),
              (const, override));
  MOCK_METHOD(PrefService*, GetPrefs, (), (const override));

 private:
  scoped_refptr<MockPasswordStoreInterface> mock_password_store_;
};

TestPasswordManagerClient::TestPasswordManagerClient() {
  mock_password_store_ = new MockPasswordStoreInterface();
}

TestPasswordManagerClient::~TestPasswordManagerClient() = default;

password_manager::PasswordStoreInterface*
TestPasswordManagerClient::GetProfilePasswordStore() const {
  return mock_password_store_.get();
}

PasswordGenerationUIData GetTestGenerationUIData1() {
  PasswordGenerationUIData data;

  data.form_data.set_action(GURL("http://www.example1.com/accounts/Login"));
  data.form_data.set_url(GURL("http://www.example1.com/accounts/LoginAuth"));

  data.generation_element = u"testelement1";
  data.max_length = 10;

  return data;
}

PasswordGenerationUIData GetTestGenerationUIData2() {
  PasswordGenerationUIData data;

  data.form_data.set_action(GURL("http://www.example2.com/accounts/Login"));
  data.form_data.set_url(GURL("http://www.example2.com/accounts/LoginAuth"));

  data.generation_element = u"testelement2";
  data.max_length = 10;

  return data;
}

MATCHER_P(PointsToSameAddress, expected, "") {
  return arg.get() == expected;
}

}  // namespace

class PasswordGenerationControllerTest
    : public ChromeRenderViewHostTestHarness {
 public:
  using CreateTouchToFillGenerationControllerFactory = base::RepeatingCallback<
      std::unique_ptr<TouchToFillPasswordGenerationController>()>;

  void SetUp() override {
    ChromeRenderViewHostTestHarness::SetUp();

    test_pwd_manager_client_ = std::make_unique<TestPasswordManagerClient>();
    password_manager_ = std::make_unique<password_manager::PasswordManager>(
        test_pwd_manager_client_.get());
    ON_CALL(*test_pwd_manager_client_, GetPasswordManager())
        .WillByDefault(Return(password_manager_.get()));
    ON_CALL(*test_pwd_manager_client_, GetPrefs())
        .WillByDefault(Return(pref_service()));

    pref_service_.registry()->RegisterIntegerPref(
        password_manager::prefs::kPasswordGenerationBottomSheetDismissCount, 0);

    password_manager_driver_ = std::make_unique<ContentPasswordManagerDriver>(
        main_rfh(), test_pwd_manager_client_.get());
    another_password_manager_driver_ =
        std::make_unique<ContentPasswordManagerDriver>(
            main_rfh(), test_pwd_manager_client_.get());

    // TODO(crbug.com/41462048): Remove once kAutofillKeyboardAccessory is
    // enabled.
    password_autofill_manager_ =
        std::make_unique<password_manager::PasswordAutofillManager>(
            password_manager_driver_.get(), &test_autofill_client_,
            test_pwd_manager_client_.get());

    ON_CALL(create_ttf_generation_controller_, Run).WillByDefault([this]() {
      return controller()->CreateTouchToFillGenerationControllerForTesting(
          std::make_unique<MockTouchToFillPasswordGenerationBridge>(),
          mock_manual_filling_controller_.AsWeakPtr());
    });

    PasswordGenerationControllerImpl::CreateForWebContentsForTesting(
        web_contents(), test_pwd_manager_client_.get(),
        mock_manual_filling_controller_.AsWeakPtr(),
        create_ttf_generation_controller_.Get());
    EXPECT_CALL(mock_manual_filling_controller_,
                OnAccessoryActionAvailabilityChanged(
                    ShouldShowAction(false),
                    autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));
    controller()->FocusedInputChanged(FocusedFieldType::kFillablePasswordField,
                                      active_driver());
  }

  PasswordGenerationController* controller() {
    return PasswordGenerationControllerImpl::FromWebContents(web_contents());
  }

  base::WeakPtr<password_manager::ContentPasswordManagerDriver>
  active_driver() {
    return password_manager_driver_->AsWeakPtrImpl();
  }

  base::WeakPtr<password_manager::ContentPasswordManagerDriver>
  non_active_driver() {
    return another_password_manager_driver_->AsWeakPtrImpl();
  }

  TestingPrefServiceSimple* pref_service() { return &pref_service_; }

 protected:
  StrictMock<MockManualFillingController> mock_manual_filling_controller_;

  std::unique_ptr<ContentPasswordManagerDriver> password_manager_driver_;
  std::unique_ptr<ContentPasswordManagerDriver>
      another_password_manager_driver_;
  base::MockCallback<CreateTouchToFillGenerationControllerFactory>
      create_ttf_generation_controller_;
  base::test::ScopedFeatureList feature_list_;

 private:
  std::unique_ptr<password_manager::PasswordManager> password_manager_;
  std::unique_ptr<password_manager::PasswordAutofillManager>
      password_autofill_manager_;
  std::unique_ptr<TestPasswordManagerClient> test_pwd_manager_client_;
  autofill::TestAutofillClient test_autofill_client_;
  TestingPrefServiceSimple pref_service_;
};

TEST_F(PasswordGenerationControllerTest, IsNotRecreatedForSameWebContents) {
  PasswordGenerationController* initial_controller =
      PasswordGenerationControllerImpl::FromWebContents(web_contents());
  EXPECT_NE(nullptr, initial_controller);
  PasswordGenerationControllerImpl::CreateForWebContents(web_contents());
  EXPECT_EQ(PasswordGenerationControllerImpl::FromWebContents(web_contents()),
            initial_controller);
}

TEST_F(PasswordGenerationControllerTest, RelaysAutomaticGenerationAvailable) {
  // TODO (crbug.com/1421753): Test this is for the
  // PasswordGenerationBottomSheet flag disabled. Add one more test for the case
  // after the bottom sheet is dismissed.
  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(true),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));
  controller()->OnAutomaticGenerationAvailable(
      active_driver(), GetTestGenerationUIData1(),
      /*has_saved_credentials=*/true, gfx::RectF(100, 20));
}

// Tests that if AutomaticGenerationAvailable is called for different
// password forms, the form and field signatures used for password generation
// are updated.
TEST_F(PasswordGenerationControllerTest,
       UpdatesSignaturesForDifferentGenerationForms) {
  // Called twice for different forms.
  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(true),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC))
      .Times(2);
  controller()->OnAutomaticGenerationAvailable(
      active_driver(), GetTestGenerationUIData1(),
      /*has_saved_credentials=*/true, gfx::RectF(100, 20));
  PasswordGenerationUIData new_ui_data = GetTestGenerationUIData2();
  controller()->OnAutomaticGenerationAvailable(active_driver(), new_ui_data,
                                               /*has_saved_credentials=*/true,
                                               gfx::RectF(100, 20));

  autofill::FormSignature form_signature =
      autofill::CalculateFormSignature(new_ui_data.form_data);
  autofill::FieldSignature field_signature =
      autofill::CalculateFieldSignatureByNameAndType(
          new_ui_data.generation_element,
          autofill::FormControlType::kInputPassword);
  EXPECT_EQ(controller()->get_form_signature_for_testing(), form_signature);
  EXPECT_EQ(controller()->get_field_signature_for_testing(), field_signature);

  EXPECT_CALL(create_ttf_generation_controller_, Run);
  controller()->OnGenerationRequested(PasswordGenerationType::kAutomatic);
}

TEST_F(PasswordGenerationControllerTest,
       RecordsGeneratedPasswordAcceptedAutomatic) {
  base::HistogramTester histogram_tester;

  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(true),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));
  controller()->OnAutomaticGenerationAvailable(
      active_driver(), GetTestGenerationUIData1(),
      /*has_saved_credentials=*/true, gfx::RectF(100, 20));

  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(false),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));
  controller()->GeneratedPasswordAccepted(u"t3stp@ssw0rd", active_driver(),
                                          PasswordGenerationType::kAutomatic);

  histogram_tester.ExpectUniqueSample(
      "KeyboardAccessory.GenerationDialogChoice.Automatic",
      GenerationDialogChoice::kAccepted, 1);
}

TEST_F(PasswordGenerationControllerTest,
       RecordsGeneratedPasswordRejectedAutomatic) {
  base::HistogramTester histogram_tester;

  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(false),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));
  controller()->GeneratedPasswordRejected(PasswordGenerationType::kAutomatic);

  histogram_tester.ExpectUniqueSample(
      "KeyboardAccessory.GenerationDialogChoice.Automatic",
      GenerationDialogChoice::kRejected, 1);
}

TEST_F(PasswordGenerationControllerTest,
       RecordsGeneratedPasswordAcceptedManual) {
  base::HistogramTester histogram_tester;

  controller()->OnGenerationRequested(PasswordGenerationType::kManual);

  EXPECT_CALL(create_ttf_generation_controller_, Run);
  controller()->ShowManualGenerationDialog(password_manager_driver_.get(),
                                           GetTestGenerationUIData1());

  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(false),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));
  controller()->GeneratedPasswordAccepted(u"t3stp@ssw0rd", active_driver(),
                                          PasswordGenerationType::kManual);

  histogram_tester.ExpectUniqueSample(
      "KeyboardAccessory.GenerationDialogChoice.Manual",
      GenerationDialogChoice::kAccepted, 1);
}

TEST_F(PasswordGenerationControllerTest,
       RecordsGeneratedPasswordRejectedManual) {
  base::HistogramTester histogram_tester;

  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(false),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));
  controller()->GeneratedPasswordRejected(PasswordGenerationType::kManual);

  histogram_tester.ExpectUniqueSample(
      "KeyboardAccessory.GenerationDialogChoice.Manual",
      GenerationDialogChoice::kRejected, 1);
}

TEST_F(PasswordGenerationControllerTest,
       SetActiveFrameOnAutomaticGenerationAvailable) {
  // TODO(crbug.com/40259397): Refactor PasswordGenerationController so that
  // OnAccessoryActionAvailabilityChanged would be called only once. Right now
  // it's called twice: the first call resets the manual filling controller
  // status and the second one sets it according to the focused input.
  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  _, autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC))
      .Times(AtMost(2));

  controller()->OnAutomaticGenerationAvailable(
      non_active_driver(), GetTestGenerationUIData2(),
      /*has_saved_credentials=*/false, gfx::RectF(100, 20));
}

TEST_F(PasswordGenerationControllerTest,
       ResetStateWhenFocusChangesToNonPassword) {
  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(false),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));

  controller()->FocusedInputChanged(FocusedFieldType::kFillableUsernameField,
                                    active_driver());
  EXPECT_FALSE(controller()->GetActiveFrameDriver());
}

TEST_F(PasswordGenerationControllerTest,
       ResetStateWhenFocusChangesToOtherFramePassword) {
  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(false),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));

  controller()->FocusedInputChanged(FocusedFieldType::kFillablePasswordField,
                                    non_active_driver());
  EXPECT_EQ(another_password_manager_driver_.get(),
            controller()->GetActiveFrameDriver().get());
}

TEST_F(PasswordGenerationControllerTest,
       RejectShowManualDialogForNonActiveFrame) {
  EXPECT_CALL(create_ttf_generation_controller_, Run).Times(0);
  controller()->ShowManualGenerationDialog(
      another_password_manager_driver_.get(), GetTestGenerationUIData1());
}

TEST_F(PasswordGenerationControllerTest, DontShowManualDialogIfFocusChanged) {
  controller()->OnGenerationRequested(PasswordGenerationType::kManual);

  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(false),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));
  controller()->FocusedInputChanged(FocusedFieldType::kFillablePasswordField,
                                    non_active_driver());
  EXPECT_CALL(create_ttf_generation_controller_, Run).Times(0);
  controller()->ShowManualGenerationDialog(password_manager_driver_.get(),
                                           GetTestGenerationUIData1());
}

TEST_F(PasswordGenerationControllerTest,
       DoesNotCallKeyboardAccessoryWhenGenerationBottomSheetRequired) {
  base::HistogramTester histogram_tester;

  auto ttf_password_generation_bridge =
      std::make_unique<MockTouchToFillPasswordGenerationBridge>();
  MockTouchToFillPasswordGenerationBridge* ttf_password_generation_bridge_ptr =
      ttf_password_generation_bridge.get();
  EXPECT_CALL(create_ttf_generation_controller_, Run)
      .WillOnce([this, &ttf_password_generation_bridge]() {
        return controller()->CreateTouchToFillGenerationControllerForTesting(
            std::move(ttf_password_generation_bridge),
            mock_manual_filling_controller_.AsWeakPtr());
      });

  // Keyboard accessory shouldn't show up.
  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(true),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC))
      .Times(0);
  EXPECT_CALL(*ttf_password_generation_bridge_ptr, Show);
  controller()->OnAutomaticGenerationAvailable(
      active_driver(), GetTestGenerationUIData1(),
      /*has_saved_credentials=*/false, gfx::RectF(100, 20));
  histogram_tester.ExpectUniqueSample(kTouchToFillTriggerOutcomeHistogramName,
                                      TouchToFillOutcome::kShown, 1);
  // Removes the keyboard suppression callback from the render widget host. It
  // needs to be done before the `PasswordGenerationController` destructor is
  // called.
  controller()->HideBottomSheetIfNeeded();
}

TEST_F(PasswordGenerationControllerTest,
       DoesNotCallKeyboardAccessoryWhenBottomSheetIsDisplayed) {
  controller()->OnAutomaticGenerationAvailable(
      active_driver(), GetTestGenerationUIData1(),
      /*has_saved_credentials=*/false, gfx::RectF(100, 20));

  // Keyboard accessory shouldn't be called.
  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  _, autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC))
      .Times(0);
  EXPECT_CALL(create_ttf_generation_controller_, Run).Times(0);
  controller()->OnAutomaticGenerationAvailable(
      active_driver(), GetTestGenerationUIData1(),
      /*has_saved_credentials=*/false, gfx::RectF(100, 20));
  // Removes the keyboard suppression callback from the render widget host. It
  // needs to be done before the `PasswordGenerationController` destructor is
  // called.
  controller()->HideBottomSheetIfNeeded();
}

TEST_F(PasswordGenerationControllerTest,
       CallsKeyboardAccessoryWhenGenerationBottomSheetFailedToShow) {
  base::HistogramTester histogram_tester;

  auto ttf_password_generation_bridge =
      std::make_unique<MockTouchToFillPasswordGenerationBridge>();
  EXPECT_CALL(*ttf_password_generation_bridge, Show).WillOnce(Return(false));
  EXPECT_CALL(create_ttf_generation_controller_, Run)
      .WillOnce([this, &ttf_password_generation_bridge]() {
        return controller()->CreateTouchToFillGenerationControllerForTesting(
            std::move(ttf_password_generation_bridge),
            mock_manual_filling_controller_.AsWeakPtr());
      });

  // Keyboard accessory should show up.
  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(true),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));
  controller()->OnAutomaticGenerationAvailable(
      active_driver(), GetTestGenerationUIData1(),
      /*has_saved_credentials=*/false, gfx::RectF(100, 20));
  histogram_tester.ExpectUniqueSample(kTouchToFillTriggerOutcomeHistogramName,
                                      TouchToFillOutcome::kFailedToDisplay, 1);
}

TEST_F(PasswordGenerationControllerTest,
       DoesNotShowGenerationBottomSheetIfSavedPasswordsAvailable) {
  base::HistogramTester histogram_tester;

  // Password generation bottom sheet must not show up. Keyboard accessory
  // should show up instead.
  EXPECT_CALL(create_ttf_generation_controller_, Run).Times(0);
  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(true),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));
  controller()->OnAutomaticGenerationAvailable(
      active_driver(), GetTestGenerationUIData1(),
      /*has_saved_credentials=*/true, gfx::RectF(100, 20));
  histogram_tester.ExpectUniqueSample(kTouchToFillTriggerOutcomeHistogramName,
                                      TouchToFillOutcome::kHasSavedCredentials,
                                      1);
}

TEST_F(PasswordGenerationControllerTest,
       DoesNotShowGenerationBottomSheetIfDismissCountAtLeast4) {
  base::HistogramTester histogram_tester;

  pref_service()->SetInteger(
      password_manager::prefs::kPasswordGenerationBottomSheetDismissCount, 4);

  // Password generation bottom sheet must not show up. Keyboard accessory
  // should show up instead.
  EXPECT_CALL(create_ttf_generation_controller_, Run).Times(0);
  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  ShouldShowAction(true),
                  autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));
  controller()->OnAutomaticGenerationAvailable(
      active_driver(), GetTestGenerationUIData1(),
      /*has_saved_credentials=*/false, gfx::RectF(100, 20));
  histogram_tester.ExpectUniqueSample(
      kTouchToFillTriggerOutcomeHistogramName,
      TouchToFillOutcome::kDismissed4TimesInARow, 1);
}

TEST_F(PasswordGenerationControllerTest,
       CallsKeyboardAccessoryAfterBottomSheetDismissed) {
  base::HistogramTester histogram_tester;
  auto ttf_password_generation_bridge =
      std::make_unique<FakeTouchToFillPasswordGenerationBridge>();
  FakeTouchToFillPasswordGenerationBridge* ttf_password_generation_bridge_ptr =
      ttf_password_generation_bridge.get();
  EXPECT_CALL(create_ttf_generation_controller_, Run)
      .WillOnce([this, &ttf_password_generation_bridge]() {
        return controller()->CreateTouchToFillGenerationControllerForTesting(
            std::move(ttf_password_generation_bridge),
            mock_manual_filling_controller_.AsWeakPtr());
      });

  // Keyboard accessory shouldn't be called.
  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  _, autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC))
      .Times(0);
  controller()->OnAutomaticGenerationAvailable(
      active_driver(), GetTestGenerationUIData1(),
      /*has_saved_credentials=*/false, gfx::RectF(100, 20));
  histogram_tester.ExpectBucketCount(kTouchToFillTriggerOutcomeHistogramName,
                                     TouchToFillOutcome::kShown, 1);

  ttf_password_generation_bridge_ptr->OnDismissed(
      /*env=*/nullptr, /*generated_password_accepted=*/false);

  // Keyboard accessory should be displayed.
  EXPECT_CALL(mock_manual_filling_controller_,
              OnAccessoryActionAvailabilityChanged(
                  _, autofill::AccessoryAction::GENERATE_PASSWORD_AUTOMATIC));
  controller()->OnAutomaticGenerationAvailable(
      active_driver(), GetTestGenerationUIData1(),
      /*has_saved_credentials=*/false, gfx::RectF(100, 20));
  histogram_tester.ExpectBucketCount(kTouchToFillTriggerOutcomeHistogramName,
                                     TouchToFillOutcome::kShownBefore, 1);

  // Removes the keyboard suppression callback from the render widget host. It
  // needs to be done before the `PasswordGenerationController` destructor is
  // called.
  controller()->HideBottomSheetIfNeeded();
}

TEST_F(PasswordGenerationControllerTest,
       RequestingGenerationResetsBottomSheetDismissCount) {
  // Set up as if user has dismissed the bottom sheet for 4 times before.
  pref_service()->SetInteger(
      password_manager::prefs::kPasswordGenerationBottomSheetDismissCount, 4);
  ASSERT_EQ(
      pref_service()->GetInteger(
          password_manager::prefs::kPasswordGenerationBottomSheetDismissCount),
      4);

  controller()->OnGenerationRequested(PasswordGenerationType::kManual);
  EXPECT_THAT(
      pref_service()->GetInteger(
          password_manager::prefs::kPasswordGenerationBottomSheetDismissCount),
      0);
}

TEST_F(PasswordGenerationControllerTest,
       ShowsBottomSheetWhenManualGenerationRequestedWithFeatureOn) {
  controller()->OnGenerationRequested(PasswordGenerationType::kManual);

  EXPECT_CALL(create_ttf_generation_controller_, Run);
  controller()->ShowManualGenerationDialog(password_manager_driver_.get(),
                                           GetTestGenerationUIData1());
}

TEST_F(PasswordGenerationControllerTest,
       ShowsBottomSheetWhenAutomaticGenerationRequestedWithFeatureOn) {
  controller()->OnAutomaticGenerationAvailable(
      active_driver(), GetTestGenerationUIData1(),
      /*has_saved_credentials=*/false, gfx::RectF(100, 20));

  EXPECT_CALL(create_ttf_generation_controller_, Run);
  controller()->OnGenerationRequested(PasswordGenerationType::kAutomatic);
}