chromium/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <map>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>

#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/gmock_move_support.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "chrome/browser/password_manager/password_manager_test_util.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/ui/hats/mock_trust_safety_sentiment_service.h"
#include "chrome/browser/ui/hats/trust_safety_sentiment_service_factory.h"
#include "chrome/browser/ui/passwords/credential_leak_dialog_controller.h"
#include "chrome/browser/ui/passwords/credential_manager_dialog_controller.h"
#include "chrome/browser/ui/passwords/manage_passwords_icon_view.h"
#include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
#include "chrome/browser/ui/passwords/password_dialog_prompts.h"
#include "chrome/browser/ui/passwords/passwords_model_delegate.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "components/device_reauth/device_authenticator.h"
#include "components/password_manager/core/browser/features/password_features.h"
#include "components/password_manager/core/browser/mock_password_form_manager_for_ui.h"
#include "components/password_manager/core/browser/move_password_to_account_store_helper.h"
#include "components/password_manager/core/browser/password_bubble_experiment.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/password_store/interactions_stats.h"
#include "components/password_manager/core/browser/password_store/mock_password_store_interface.h"
#include "components/password_manager/core/browser/password_store/test_password_store.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/password_manager/core/common/password_manager_ui.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/base/consent_level.h"
#include "components/signin/public/base/signin_metrics.h"
#include "components/signin/public/base/signin_switches.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/identity_test_utils.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_utils.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
#include "components/device_reauth/mock_device_authenticator.h"
#endif

MockPasswordFormManagerForUI;
MockPasswordStoreInterface;
PasswordForm;
ReauthSucceeded;
InsecureType;
InsecurityMetadata;
PasswordForm;
_;
AtLeast;
AtMost;
Contains;
DoAll;
ElementsAre;
Eq;
Exactly;
IsEmpty;
Not;
Pointee;
Return;
ReturnRef;
SaveArg;

namespace {

MATCHER_P3(MatchesLoginAndURL,
           username,
           password,
           url,
           "matches username, password and url") {}

// A random URL.
constexpr char kExampleUrl[] =;
constexpr char16_t kExampleUsername[] =;

// Number of dismissals that for sure suppresses the bubble.
constexpr int kGreatDissmisalCount =;

class CredentialManagementDialogPromptMock : public AccountChooserPrompt,
                                             public AutoSigninFirstRunPrompt {};

class PasswordLeakDialogMock : public CredentialLeakPrompt {};

class TestManagePasswordsIconView : public ManagePasswordsIconView {};

class TestPasswordManagerClient
    : public password_manager::StubPasswordManagerClient {};

// This subclass is used to disable some code paths which are not essential for
// testing.
class TestManagePasswordsUIController : public ManagePasswordsUIController {};

TestManagePasswordsUIController::TestManagePasswordsUIController(
    content::WebContents* contents,
    password_manager::PasswordManagerClient* client)
    :{}

void TestManagePasswordsUIController::UpdateBubbleAndIconVisibility() {}

void TestManagePasswordsUIController::HidePasswordBubble() {}

password_manager::PasswordForm BuildFormFromLoginAndURL(
    const std::string& username,
    const std::string& password,
    const std::string& url) {}

password_manager::PasswordForm CreateInsecureCredential(PasswordForm form) {}

std::unique_ptr<MockPasswordFormManagerForUI> CreateFormManagerWithBestMatches(
    const std::vector<PasswordForm>& best_matches,
    const PasswordForm* password_form,
    bool is_blocklisted = false) {}

}  // namespace

class ManagePasswordsUIControllerTest : public ChromeRenderViewHostTestHarness {};

void ManagePasswordsUIControllerTest::SetUp() {}

void ManagePasswordsUIControllerTest::ExpectIconStateIs(
    password_manager::ui::State state) {}

void ManagePasswordsUIControllerTest::ExpectIconAndControllerStateIs(
    password_manager::ui::State state) {}

void ManagePasswordsUIControllerTest::TestNotChangingStateOnAutofill(
    password_manager::ui::State state) {}

void ManagePasswordsUIControllerTest::WaitForPasswordStore() {}

