chromium/chrome/browser/password_manager/chrome_password_manager_client_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 "chrome/browser/password_manager/chrome_password_manager_client.h"

#include <stdint.h>

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

#include "base/command_line.h"
#include "base/containers/span.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "chrome/browser/autofill/mock_manual_filling_view.h"
#include "chrome/browser/keyboard_accessory/test_utils/android/mock_address_accessory_controller.h"
#include "chrome/browser/password_manager/password_manager_settings_service_factory.h"
#include "chrome/browser/password_manager/profile_password_store_factory.h"
#include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
#include "chrome/browser/safe_browsing/user_interaction_observer.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/browser/ui/autofill/chrome_autofill_client.h"
#include "chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller_impl.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "components/autofill/content/browser/autofill_test_utils.h"
#include "components/autofill/content/browser/content_autofill_client.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/content/common/mojom/autofill_agent.mojom.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/browser/logging/log_receiver.h"
#include "components/autofill/core/browser/logging/log_router.h"
#include "components/autofill/core/browser/test_autofill_manager_waiter.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_test_utils.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/signatures.h"
#include "components/autofill/core/common/unique_ids.h"
#include "components/device_reauth/mock_device_authenticator.h"
#include "components/password_manager/content/browser/content_password_manager_driver.h"
#include "components/password_manager/content/browser/password_manager_log_router_factory.h"
#include "components/password_manager/core/browser/credential_cache.h"
#include "components/password_manager/core/browser/credentials_filter.h"
#include "components/password_manager/core/browser/mock_password_manager_settings_service.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/password_store/mock_password_store_interface.h"
#include "components/password_manager/core/browser/password_store/password_store_consumer.h"
#include "components/password_manager/core/browser/split_stores_and_local_upm.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/safe_browsing/buildflags.h"
#include "components/safe_browsing/core/common/features.h"
#include "components/sessions/content/content_record_password_state.h"
#include "components/sync/test/test_sync_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/mock_navigation_handle.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/web_contents_tester.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "url/url_constants.h"

#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "extensions/common/constants.h"
#endif

#if BUILDFLAG(FULL_SAFE_BROWSING)
#include "components/safe_browsing/content/browser/password_protection/mock_password_protection_service.h"
#endif

#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#include "chrome/browser/autofill/mock_manual_filling_view.h"
#include "chrome/browser/keyboard_accessory/android/manual_filling_controller_impl.h"
#include "chrome/browser/keyboard_accessory/android/password_accessory_controller_impl.h"
#include "chrome/browser/keyboard_accessory/test_utils/android/mock_address_accessory_controller.h"
#include "chrome/browser/keyboard_accessory/test_utils/android/mock_manual_filling_controller.h"
#include "chrome/browser/keyboard_accessory/test_utils/android/mock_password_accessory_controller.h"
#include "chrome/browser/keyboard_accessory/test_utils/android/mock_payment_method_accessory_controller.h"
#include "chrome/browser/password_manager/account_password_store_factory.h"
#include "chrome/browser/password_manager/android/password_generation_controller.h"
#else
#include "chrome/browser/ui/hats/hats_service_factory.h"
#include "chrome/browser/ui/hats/mock_hats_service.h"
#endif  // BUILDFLAG(IS_ANDROID)

CalculateFormSignature;
ContentAutofillClient;
ContentAutofillDriver;
FieldRendererId;
FormControlType;
FormData;
FormFieldData;
FocusedFieldType;
CreateFormDataForRenderFrameHost;
CreateTestFormField;
BrowserContext;
WebContents;

PasswordForm;
PasswordManagerClient;
PasswordManagerSetting;
PasswordStoreConsumer;
GetPasswordStateFromNavigation;
SerializedNavigationEntry;
_;
Key;
NiceMock;
Return;
SaveArg;
StrictMock;
UnorderedElementsAre;

#if BUILDFLAG(IS_ANDROID)
using base::android::BuildInfo;
using password_manager::CredentialCache;
using password_manager::MockPasswordStoreInterface;
#endif

namespace {

#if BUILDFLAG(IS_ANDROID)
FormData MakePasswordFormData() {
  FormData form_data;
  form_data.set_url(GURL("https://www.example.com/"));
  form_data.set_action(GURL("https://www.example.com/"));
  form_data.set_name(u"form-name");

  FormFieldData field;
  field.set_name(u"password-element");
  field.set_id_attribute(field.name());
  field.set_name_attribute(field.name());
  field.set_form_control_type(autofill::FormControlType::kInputPassword);
  field.set_renderer_id(FieldRendererId(123));
  form_data.set_fields({field});

  return form_data;
}

PasswordForm MakePasswordForm() {
  PasswordForm form;
  form.url = GURL("https://www.example.com/");
  form.action = GURL("https://www.example.com/");
  form.password_element = u"password-element";
  form.submit_element = u"signIn";
  form.signon_realm = "https://www.example.com/";
  form.in_store = PasswordForm::Store::kProfileStore;
  form.match_type = PasswordForm::MatchType::kExact;
  return form;
}
#endif

// TODO(crbug.com/40412780): Get rid of the mocked client in the client's own
// test.
class MockChromePasswordManagerClient : public ChromePasswordManagerClient {};

class DummyLogReceiver : public autofill::LogReceiver {};

class FakePasswordAutofillAgent
    : public autofill::mojom::PasswordAutofillAgent {};

#if BUILDFLAG(IS_ANDROID)

class MockPasswordAccessoryControllerImpl
    : public PasswordAccessoryControllerImpl {
 public:
  MockPasswordAccessoryControllerImpl(
      content::WebContents* web_contents,
      password_manager::CredentialCache* credential_cache,
      base::WeakPtr<ManualFillingController> mf_controller,
      password_manager::PasswordManagerClient* password_client,
      PasswordDriverSupplierForFocusedFrame driver_supplier)
      : PasswordAccessoryControllerImpl(web_contents,
                                        credential_cache,
                                        mf_controller,
                                        password_client,
                                        driver_supplier,
                                        base::DoNothing()) {}

  MOCK_METHOD(void,
              RefreshSuggestionsForField,
              (autofill::mojom::FocusedFieldType),
              (override));
  MOCK_METHOD(void,
              UpdateCredManReentryUi,
              (autofill::mojom::FocusedFieldType),
              (override));
};

#endif

std::unique_ptr<KeyedService> CreateTestSyncService(
    content::BrowserContext* context) {}

}  // namespace

