// 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 <algorithm>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "base/android/device_info.h"
#include "base/command_line.h"
#include "base/containers/span.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/json/json_reader.h"
#include "base/memory/raw_ptr.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/critical_actions/critical_action_factory.h"
#include "chrome/browser/keyboard_accessory/test_utils/android/mock_address_accessory_controller.h"
#include "chrome/browser/keyboard_accessory/test_utils/android/mock_at_memory_accessory_controller.h"
#include "chrome/browser/password_manager/chrome_password_change_service.h"
#include "chrome/browser/password_manager/factories/password_manager_settings_service_factory.h"
#include "chrome/browser/password_manager/factories/profile_password_store_factory.h"
#include "chrome/browser/password_manager/password_change_delegate_mock.h"
#include "chrome/browser/password_manager/password_change_service_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/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/foundations/test_autofill_manager_waiter.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_utils/autofill_test_utils.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/critical_actions/core/browser/critical_action_service.h"
#include "components/critical_actions/core/browser/critical_action_types.h"
#include "components/device_reauth/device_authenticator.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/features/password_features.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_form_converters.h"
#include "components/password_manager/core/browser/password_store/password_store_consumer.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_service.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_controller.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/prerender_test_util.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/origin.h"
#include "url/url_constants.h"

#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
#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/i18n/rtl.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/android/grouped_affiliations/acknowledge_grouped_credential_sheet_controller_test_helper.h"
#include "chrome/browser/password_manager/android/password_generation_controller.h"
#include "chrome/browser/password_manager/chrome_webauthn_credentials_delegate.h"
#include "chrome/browser/password_manager/chrome_webauthn_credentials_delegate_factory.h"
#include "chrome/browser/password_manager/factories/account_password_store_factory.h"
#include "chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_controller.h"
#include "chrome/browser/touch_to_fill/password_manager/touch_to_fill_password_manager_delegate.h"
#include "components/password_manager/content/browser/mock_keyboard_replacing_surface_visibility_controller.h"
#include "components/password_manager/core/browser/passkey_credential.h"
#include "components/webauthn/android/cred_man_support.h"
#include "components/webauthn/android/webauthn_cred_man_delegate.h"
#else
#include "chrome/browser/ui/hats/hats_service_factory.h"
#include "chrome/browser/ui/hats/mock_hats_service.h"
#include "chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_view.h"
#endif  // BUILDFLAG(IS_ANDROID)

using ::autofill::CalculateFormSignature;
using ::autofill::ContentAutofillClient;
using ::autofill::ContentAutofillDriver;
using ::autofill::FieldRendererId;
using ::autofill::FormControlType;
using ::autofill::FormData;
using ::autofill::FormFieldData;
using ::autofill::mojom::FocusedFieldType;
using ::autofill::test::CreateFormDataForRenderFrameHost;
using ::autofill::test::CreateTestFormField;
using ::content::BrowserContext;
using ::content::WebContents;
using ::password_manager::ContentPasswordManagerDriver;
using ::password_manager::PasswordForm;
using ::password_manager::PasswordManagerClient;
using ::password_manager::PasswordManagerSetting;
using ::password_manager::PasswordStoreConsumer;
using ::sessions::GetPasswordStateFromNavigation;
using ::sessions::SerializedNavigationEntry;
using ::testing::_;
using ::testing::Eq;
using ::testing::Key;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::StrictMock;
using ::testing::UnorderedElementsAre;

#if BUILDFLAG(IS_ANDROID)
using ::device_reauth::BiometricStatus;
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 {
 public:
  static MockChromePasswordManagerClient* CreateForWebContentsAndGet(
      content::WebContents* contents) {
    auto* client = new MockChromePasswordManagerClient(contents);
    contents->SetUserData(UserDataKey(), base::WrapUnique(client));
    return client;
  }

  MOCK_METHOD(net::CertStatus, GetMainFrameCertStatus, (), (const override));

  MockChromePasswordManagerClient(const MockChromePasswordManagerClient&) =
      delete;
  MockChromePasswordManagerClient& operator=(
      const MockChromePasswordManagerClient&) = delete;

#if BUILDFLAG(FULL_SAFE_BROWSING)
  safe_browsing::PasswordProtectionService* GetPasswordProtectionService()
      const override {
    return password_protection_service_.get();
  }

  safe_browsing::MockPasswordProtectionService* password_protection_service() {
    return password_protection_service_.get();
  }
#endif

 private:
  explicit MockChromePasswordManagerClient(content::WebContents* web_contents)
      : ChromePasswordManagerClient(web_contents) {
#if BUILDFLAG(FULL_SAFE_BROWSING)
    password_protection_service_ =
        std::make_unique<safe_browsing::MockPasswordProtectionService>();
#endif
  }

#if BUILDFLAG(FULL_SAFE_BROWSING)
  std::unique_ptr<safe_browsing::MockPasswordProtectionService>
      password_protection_service_;
#endif
};

class DummyLogReceiver : public autofill::LogReceiver {
 public:
  DummyLogReceiver() = default;

  DummyLogReceiver(const DummyLogReceiver&) = delete;
  DummyLogReceiver& operator=(const DummyLogReceiver&) = delete;

  void LogEntry(const base::DictValue& entry) override {}
};

class FakePasswordAutofillAgent
    : public autofill::mojom::PasswordAutofillAgent {
 public:
  void BindReceiver(mojo::ScopedInterfaceEndpointHandle handle) {
    receiver_.Bind(
        mojo::PendingAssociatedReceiver<autofill::mojom::PasswordAutofillAgent>(
            std::move(handle)));
  }

  bool called_set_logging_state() { return called_set_logging_state_; }

  bool logging_state_active() { return logging_state_active_; }

  void reset_data() {
    called_set_logging_state_ = false;
    logging_state_active_ = false;
  }

 private:
  // autofill::mojom::PasswordAutofillAgent:
  void ApplyFillDataOnParsingCompletion(
      const autofill::PasswordFormFillData& form_data) override {}

  void FillPasswordSuggestion(
      const std::u16string& username,
      const std::u16string& password,
      base::OnceCallback<void(bool)> success_callback) override {}

  void FillPasswordSuggestionById(
      autofill::FieldRendererId username_element_id,
      autofill::FieldRendererId password_element_id,
      const std::u16string& username,
      const std::u16string& password,
      autofill::AutofillSuggestionTriggerSource suggestion_source) override {}

  void PreviewPasswordSuggestionById(
      autofill::FieldRendererId username_element_id,
      autofill::FieldRendererId password_element_id,
      const std::u16string& username,
      const std::u16string& password) override {}

  void InformNoSavedCredentials(
      bool should_show_popup_without_passwords) override {}

  void FillIntoFocusedField(bool is_password,
                            const std::u16string& credential) override {}
  void PreviewField(autofill::FieldRendererId field_id,
                    const std::u16string& value) override {}
  void FillField(autofill::FieldRendererId field_id,
                 const std::u16string& value,
                 autofill::FieldPropertiesMask field_properties,
                 base::OnceCallback<void(bool)> success_callback) override {}
  void FillChangePasswordForm(
      FieldRendererId password_element_id,
      FieldRendererId new_password_element_id,
      FieldRendererId confirm_password_element_id,
      const std::u16string& old_password,
      const std::u16string& new_password,
      FillChangePasswordFormCallback callback) override {}
  void AnnotateFieldsWithParsingResult(
      const autofill::ParsingResult& parsing_result) override {}
  void CheckViewAreaVisible(FieldRendererId field_id,
                            CheckViewAreaVisibleCallback callback) override {}
  void SetLoggingState(bool active) override {
    called_set_logging_state_ = true;
    logging_state_active_ = active;
  }

#if BUILDFLAG(IS_ANDROID)
  void TriggerFormSubmission() override {}
#endif

  // Records whether SetLoggingState() gets called.
  bool called_set_logging_state_ = false;
  // Records data received via SetLoggingState() call.
  bool logging_state_active_ = false;

  mojo::AssociatedReceiver<autofill::mojom::PasswordAutofillAgent> receiver_{
      this};
};

#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,
            /*grouped_credential_sheet_controller=*/nullptr,
            /*password_manager_error_message_helper_bridge=*/nullptr) {}

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

#endif

class MockPasswordChangeService : public ChromePasswordChangeService {
 public:
  MockPasswordChangeService()
      : ChromePasswordChangeService(/*pref_service*/ nullptr,
                                    /*affiliation_service=*/nullptr,
                                    /*optimization_keyed_service=*/nullptr,
                                    /*settings_service=*/nullptr,
                                    /*feature_manager=*/nullptr,
                                    /*log_router*/ nullptr) {}

  MOCK_METHOD(void,
              OfferPasswordChangeUi,
              (password_manager::PasswordForm, content::WebContents*),
              (override));
  MOCK_METHOD(PasswordChangeDelegate*,
              GetPasswordChangeDelegate,
              (content::WebContents*),
              (override));
};

std::unique_ptr<KeyedService> CreateTestSyncService(
    content::BrowserContext* context) {
  return std::make_unique<syncer::TestSyncService>();
}

std::unique_ptr<KeyedService> CreateMockPasswordChangeService(
    content::BrowserContext* context) {
  return std::make_unique<MockPasswordChangeService>();
}

#if BUILDFLAG(IS_ANDROID)
class MockTouchToFillPasswordManagerController
    : public TouchToFillPasswordManagerController {
 public:
  MockTouchToFillPasswordManagerController(
      Profile* profile,
      base::WeakPtr<
          password_manager::KeyboardReplacingSurfaceVisibilityController>
          visibility_controller)
      : TouchToFillPasswordManagerController(profile,
                                             visibility_controller,
                                             nullptr) {}

  MOCK_METHOD(void,
              InitData,
              (std::vector<TouchToFillPasswordManagerView::Credential>,
               base::WeakPtr<password_manager::ContentPasswordManagerDriver>),
              (override));

  MOCK_METHOD(bool,
              Show,
              (std::unique_ptr<TouchToFillPasswordManagerDelegate>,
               webauthn::WebAuthnCredManDelegate*),
              (override));
};
#endif  // BUILDFLAG_IS_ANDROID)

class MockCriticalActionService
    : public critical_actions::CriticalActionService {
 public:
  MockCriticalActionService(
      const base::FilePath& db_path,
      scoped_refptr<base::SequencedTaskRunner> backend_task_runner)
      : critical_actions::CriticalActionService(db_path, backend_task_runner) {}
  ~MockCriticalActionService() override = default;

  MOCK_METHOD(void,
              AddCriticalAction,
              (const critical_actions::CriticalActionEntry& entry),
              (override));
  MOCK_METHOD(void,
              AddCriticalActionWithNavigationId,
              (const critical_actions::CriticalActionEntry& entry,
               int64_t navigation_id),
              (override));
  MOCK_METHOD(void, OnNavigationDiscarded, (int64_t navigation_id), (override));
};

}  // namespace