TEST_F(ManagePasswordsUIControllerTest, DefaultState) {}

TEST_F(ManagePasswordsUIControllerTest, PasswordAutofilled) {}

TEST_F(ManagePasswordsUIControllerTest, PasswordSubmitted) {}

TEST_F(ManagePasswordsUIControllerTest, BlocklistedFormPasswordSubmitted) {}

TEST_F(ManagePasswordsUIControllerTest, PasswordSubmittedBubbleSuppressed) {}

TEST_F(ManagePasswordsUIControllerTest, PasswordSubmittedBubbleNotSuppressed) {}

TEST_F(ManagePasswordsUIControllerTest, PasswordSubmittedBubbleCancelled) {}

TEST_F(ManagePasswordsUIControllerTest, DefaultStoreChanged) {}

TEST_F(ManagePasswordsUIControllerTest,
       BlocklistedFormPasswordSubmittedDoesNotGetAutomaticWarning) {}

TEST_F(ManagePasswordsUIControllerTest,
       IfSaveBubbleIsSuppressedNoAutomaticWarning) {}

TEST_F(ManagePasswordsUIControllerTest, PasswordSaved) {}

TEST_F(ManagePasswordsUIControllerTest, PhishedPasswordUpdated) {}

TEST_F(ManagePasswordsUIControllerTest, PasswordSavedUKMRecording) {}

TEST_F(ManagePasswordsUIControllerTest,
       PasswordSavedInAccountStoreWhenReauthSucceeds) {}

TEST_F(ManagePasswordsUIControllerTest,
       PasswordNotSavedInAccountStoreWhenReauthFails) {}

TEST_F(ManagePasswordsUIControllerTest, PasswordBlocklisted) {}

TEST_F(ManagePasswordsUIControllerTest,
       PasswordBlocklistedWithExistingCredentials) {}

TEST_F(ManagePasswordsUIControllerTest, NormalNavigations) {}

TEST_F(ManagePasswordsUIControllerTest, NormalNavigationsClosedBubble) {}

TEST_F(ManagePasswordsUIControllerTest, PasswordSubmittedToNonWebbyURL) {}

TEST_F(ManagePasswordsUIControllerTest, BlocklistedElsewhere) {}

TEST_F(ManagePasswordsUIControllerTest, AutomaticPasswordSave) {}

TEST_F(ManagePasswordsUIControllerTest, ChooseCredentialLocal) {}

TEST_F(ManagePasswordsUIControllerTest, ChooseCredentialLocalButFederated) {}

TEST_F(ManagePasswordsUIControllerTest, ChooseCredentialCancel) {}

TEST_F(ManagePasswordsUIControllerTest, ChooseCredentialPrefetch) {}

TEST_F(ManagePasswordsUIControllerTest, ChooseCredentialPSL) {}

TEST_F(ManagePasswordsUIControllerTest,
       PromptSaveBubbleAfterDefaultStoreChanged) {}

TEST_F(ManagePasswordsUIControllerTest,
       DefaultStoreChangedBubbleClosedAndKeyIconPressedManually) {}

TEST_F(ManagePasswordsUIControllerTest, AutoSignin) {}

TEST_F(ManagePasswordsUIControllerTest, AutoSigninFirstRun) {}

TEST_F(ManagePasswordsUIControllerTest, AutoSigninFirstRunAfterAutofill) {}

TEST_F(ManagePasswordsUIControllerTest, AutoSigninFirstRunAfterNavigation) {}

TEST_F(ManagePasswordsUIControllerTest, AutofillDuringAutoSignin) {}

TEST_F(ManagePasswordsUIControllerTest, InactiveOnPSLMatched) {}

TEST_F(ManagePasswordsUIControllerTest, UpdatePasswordSubmitted) {}

TEST_F(ManagePasswordsUIControllerTest, PasswordUpdated) {}

TEST_F(ManagePasswordsUIControllerTest, SavePendingStatePasswordAutofilled) {}

TEST_F(ManagePasswordsUIControllerTest, UpdatePendingStatePasswordAutofilled) {}

TEST_F(ManagePasswordsUIControllerTest, ConfirmationStatePasswordAutofilled) {}