class ChromePasswordManagerClientTest : public ChromeRenderViewHostTestHarness {};

void ChromePasswordManagerClientTest::SetUp() {}

void ChromePasswordManagerClientTest::TearDown() {}

ChromePasswordManagerClient* ChromePasswordManagerClientTest::GetClient() {}

bool ChromePasswordManagerClientTest::WasLoggingActivationMessageSent(
    bool* activation_flag) {}

TEST_F(ChromePasswordManagerClientTest, LogEntryNotifyRenderer) {}

TEST_F(ChromePasswordManagerClientTest,
       SavingPasswordsTrueDeterminedByService) {}

TEST_F(ChromePasswordManagerClientTest,
       SavingPasswordsFalseDeterminedByService) {}

TEST_F(ChromePasswordManagerClientTest, SavingAndFillingEnabledConditionsTest) {}

TEST_F(ChromePasswordManagerClientTest,
       SavingAndFillingDisabledConditionsInGuestAndIncognitoProfiles) {}

TEST_F(ChromePasswordManagerClientTest, ReceivesAutofillPredictions) {}

TEST_F(ChromePasswordManagerClientTest,
       ReceivesAutofillPredictionsFromMultipleFrames) {}

TEST_F(ChromePasswordManagerClientTest, AutoSignInEnabledDeterminedByService) {}

TEST_F(ChromePasswordManagerClientTest,
       AutoSignInDisableddDeterminedByService) {}

#if BUILDFLAG(IS_ANDROID)
TEST_F(ChromePasswordManagerClientTest, AutoSignInDisabledOnAutomotive) {
  if (!BuildInfo::GetInstance()->is_automotive()) {
    GTEST_SKIP() << "This test should only run on automotive.";
  }
  EXPECT_FALSE(GetClient()->IsAutoSignInEnabled());
}
#endif

class ChromePasswordManagerClientAutomatedTest
    : public ChromePasswordManagerClientTest,
      public testing::WithParamInterface<bool> {};

INSTANTIATE_TEST_SUITE_P();

TEST_P(ChromePasswordManagerClientAutomatedTest, SavingDependsOnAutomation) {}

// Check that password manager is disabled on about:blank pages.
// See https://crbug.com/756587.
TEST_F(ChromePasswordManagerClientTest, SavingAndFillingDisabledForAboutBlank) {}

TEST_F(ChromePasswordManagerClientTest,
       IsFillingAndSavingOnGooglePasswordPage) {}

#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
// Test that authentication is not possible if the `authenticator` is `nullptr`.
TEST_F(ChromePasswordManagerClientTest, CanUseBiometricAuthNoAuthenticator) {
  EXPECT_FALSE(GetClient()->IsReauthBeforeFillingRequired(
      /*authenticator=*/nullptr));
}

// Test that authentication is not possible if the device doesn't have
// necessary hardware for biometric authentication.
TEST_F(ChromePasswordManagerClientTest, CanUseBiometricAuthNoBiometrics) {
  device_reauth::MockDeviceAuthenticator authenticator;
  // Both prefs are registered by the `PasswordManager`.
  local_state_.Get()->SetBoolean(
      password_manager::prefs::kHadBiometricsAvailable, false);
  profile()->GetTestingPrefService()->SetBoolean(
      password_manager::prefs::kBiometricAuthenticationBeforeFilling, true);
  EXPECT_FALSE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
}

// Test that authentication is not possible if the user didn't configure the
// corresponding setting.
TEST_F(ChromePasswordManagerClientTest, CanUseBiometricAuthSettingDisabled) {
  device_reauth::MockDeviceAuthenticator authenticator;
  // Both prefs are registered by the `PasswordManager`.
  local_state_.Get()->SetBoolean(
      password_manager::prefs::kHadBiometricsAvailable, true);
  profile()->GetTestingPrefService()->SetBoolean(
      password_manager::prefs::kBiometricAuthenticationBeforeFilling, false);
  EXPECT_FALSE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
}