class ChromePasswordManagerClientTest : public ChromeRenderViewHostTestHarness {
 public:
  ChromePasswordManagerClientTest()
      : ChromeRenderViewHostTestHarness(
            base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
    scoped_feature_list_.InitAndEnableFeature(safe_browsing::kDelayedWarnings);
  }
  ~ChromePasswordManagerClientTest() override = default;

  void SetUp() override;
  void TearDown() override;

  void SetupBasicTestSync() {
    SyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
        profile(), base::BindRepeating(&CreateTestSyncService));
  }

  void SetupSettingsServiceFactory() {
    PasswordManagerSettingsServiceFactory::GetInstance()->SetTestingFactory(
        profile(), base::BindRepeating([](content::BrowserContext* context)
                                           -> std::unique_ptr<KeyedService> {
          return std::make_unique<
              NiceMock<password_manager::MockPasswordManagerSettingsService>>();
        }));
  }

  void SetupMockPasswordChangeService() {
    PasswordChangeServiceFactory::GetInstance()->SetTestingFactoryAndUse(
        profile(), base::BindRepeating(&CreateMockPasswordChangeService));
  }

 protected:
  ChromePasswordManagerClient* GetClient();

  std::unique_ptr<password_manager::ContentPasswordManagerDriver>
  CreateContentPasswordManagerDriver(content::RenderFrameHost* rfh);

  password_manager::MockPasswordManagerSettingsService& settings_service() {
    return static_cast<password_manager::MockPasswordManagerSettingsService&>(
        *PasswordManagerSettingsServiceFactory::GetForProfile(profile()));
  }
  syncer::TestSyncService* sync_service() {
    return static_cast<syncer::TestSyncService*>(
        SyncServiceFactory::GetInstance()->GetForProfile(profile()));
  }
  MockPasswordChangeService* password_change_service() {
    return static_cast<MockPasswordChangeService*>(
        PasswordChangeServiceFactory::GetInstance()->GetForProfile(profile()));
  }

  // If autofill::mojom::PasswordAutofillAgent::SetLoggingState() got called,
  // copies its argument into `activation_flag` and returns true. Otherwise
  // returns false.
  bool WasLoggingActivationMessageSent(bool* activation_flag);

  FormData CreateLoginFormData();
  FormData CreateLoginFormDataForFrame(content::RenderFrameHost* rfh);

  FakePasswordAutofillAgent fake_agent_;

 private:
  autofill::test::AutofillUnitTestEnvironment autofill_environment_{
      {.disable_server_communication = true}};
  base::test::ScopedFeatureList scoped_feature_list_;
#if BUILDFLAG(IS_ANDROID)
  std::unique_ptr<ui::WindowAndroid::ScopedWindowAndroidForTesting>
      window_android_ = ui::WindowAndroid::CreateForTesting();
#endif  // BUILDFLAG(IS_ANDROID)
};

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

#if BUILDFLAG(IS_ANDROID)
  window_android_.get()->get()->AddChild(web_contents()->GetNativeView());
#endif  // BUILDFLAG(IS_ANDROID)
  ProfilePasswordStoreFactory::GetInstance()->SetTestingFactory(
      GetBrowserContext(),
      base::BindRepeating(&password_manager::BuildPasswordStoreInterface<
                          content::BrowserContext,
                          password_manager::MockPasswordStoreInterface>));

  blink::AssociatedInterfaceProvider* remote_interfaces =
      web_contents()->GetPrimaryMainFrame()->GetRemoteAssociatedInterfaces();
  remote_interfaces->OverrideBinderForTesting(
      autofill::mojom::PasswordAutofillAgent::Name_,
      base::BindRepeating(&FakePasswordAutofillAgent::BindReceiver,
                          base::Unretained(&fake_agent_)));

  // In order for the `PasswordFeatureManager` to be initialized correctly
  // the testing sync service must be set up before the client.
  SetupBasicTestSync();
  // `ChromePasswordManagerClient` observes `AutofillManager`s, so
  // `ChromeAutofillClient` needs to be set up, too.
  autofill::ChromeAutofillClient::CreateForWebContents(web_contents());
  ChromePasswordManagerClient::CreateForWebContents(web_contents());

  SetupSettingsServiceFactory();
  SetupMockPasswordChangeService();
}

void ChromePasswordManagerClientTest::TearDown() {
  ChromeRenderViewHostTestHarness::TearDown();
}

ChromePasswordManagerClient* ChromePasswordManagerClientTest::GetClient() {
  return ChromePasswordManagerClient::FromWebContents(web_contents());
}

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

bool ChromePasswordManagerClientTest::WasLoggingActivationMessageSent(
    bool* activation_flag) {
  base::RunLoop().RunUntilIdle();
  if (!fake_agent_.called_set_logging_state()) {
    return false;
  }

  if (activation_flag) {
    *activation_flag = fake_agent_.logging_state_active();
  }
  fake_agent_.reset_data();
  return true;
}

FormData ChromePasswordManagerClientTest::CreateLoginFormData() {
  return CreateLoginFormDataForFrame(main_rfh());
}

FormData ChromePasswordManagerClientTest::CreateLoginFormDataForFrame(
    content::RenderFrameHost* rfh) {
  FormData form = CreateFormDataForRenderFrameHost(
      *rfh, {CreateTestFormField("Username", "username", "",
                                 FormControlType::kInputText),
             CreateTestFormField("Password", "password", "",
                                 FormControlType::kInputPassword)});
  form.set_name(u"login");
  return form;
}

TEST_F(ChromePasswordManagerClientTest, LogEntryNotifyRenderer) {
  bool logging_active = true;
  // Ensure the existence of a driver, which will send the IPCs we listen for
  // below.
  NavigateAndCommit(GURL("about:blank"));

  // Initially, the logging should be off, so no IPC messages.
  EXPECT_TRUE(!WasLoggingActivationMessageSent(&logging_active) ||
              !logging_active)
      << "logging_active=" << logging_active;

  DummyLogReceiver log_receiver;
  autofill::LogRouter* log_router =
      password_manager::PasswordManagerLogRouterFactory::GetForBrowserContext(
          profile());
  log_router->RegisterReceiver(&log_receiver);

  // Now that the log router has a receiver, create the log manager, which
  // should notify upon construction that logging is now available.
  autofill::LogManager* log_manager = GetClient()->GetCurrentLogManager();
  EXPECT_TRUE(log_manager && log_manager->IsLoggingActive());

  EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active));
  EXPECT_TRUE(logging_active);

  log_router->UnregisterReceiver(&log_receiver);
  EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active));
  EXPECT_FALSE(logging_active);
}

TEST_F(ChromePasswordManagerClientTest,
       SavingPasswordsTrueDeterminedByService) {
  // Test that saving passwords depends on querying the settings service.
  ChromePasswordManagerClient* client = GetClient();
  ON_CALL(settings_service(),
          IsSettingEnabled(PasswordManagerSetting::kOfferToSavePasswords))
      .WillByDefault(Return(true));
  const GURL kUrlOn("https://accounts.google.com");
  EXPECT_TRUE(client->IsSavingAndFillingEnabled(url::Origin::Create(kUrlOn)));
}

TEST_F(ChromePasswordManagerClientTest,
       SavingPasswordsFalseDeterminedByService) {
  // Test that saving passwords depends on querying the settings service.
  ChromePasswordManagerClient* client = GetClient();
  EXPECT_CALL(settings_service(),
              IsSettingEnabled(PasswordManagerSetting::kOfferToSavePasswords))
      .WillOnce(Return(false));
  const GURL kUrlOn("https://accounts.google.com");
  EXPECT_FALSE(client->IsSavingAndFillingEnabled(url::Origin::Create(kUrlOn)));
}

TEST_F(ChromePasswordManagerClientTest, SavingAndFillingEnabledConditionsTest) {
  std::unique_ptr<WebContents> test_web_contents(
      content::WebContentsTester::CreateTestWebContents(
          web_contents()->GetBrowserContext(), nullptr));
  autofill::ChromeAutofillClient::CreateForWebContents(test_web_contents.get());
  MockChromePasswordManagerClient* client =
      MockChromePasswordManagerClient::CreateForWebContentsAndGet(
          test_web_contents.get());
  ON_CALL(*client, GetMainFrameCertStatus()).WillByDefault(Return(0));
  // Functionality disabled if there is an SSL error.
  EXPECT_CALL(*client, GetMainFrameCertStatus())
      .WillRepeatedly(Return(net::CERT_STATUS_AUTHORITY_INVALID));
  const GURL kUrlOn("https://accounts.google.com");
  EXPECT_FALSE(client->IsSavingAndFillingEnabled(url::Origin::Create(kUrlOn)));
  EXPECT_FALSE(client->IsFillingEnabled(url::Origin::Create(kUrlOn)));

  // Disable password saving.
  ON_CALL(settings_service(),
          IsSettingEnabled(PasswordManagerSetting::kOfferToSavePasswords))
      .WillByDefault(Return(false));

  // Functionality disabled if there are SSL errors and the manager itself is
  // disabled.
  EXPECT_FALSE(client->IsSavingAndFillingEnabled(url::Origin::Create(kUrlOn)));
  EXPECT_FALSE(client->IsFillingEnabled(url::Origin::Create(kUrlOn)));

  // Saving disabled if there are no SSL errors, but the manager itself is
  // disabled.
  EXPECT_CALL(*client, GetMainFrameCertStatus()).WillRepeatedly(Return(0));
  EXPECT_FALSE(client->IsSavingAndFillingEnabled(url::Origin::Create(kUrlOn)));
  EXPECT_TRUE(client->IsFillingEnabled(url::Origin::Create(kUrlOn)));

  // Enable password saving.
  ON_CALL(settings_service(),
          IsSettingEnabled(PasswordManagerSetting::kOfferToSavePasswords))
      .WillByDefault(Return(true));

  // Functionality enabled if there are no SSL errors and the manager is
  // enabled.
  EXPECT_CALL(*client, GetMainFrameCertStatus()).WillRepeatedly(Return(0));
  EXPECT_TRUE(client->IsSavingAndFillingEnabled(url::Origin::Create(kUrlOn)));
  EXPECT_TRUE(client->IsFillingEnabled(url::Origin::Create(kUrlOn)));
}