TEST_F(ManagePasswordsUIControllerTest, OpenBubbleTwice) {}

TEST_F(ManagePasswordsUIControllerTest, ManualFallbackForSaving_UseFallback) {}

// Verifies that after OnHideManualFallbackForSaving, the password manager icon
// goes into a state that allows managing existing passwords, if these existed
// before the manual fallback.
TEST_F(ManagePasswordsUIControllerTest,
       ManualFallbackForSaving_HideFallback_WithPreexistingPasswords) {}

// Verify that after OnHideManualFallbackForSaving, the password manager icon
// goes away if no passwords were persited before the manual fallback.
TEST_F(ManagePasswordsUIControllerTest,
       ManualFallbackForSaving_HideFallback_WithoutPreexistingPasswords) {}

TEST_F(ManagePasswordsUIControllerTest,
       ManualFallbackForSaving_HideFallback_Timeout) {}

TEST_F(ManagePasswordsUIControllerTest,
       ManualFallbackForSaving_OpenBubbleBlocksFallbackHiding) {}

TEST_F(ManagePasswordsUIControllerTest,
       ManualFallbackForSavingFollowedByAutomaticBubble) {}

TEST_F(ManagePasswordsUIControllerTest,
       ManualFallbackForSaving_HideAutomaticBubble) {}

TEST_F(ManagePasswordsUIControllerTest,
       ManualFallbackForSaving_GeneratedPassword) {}

TEST_F(ManagePasswordsUIControllerTest,
       PasswordDetails_OnShowPasswordIsInitialBubbleCredential) {}

TEST_F(ManagePasswordsUIControllerTest,
       PasswordDetails_BubbleIsInactiveAfterClosingPasswordDetails) {}

TEST_F(ManagePasswordsUIControllerTest,
       PasswordDetails_BubbleSwitchesToListAfterClosingPasswordDetails) {}

// The following test is being run on platforms that support device
// authentication, as on others the callback is stubbed to return `true`.
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
TEST_F(ManagePasswordsUIControllerTest, PasswordDetails_IsntShownIfAuthFailed) {
  auto mock_authenticator =
      std::make_unique<device_reauth::MockDeviceAuthenticator>();
  EXPECT_CALL(*mock_authenticator, AuthenticateWithMessage)
      .WillOnce([](const std::u16string&,
                   device_reauth::DeviceAuthenticator::AuthenticateCallback
                       callback) { std::move(callback).Run(false); });
  EXPECT_CALL(client(), GetDeviceAuthenticator)
      .WillOnce(Return(testing::ByMove(std::move(mock_authenticator))));

  password_manager::PasswordForm form;
  form.username_value = u"user";
  form.password_value = u"passw0rd";
  controller()->OnOpenPasswordDetailsBubble(form);

  EXPECT_EQ(
      controller()->GetManagePasswordsSingleCredentialDetailsModeCredential(),
      std::nullopt);
  EXPECT_EQ(controller()->GetState(), password_manager::ui::INACTIVE_STATE);
}
#endif

TEST_F(ManagePasswordsUIControllerTest, AutofillDuringSignInPromo) {}

TEST_F(ManagePasswordsUIControllerTest, SaveBubbleAfterLeakCheck) {}

TEST_F(ManagePasswordsUIControllerTest,
       NoSaveBubbleAfterLeakCheckForBlocklistedWebsites) {}

TEST_F(ManagePasswordsUIControllerTest, UpdateBubbleAfterLeakCheck) {}

TEST_F(ManagePasswordsUIControllerTest,
       NotifyUnsyncedCredentialsWillBeDeleted) {}

TEST_F(ManagePasswordsUIControllerTest, SaveUnsyncedCredentialsInProfileStore) {}

TEST_F(ManagePasswordsUIControllerTest, DiscardUnsyncedCredentials) {}

TEST_F(ManagePasswordsUIControllerTest, OpenBubbleForMovableForm) {}

TEST_F(ManagePasswordsUIControllerTest, OpenMoveBubbleFromManagementBubble) {}

TEST_F(ManagePasswordsUIControllerTest, CloseMoveBubble) {}