// Test that authentication is possible if both the biometric authentication
// hardware is available and the user configured the corresponding setting.
TEST_F(ChromePasswordManagerClientTest, CanUseBiometricAuthSettingEnabled) {
  device_reauth::MockDeviceAuthenticator authenticator;
  // Both prefs are registered by the `PasswordManager`.
  local_state_.Get()->SetBoolean(
      password_manager::prefs::kHadBiometricsAvailable, true);
  profile()->GetTestingPrefService()->SetBoolean(
      password_manager::prefs::kBiometricAuthenticationBeforeFilling, true);
  EXPECT_TRUE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
}

#elif BUILDFLAG(IS_ANDROID)
// Test that authentication is not possible if the `authenticator` is `nullptr`.
TEST_F(ChromePasswordManagerClientTest, CanUseBiometricAuthAndroid) {
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    // Authentication is always available for automotive and the `authenticator`
    // is always available.
    device_reauth::MockDeviceAuthenticator authenticator;
    EXPECT_TRUE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
  } else {
    EXPECT_FALSE(GetClient()->IsReauthBeforeFillingRequired(
        /*authenticator=*/nullptr));
  }
}

// Test that authentication is not possible if the `kBiometricTouchToFill`
// feature is not enabled.
TEST_F(ChromePasswordManagerClientTest,
       CanUseBiometricAuthAndroidFeatureIsDisabled) {
  // Authentication is always available for automotive.
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    GTEST_SKIP();
  }
  device_reauth::MockDeviceAuthenticator authenticator;
  ON_CALL(authenticator, CanAuthenticateWithBiometricOrScreenLock)
      .WillByDefault(Return(true));
  EXPECT_FALSE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
}

// Test that authentication is not possible if the
// `CanAuthenticateWithBiometrics` returns `false` when `kBiometricTouchToFill`
// is enabled.
TEST_F(ChromePasswordManagerClientTest,
       CanUseBiometricAuthAndroidAuthDisabled) {
  // Authentication is always available for automotive.
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    GTEST_SKIP();
  }
  base::HistogramTester histogram_tester;
  base::test::ScopedFeatureList enabled_features(
      password_manager::features::kBiometricTouchToFill);
  device_reauth::MockDeviceAuthenticator authenticator;
  ON_CALL(authenticator, CanAuthenticateWithBiometricOrScreenLock)
      .WillByDefault(Return(false));
  EXPECT_FALSE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
  histogram_tester.ExpectUniqueSample(
      "PasswordManager.BiometricAuthPwdFillAndroid."
      "CanAuthenticateWithBiometricOrScreenLock",
      false, 1);
}

// Test that authentication is not possible if the
// `CanAuthenticateWithBiometrics` returns `true`, but the
// `kBiometricReauthBeforePwdFilling` pref is set to false when
// `kBiometricTouchToFill` is enabled.
TEST_F(ChromePasswordManagerClientTest,
       CanUseBiometricAuthAndroidPrefDisabled) {
  // Authentication is always available for automotive.
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    GTEST_SKIP();
  }
  base::test::ScopedFeatureList enabled_features(
      password_manager::features::kBiometricTouchToFill);
  device_reauth::MockDeviceAuthenticator authenticator;
  ON_CALL(authenticator, CanAuthenticateWithBiometricOrScreenLock)
      .WillByDefault(Return(true));
  EXPECT_FALSE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
}

// Test that authentication is possible if the `CanAuthenticateWithBiometrics`
// returns `true` and the `kBiometricReauthBeforePwdFilling` pref is set to true
// when `kBiometricTouchToFill` is enabled.
TEST_F(ChromePasswordManagerClientTest, CanUseBiometricAuthAndroidAuthEnabled) {
  // Authentication is always available for automotive.
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    GTEST_SKIP();
  }

  base::HistogramTester histogram_tester;
  base::test::ScopedFeatureList enabled_features(
      password_manager::features::kBiometricTouchToFill);
  device_reauth::MockDeviceAuthenticator authenticator;
  profile()->GetTestingPrefService()->SetBoolean(
      password_manager::prefs::kBiometricAuthenticationBeforeFilling, true);
  ON_CALL(authenticator, CanAuthenticateWithBiometricOrScreenLock)
      .WillByDefault(Return(true));
  EXPECT_TRUE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
  histogram_tester.ExpectUniqueSample(
      "PasswordManager.BiometricAuthPwdFillAndroid."
      "CanAuthenticateWithBiometricOrScreenLock",
      true, 1);
}

// Test that authentication is possible if the `CanAuthenticateWithBiometrics`
// returns `true` on auto regardless of the pref and flag value.
TEST_F(ChromePasswordManagerClientTest,
       CanUseBiometricAuthAndroidAlwaysTrueOnAutomotive) {
  // Authentication is always available for automotive.
  if (!base::android::BuildInfo::GetInstance()->is_automotive()) {
    GTEST_SKIP();
  }
  device_reauth::MockDeviceAuthenticator authenticator;
  ON_CALL(authenticator, CanAuthenticateWithBiometricOrScreenLock)
      .WillByDefault(Return(true));
  EXPECT_TRUE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
}

#else
// Test that authentication is not possible on other platforms.
TEST_F(ChromePasswordManagerClientTest, CanUseBiometricAuth) {}
#endif  // BUILDFLAG(IS_ANDROID)