TEST_F(ChromePasswordManagerClientTest,
       SavingAndFillingDisabledConditionsInGuestAndIncognitoProfiles) {
  ON_CALL(settings_service(),
          IsSettingEnabled(PasswordManagerSetting::kOfferToSavePasswords))
      .WillByDefault(Return(true));
  std::unique_ptr<WebContents> incognito_web_contents(
      content::WebContentsTester::CreateTestWebContents(
          profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true), nullptr));
  autofill::ChromeAutofillClient::CreateForWebContents(
      incognito_web_contents.get());
  MockChromePasswordManagerClient* client =
      MockChromePasswordManagerClient::CreateForWebContentsAndGet(
          incognito_web_contents.get());
  EXPECT_CALL(*client, GetMainFrameCertStatus()).WillRepeatedly(Return(0));

  // Saving disabled in Incognito mode.
  const GURL kUrlOn("https://accounts.google.com");
  EXPECT_FALSE(client->IsSavingAndFillingEnabled(url::Origin::Create(kUrlOn)));
  EXPECT_TRUE(client->IsFillingEnabled(url::Origin::Create(kUrlOn)));

  // In guest mode saving, filling and manual filling are disabled.
  profile()->SetGuestSession(true);
  profile()
      ->GetPrimaryOTRProfile(/*create_if_needed=*/true)
      ->AsTestingProfile()
      ->SetGuestSession(true);
  EXPECT_FALSE(client->IsSavingAndFillingEnabled(url::Origin::Create(kUrlOn)));
  EXPECT_FALSE(client->IsFillingEnabled(url::Origin::Create(kUrlOn)));
}

TEST_F(ChromePasswordManagerClientTest, OnFedCmFederatedLogin) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(
      password_manager::features::kPreventPasswordManagerOnFederatedLogin);

  base::HistogramTester histogram_tester;

  // Call with success = false. Should not record histogram.
  static_cast<content::WebContentsObserver*>(GetClient())
      ->OnFedCmFederatedLogin(false);
  histogram_tester.ExpectTotalCount(
      "PasswordManager.FederatedLogin.SavePromptPrevented", 0);

  // Call with success = true. Should record histogram (false because no
  // submitted manager).
  static_cast<content::WebContentsObserver*>(GetClient())
      ->OnFedCmFederatedLogin(true);
  histogram_tester.ExpectUniqueSample(
      "PasswordManager.FederatedLogin.SavePromptPrevented", false, 1);
}

TEST_F(ChromePasswordManagerClientTest, OnNonPasswordLoginDetectedDelegation) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(
      password_manager::features::kPreventPasswordManagerOnFederatedLogin);

  base::HistogramTester histogram_tester;

  // Create a popup WebContents.
  std::unique_ptr<content::WebContents> popup_web_contents(
      content::WebContentsTester::CreateTestWebContents(
          web_contents()->GetBrowserContext(), nullptr));
  autofill::ChromeAutofillClient::CreateForWebContents(
      popup_web_contents.get());
  ChromePasswordManagerClient::CreateForWebContents(popup_web_contents.get());
  ChromePasswordManagerClient* popup_client =
      ChromePasswordManagerClient::FromWebContents(popup_web_contents.get());

  // Set the main WebContents as the opener of the popup.
  content::WebContentsTester::For(popup_web_contents.get())
      ->SetOpener(web_contents());

  // Trigger non-password login detection on the popup.
  popup_client->OnNonFedCmFederatedLogin();

  // The notification should have been delegated to the main WebContents'
  // PasswordManager, which records the histogram.
  histogram_tester.ExpectUniqueSample(
      "PasswordManager.FederatedLogin.SavePromptPrevented", false, 1);
}

TEST_F(ChromePasswordManagerClientTest, OnNonPasswordLoginDetectedOpenerCycle) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndEnableFeature(
      password_manager::features::kPreventPasswordManagerOnFederatedLogin);

  base::HistogramTester histogram_tester;

  // Create two WebContents.
  std::unique_ptr<content::WebContents> web_contents_a(
      content::WebContentsTester::CreateTestWebContents(
          web_contents()->GetBrowserContext(), nullptr));
  autofill::ChromeAutofillClient::CreateForWebContents(web_contents_a.get());
  ChromePasswordManagerClient::CreateForWebContents(web_contents_a.get());
  ChromePasswordManagerClient* client_a =
      ChromePasswordManagerClient::FromWebContents(web_contents_a.get());

  std::unique_ptr<content::WebContents> web_contents_b(
      content::WebContentsTester::CreateTestWebContents(
          web_contents()->GetBrowserContext(), nullptr));
  autofill::ChromeAutofillClient::CreateForWebContents(web_contents_b.get());
  ChromePasswordManagerClient::CreateForWebContents(web_contents_b.get());

  // Set up a cycle in the opener relationship: A -> B -> A.
  content::WebContentsTester::For(web_contents_a.get())
      ->SetOpener(web_contents_b.get());
  content::WebContentsTester::For(web_contents_b.get())
      ->SetOpener(web_contents_a.get());

  // Trigger non-password login detection on A.
  // With the recursion removed, this will directly invoke the PasswordManager
  // on B and return immediately, without causing infinite recursion or hanging.
  client_a->OnNonFedCmFederatedLogin();

  // B's PasswordManager should have handled the notification and recorded the
  // histogram. A's PasswordManager is not called.
  histogram_tester.ExpectUniqueSample(
      "PasswordManager.FederatedLogin.SavePromptPrevented", false, 1);
}

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
    BUILDFLAG(IS_CHROMEOS)
// Test for the PasswordManagerBlocklist policy.
TEST_F(ChromePasswordManagerClientTest, PasswordManagerBlocklistPolicy) {
  // Make sure saving passwords is enabled.
  ON_CALL(settings_service(),
          IsSettingEnabled(PasswordManagerSetting::kOfferToSavePasswords))
      .WillByDefault(Return(true));
  // Check that the blocklist is initially empty.
  EXPECT_TRUE(profile()
                  ->GetTestingPrefService()
                  ->GetList(password_manager::prefs::kPasswordManagerBlocklist)
                  .empty());
  // Add a URL to the blocklist.
  {
    base::ListValue blocked_list;
    blocked_list.Append("https://example.com");
    profile()->GetTestingPrefService()->SetList(
        password_manager::prefs::kPasswordManagerBlocklist,
        std::move(blocked_list));
  }

  // Verify the URL was added.
  EXPECT_FALSE(profile()
                   ->GetTestingPrefService()
                   ->GetList(password_manager::prefs::kPasswordManagerBlocklist)
                   .empty());
  // Expect the password manager to be disallowed for the URL
  // and thus saving passwords should be disallowed.
  EXPECT_FALSE(GetClient()->IsSavingAndFillingEnabled(
      url::Origin::Create(GURL("https://example.com"))));
  // Clear the blocklist pref.
  profile()->GetTestingPrefService()->ClearPref(
      password_manager::prefs::kPasswordManagerBlocklist);
  // Verify blocklist is empty.
  EXPECT_TRUE(profile()
                  ->GetTestingPrefService()
                  ->GetList(password_manager::prefs::kPasswordManagerBlocklist)
                  .empty());
  // Password manager and saving passwords should be allowed again
  EXPECT_TRUE(GetClient()->IsSavingAndFillingEnabled(
      url::Origin::Create(GURL("https://example.com"))));
}
#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
        // BUILDFLAG(IS_CHROMEOS)

TEST_F(ChromePasswordManagerClientTest,
       PasswordManagerReceivesAutofillPredictions) {
  constexpr char kUrl[] = "https://www.foo.com/login.html";

  NavigateAndCommit(GURL(kUrl));
  ContentAutofillDriver* autofill_driver =
      ContentAutofillDriver::GetForRenderFrameHost(main_rfh());
  ASSERT_TRUE(autofill_driver);

  FormData form = CreateLoginFormData();
  {
    autofill::TestAutofillManagerWaiter waiter(
        autofill_driver->GetAutofillManager(),
        {autofill::AutofillManagerEvent::kFormsSeen});
    autofill_driver->renderer_events().FormsSeen(/*updated_forms=*/{form},
                                                 /*removed_forms=*/{});
    ASSERT_TRUE(waiter.Wait(/*num_expected_relevant_events=*/1));
  }

  // Simulate that the field types have been determined, since server
  // communication is turned off.
  using Observer = autofill::AutofillManager::Observer;
  autofill_driver->GetAutofillManager().NotifyObservers(
      &Observer::OnFieldTypesDetermined, form.global_id(),
      Observer::FieldTypeSource::kAutofillServer,
      /*small_forms_were_parsed=*/false);

  ContentPasswordManagerDriver* password_driver =
      ContentPasswordManagerDriver::GetForRenderFrameHost(main_rfh());
  password_manager::DriverId driver_id = password_driver->GetId();

  EXPECT_THAT(static_cast<const password_manager::PasswordManager*>(
                  GetClient()->GetPasswordManager())
                  ->GetServerPredictionsForTesting(),
              UnorderedElementsAre(
                  Key(testing::Pair(CalculateFormSignature(form), driver_id))));
}

TEST_F(ChromePasswordManagerClientTest,
       PasswordManagerReceivesPasswordFormClassifierPredictions) {
  base::test::ScopedFeatureList features;
  features.InitWithFeatures(
      {password_manager::features::kPasswordFormClientsideClassifier,
       password_manager::features::
           kApplyClientsideModelPredictionsForPasswordTypes},
      /*disabled_features=*/{});
  constexpr char kUrl[] = "https://www.foo.com/login.html";

  NavigateAndCommit(GURL(kUrl));
  ContentAutofillDriver* autofill_driver =
      ContentAutofillDriver::GetForRenderFrameHost(main_rfh());
  ASSERT_TRUE(autofill_driver);

  ContentPasswordManagerDriver* password_driver =
      ContentPasswordManagerDriver::GetForRenderFrameHost(main_rfh());
  ASSERT_TRUE(password_driver);

  FormData form = CreateLoginFormData();
  {
    autofill::TestAutofillManagerWaiter waiter(
        autofill_driver->GetAutofillManager(),
        {autofill::AutofillManagerEvent::kFormsSeen});
    autofill_driver->renderer_events().FormsSeen(/*updated_forms=*/{form},
                                                 /*removed_forms=*/{});
    ASSERT_TRUE(waiter.Wait(/*num_expected_relevant_events=*/1));
  }

  // Simulate that the field types have been determined.
  using Observer = autofill::AutofillManager::Observer;
  autofill_driver->GetAutofillManager().NotifyObservers(
      &Observer::OnFieldTypesDetermined, form.global_id(),
      Observer::FieldTypeSource::kHeuristicsOrAutocomplete,
      /*small_forms_were_parsed=*/false);

  auto received_predictions =
      static_cast<const password_manager::PasswordManager*>(
          GetClient()->GetPasswordManager())
          ->GetClassifierModelPredictionsForTesting();
  // Check that predictions are available for the form.
  auto form_key = std::make_pair(password_driver, form.renderer_id());
  ASSERT_THAT(received_predictions, UnorderedElementsAre(Key(form_key)));
  // Check that predictions are available for all form fields.
  EXPECT_THAT(received_predictions[form_key],
              UnorderedElementsAre(Key(form.fields()[0].renderer_id()),
                                   Key(form.fields()[1].renderer_id())));
}