TEST_F(ManagePasswordsUIControllerTest, OpenSafeStateBubble) {}

TEST_F(ManagePasswordsUIControllerTest, OpenMoreToFixBubble) {}

TEST_F(ManagePasswordsUIControllerTest, NoMoreToFixBubbleIfPromoStillOpen) {}

TEST_F(ManagePasswordsUIControllerTest, UsernameAdded) {}

TEST_F(ManagePasswordsUIControllerTest, IsDeviceAuthenticatorObtained) {}

TEST_F(ManagePasswordsUIControllerTest, PasskeySavedWithoutGpmPinCreation) {}

TEST_F(ManagePasswordsUIControllerTest, PasskeySavedWithGpmPinCreation) {}

TEST_F(ManagePasswordsUIControllerTest, InvalidPasskeyDeleted) {}

TEST_F(ManagePasswordsUIControllerTest, OpenPasskeyUpdatedBubble) {}

TEST_F(ManagePasswordsUIControllerTest, OpenPasskeyNotAcceptedBubble) {}

#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
TEST_F(ManagePasswordsUIControllerTest,
       ShouldShowBiometricAuthenticationForFillingPromo) {
  std::vector<PasswordForm> best_matches;
  auto test_form_manager =
      CreateFormManagerWithBestMatches(best_matches, &submitted_form());
  controller()->OnPasswordSubmitted(std::move(test_form_manager));

  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kHasUserInteractedWithBiometricAuthPromo, false);
  profile()->GetPrefs()->SetInteger(
      password_manager::prefs::kBiometricAuthBeforeFillingPromoShownCounter, 0);
  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kBiometricAuthenticationBeforeFilling, false);

  EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility());
  controller()->OnBiometricAuthenticationForFilling(profile()->GetPrefs());
  EXPECT_EQ(1, profile()->GetPrefs()->GetInteger(
                   password_manager::prefs::
                       kBiometricAuthBeforeFillingPromoShownCounter));
  ExpectIconAndControllerStateIs(
      password_manager::ui::BIOMETRIC_AUTHENTICATION_FOR_FILLING_STATE);
}

// Test if BiometricAuthForFilling promo is not shown if user interacted with
// the promo earlier.
TEST_F(ManagePasswordsUIControllerTest,
       ShouldNotShowBiometricAuthenticationForFillingPromoUserInteracted) {
  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kHasUserInteractedWithBiometricAuthPromo, true);
  profile()->GetPrefs()->SetInteger(
      password_manager::prefs::kBiometricAuthBeforeFillingPromoShownCounter, 1);
  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kBiometricAuthenticationBeforeFilling, false);

  EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility()).Times(0);
  controller()->OnBiometricAuthenticationForFilling(profile()->GetPrefs());
  EXPECT_EQ(1, profile()->GetPrefs()->GetInteger(
                   password_manager::prefs::
                       kBiometricAuthBeforeFillingPromoShownCounter));
}

// Test if BiometricAuthForFilling promo is not shown if User turned on the
// feature manually in settings.
TEST_F(ManagePasswordsUIControllerTest,
       ShouldNotShowBiometricAuthenticationForFillingPromoUserTurnedOnManualy) {
  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kHasUserInteractedWithBiometricAuthPromo, false);
  profile()->GetPrefs()->SetInteger(
      password_manager::prefs::kBiometricAuthBeforeFillingPromoShownCounter, 0);
  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kBiometricAuthenticationBeforeFilling, true);

  EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility()).Times(0);
  controller()->OnBiometricAuthenticationForFilling(profile()->GetPrefs());
  EXPECT_EQ(0, profile()->GetPrefs()->GetInteger(
                   password_manager::prefs::
                       kBiometricAuthBeforeFillingPromoShownCounter));
}