namespace {

struct SchemeTestCase {};
const SchemeTestCase kSchemeTestCases[] =;

// Parameterized test that takes a URL scheme as a parameter. Every scheme
// requires a separate test because NavigateAndCommit can be called only once.
class ChromePasswordManagerClientSchemeTest
    : public ChromePasswordManagerClientTest,
      public ::testing::WithParamInterface<const char*> {};

TEST_P(ChromePasswordManagerClientSchemeTest,
       SavingAndFillingOnDifferentSchemes) {}

INSTANTIATE_TEST_SUITE_P();

}  // namespace

TEST_F(ChromePasswordManagerClientTest, GetLastCommittedEntryURL_Empty) {}

TEST_F(ChromePasswordManagerClientTest, GetLastCommittedEntryURL) {}

TEST_F(ChromePasswordManagerClientTest, WebUINoLogging) {}

// State transition: Unannotated
TEST_F(ChromePasswordManagerClientTest, AnnotateNavigationEntryUnannotated) {}

// State transition: unknown->false
TEST_F(ChromePasswordManagerClientTest, AnnotateNavigationEntryToFalse) {}

// State transition: false->true
TEST_F(ChromePasswordManagerClientTest, AnnotateNavigationEntryToTrue) {}

// State transition: true->false (retains true)
TEST_F(ChromePasswordManagerClientTest, AnnotateNavigationEntryTrueToFalse) {}

// Handle missing ChromePasswordManagerClient instance in BindCredentialManager
// gracefully.
TEST_F(ChromePasswordManagerClientTest, BindCredentialManager_MissingInstance) {}

TEST_F(ChromePasswordManagerClientTest, CanShowBubbleOnURL) {}

#if !BUILDFLAG(IS_ANDROID)
// Test that the hats service is called with the expected params.
TEST_F(ChromePasswordManagerClientTest,
       TriggerUserPerceptionOfAutofillPasswordSurvey) {}

TEST_F(
    ChromePasswordManagerClientTest,
    TriggerUserPerceptionOfAutofillPasswordSurvey_EmptyFillingAssistanceString_DoNotCallHats) {}
#endif

#if BUILDFLAG(FULL_SAFE_BROWSING)
TEST_F(ChromePasswordManagerClientTest,
       VerifyMaybeStartPasswordFieldOnFocusRequestCalled) {}

// SafeBrowsing Delayed Warnings experiment can delay certain SafeBrowsing
// warnings until user interaction. This test checks that when a SafeBrowsing
// warning is delayed, password saving and filling is disabled on the page.
TEST_F(ChromePasswordManagerClientTest,
       SavingAndFillingDisabledConditionsDelayedWarnings) {}
#endif

TEST_F(ChromePasswordManagerClientTest, MissingUIDelegate) {}

#if BUILDFLAG(IS_ANDROID)
class ChromePasswordManagerClientAndroidTest
    : public ChromePasswordManagerClientTest {
 protected:
  std::unique_ptr<password_manager::ContentPasswordManagerDriver>
  CreateContentPasswordManagerDriver(content::RenderFrameHost* rfh);

  void SetUp() override;

  void CreateManualFillingController(content::WebContents* web_contents);
  void SetUpGenerationPreconditions(const GURL& url);
  MockPasswordAccessoryControllerImpl* SetUpMockPwdAccessoryForClientUse(
      password_manager::PasswordManagerDriver* driver);

  ManualFillingControllerImpl* controller() {
    return ManualFillingControllerImpl::FromWebContents(web_contents());
  }

  MockManualFillingView* view() {
    return static_cast<MockManualFillingView*>(controller()->view());
  }

  void AdvanceClock(const base::TimeDelta& delta) {
    task_environment()->AdvanceClock(delta);
  }

 private:
  NiceMock<MockPasswordAccessoryController> mock_pwd_controller_;
  NiceMock<MockAddressAccessoryController> mock_address_controller_;
  NiceMock<MockPaymentMethodAccessoryController>
      mock_payment_method_controller_;
};

void ChromePasswordManagerClientAndroidTest::SetUp() {
  ChromePasswordManagerClientTest::SetUp();
  ProfilePasswordStoreFactory::GetInstance()->SetTestingFactory(
      GetBrowserContext(),
      base::BindRepeating(
          &password_manager::BuildPasswordStoreInterface<
              content::BrowserContext, MockPasswordStoreInterface>));
  AccountPasswordStoreFactory::GetInstance()->SetTestingFactory(
      GetBrowserContext(),
      base::BindRepeating(
          &password_manager::BuildPasswordStoreInterface<
              content::BrowserContext, MockPasswordStoreInterface>));
  PasswordManagerSettingsServiceFactory::GetInstance()->SetTestingFactory(
      GetBrowserContext(),
      base::BindRepeating([](content::BrowserContext* context)
                              -> std::unique_ptr<KeyedService> {
        return std::make_unique<
            NiceMock<password_manager::MockPasswordManagerSettingsService>>();
      }));
}

std::unique_ptr<password_manager::ContentPasswordManagerDriver>
ChromePasswordManagerClientAndroidTest::CreateContentPasswordManagerDriver(
    content::RenderFrameHost* rfh) {
  return std::make_unique<password_manager::ContentPasswordManagerDriver>(
      rfh, GetClient());
}