TEST_F(ChromePasswordManagerClientTest,
       PasswordManagerReceivesAutofillPredictionsFromMultipleFrames) {
  constexpr char kUrl1[] = "https://www.foo.com/login.html";
  constexpr char kUrl2[] = "https://www.foo.com/otp.html";

  NavigateAndCommit(GURL(kUrl1));
  content::RenderFrameHost* child_rfh =
      content::RenderFrameHostTester::For(main_rfh())
          ->AppendChild(std::string("child"));
  child_rfh = content::NavigationSimulator::NavigateAndCommitFromDocument(
      GURL(kUrl2), child_rfh);
  ContentAutofillClient* autofill_client =
      ContentAutofillClient::FromWebContents(web_contents());
  ASSERT_TRUE(autofill_client);
  ContentAutofillDriver* main_driver =
      ContentAutofillDriver::GetForRenderFrameHost(main_rfh());
  ContentAutofillDriver* child_driver =
      ContentAutofillDriver::GetForRenderFrameHost(child_rfh);
  ASSERT_TRUE(main_driver);
  ASSERT_TRUE(child_driver);

  FormData main_form = CreateFormDataForRenderFrameHost(
      *main_rfh(), {CreateTestFormField("Username", "username", "",
                                        FormControlType::kInputText),
                    CreateTestFormField("Password", "password", "",
                                        FormControlType::kInputPassword)});
  FormData child_form = CreateFormDataForRenderFrameHost(
      *child_rfh,
      {CreateTestFormField("OTP", "OTP", "", FormControlType::kInputText)});

  // Ensure that the child frame is picked up as a child frame of `main_form`.
  {
    autofill::FrameTokenWithPredecessor child_frame_information;
    child_frame_information.token = child_form.host_frame();
    main_form.set_child_frames({child_frame_information});
  }

  {
    autofill::TestAutofillManagerWaiter waiter(
        main_driver->GetAutofillManager(),
        {autofill::AutofillManagerEvent::kFormsSeen});
    main_driver->renderer_events().FormsSeen(/*updated_forms=*/{main_form},
                                             /*removed_forms=*/{});
    child_driver->renderer_events().FormsSeen(/*updated_forms=*/{child_form},
                                              /*removed_forms=*/{});
    ASSERT_TRUE(waiter.Wait(/*num_expected_relevant_events=*/2));
  }

  // Simulate that the field types have been determined, since server
  // communication is turned off.
  using Observer = autofill::AutofillManager::Observer;
  main_driver->GetAutofillManager().NotifyObservers(
      &Observer::OnFieldTypesDetermined, main_form.global_id(),
      Observer::FieldTypeSource::kAutofillServer,
      /*small_forms_were_parsed=*/false);

  // Even though `OnFieldTypesDetermined` was only called for a single form (the
  // browser form that is the result of merging both forms), password manager
  // receives predictions for both the main and the child form.
  ContentPasswordManagerDriver* main_password_driver =
      ContentPasswordManagerDriver::GetForRenderFrameHost(main_rfh());
  ContentPasswordManagerDriver* child_password_driver =
      ContentPasswordManagerDriver::GetForRenderFrameHost(child_rfh);
  password_manager::DriverId main_driver_id = main_password_driver->GetId();
  password_manager::DriverId child_driver_id = child_password_driver->GetId();

  EXPECT_THAT(
      static_cast<const password_manager::PasswordManager*>(
          GetClient()->GetPasswordManager())
          ->GetServerPredictionsForTesting(),
      UnorderedElementsAre(
          Key(testing::Pair(CalculateFormSignature(main_form), main_driver_id)),
          Key(testing::Pair(CalculateFormSignature(child_form),
                            child_driver_id))));
}

TEST_F(ChromePasswordManagerClientTest,
       PasswordManagerDoesNotReceiveAutofillPredictionsFromOpaqueOriginFrame) {
  constexpr char kUrl1[] = "https://www.foo.com/login.html";
  constexpr char kUrl2[] = "data:text/html,<html></html>";

  NavigateAndCommit(GURL(kUrl1));
  content::RenderFrameHost* child_rfh =
      content::RenderFrameHostTester::For(main_rfh())
          ->AppendChild(std::string("child"));
  child_rfh = content::NavigationSimulator::NavigateAndCommitFromDocument(
      GURL(kUrl2), child_rfh);
  ContentAutofillDriver* main_driver =
      ContentAutofillDriver::GetForRenderFrameHost(main_rfh());
  ContentAutofillDriver* child_driver =
      ContentAutofillDriver::GetForRenderFrameHost(child_rfh);
  ASSERT_TRUE(main_driver);
  ASSERT_TRUE(child_driver);

  FormData main_form = CreateFormDataForRenderFrameHost(
      *main_rfh(), {CreateTestFormField("Username", "username", "",
                                        FormControlType::kInputText),
                    CreateTestFormField("Password", "password", "",
                                        FormControlType::kInputPassword)});
  FormData child_form = CreateFormDataForRenderFrameHost(
      *child_rfh,
      {CreateTestFormField("OTP", "OTP", "", FormControlType::kInputText)});

  // Ensure that the child frame is picked up as a child frame of `main_form`.
  {
    autofill::FrameTokenWithPredecessor child_frame_information;
    child_frame_information.token = child_form.host_frame();
    main_form.set_child_frames({child_frame_information});
  }

  {
    autofill::TestAutofillManagerWaiter waiter(
        main_driver->GetAutofillManager(),
        {autofill::AutofillManagerEvent::kFormsSeen});
    main_driver->renderer_events().FormsSeen(/*updated_forms=*/{main_form},
                                             /*removed_forms=*/{});
    child_driver->renderer_events().FormsSeen(/*updated_forms=*/{child_form},
                                              /*removed_forms=*/{});
    ASSERT_TRUE(waiter.Wait(/*num_expected_relevant_events=*/2));
  }

  // Simulate that the field types have been determined, since server
  // communication is turned off.
  using Observer = autofill::AutofillManager::Observer;
  main_driver->GetAutofillManager().NotifyObservers(
      &Observer::OnFieldTypesDetermined, main_form.global_id(),
      Observer::FieldTypeSource::kAutofillServer,
      /*small_forms_were_parsed=*/false);

  ContentPasswordManagerDriver* main_password_driver =
      ContentPasswordManagerDriver::GetForRenderFrameHost(main_rfh());
  password_manager::DriverId main_driver_id = main_password_driver->GetId();

  // Since the child frame is a data URL (opaque origin), predictions should NOT
  // be propagated for it. Thus, only the main form's predictions are received.
  EXPECT_THAT(static_cast<const password_manager::PasswordManager*>(
                  GetClient()->GetPasswordManager())
                  ->GetServerPredictionsForTesting(),
              UnorderedElementsAre(Key(testing::Pair(
                  CalculateFormSignature(main_form), main_driver_id))));
}

TEST_F(ChromePasswordManagerClientTest,
       GetPasswordManagerDelegateReturnsAutofillManagerForOnlyFrame) {
  NavigateAndCommit(GURL("https://www.foo.com/login.html"));
  auto* driver =
      ContentPasswordManagerDriver::GetForRenderFrameHost(main_rfh());
  ASSERT_TRUE(driver);

  autofill::FieldGlobalId field_id =
      CreateLoginFormData().fields()[0].global_id();

  EXPECT_EQ(driver->GetPasswordAutofillManager(),
            GetClient()->GetAutofillDelegate(field_id));
}

TEST_F(ChromePasswordManagerClientTest,
       GetPasswordManagerDelegateReturnsAutofillManagerForSubFrame) {
  // Create the main frame with decoy data. Should not affect the expectation.
  NavigateAndCommit(GURL("https://www.foo.com/login.html"));
  ASSERT_TRUE(ContentPasswordManagerDriver::GetForRenderFrameHost(main_rfh()));
  CreateLoginFormData();

  content::RenderFrameHost* subframe =
      content::RenderFrameHostTester::For(main_rfh())->AppendChild("subframe");
  ContentPasswordManagerDriver* sub_frame_driver =
      ContentPasswordManagerDriver::GetForRenderFrameHost(subframe);
  autofill::FieldGlobalId field_id =
      CreateLoginFormDataForFrame(subframe).fields()[0].global_id();

  EXPECT_EQ(sub_frame_driver->GetPasswordAutofillManager(),
            GetClient()->GetAutofillDelegate(field_id));
}