// Test if BiometricAuthForFilling promo is not shown if User turned on the
// feature through promo.
TEST_F(
    ManagePasswordsUIControllerTest,
    ShouldNotShowBiometricAuthenticationForFillingPromoUserTurnedOnViaPromo) {
  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kHasUserInteractedWithBiometricAuthPromo, true);
  profile()->GetPrefs()->SetInteger(
      password_manager::prefs::kBiometricAuthBeforeFillingPromoShownCounter, 1);
  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kBiometricAuthenticationBeforeFilling, true);

  EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility()).Times(0);
  controller()->OnBiometricAuthenticationForFilling(profile()->GetPrefs());
  EXPECT_EQ(1, profile()->GetPrefs()->GetInteger(
                   password_manager::prefs::
                       kBiometricAuthBeforeFillingPromoShownCounter));
}

// Test if BiometricAuthForFilling promo is not shown if User have seen promo
// more than
// `kMaxNumberOfTimesBiometricAuthForFillingPromoWillBeShown` times.
TEST_F(ManagePasswordsUIControllerTest,
       ShouldNotShowBiometricAuthenticationForFillingPromoCounterLimit) {
  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kHasUserInteractedWithBiometricAuthPromo, false);
  profile()->GetPrefs()->SetInteger(
      password_manager::prefs::kBiometricAuthBeforeFillingPromoShownCounter,
      kMaxNumberOfTimesBiometricAuthForFillingPromoWillBeShown + 1);
  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kBiometricAuthenticationBeforeFilling, false);

  EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility()).Times(0);
  controller()->OnBiometricAuthenticationForFilling(profile()->GetPrefs());
  EXPECT_EQ(kMaxNumberOfTimesBiometricAuthForFillingPromoWillBeShown + 1,
            profile()->GetPrefs()->GetInteger(
                password_manager::prefs::
                    kBiometricAuthBeforeFillingPromoShownCounter));
}

// On one specific tab BiometricAuthForFilling promo should be shown no more
// than once.
TEST_F(ManagePasswordsUIControllerTest,
       ShouldNotShowBiometricAuthenticationForFillingPromoTwiceOnTheSameTab) {
  std::vector<PasswordForm> best_matches;
  auto test_form_manager =
      CreateFormManagerWithBestMatches(best_matches, &submitted_form());
  controller()->OnPasswordSubmitted(std::move(test_form_manager));

  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kHasUserInteractedWithBiometricAuthPromo, false);
  profile()->GetPrefs()->SetInteger(
      password_manager::prefs::kBiometricAuthBeforeFillingPromoShownCounter, 0);
  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kBiometricAuthenticationBeforeFilling, false);

  EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility());
  controller()->OnBiometricAuthenticationForFilling(profile()->GetPrefs());
  ExpectIconAndControllerStateIs(
      password_manager::ui::BIOMETRIC_AUTHENTICATION_FOR_FILLING_STATE);

  EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility()).Times(0);
  controller()->OnBiometricAuthenticationForFilling(profile()->GetPrefs());
}

TEST_F(ManagePasswordsUIControllerTest,
       BiometricAuthPromoNotShowIfThereIsAnotherDialog) {
  // Show account chooser dialog.
  std::vector<std::unique_ptr<PasswordForm>> local_credentials;
  local_credentials.emplace_back(
      std::make_unique<PasswordForm>(test_local_form()));
  url::Origin origin = url::Origin::Create(GURL(kExampleUrl));
  CredentialManagerDialogController* dialog_controller = nullptr;
  EXPECT_CALL(*controller(), CreateAccountChooser(_))
      .WillOnce(
          DoAll(SaveArg<0>(&dialog_controller), Return(&dialog_prompt())));
  EXPECT_CALL(dialog_prompt(), ShowAccountChooser());
  EXPECT_CALL(*controller(), HasBrowserWindow()).WillOnce(Return(true));
  base::MockCallback<ManagePasswordsState::CredentialsCallback> choose_callback;
  EXPECT_TRUE(controller()->OnChooseCredentials(std::move(local_credentials),
                                                origin, choose_callback.Get()));
  EXPECT_EQ(password_manager::ui::CREDENTIAL_REQUEST_STATE,
            controller()->GetState());

  // Now try to show promo for biometric auth before filling.
  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kHasUserInteractedWithBiometricAuthPromo, false);
  profile()->GetPrefs()->SetInteger(
      password_manager::prefs::kBiometricAuthBeforeFillingPromoShownCounter, 0);
  profile()->GetPrefs()->SetBoolean(
      password_manager::prefs::kBiometricAuthenticationBeforeFilling, false);

  controller()->OnBiometricAuthenticationForFilling(profile()->GetPrefs());
  EXPECT_EQ(0, profile()->GetPrefs()->GetInteger(
                   password_manager::prefs::
                       kBiometricAuthBeforeFillingPromoShownCounter));

  // Verify that account chooser is still shown.
  EXPECT_EQ(password_manager::ui::CREDENTIAL_REQUEST_STATE,
            controller()->GetState());

  // Choose a credential to verify that there is no crash.
  EXPECT_CALL(choose_callback, Run(Pointee(test_local_form())));
  dialog_controller->OnChooseCredentials(
      *dialog_controller->GetLocalForms()[0],
      password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD);
  EXPECT_EQ(password_manager::ui::MANAGE_STATE, controller()->GetState());
}