void ChromePasswordManagerClientAndroidTest::CreateManualFillingController(
    content::WebContents* web_contents) {
  ManualFillingControllerImpl::CreateForWebContentsForTesting(
      web_contents, mock_pwd_controller_.AsWeakPtr(),
      mock_address_controller_.AsWeakPtr(),
      mock_payment_method_controller_.AsWeakPtr(),
      std::make_unique<NiceMock<MockManualFillingView>>());
}

void ChromePasswordManagerClientAndroidTest::SetUpGenerationPreconditions(
    const GURL& url) {
  // Navigate to the url of the form.
  NavigateAndCommit(url);

  // Make sure saving passwords is enabled.
  ON_CALL(settings_service(),
          IsSettingEnabled(PasswordManagerSetting::kOfferToSavePasswords))
      .WillByDefault(Return(true));

  // Password sync needs to be enabled for generation
  sync_service()->SetIsUsingExplicitPassphrase(false);
  sync_service()->GetUserSettings()->SetSelectedTypes(
      /*sync_everything=*/false,
      /*types=*/{syncer::UserSelectableType::kPasswords});

  // Make sure the main frame is focused, so that a focus event on the password
  // field later is considered valid.
  FocusWebContentsOnMainFrame();
}

MockPasswordAccessoryControllerImpl*
ChromePasswordManagerClientAndroidTest::SetUpMockPwdAccessoryForClientUse(
    password_manager::PasswordManagerDriver* driver) {
  // Make a driver supplier, since the password accessory needs one
  base::RepeatingCallback<password_manager::PasswordManagerDriver*(
      content::WebContents*)>
      driver_supplier =
          base::BindLambdaForTesting([=](WebContents*) { return driver; });

  NiceMock<MockManualFillingController> mock_mf_controller;
  std::unique_ptr<MockPasswordAccessoryControllerImpl> mock_pwd_controller =
      std::make_unique<MockPasswordAccessoryControllerImpl>(
          web_contents(), GetClient()->GetCredentialCacheForTesting(),
          mock_mf_controller.AsWeakPtr(), GetClient(),
          std::move(driver_supplier));
  MockPasswordAccessoryControllerImpl* weak_mock_pwd_controller =
      mock_pwd_controller.get();

  // Tie the mock accessory to the `WebContents` so that the client uses is.
  web_contents()->SetUserData(weak_mock_pwd_controller->UserDataKey(),
                              std::move(mock_pwd_controller));

  return weak_mock_pwd_controller;
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       FocusedInputChangedNoFrameFillableField) {
  CreateManualFillingController(web_contents());
  ASSERT_FALSE(web_contents()->GetFocusedFrame());

  ChromePasswordManagerClient* client = GetClient();

  std::unique_ptr<password_manager::ContentPasswordManagerDriver> driver =
      CreateContentPasswordManagerDriver(main_rfh());
  client->FocusedInputChanged(driver.get(), FieldRendererId(123),
                              FocusedFieldType::kFillablePasswordField);

  PasswordGenerationController* pwd_generation_controller =
      PasswordGenerationController::GetIfExisting(web_contents());
  EXPECT_FALSE(pwd_generation_controller);
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       FocusedInputChangedNoFrameNoField) {
  CreateManualFillingController(web_contents());
  std::unique_ptr<password_manager::ContentPasswordManagerDriver> driver =
      CreateContentPasswordManagerDriver(main_rfh());

  // Simulate that an element was focused before as far as the generation
  // controller is concerned.
  PasswordGenerationController* pwd_generation_controller =
      PasswordGenerationController::GetOrCreate(web_contents());
  pwd_generation_controller->FocusedInputChanged(
      FocusedFieldType::kFillablePasswordField, driver->AsWeakPtrImpl());

  ChromePasswordManagerClient* client = GetClient();

  ASSERT_FALSE(web_contents()->GetFocusedFrame());
  ASSERT_TRUE(pwd_generation_controller->GetActiveFrameDriver());
  client->FocusedInputChanged(driver.get(), FieldRendererId(123),
                              FocusedFieldType::kUnknown);

  // Check that the event was processed by the generation controller and that
  // the active frame driver was unset.
  EXPECT_FALSE(pwd_generation_controller->GetActiveFrameDriver());
}

TEST_F(ChromePasswordManagerClientAndroidTest, FocusedInputChangedWrongFrame) {
  ChromePasswordManagerClient* client = GetClient();

  // Set up the main frame.
  NavigateAndCommit(GURL("https://example.com"));
  FocusWebContentsOnMainFrame();
  CreateManualFillingController(web_contents());

  content::RenderFrameHost* subframe =
      content::RenderFrameHostTester::For(main_rfh())->AppendChild("subframe");
  std::unique_ptr<password_manager::ContentPasswordManagerDriver> driver =
      CreateContentPasswordManagerDriver(subframe);
  client->FocusedInputChanged(driver.get(), FieldRendererId(123),
                              FocusedFieldType::kFillablePasswordField);

  PasswordGenerationController* pwd_generation_controller =
      PasswordGenerationController::GetIfExisting(web_contents());

  // Check that no generation controller was created, since this event should be
  // rejected and not passed on to a generation controller.
  EXPECT_FALSE(pwd_generation_controller);
}