TEST_F(ChromePasswordManagerClientTest, AutoSignInEnabledDeterminedByService) {
#if BUILDFLAG(IS_ANDROID)
  if (base::android::device_info::is_automotive()) {
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif

  // Test that auto sign in being allowed depends on querying the settings
  // service.
  ChromePasswordManagerClient* client = GetClient();
  ON_CALL(settings_service(),
          IsSettingEnabled(PasswordManagerSetting::kAutoSignIn))
      .WillByDefault(Return(true));
  EXPECT_TRUE(client->IsAutoSignInEnabled());
}

TEST_F(ChromePasswordManagerClientTest,
       AutoSignInDisableddDeterminedByService) {
#if BUILDFLAG(IS_ANDROID)
  if (base::android::device_info::is_automotive()) {
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif
  // Test that auto sign in being disallowed depends on querying the settings
  // service.
  ChromePasswordManagerClient* client = GetClient();
  ON_CALL(settings_service(),
          IsSettingEnabled(PasswordManagerSetting::kAutoSignIn))
      .WillByDefault(Return(false));
  EXPECT_FALSE(client->IsAutoSignInEnabled());
}

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

class ChromePasswordManagerClientAutomatedTest
    : public ChromePasswordManagerClientTest,
      public testing::WithParamInterface<bool> {
 public:
  ChromePasswordManagerClientAutomatedTest() {
    if (GetParam()) {
      base::CommandLine::ForCurrentProcess()->AppendSwitch(
          switches::kEnableAutomation);
    }
  }
};

INSTANTIATE_TEST_SUITE_P(AutomatedTestPasswordHandling,
                         ChromePasswordManagerClientAutomatedTest,
                         testing::Bool());

TEST_P(ChromePasswordManagerClientAutomatedTest, SavingDependsOnAutomation) {
  // Test that saving passwords UI is disabled for automated tests,
  // and enabled for non-automated tests.
  ChromePasswordManagerClient* client = GetClient();
  // If saving isn't allowed it shouldn't be due to the setting, so make
  // sure that is enabled.
  ON_CALL(settings_service(),
          IsSettingEnabled(PasswordManagerSetting::kOfferToSavePasswords))
      .WillByDefault(Return(true));
  const GURL kUrlOn("https://accounts.google.com");
  EXPECT_NE(client->IsSavingAndFillingEnabled(url::Origin::Create(kUrlOn)),
            GetParam());
}

// Check that password manager is disabled on about:blank pages.
// See https://crbug.com/40088741.
TEST_F(ChromePasswordManagerClientTest, SavingAndFillingDisabledForAboutBlank) {
  const GURL kUrl(url::kAboutBlankURL);
  NavigateAndCommit(kUrl);
  EXPECT_TRUE(GetClient()->GetLastCommittedOrigin().opaque());
  EXPECT_FALSE(
      GetClient()->IsSavingAndFillingEnabled(url::Origin::Create(kUrl)));
  EXPECT_FALSE(GetClient()->IsFillingEnabled(url::Origin::Create(kUrl)));
}

TEST_F(ChromePasswordManagerClientTest, OpaqueOriginFillingFeatureGated) {
  // Use a data URL which results in an opaque origin.
  const GURL kDataUrl("data:text/html,<html></html>");
  NavigateAndCommit(kDataUrl);
  ASSERT_TRUE(GetClient()->GetLastCommittedOrigin().opaque());

  // By default, the feature is enabled, so filling is disabled for opaque
  // origins.
  EXPECT_FALSE(
      GetClient()->IsFillingEnabled(GetClient()->GetLastCommittedOrigin()));

  // Disable the feature.
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndDisableFeature(
      password_manager::features::kPasswordBlockOpaqueOrigins);

  // When the feature is disabled, filling should be enabled for data URLs
  // (since the scheme is web-safe and it's not a disallowed URL).
  // Without URL, it should still return false even if feature is disabled
  // because we cannot verify the scheme of the opaque origin.
  EXPECT_FALSE(
      GetClient()->IsFillingEnabled(GetClient()->GetLastCommittedOrigin()));

  // With URL, it should return true.
  EXPECT_TRUE(
      GetClient()->IsFillingEnabled(GetClient()->GetLastCommittedOrigin(),
                                    GetClient()->GetLastCommittedURL()));
}

TEST_F(ChromePasswordManagerClientTest, NoFillingOnInvalidUrls) {
  GURL kEmpty;
  ASSERT_FALSE(kEmpty.is_valid());

  EXPECT_FALSE(
      GetClient()->IsFillingEnabled(url::Origin::Create(kEmpty), kEmpty));

  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndDisableFeature(
      password_manager::features::kPasswordBlockOpaqueOrigins);
  EXPECT_FALSE(
      GetClient()->IsFillingEnabled(url::Origin::Create(kEmpty), kEmpty));
}

TEST_F(ChromePasswordManagerClientTest,
       IsFillingAndSavingOnGooglePasswordPage) {
  PasswordManagerClient* client = GetClient();
  EXPECT_FALSE(client->IsSavingAndFillingEnabled(
      url::Origin::Create(GURL("https://passwords.google.com/path?query=1"))));
  EXPECT_FALSE(client->IsFillingEnabled(
      url::Origin::Create(GURL("https://passwords.google.com/path?query=1"))));
}

#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
// 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`.
  TestingBrowserProcess::GetGlobal()->local_state()->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`.
  TestingBrowserProcess::GetGlobal()->local_state()->SetBoolean(
      password_manager::prefs::kHadBiometricsAvailable, true);
  profile()->GetTestingPrefService()->SetBoolean(
      password_manager::prefs::kBiometricAuthenticationBeforeFilling, false);
  EXPECT_FALSE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
}
#endif  // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)

#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
// 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`.
  TestingBrowserProcess::GetGlobal()->local_state()->SetBoolean(
      password_manager::prefs::kHadBiometricsAvailable, true);
  profile()->GetTestingPrefService()->SetBoolean(
      password_manager::prefs::kBiometricAuthenticationBeforeFilling, true);
  EXPECT_TRUE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
}
#endif

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

#if BUILDFLAG(IS_ANDROID)
// Test that authentication is not possible if the `authenticator` is `nullptr`.
TEST_F(ChromePasswordManagerClientTest, CanUseBiometricAuthAndroid) {
  if (base::android::device_info::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::device_info::is_automotive()) {
    GTEST_SKIP();
  }
  device_reauth::MockDeviceAuthenticator authenticator;
  ON_CALL(authenticator, GetBiometricAvailabilityStatus)
      .WillByDefault(Return(BiometricStatus::kBiometricsAvailable));
  EXPECT_FALSE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
}

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

// Test that authentication is not possible if the
// `GetBiometricAvailabilityStatus` returns `kBiometricsAvailable`, 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::device_info::is_automotive()) {
    GTEST_SKIP();
  }
  base::test::ScopedFeatureList enabled_features(
      password_manager::features::kBiometricTouchToFill);
  device_reauth::MockDeviceAuthenticator authenticator;
  ON_CALL(authenticator, GetBiometricAvailabilityStatus)
      .WillByDefault(Return(BiometricStatus::kBiometricsAvailable));
  EXPECT_FALSE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
}

// Test that authentication is possible if the `GetBiometricAvailabilityStatus`
// returns `kOnlyLskfAvailable` 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::device_info::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, GetBiometricAvailabilityStatus)
      .WillByDefault(Return(BiometricStatus::kOnlyLskfAvailable));
  EXPECT_TRUE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
  histogram_tester.ExpectUniqueSample(
      "PasswordManager.BiometricAuthPwdFillAndroid."
      "CanAuthenticateWithBiometricOrScreenLock",
      true, 1);
}

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

#else
// Test that authentication is not possible on other platforms.
TEST_F(ChromePasswordManagerClientTest, CanUseBiometricAuth) {
  device_reauth::MockDeviceAuthenticator authenticator;
  EXPECT_FALSE(GetClient()->IsReauthBeforeFillingRequired(&authenticator));
}
#endif  // BUILDFLAG(IS_ANDROID)

namespace {

struct SchemeTestCase {
  const char* scheme;
  bool password_manager_works;
};
const SchemeTestCase kSchemeTestCases[] = {
    {url::kHttpScheme, true},
    {url::kHttpsScheme, true},
    {url::kDataScheme, false},

    {"invalid-scheme-i-just-made-up", false},
    {content::kChromeDevToolsScheme, false},
    {content::kChromeUIScheme, false},
    {url::kMailToScheme, false},
};

// 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*> {
 public:
  void SetUp() override {
    ChromePasswordManagerClientTest::SetUp();
    ProfilePasswordStoreFactory::GetInstance()->SetTestingFactory(
        GetBrowserContext(),
        base::BindRepeating(&password_manager::BuildPasswordStoreInterface<
                            content::BrowserContext,
                            password_manager::MockPasswordStoreInterface>));
  }

  static std::vector<const char*> GetSchemes() {
    std::vector<const char*> result;
    for (const SchemeTestCase& test_case : kSchemeTestCases) {
      result.push_back(test_case.scheme);
    }
    return result;
  }
};

TEST_P(ChromePasswordManagerClientSchemeTest,
       SavingAndFillingOnDifferentSchemes) {
  const GURL url(base::StringPrintf("%s://example.org", GetParam()));
  VLOG(0) << url.possibly_invalid_spec();
  NavigateAndCommit(url);
  EXPECT_EQ(url::Origin::Create(url).GetURL(),
            GetClient()->GetLastCommittedOrigin().GetURL());

  auto* it = std::ranges::find_if(kSchemeTestCases, [](auto test_case) {
    return strcmp(test_case.scheme, GetParam()) == 0;
  });
  // If saving isn't allowed it shouldn't be due to the setting, so make
  // sure that is enabled.
  ON_CALL(settings_service(),
          IsSettingEnabled(PasswordManagerSetting::kOfferToSavePasswords))
      .WillByDefault(Return(true));
  ASSERT_FALSE(it == std::end(kSchemeTestCases));
  EXPECT_EQ(it->password_manager_works,
            GetClient()->IsSavingAndFillingEnabled(url::Origin::Create(url)));
  EXPECT_EQ(it->password_manager_works,
            GetClient()->IsFillingEnabled(url::Origin::Create(url)));
}

INSTANTIATE_TEST_SUITE_P(
    All,
    ChromePasswordManagerClientSchemeTest,
    ::testing::ValuesIn(ChromePasswordManagerClientSchemeTest::GetSchemes()));

}  // namespace

TEST_F(ChromePasswordManagerClientTest, GetLastCommittedEntryURL_Empty) {
  EXPECT_TRUE(GetClient()->GetLastCommittedOrigin().opaque());
}

TEST_F(ChromePasswordManagerClientTest, GetLastCommittedEntryURL) {
  GURL kUrl(
      "https://accounts.google.com/ServiceLogin?continue="
      "https://passwords.google.com/settings");
  NavigateAndCommit(kUrl);
  EXPECT_EQ(url::Origin::Create(kUrl), GetClient()->GetLastCommittedOrigin());
}

TEST_F(ChromePasswordManagerClientTest, WebUINoLogging) {
  // Make sure that logging is active.
  autofill::LogRouter* log_router =
      password_manager::PasswordManagerLogRouterFactory::GetForBrowserContext(
          profile());
  DummyLogReceiver log_receiver;
  log_router->RegisterReceiver(&log_receiver);

  // But then navigate to a WebUI, there the logging should not be active.
  NavigateAndCommit(GURL("chrome://password-manager-internals/"));

  autofill::LogManager* log_manager = GetClient()->GetCurrentLogManager();
  EXPECT_FALSE(log_manager && log_manager->IsLoggingActive());

  log_router->UnregisterReceiver(&log_receiver);
}