TEST_F(ManagePasswordsUIControllerTest, BiometricActivationConfirmation) {
  std::vector<PasswordForm> best_matches;
  auto test_form_manager =
      CreateFormManagerWithBestMatches(best_matches, &submitted_form());
  controller()->OnPasswordSubmitted(std::move(test_form_manager));
  controller()->ShowBiometricActivationConfirmation();
  EXPECT_EQ(password_manager::ui::BIOMETRIC_AUTHENTICATION_CONFIRMATION_STATE,
            controller()->GetState());

  // After closing buble state switches automatically to MANAGE_STATE.
  EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility());
  controller()->OnBubbleHidden();
  ExpectIconAndControllerStateIs(password_manager::ui::MANAGE_STATE);
}

TEST_F(ManagePasswordsUIControllerTest,
       BiometricActivationConfirmationNotShownOnTopOfAnotherDialog) {
  // Show account chooser dialog.
  std::vector<std::unique_ptr<PasswordForm>> local_credentials;
  local_credentials.emplace_back(
      std::make_unique<PasswordForm>(test_local_form()));
  url::Origin origin = url::Origin::Create(GURL(kExampleUrl));
  CredentialManagerDialogController* dialog_controller = nullptr;
  EXPECT_CALL(*controller(), CreateAccountChooser(_))
      .WillOnce(
          DoAll(SaveArg<0>(&dialog_controller), Return(&dialog_prompt())));
  EXPECT_CALL(dialog_prompt(), ShowAccountChooser());
  EXPECT_CALL(*controller(), HasBrowserWindow()).WillOnce(Return(true));
  base::MockCallback<ManagePasswordsState::CredentialsCallback> choose_callback;
  EXPECT_TRUE(controller()->OnChooseCredentials(std::move(local_credentials),
                                                origin, choose_callback.Get()));

  controller()->ShowBiometricActivationConfirmation();
  // Verify that account chooser is still shown.
  EXPECT_EQ(password_manager::ui::CREDENTIAL_REQUEST_STATE,
            controller()->GetState());
}

TEST_F(ManagePasswordsUIControllerTest,
       AuthenticateWithMessageTwiceCancelsFirstCall) {
  auto mock_authenticator =
      std::make_unique<device_reauth::MockDeviceAuthenticator>();
  auto* mock_authenticator_ptr = mock_authenticator.get();

  EXPECT_CALL(*mock_authenticator_ptr, AuthenticateWithMessage);
  EXPECT_CALL(client(), GetDeviceAuthenticator)
      .WillOnce(Return(testing::ByMove(std::move(mock_authenticator))));

  controller()->AuthenticateUserWithMessage(/*message=*/u"", base::DoNothing());

  auto mock_authenticator2 =
      std::make_unique<device_reauth::MockDeviceAuthenticator>();

  EXPECT_CALL(*mock_authenticator_ptr, Cancel);
  EXPECT_CALL(*mock_authenticator2.get(), AuthenticateWithMessage);
  EXPECT_CALL(client(), GetDeviceAuthenticator)
      .WillOnce(Return(testing::ByMove(std::move(mock_authenticator2))));

  controller()->AuthenticateUserWithMessage(/*message=*/u"", base::DoNothing());
}