TEST_F(ChromePasswordManagerClientAndroidTest, FocusedInputChangedGoodFrame) {
  ChromePasswordManagerClient* client = GetClient();
  CreateManualFillingController(web_contents());

  std::unique_ptr<password_manager::ContentPasswordManagerDriver> driver =
      CreateContentPasswordManagerDriver(main_rfh());
  FocusWebContentsOnMainFrame();
  client->FocusedInputChanged(driver.get(), FieldRendererId(123),
                              FocusedFieldType::kFillablePasswordField);

  PasswordGenerationController* pwd_generation_controller =
      PasswordGenerationController::GetIfExisting(web_contents());
  EXPECT_TRUE(pwd_generation_controller);
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       FocusedInputChangedFormsNotFetchedMessagesFeature) {
  FormData observed_form_data = MakePasswordFormData();
  SetUpGenerationPreconditions(observed_form_data.url());

  std::unique_ptr<password_manager::ContentPasswordManagerDriver> driver =
      CreateContentPasswordManagerDriver(main_rfh());

  // Since the test uses a mock store, the consumer won't be called
  // back with results, which simulates the password forms not being fetched
  // before the field is focused.
  driver->GetPasswordManager()->OnPasswordFormsParsed(driver.get(),
                                                      {observed_form_data});

  MockPasswordAccessoryControllerImpl* weak_mock_pwd_controller =
      SetUpMockPwdAccessoryForClientUse(driver.get());

  EXPECT_CALL(
      *weak_mock_pwd_controller,
      RefreshSuggestionsForField(FocusedFieldType::kFillablePasswordField));
  GetClient()->FocusedInputChanged(driver.get(),
                                   observed_form_data.fields()[0].renderer_id(),
                                   FocusedFieldType::kFillablePasswordField);
}

// https://crbug.com/346331137: Broken after M4 rollout.
TEST_F(ChromePasswordManagerClientAndroidTest,
       DISABLED_FocusedInputChangedFormsFetchedSplitStores) {
  profile()->GetTestingPrefService()->SetInteger(
      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(
          password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOn));
  FormData observed_form_data = MakePasswordFormData();
  SetUpGenerationPreconditions(observed_form_data.url());

  std::unique_ptr<password_manager::ContentPasswordManagerDriver> driver =
      CreateContentPasswordManagerDriver(main_rfh());

  // Simulate credential fetching from the stores.
  MockPasswordStoreInterface* mock_account_store =
      static_cast<MockPasswordStoreInterface*>(
          GetClient()->GetAccountPasswordStore());
  base::WeakPtr<PasswordStoreConsumer> store_consumer;
  EXPECT_CALL(*mock_account_store, IsAbleToSavePasswords)
      .WillRepeatedly(Return(true));
  EXPECT_CALL(*mock_account_store, GetLogins(_, _))
      .WillOnce(SaveArg<1>(&store_consumer));

  MockPasswordStoreInterface* mock_profile_store =
      static_cast<MockPasswordStoreInterface*>(
          GetClient()->GetProfilePasswordStore());
  // The consumer for both stores is the same.
  EXPECT_CALL(*mock_profile_store, GetLogins(_, _));

  driver->GetPasswordManager()->OnPasswordFormsParsed(driver.get(),
                                                      {observed_form_data});

  std::vector<PasswordForm> account_store_forms = {MakePasswordForm()};
  store_consumer->OnGetPasswordStoreResultsOrErrorFrom(
      mock_account_store, std::move(account_store_forms));

  std::vector<PasswordForm> profile_store_forms = {MakePasswordForm()};
  store_consumer->OnGetPasswordStoreResultsOrErrorFrom(
      mock_profile_store, std::move(profile_store_forms));

  MockPasswordAccessoryControllerImpl* weak_mock_pwd_controller =
      SetUpMockPwdAccessoryForClientUse(driver.get());
  EXPECT_CALL(
      *weak_mock_pwd_controller,
      RefreshSuggestionsForField(FocusedFieldType::kFillablePasswordField));
  GetClient()->FocusedInputChanged(driver.get(),
                                   observed_form_data.fields()[0].renderer_id(),
                                   FocusedFieldType::kFillablePasswordField);
}