// State transition: Unannotated
TEST_F(ChromePasswordManagerClientTest, AnnotateNavigationEntryUnannotated) {
  NavigateAndCommit(GURL("about:blank"));

  EXPECT_EQ(
      SerializedNavigationEntry::PASSWORD_STATE_UNKNOWN,
      GetPasswordStateFromNavigation(controller().GetLastCommittedEntry()));
}

// State transition: unknown->false
TEST_F(ChromePasswordManagerClientTest, AnnotateNavigationEntryToFalse) {
  NavigateAndCommit(GURL("about:blank"));

  GetClient()->AnnotateNavigationEntry(false);
  EXPECT_EQ(
      SerializedNavigationEntry::NO_PASSWORD_FIELD,
      GetPasswordStateFromNavigation(controller().GetLastCommittedEntry()));
}

// State transition: false->true
TEST_F(ChromePasswordManagerClientTest, AnnotateNavigationEntryToTrue) {
  NavigateAndCommit(GURL("about:blank"));

  GetClient()->AnnotateNavigationEntry(false);
  GetClient()->AnnotateNavigationEntry(true);
  EXPECT_EQ(
      SerializedNavigationEntry::HAS_PASSWORD_FIELD,
      GetPasswordStateFromNavigation(controller().GetLastCommittedEntry()));
}

// State transition: true->false (retains true)
TEST_F(ChromePasswordManagerClientTest, AnnotateNavigationEntryTrueToFalse) {
  NavigateAndCommit(GURL("about:blank"));

  GetClient()->AnnotateNavigationEntry(true);
  GetClient()->AnnotateNavigationEntry(false);
  EXPECT_EQ(
      SerializedNavigationEntry::HAS_PASSWORD_FIELD,
      GetPasswordStateFromNavigation(controller().GetLastCommittedEntry()));
}

TEST_F(ChromePasswordManagerClientTest, CanShowBubbleOnURL) {
  struct TestCase {
    const char* scheme;
    bool can_show_bubble;
  } kTestCases[] = {
      {url::kHttpScheme, true},
      {url::kHttpsScheme, true},
      {url::kDataScheme, true},
      {url::kBlobScheme, true},
      {url::kFileSystemScheme, true},

      {"invalid-scheme-i-just-made-up", false},
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
      {extensions::kExtensionScheme, false},
#endif
      {url::kAboutScheme, false},
      {content::kChromeDevToolsScheme, false},
      {content::kChromeUIScheme, false},
      {url::kJavaScriptScheme, false},
      {url::kMailToScheme, false},
      {content::kViewSourceScheme, false},
  };

  for (const TestCase& test_case : kTestCases) {
    // CanShowBubbleOnURL currently only depends on the scheme.
    GURL url(base::StringPrintf("%s://example.org", test_case.scheme));
    SCOPED_TRACE(url.possibly_invalid_spec());
    EXPECT_EQ(test_case.can_show_bubble,
              ChromePasswordManagerClient::CanShowBubbleOnURL(url));
  }
}

#if !BUILDFLAG(IS_ANDROID)
// Test that the hats service is called with the expected params.
TEST_F(ChromePasswordManagerClientTest,
       TriggerUserPerceptionOfAutofillPasswordSurvey) {
  MockHatsService* mock_hats_service = static_cast<MockHatsService*>(
      HatsServiceFactory::GetInstance()->SetTestingFactoryAndUse(
          profile(), base::BindRepeating(&BuildMockHatsService)));
  EXPECT_CALL(*mock_hats_service, CanShowAnySurvey)
      .WillRepeatedly(Return(true));

  const std::string filling_assistane = "Automatically filled";
  const SurveyStringData filling_assistance_in_product_data = {
      {"Filling assistance", filling_assistane}};
  EXPECT_CALL(*mock_hats_service,
              LaunchDelayedSurveyForWebContents(
                  kHatsSurveyTriggerAutofillPasswordUserPerception, _, _, _,
                  filling_assistance_in_product_data, _, _, _, _, _));

  GetClient()->TriggerUserPerceptionOfPasswordManagerSurvey(filling_assistane);
}

TEST_F(
    ChromePasswordManagerClientTest,
    TriggerUserPerceptionOfAutofillPasswordSurvey_EmptyFillingAssistanceString_DoNotCallHats) {
  MockHatsService* mock_hats_service = static_cast<MockHatsService*>(
      HatsServiceFactory::GetInstance()->SetTestingFactoryAndUse(
          profile(), base::BindRepeating(&BuildMockHatsService)));

  EXPECT_CALL(*mock_hats_service, LaunchDelayedSurveyForWebContents).Times(0);

  GetClient()->TriggerUserPerceptionOfPasswordManagerSurvey("");
}
#endif

#if BUILDFLAG(FULL_SAFE_BROWSING)
TEST_F(ChromePasswordManagerClientTest,
       VerifyMaybeStartPasswordFieldOnFocusRequestCalled) {
  std::unique_ptr<WebContents> test_web_contents(
      content::WebContentsTester::CreateTestWebContents(
          web_contents()->GetBrowserContext(), nullptr));
  autofill::ChromeAutofillClient::CreateForWebContents(test_web_contents.get());
  MockChromePasswordManagerClient* client =
      MockChromePasswordManagerClient::CreateForWebContentsAndGet(
          test_web_contents.get());
  ON_CALL(*client, GetMainFrameCertStatus()).WillByDefault(Return(0));
  EXPECT_CALL(*client->password_protection_service(),
              MaybeStartPasswordFieldOnFocusRequest)
      .Times(1);
  PasswordManagerClient* mojom_client = client;
  mojom_client->CheckSafeBrowsingReputation(GURL("http://foo.com/submit"),
                                            GURL("http://foo.com/iframe.html"));
}

// 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) {
  std::unique_ptr<WebContents> test_web_contents(
      content::WebContentsTester::CreateTestWebContents(
          web_contents()->GetBrowserContext(), nullptr));

  // Warnings are delayed until the user interacts with the page. This is
  // achieved by attaching an observer (SafeBrowsingUserInteractionObserver) to
  // the current WebContents. Create an observer and attach it to simulate a
  // delayed warning.
  auto ui_manager =
      base::MakeRefCounted<safe_browsing::TestSafeBrowsingUIManager>();
  security_interstitials::UnsafeResource resource;
  safe_browsing::SafeBrowsingUserInteractionObserver::CreateForWebContents(
      test_web_contents.get(), resource, ui_manager);
  autofill::ChromeAutofillClient::CreateForWebContents(test_web_contents.get());
  MockChromePasswordManagerClient* client =
      MockChromePasswordManagerClient::CreateForWebContentsAndGet(
          test_web_contents.get());
  ON_CALL(*client, GetMainFrameCertStatus()).WillByDefault(Return(0));
  // Saving is disabled when the page has a delayed SafeBrowsing warning.
  const GURL kUrlOn("https://accounts.google.com");
  EXPECT_FALSE(client->IsSavingAndFillingEnabled(url::Origin::Create(kUrlOn)));
  EXPECT_FALSE(client->IsFillingEnabled(url::Origin::Create(kUrlOn)));
}
#endif

TEST_F(ChromePasswordManagerClientTest, MissingUIDelegate) {
  // Checks that the saving fallback methods don't crash if there is no UI
  // delegate. It can happen on ChromeOS login form, for example.
  GURL kUrl("https://example.com/");
  NavigateAndCommit(kUrl);
  PasswordManagerClient* client = GetClient();
  client->ShowManualFallbackForSaving(nullptr, false, false);
  client->HideManualFallbackForSaving();
}

class ChromePasswordManagerClientCriticalActionsTest
    : public ChromePasswordManagerClientTest {
 public:
  void SetUp() override {
    ChromePasswordManagerClientTest::SetUp();

    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    base::FilePath db_path =
        temp_dir_.GetPath().AppendASCII("TestCriticalActions.db");
    scoped_refptr<base::SequencedTaskRunner> backend_task_runner =
        base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});

    // Setup the mock CriticalActionService factory.
    auto mock_service = std::make_unique<NiceMock<MockCriticalActionService>>(
        db_path, backend_task_runner);
    mock_service_ = mock_service.get();

    critical_actions::CriticalActionFactory::GetInstance()->SetTestingFactory(
        profile(),
        base::BindOnce(
            [](std::unique_ptr<NiceMock<MockCriticalActionService>> service,
               content::BrowserContext* context)
                -> std::unique_ptr<KeyedService> { return std::move(service); },
            std::move(mock_service)));

    // Setup a committed main frame navigation and visit ID.
    auto simulator = content::NavigationSimulator::CreateBrowserInitiated(
        test_url_, web_contents());
    simulator->Start();
    nav_id_ = simulator->GetNavigationHandle()->GetNavigationId();
    simulator->Commit();
  }

  void TearDown() override {
    DeleteContents();
    mock_service_ = nullptr;
    ChromePasswordManagerClientTest::TearDown();
  }

 protected:
  MockCriticalActionService* mock_service() { return mock_service_; }
  const GURL& test_url() const { return test_url_; }
  int64_t nav_id() const { return nav_id_; }

 private:
  base::ScopedTempDir temp_dir_;
  raw_ptr<MockCriticalActionService> mock_service_ = nullptr;
  const GURL test_url_{"https://example.com/login"};
  int64_t nav_id_ = 0;
};

TEST_F(ChromePasswordManagerClientCriticalActionsTest,
       DelegatesToCriticalActionServiceWithNavigationId) {
  // Expect OnPasswordFilled to call AddCriticalActionWithNavigationId with the
  // main frame navigation ID.
  EXPECT_CALL(*mock_service(), AddCriticalActionWithNavigationId)
      .WillOnce([&](const critical_actions::CriticalActionEntry& entry,
                    int64_t navigation_id) {
        EXPECT_EQ(entry.action_type, critical_actions::ActionType::kFormFill);
        EXPECT_EQ(entry.action_source,
                  critical_actions::ActionSource::kPasswordManager);
        EXPECT_EQ(entry.url, test_url());
        EXPECT_EQ(navigation_id, nav_id());

        auto parsed_json =
            base::JSONReader::Read(entry.metadata, base::JSON_PARSE_RFC);
        ASSERT_TRUE(parsed_json.has_value());
        ASSERT_TRUE(parsed_json->is_dict());
        const std::string* type_val = parsed_json->GetDict().FindString("type");
        ASSERT_TRUE(type_val);
        EXPECT_EQ(*type_val, "password_manager_autofill");
      });

  GetClient()->OnPasswordFilled(
      nullptr, test_url(),
      PasswordManagerClient::PasswordFillTrigger::kPasswordManagerAutofill);
}