TEST_F(ManagePasswordsUIControllerTest, AuthenticationCancledOnPageChange) {
  base::MockCallback<base::OnceCallback<void(bool)>> result_callback;
  auto mock_authenticator =
      std::make_unique<device_reauth::MockDeviceAuthenticator>();
  auto* mock_authenticator_ptr = mock_authenticator.get();

  EXPECT_CALL(*mock_authenticator_ptr, AuthenticateWithMessage);
  EXPECT_CALL(client(), GetDeviceAuthenticator)
      .WillOnce(Return(testing::ByMove(std::move(mock_authenticator))));

  controller()->AuthenticateUserWithMessage(/*message=*/u"", base::DoNothing());

  EXPECT_CALL(*mock_authenticator_ptr, Cancel);

  static_cast<content::WebContentsObserver*>(controller())
      ->PrimaryPageChanged(controller()->GetWebContents()->GetPrimaryPage());
}

TEST_F(ManagePasswordsUIControllerTest, OnBiometricAuthBeforeFillingDeclined) {
  std::vector<PasswordForm> best_matches;
  auto test_form_manager =
      CreateFormManagerWithBestMatches(best_matches, &submitted_form());
  controller()->OnPasswordSubmitted(std::move(test_form_manager));
  controller()->OnBiometricAuthenticationForFilling(profile()->GetPrefs());

  ASSERT_EQ(password_manager::ui::BIOMETRIC_AUTHENTICATION_FOR_FILLING_STATE,
            controller()->GetState());

  controller()->OnBiometricAuthBeforeFillingDeclined();
  ASSERT_EQ(password_manager::ui::MANAGE_STATE, controller()->GetState());
}

#endif  // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)

#if BUILDFLAG(IS_MAC)
TEST_F(ManagePasswordsUIControllerTest, OnKeychainErrorShouldShowBubble) {
  base::test::ScopedFeatureList scoped_feature_list;
  scoped_feature_list.InitAndEnableFeature(
      password_manager::features::kRestartToGainAccessToKeychain);
  profile()->GetPrefs()->SetInteger(
      password_manager::prefs::kRelaunchChromeBubbleDismissedCounter, 0);
  EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility());
  controller()->OnKeychainError();
  EXPECT_EQ(password_manager::ui::KEYCHAIN_ERROR_STATE,
            controller()->GetState());
}

TEST_F(ManagePasswordsUIControllerTest, OnKeychainErrorShouldNotShowBubble) {
  base::test::ScopedFeatureList scoped_feature_list;
  scoped_feature_list.InitAndEnableFeature(
      password_manager::features::kRestartToGainAccessToKeychain);
  profile()->GetPrefs()->SetInteger(
      password_manager::prefs::kRelaunchChromeBubbleDismissedCounter, 4);
  EXPECT_CALL(*controller(), OnUpdateBubbleAndIconVisibility()).Times(0);
  controller()->OnKeychainError();
  EXPECT_EQ(password_manager::ui::INACTIVE_STATE, controller()->GetState());
}
#endif

class ManagePasswordsUIControllerWithBrowserTest
    : public BrowserWithTestWindowTest {};

void ManagePasswordsUIControllerWithBrowserTest::SetUp() {}

TEST_F(ManagePasswordsUIControllerWithBrowserTest,
       OnAutofillingSharedPasswordNotNotifiedYet) {}

TEST_F(ManagePasswordsUIControllerWithBrowserTest,
       OnAutofillingSharedPasswordNotifiedAlready) {}

#if BUILDFLAG(ENABLE_DICE_SUPPORT)
class TestPasswordManagerClientWithStores
    : public password_manager::StubPasswordManagerClient {};

class ManagePasswordsUIControllerWithBrowserTestExplicitBrowserSignin
    : public ChromeRenderViewHostTestHarness {};

void ManagePasswordsUIControllerWithBrowserTestExplicitBrowserSignin::SetUp() {}

MATCHER_P(FormMatches, form, "") {}

TEST_F(ManagePasswordsUIControllerWithBrowserTestExplicitBrowserSignin,
       MovePasswordUponSigninWithExistingAccount) {}
#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)