// https://crbug.com/346331137: Broken after M4 rollout.
TEST_F(ChromePasswordManagerClientAndroidTest,
       DISABLED_FocusedInputChangedFormsFetchedSingleStore) {
  profile()->GetTestingPrefService()->SetInteger(
      password_manager::prefs::kPasswordsUseUPMLocalAndSeparateStores,
      static_cast<int>(
          password_manager::prefs::UseUpmLocalAndSeparateStoresState::kOff));
  FormData observed_form_data = MakePasswordFormData();
  SetUpGenerationPreconditions(observed_form_data.url());

  std::unique_ptr<password_manager::ContentPasswordManagerDriver> driver =
      CreateContentPasswordManagerDriver(main_rfh());

  // Simulate credential fetching from the store.
  base::WeakPtr<PasswordStoreConsumer> store_consumer;
  MockPasswordStoreInterface* mock_profile_store =
      static_cast<MockPasswordStoreInterface*>(
          GetClient()->GetProfilePasswordStore());

  EXPECT_CALL(*mock_profile_store, IsAbleToSavePasswords)
      .WillRepeatedly(Return(true));
  EXPECT_CALL(*mock_profile_store, GetLogins(_, _))
      .WillOnce(SaveArg<1>(&store_consumer));
  driver->GetPasswordManager()->OnPasswordFormsParsed(driver.get(),
                                                      {observed_form_data});

  std::vector<PasswordForm> forms = {MakePasswordForm()};
  store_consumer->OnGetPasswordStoreResultsOrErrorFrom(mock_profile_store,
                                                       std::move(forms));

  MockPasswordAccessoryControllerImpl* weak_mock_pwd_controller =
      SetUpMockPwdAccessoryForClientUse(driver.get());
  EXPECT_CALL(
      *weak_mock_pwd_controller,
      RefreshSuggestionsForField(FocusedFieldType::kFillablePasswordField));
  GetClient()->FocusedInputChanged(driver.get(),
                                   observed_form_data.fields()[0].renderer_id(),
                                   FocusedFieldType::kFillablePasswordField);
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       FocusedInputChangeUpdatesCredManReentryUi) {
  std::unique_ptr<password_manager::ContentPasswordManagerDriver> driver =
      CreateContentPasswordManagerDriver(main_rfh());
  MockPasswordAccessoryControllerImpl* weak_mock_pwd_controller =
      SetUpMockPwdAccessoryForClientUse(driver.get());

  EXPECT_CALL(*weak_mock_pwd_controller, UpdateCredManReentryUi);

  GetClient()->FocusedInputChanged(driver.get(), FieldRendererId(123),
                                   FocusedFieldType::kFillablePasswordField);
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       SameDocumentNavigationDoesNotClearCache) {
  auto origin = url::Origin::Create(GURL("https://example.com"));
  std::vector<PasswordForm> forms = {MakePasswordForm()};
  GetClient()
      ->GetCredentialCacheForTesting()
      ->SaveCredentialsAndBlocklistedForOrigin(
          forms, CredentialCache::IsOriginBlocklisted(false), origin);

  // Check that a navigation within the same document does not clear the cache.
  content::MockNavigationHandle handle(web_contents());
  handle.set_is_same_document(true);
  handle.set_has_committed(true);
  static_cast<content::WebContentsObserver*>(GetClient())
      ->DidFinishNavigation(&handle);

  EXPECT_FALSE(GetClient()
                   ->GetCredentialCacheForTesting()
                   ->GetCredentialStore(origin)
                   .GetCredentials()
                   .empty());

  // Check that a navigation to a different origin clears the cache.
  NavigateAndCommit(GURL("https://example.org"));
  EXPECT_TRUE(GetClient()
                  ->GetCredentialCacheForTesting()
                  ->GetCredentialStore(origin)
                  .GetCredentials()
                  .empty());
}

TEST_F(ChromePasswordManagerClientAndroidTest, HideFillingUIOnNavigatingAway) {
  CreateManualFillingController(web_contents());
  // Navigate to a URL with a bubble/popup.
  GURL kUrl1("https://example.com/");
  NavigateAndCommit(kUrl1);
  EXPECT_TRUE(ChromePasswordManagerClient::CanShowBubbleOnURL(kUrl1));

  // Navigating away should call Hide.
  EXPECT_CALL(*view(), Hide());
  GURL kUrl2("https://accounts.google.com");
  NavigateAndCommit(kUrl2);
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       FormSubmissionTrackingAfterTouchToLogin_NotStarted) {
  // As tracking is not started yet, no metric reports are expected.
  base::HistogramTester uma_recorder;
  GetClient()->NotifyOnSuccessfulLogin(u"username");
  uma_recorder.ExpectTotalCount(
      "PasswordManager.TouchToFill.TimeToSuccessfulLogin", 0);
  uma_recorder.ExpectTotalCount(
      "PasswordManager.TouchToFill.SuccessfulSubmissionWasObserved", 0);
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       FormSubmissionTrackingAfterTouchToLogin_Resetted) {
  // Tracking started, but was reset before a successful login (e.g. a user
  // manually edited a field).
  base::HistogramTester uma_recorder;
  GetClient()->StartSubmissionTrackingAfterTouchToFill(u"username");
  GetClient()->ResetSubmissionTrackingAfterTouchToFill();
  GetClient()->NotifyOnSuccessfulLogin(u"username");
  uma_recorder.ExpectTotalCount(
      "PasswordManager.TouchToFill.TimeToSuccessfulLogin", 0);
  uma_recorder.ExpectUniqueSample(
      "PasswordManager.TouchToFill.SuccessfulSubmissionWasObserved", false, 1);
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       FormSubmissionTrackingAfterTouchToLogin_AnotherUsername) {
  // Tracking started but a successful login was observed for a wrong
  // username.
  base::HistogramTester uma_recorder;
  GetClient()->StartSubmissionTrackingAfterTouchToFill(u"username");
  GetClient()->NotifyOnSuccessfulLogin(u"another_username");
  uma_recorder.ExpectTotalCount(
      "PasswordManager.TouchToFill.TimeToSuccessfulLogin", 0);
  uma_recorder.ExpectUniqueSample(
      "PasswordManager.TouchToFill.SuccessfulSubmissionWasObserved", false, 1);
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       FormSubmissionTrackingAfterTouchToLogin_StaleTracking) {
  // Tracking started too long ago, ignore a successful login.
  base::HistogramTester uma_recorder;
  GetClient()->StartSubmissionTrackingAfterTouchToFill(u"username");
  AdvanceClock(base::Minutes(2));
  GetClient()->NotifyOnSuccessfulLogin(u"username");
  uma_recorder.ExpectTotalCount(
      "PasswordManager.TouchToFill.TimeToSuccessfulLogin", 0);
  uma_recorder.ExpectUniqueSample(
      "PasswordManager.TouchToFill.SuccessfulSubmissionWasObserved", false, 1);
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       FormSubmissionTrackingAfterTouchToLogin_Succeeded) {
  // Tracking started and a successful login was observed for the correct
  // username recently, expect a metric report.
  base::HistogramTester uma_recorder;
  GetClient()->StartSubmissionTrackingAfterTouchToFill(u"username");
  GetClient()->NotifyOnSuccessfulLogin(u"username");
  uma_recorder.ExpectTotalCount(
      "PasswordManager.TouchToFill.TimeToSuccessfulLogin", 1);
  uma_recorder.ExpectUniqueSample(
      "PasswordManager.TouchToFill.SuccessfulSubmissionWasObserved", true, 1);
  // Should be reported only once.
  GetClient()->NotifyOnSuccessfulLogin(u"username");
  uma_recorder.ExpectTotalCount(
      "PasswordManager.TouchToFill.TimeToSuccessfulLogin", 1);
  uma_recorder.ExpectUniqueSample(
      "PasswordManager.TouchToFill.SuccessfulSubmissionWasObserved", true, 1);
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       RefreshPasswordManagerSettingsIfNeededUPMFeatureEnabled) {
  EXPECT_CALL(settings_service(), RequestSettingsFromBackend);
  GetClient()->RefreshPasswordManagerSettingsIfNeeded();
}