TEST_F(ChromePasswordManagerClientCriticalActionsTest,
       NotifiesCriticalActionServiceOnUncommittedNavigation) {
  auto simulator = content::NavigationSimulator::CreateBrowserInitiated(
      GURL("https://example.com/other"), web_contents());
  simulator->Start();
  int64_t uncommitted_nav_id =
      simulator->GetNavigationHandle()->GetNavigationId();

  EXPECT_CALL(*mock_service(), OnNavigationDiscarded(uncommitted_nav_id));

  simulator->Fail(net::ERR_ABORTED);

  // Verify that the call happened and clear expectations so that
  // TearDown's DeleteContents() doesn't trigger noise.
  testing::Mock::VerifyAndClearExpectations(mock_service());
}

TEST_F(ChromePasswordManagerClientTest, GetActionableError) {
  password_manager::MockPasswordStoreInterface* mock_profile_store =
      static_cast<password_manager::MockPasswordStoreInterface*>(
          GetClient()->GetProfilePasswordStore());
  EXPECT_CALL(*mock_profile_store, GetError)
      .WillRepeatedly(
          Return(password_manager::ActionableError::kTrustedVaultKeyNeeded));
  EXPECT_EQ(password_manager::ActionableError::kTrustedVaultKeyNeeded,
            GetClient()->GetActionableError());

  EXPECT_CALL(*mock_profile_store, GetError)
      .WillRepeatedly(Return(password_manager::ActionableError::kNoError));
  EXPECT_EQ(password_manager::ActionableError::kNoError,
            GetClient()->GetActionableError());
}

#if BUILDFLAG(IS_ANDROID)
class ChromePasswordManagerClientAndroidTest
    : public ChromePasswordManagerClientTest {
 protected:
  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);
  }

  MockTouchToFillPasswordManagerController*
  MakeMockTouchToFillPasswordManagerController() {
    visibility_controller_ = std::make_unique<
        password_manager::MockKeyboardReplacingSurfaceVisibilityController>();
    auto owned_ttf_controller =
        std::make_unique<MockTouchToFillPasswordManagerController>(
            profile(), visibility_controller_->AsWeakPtr());
    auto* ttf_controller = owned_ttf_controller.get();
    GetClient()->SetTouchToFillPasswordManagerControllerForTesting(
        std::move(owned_ttf_controller));
    return ttf_controller;
  }

  autofill::PasswordSuggestionRequest GetFocusedFieldSuggestionRequest(
      const FormData& form) {
    auto get_field_id = [&form](size_t i) {
      return autofill::FieldGlobalId{
          .frame_token = form.host_frame(),
          .renderer_id = i < form.fields().size()
                             ? form.fields()[i].renderer_id()
                             : autofill::FieldRendererId()};
    };
    return autofill::PasswordSuggestionRequest(
        autofill::TriggeringField(form.fields()[0].global_id(),
                                  autofill::AutofillSuggestionTriggerSource::
                                      kPasswordManagerProcessedFocusedField,
                                  base::i18n::LEFT_TO_RIGHT, u"",
                                  /*show_webauthn_credentials=*/true,
                                  /*show_identity_credentials=*/false,
                                  gfx::RectF()),
        form,
        /*username_field_id=*/get_field_id(0),
        /*password_field_id=*/get_field_id(1));
  }

 private:
  NiceMock<MockPasswordAccessoryController> mock_pwd_controller_;
  NiceMock<MockAddressAccessoryController> mock_address_controller_;
  NiceMock<MockPaymentMethodAccessoryController>
      mock_payment_method_controller_;
  NiceMock<MockAtMemoryAccessoryController> mock_at_memory_controller_;
  std::unique_ptr<
      password_manager::MockKeyboardReplacingSurfaceVisibilityController>
      visibility_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>>();
      }));
}

void ChromePasswordManagerClientAndroidTest::CreateManualFillingController(
    content::WebContents* web_contents) {
  ManualFillingControllerImpl::CreateForWebContentsForTesting(
      web_contents, mock_pwd_controller_.AsWeakPtr(),
      mock_address_controller_.AsWeakPtr(),
      mock_payment_method_controller_.AsWeakPtr(),
      mock_at_memory_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(
      /*is_field_eligible_for_generation=*/true, 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,
                  /*is_field_eligible_for_manual_generation=*/true));
  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) {
  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, GetError)
      .WillRepeatedly(Return(password_manager::ActionableError::kNoError));
  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, FromPasswordForms(std::move(account_store_forms)));

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

  MockPasswordAccessoryControllerImpl* weak_mock_pwd_controller =
      SetUpMockPwdAccessoryForClientUse(driver.get());
  EXPECT_CALL(*weak_mock_pwd_controller,
              RefreshSuggestionsForField(
                  FocusedFieldType::kFillablePasswordField,
                  /*is_field_eligible_for_manual_generation=*/true));
  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) {
  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, GetError)
      .WillRepeatedly(Return(password_manager::ActionableError::kNoError));
  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, FromPasswordForms(std::move(forms)));

  MockPasswordAccessoryControllerImpl* weak_mock_pwd_controller =
      SetUpMockPwdAccessoryForClientUse(driver.get());
  EXPECT_CALL(*weak_mock_pwd_controller,
              RefreshSuggestionsForField(
                  FocusedFieldType::kFillablePasswordField,
                  /*is_field_eligible_for_manual_generation=*/true));
  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), std::nullopt,
          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);
  handle.set_render_frame_host(main_rfh());
  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();
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       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), std::nullopt,
          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(password_manager::EqStoredCredential(
                                              shared_not_notified_profile),
                                          _));
  EXPECT_CALL(*account_store, UpdateLogin(password_manager::EqStoredCredential(
                                              shared_not_notified_account),
                                          _));
  GetClient()->MarkSharedCredentialsAsNotified(origin);
}

#endif  //  BUILDFLAG(IS_ANDROID)

#if !BUILDFLAG(IS_ANDROID)

class FakePasswordCrossDomainConfirmationPopupView
    : public PasswordCrossDomainConfirmationPopupView {
 public:
  explicit FakePasswordCrossDomainConfirmationPopupView(
      base::OnceClosure confirmation_callback)
      : confirmation_callback_(std::move(confirmation_callback)) {}

  void Confirm() { std::move(confirmation_callback_).Run(); }

  MOCK_METHOD(void, Hide, (), (override));
  MOCK_METHOD(bool, OverlapsWithPictureInPictureWindow, (), (const, override));

  base::WeakPtr<PasswordCrossDomainConfirmationPopupView> GetWeakPtr() {
    return weak_ptr_factory_.GetWeakPtr();
  }

 private:
  base::OnceClosure confirmation_callback_;
  base::WeakPtrFactory<FakePasswordCrossDomainConfirmationPopupView>
      weak_ptr_factory_{this};
};

TEST_F(ChromePasswordManagerClientTest, ShowCrossDomainConfirmationPopup) {
// This simple method of the web contents repositioning doesn't work on Mac.
// The screen coordinates calculation testing is skipped on this platform, but
// the logic is completely platform independent and is being tested on others.
#if !BUILDFLAG(IS_MAC)
  web_contents()->GetNativeView()->SetBounds(gfx::Rect(100, 100, 1000, 1000));
#endif  // !BUILDFLAG(IS_MAC)

  // Controller requests the focused frame, this call makes sure there is one.
  FocusWebContentsOnMainFrame();

  base::MockRepeatingCallback<
      std::unique_ptr<PasswordCrossDomainConfirmationPopupControllerImpl>()>
      popup_factory;
  auto controller =
      std::make_unique<PasswordCrossDomainConfirmationPopupControllerImpl>(
          web_contents());
  base::MockOnceClosure accepted_callback;
  auto view = std::make_unique<FakePasswordCrossDomainConfirmationPopupView>(
      accepted_callback.Get());
  controller->set_view_factory_for_testing(base::BindRepeating(
      [](FakePasswordCrossDomainConfirmationPopupView* view,
         base::WeakPtr<autofill::AutofillPopupViewDelegate> delegate,
         const GURL& domain, const std::u16string& password_origin,
         base::OnceClosure confirmation_callback,
         base::OnceClosure cancel_callback) { return view->GetWeakPtr(); },
      base::Unretained(view.get())));

  EXPECT_CALL(popup_factory, Run)
      .WillOnce(testing::Return(std::move(controller)));
  GetClient()->set_cross_domain_confirmation_popup_factory_for_testing(
      popup_factory.Get());

  GetClient()->ShowCrossDomainConfirmationPopup(
      gfx::RectF(100, 100), base::i18n::TextDirection::LEFT_TO_RIGHT,
      GURL("https://google.com"), u"google.de", /*show_warning_text=*/false,
      accepted_callback.Get());

  EXPECT_CALL(accepted_callback, Run);
  view->Confirm();
}
#endif  //  !BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(IS_ANDROID)
TEST_F(ChromePasswordManagerClientTest,
       ShowAndAcceptCrossDomainConfirmationPopup) {
  AcknowledgeGroupedCredentialSheetControllerTestHelper helper;
  GetClient()->set_cross_domain_confirmation_popup_factory_for_testing(
      base::BindRepeating(
          &AcknowledgeGroupedCredentialSheetControllerTestHelper::
              CreateController,
          base::Unretained(&helper)));

  base::MockOnceClosure accepted_callback;
  // Need to store the returned controller to dismiss the sheet.
  std::unique_ptr<
      password_manager::PasswordCrossDomainConfirmationPopupController>
      controller = GetClient()->ShowCrossDomainConfirmationPopup(
          gfx::RectF(100, 100), base::i18n::TextDirection::LEFT_TO_RIGHT,
          GURL("https://google.com"), u"google.de", /*show_warning_text=*/true,
          accepted_callback.Get());
  EXPECT_CALL(accepted_callback, Run);
  helper.DismissSheet(
      AcknowledgeGroupedCredentialSheetBridge::DismissReason::kAccept);
}

TEST_F(ChromePasswordManagerClientTest,
       ShowAndDeclineCrossDomainConfirmationPopup) {
  AcknowledgeGroupedCredentialSheetControllerTestHelper helper;
  GetClient()->set_cross_domain_confirmation_popup_factory_for_testing(
      base::BindRepeating(
          &AcknowledgeGroupedCredentialSheetControllerTestHelper::
              CreateController,
          base::Unretained(&helper)));

  base::MockOnceClosure accepted_callback;
  // Need to store the returned controller to dismiss the sheet.
  std::unique_ptr<
      password_manager::PasswordCrossDomainConfirmationPopupController>
      controller = GetClient()->ShowCrossDomainConfirmationPopup(
          gfx::RectF(100, 100), base::i18n::TextDirection::LEFT_TO_RIGHT,
          GURL("https://google.com"), u"google.de", /*show_warning_text=*/true,
          accepted_callback.Get());
  EXPECT_CALL(accepted_callback, Run).Times(0);
  helper.DismissSheet(
      AcknowledgeGroupedCredentialSheetBridge::DismissReason::kBack);
}
#endif  // BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(IS_ANDROID)
TEST_F(ChromePasswordManagerClientAndroidTest,
       DelaySuggestionsSheetWhenPasskeysPending) {
  webauthn::WebAuthnCredManDelegate::override_cred_man_support_for_testing(
      webauthn::CredManSupport::DISABLED);
  base::test::ScopedFeatureList features(
      password_manager::features::
          kDelaySuggestionsOnAutofocusWaitingForPasskeys);
  CreateManualFillingController(web_contents());

  auto* ttf_controller = MakeMockTouchToFillPasswordManagerController();

  EXPECT_CALL(*ttf_controller, InitData).Times(0);
  EXPECT_CALL(*ttf_controller, Show).Times(0);

  constexpr char kUrl[] = "https://www.foo.com/login.html";
  NavigateAndCommit(GURL(kUrl));
  ContentAutofillDriver* autofill_driver =
      ContentAutofillDriver::GetForRenderFrameHost(main_rfh());
  ASSERT_TRUE(autofill_driver);

  std::vector<FormFieldData> fields = {CreateTestFormField(
      "Username:", "username", "", FormControlType::kInputText, "webauthn")};
  FormData form =
      CreateFormDataForRenderFrameHost(*main_rfh(), std::move(fields));
  {
    autofill::TestAutofillManagerWaiter waiter(
        autofill_driver->GetAutofillManager(),
        {autofill::AutofillManagerEvent::kFormsSeen});
    autofill_driver->renderer_events().FormsSeen(/*updated_forms=*/{form},
                                                 /*removed_forms=*/{});
    ASSERT_TRUE(waiter.Wait(/*num_expected_relevant_events=*/1));
  }

  GetClient()->ShowKeyboardReplacingSurface(
      ContentPasswordManagerDriver::GetForRenderFrameHost(main_rfh()),
      GetFocusedFieldSuggestionRequest(form));

  base::RunLoop().RunUntilIdle();

  std::vector<TouchToFillPasswordManagerView::Credential> credentials{};
  EXPECT_CALL(*ttf_controller, InitData(Eq(credentials), _));
  EXPECT_CALL(*ttf_controller, Show).WillOnce(Return(true));

  // Simulate an empty passkey list being provided.
  ChromeWebAuthnCredentialsDelegateFactory::GetFactory(web_contents())
      ->GetDelegateForFrame(main_rfh())
      ->OnCredentialsReceived(
          std::vector<password_manager::PasskeyCredential>(),
          ChromeWebAuthnCredentialsDelegate::SecurityKeyOrHybridFlowAvailable(
              true));
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       DelaySuggestionsSheetWhenPasskeysPendingTimeOut) {
  webauthn::WebAuthnCredManDelegate::override_cred_man_support_for_testing(
      webauthn::CredManSupport::DISABLED);
  base::test::ScopedFeatureList features(
      password_manager::features::
          kDelaySuggestionsOnAutofocusWaitingForPasskeys);
  CreateManualFillingController(web_contents());

  auto* ttf_controller = MakeMockTouchToFillPasswordManagerController();
  EXPECT_CALL(*ttf_controller, InitData).Times(0);
  EXPECT_CALL(*ttf_controller, Show).Times(0);

  constexpr char kUrl[] = "https://www.foo.com/login.html";
  NavigateAndCommit(GURL(kUrl));
  ContentAutofillDriver* autofill_driver =
      ContentAutofillDriver::GetForRenderFrameHost(main_rfh());
  ASSERT_TRUE(autofill_driver);

  std::vector<FormFieldData> fields = {CreateTestFormField(
      "Username:", "username", "", FormControlType::kInputText, "webauthn")};
  FormData form =
      CreateFormDataForRenderFrameHost(*main_rfh(), std::move(fields));
  {
    autofill::TestAutofillManagerWaiter waiter(
        autofill_driver->GetAutofillManager(),
        {autofill::AutofillManagerEvent::kFormsSeen});
    autofill_driver->renderer_events().FormsSeen(/*updated_forms=*/{form},
                                                 /*removed_forms=*/{});
    ASSERT_TRUE(waiter.Wait(/*num_expected_relevant_events=*/1));
  }

  GetClient()->ShowKeyboardReplacingSurface(
      ContentPasswordManagerDriver::GetForRenderFrameHost(main_rfh()),
      GetFocusedFieldSuggestionRequest(form));

  base::RunLoop().RunUntilIdle();

  base::RunLoop waiter;
  std::vector<TouchToFillPasswordManagerView::Credential> credentials{};
  EXPECT_CALL(*ttf_controller, InitData(Eq(credentials), _));
  EXPECT_CALL(*ttf_controller, Show)
      .WillOnce([&waiter](std::unique_ptr<TouchToFillPasswordManagerDelegate>,
                          webauthn::WebAuthnCredManDelegate*) {
        waiter.Quit();
        return true;
      });

  // Simulate a timeout.
  AdvanceClock(base::Seconds(5));
  waiter.Run();

  EXPECT_CALL(*ttf_controller, InitData).Times(0);
  EXPECT_CALL(*ttf_controller, Show).Times(0);

  // Simulate an empty passkey list being provided. Nothing should happen
  // because the timer has already expired.
  ChromeWebAuthnCredentialsDelegateFactory::GetFactory(web_contents())
      ->GetDelegateForFrame(main_rfh())
      ->OnCredentialsReceived(
          std::vector<password_manager::PasskeyCredential>(),
          ChromeWebAuthnCredentialsDelegate::SecurityKeyOrHybridFlowAvailable(
              true));
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       DelaySuggestionsSheetWhenPasskeysTimerCancelledWhenFocusLost) {
  webauthn::WebAuthnCredManDelegate::override_cred_man_support_for_testing(
      webauthn::CredManSupport::DISABLED);
  base::test::ScopedFeatureList features(
      password_manager::features::
          kDelaySuggestionsOnAutofocusWaitingForPasskeys);
  CreateManualFillingController(web_contents());

  auto* ttf_controller = MakeMockTouchToFillPasswordManagerController();
  EXPECT_CALL(*ttf_controller, InitData).Times(0);
  EXPECT_CALL(*ttf_controller, Show).Times(0);

  constexpr char kUrl[] = "https://www.foo.com/login.html";
  NavigateAndCommit(GURL(kUrl));
  ContentAutofillDriver* autofill_driver =
      ContentAutofillDriver::GetForRenderFrameHost(main_rfh());
  ASSERT_TRUE(autofill_driver);

  std::vector<FormFieldData> fields = {CreateTestFormField(
      "Username:", "username", "", FormControlType::kInputText, "webauthn")};
  FormData form =
      CreateFormDataForRenderFrameHost(*main_rfh(), std::move(fields));
  {
    autofill::TestAutofillManagerWaiter waiter(
        autofill_driver->GetAutofillManager(),
        {autofill::AutofillManagerEvent::kFormsSeen});
    autofill_driver->renderer_events().FormsSeen(/*updated_forms=*/{form},
                                                 /*removed_forms=*/{});
    ASSERT_TRUE(waiter.Wait(/*num_expected_relevant_events=*/1));
  }

  auto* driver =
      ContentPasswordManagerDriver::GetForRenderFrameHost(main_rfh());
  GetClient()->ShowKeyboardReplacingSurface(
      driver, GetFocusedFieldSuggestionRequest(form));

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

  // Simulate a timeout. The timer should be cancelled so TTF methods should not
  // be called.
  AdvanceClock(base::Seconds(5));
  base::RunLoop().RunUntilIdle();
}

TEST_F(ChromePasswordManagerClientAndroidTest,
       DoNotShowKeyboardReplacingSurfaceForInactiveFrame) {
  webauthn::WebAuthnCredManDelegate::override_cred_man_support_for_testing(
      webauthn::CredManSupport::DISABLED);
  CreateManualFillingController(web_contents());

  auto* ttf_controller = MakeMockTouchToFillPasswordManagerController();
  EXPECT_CALL(*ttf_controller, InitData).Times(0);
  EXPECT_CALL(*ttf_controller, Show).Times(0);

  constexpr char kUrl[] = "https://www.foo.com/login.html";
  NavigateAndCommit(GURL(kUrl));

  content::RenderFrameHostWrapper old_rfh(main_rfh());
  ContentAutofillDriver* autofill_driver =
      ContentAutofillDriver::GetForRenderFrameHost(old_rfh.get());
  ASSERT_TRUE(autofill_driver);

  std::vector<FormFieldData> fields = {CreateTestFormField(
      "Username:", "username", "", FormControlType::kInputText, "webauthn")};
  FormData form =
      CreateFormDataForRenderFrameHost(*old_rfh.get(), std::move(fields));
  {
    autofill::TestAutofillManagerWaiter waiter(
        autofill_driver->GetAutofillManager(),
        {autofill::AutofillManagerEvent::kFormsSeen});
    autofill_driver->renderer_events().FormsSeen(/*updated_forms=*/{form},
                                                 /*removed_forms=*/{});
    ASSERT_TRUE(waiter.Wait(/*num_expected_relevant_events=*/1));
  }

  auto* old_driver =
      ContentPasswordManagerDriver::GetForRenderFrameHost(old_rfh.get());

  GetClient()->ShowKeyboardReplacingSurface(
      old_driver, GetFocusedFieldSuggestionRequest(form));

  // Navigate to another site so old_rfh becomes inactive.
  NavigateAndCommit(GURL("https://www.bar.com/page2.html"));
  ASSERT_FALSE(old_rfh.get()->IsActive());

  // Passkeys arrive for the old driver/frame after page navigation.
  ChromeWebAuthnCredentialsDelegateFactory::GetFactory(web_contents())
      ->GetDelegateForFrame(old_rfh.get())
      ->OnCredentialsReceived(
          std::vector<password_manager::PasskeyCredential>(),
          ChromeWebAuthnCredentialsDelegate::SecurityKeyOrHybridFlowAvailable(
              true));
}

#endif  // BUILDFLAG(IS_ANDROID)