class ChromePasswordManagerClientWithAccountStoreAndroidTest
    : public ChromePasswordManagerClientAndroidTest {
  void SetUp() override {
    // Override the GMS version to be big enough for local UPM support, so these
    // tests still pass in bots with an outdated version.
    base::android::BuildInfo::GetInstance()->set_gms_version_code_for_test(
        base::NumberToString(password_manager::GetLocalUpmMinGmsVersion()));

    ChromePasswordManagerClientAndroidTest::SetUp();

    AccountPasswordStoreFactory::GetInstance()->SetTestingFactory(
        GetBrowserContext(),
        base::BindRepeating(
            &password_manager::BuildPasswordStoreInterface<
                content::BrowserContext, MockPasswordStoreInterface>));
  }
};

TEST_F(ChromePasswordManagerClientWithAccountStoreAndroidTest,
       MarkSharedCredentialsAsNotified) {
  GURL kURL = GURL("https://example.com");
  auto origin = url::Origin::Create(kURL);
  auto not_shared = MakePasswordForm();
  not_shared.username_value = u"not_shared";

  auto shared_and_notified = MakePasswordForm();
  shared_and_notified.username_value = u"shared_and_notified";
  shared_and_notified.type = PasswordForm::Type::kReceivedViaSharing;
  shared_and_notified.sharing_notification_displayed = true;

  auto shared_not_notified_profile = MakePasswordForm();
  shared_not_notified_profile.username_value = u"shared_not_notified_profile";
  shared_not_notified_profile.type = PasswordForm::Type::kReceivedViaSharing;
  shared_not_notified_profile.sharing_notification_displayed = false;
  shared_not_notified_profile.in_store = PasswordForm::Store::kProfileStore;

  auto shared_not_notified_account = MakePasswordForm();
  shared_not_notified_account.username_value = u"shared_not_notified_account";
  shared_not_notified_account.type = PasswordForm::Type::kReceivedViaSharing;
  shared_not_notified_account.sharing_notification_displayed = false;
  shared_not_notified_account.in_store = PasswordForm::Store::kAccountStore;

  std::vector<PasswordForm> forms = {not_shared, shared_and_notified,
                                     shared_not_notified_profile,
                                     shared_not_notified_account};
  GetClient()
      ->GetCredentialCacheForTesting()
      ->SaveCredentialsAndBlocklistedForOrigin(
          forms, CredentialCache::IsOriginBlocklisted(false), origin);

  MockPasswordStoreInterface* profile_store =
      static_cast<MockPasswordStoreInterface*>(
          GetClient()->GetProfilePasswordStore());

  MockPasswordStoreInterface* account_store =
      static_cast<MockPasswordStoreInterface*>(
          GetClient()->GetAccountPasswordStore());

  shared_not_notified_profile.sharing_notification_displayed = true;
  shared_not_notified_account.sharing_notification_displayed = true;
  EXPECT_CALL(*profile_store, UpdateLogin(shared_not_notified_profile, _));
  EXPECT_CALL(*account_store, UpdateLogin(shared_not_notified_account, _));
  GetClient()->MarkSharedCredentialsAsNotified(kURL);
}

#endif  //  BUILDFLAG(IS_ANDROID)

#if !BUILDFLAG(IS_ANDROID)

class MockPasswordCrossDomainConfirmationPopupController
    : public password_manager::PasswordCrossDomainConfirmationPopupController {};

TEST_F(ChromePasswordManagerClientTest, ShowCrossDomainConfirmationPopup) {}

#endif  //  !BUILDFLAG(IS_ANDROID)