// Copyright 2024 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/enterprise/data_protection/data_protection_clipboard_utils.h"

#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h"
#include "chrome/browser/enterprise/connectors/analysis/copy_warning_delegate_tracker.h"
#include "chrome/browser/enterprise/connectors/test/active_user_test_mixin.h"
#include "chrome/browser/enterprise/connectors/test/deep_scanning_test_utils.h"
#include "chrome/browser/enterprise/connectors/test/fake_content_analysis_delegate.h"
#include "chrome/browser/enterprise/data_controls/desktop_data_controls_dialog.h"
#include "chrome/browser/enterprise/data_controls/desktop_data_controls_dialog_test_helper.h"
#include "chrome/browser/policy/dm_token_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_test_util.h"
#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/toasts/api/toast_id.h"
#include "chrome/browser/ui/toasts/toast_controller.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/enterprise/connectors/core/features.h"
#include "components/enterprise/connectors/core/reporting_test_utils.h"
#include "components/enterprise/data_controls/content/browser/last_replaced_clipboard_data.h"
#include "components/enterprise/data_controls/core/browser/features.h"
#include "components/enterprise/data_controls/core/browser/test_utils.h"
#include "components/policy/core/common/cloud/cloud_policy_client.h"
#include "components/policy/core/common/cloud/cloud_policy_core.h"
#include "components/policy/core/common/cloud/dm_token.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
#include "components/policy/core/common/cloud/realtime_reporting_job_configuration.h"
#include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
#include "components/policy/core/common/policy_types.h"
#include "components/safe_browsing/core/common/features.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/clipboard_types.h"
#include "content/public/common/drop_data.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/permissions_test_utils.h"
#include "content/public/test/test_utils.h"
#include "third_party/blink/public/common/permissions/permission_utils.h"
#include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
#include "ui/base/clipboard/clipboard_metadata.h"
#include "ui/base/clipboard/clipboard_monitor.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/clipboard/test/clipboard_test_util.h"
#include "ui/base/clipboard/test/test_clipboard.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/widget/widget_delegate.h"

namespace enterprise_data_protection {

namespace {

constexpr char kWorkspaceUrlForUser0[] = "https://docs.google.com/u/0/";
constexpr char kWorkspaceUrlForUser1[] =
    "https://mail.google.com/foo/bar?authuser=1";
constexpr char kNonWorkspaceUrl[] = "https://not.workspace.com/";
constexpr char kUserName[] = "test-user@chromium.org";

constexpr char kContentAreaUser0[] = "foo@gmail.com";
constexpr char kContentAreaUser1[] = "bar@gmail.com";

content::ClipboardPasteData MakeClipboardPasteData(
    std::string text,
    std::string image,
    std::vector<base::FilePath> file_paths) {
  content::ClipboardPasteData clipboard_paste_data;
  clipboard_paste_data.text = base::UTF8ToUTF16(text);
  clipboard_paste_data.png = std::vector<uint8_t>(image.begin(), image.end());
  clipboard_paste_data.file_paths = std::move(file_paths);
  return clipboard_paste_data;
}

// TODO(crbug.com/387484337): Set up equivalent browser tests for Clank.
// Tests for functions and classes declared in data_protection_clipboard_utils.h
// For browser tests that test data protection integration with Chrome's
// clipboard logic, see clipboard_browsertests.cc
class DataControlsClipboardUtilsBrowserTest
    : public MixinBasedInProcessBrowserTest,
      public testing::WithParamInterface<std::tuple<bool, bool>> {
 public:
  DataControlsClipboardUtilsBrowserTest() {
    std::vector<base::test::FeatureRef> enabled_features = {
        data_controls::kDataControlsSearchWith,
        enterprise_connectors::kContentAnalysisClipboardCopy,
        enterprise_connectors::kGlicBulkDataEntrySupport,
        data_controls::kDataControlsGlic,
        safe_browsing::kClientSideDetectionClipboardCopyApi};
    std::vector<base::test::FeatureRef> disabled_features = {};

    scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
    active_user_test_mixin_ =
        std::make_unique<enterprise_connectors::test::ActiveUserTestMixin>(
            &mixin_host_, this, &embedded_https_test_server(),
            std::vector<const char*>({kContentAreaUser0, kContentAreaUser1}));

    ui::TestClipboard::CreateForCurrentThread();
  }

  ~DataControlsClipboardUtilsBrowserTest() override {
    ui::Clipboard::DestroyClipboardForCurrentThread();
  }

  void SetupContentAnalysisToBlockCopy() {
    enterprise_connectors::test::SetAnalysisConnector(
        browser()->GetProfile()->GetPrefs(),
        enterprise_connectors::AnalysisConnector::DATA_COPIED,
        R"(
          {
            "service_provider": "google",
            "enable": [
              {
                "url_list": ["*"],
                "tags": ["dlp"]
              }
            ],
            "block_until_verdict": 1
          })",
        machine_scope());

    auto status_callback = base::BindRepeating([](const std::string& contents,
                                                  const base::FilePath& path) {
      return enterprise_connectors::test::FakeContentAnalysisDelegate::
          DlpResponse(
              enterprise_connectors::ContentAnalysisResponse::Result::SUCCESS,
              "dlp", enterprise_connectors::TriggeredRule::BLOCK);
    });
    enterprise_connectors::ContentAnalysisDelegate::SetFactoryForTesting(
        base::BindRepeating(
            &enterprise_connectors::test::FakeContentAnalysisDelegate::Create,
            base::DoNothing(), status_callback, "dm_token"));
  }

  void SetupContentAnalysisToBlock() {
    enterprise_connectors::test::SetAnalysisConnector(
        browser()->GetProfile()->GetPrefs(),
        enterprise_connectors::AnalysisConnector::BULK_DATA_ENTRY,
        R"(
          {
            "service_provider": "google",
            "enable": [
              {
                "url_list": ["*"],
                "tags": ["dlp"]
              }
            ],
            "block_until_verdict": 1
          })",
        machine_scope());

    auto status_callback = base::BindRepeating([](const std::string& contents,
                                                  const base::FilePath& path) {
      return enterprise_connectors::test::FakeContentAnalysisDelegate::
          DlpResponse(
              enterprise_connectors::ContentAnalysisResponse::Result::SUCCESS,
              "dlp", enterprise_connectors::TriggeredRule::BLOCK);
    });
    enterprise_connectors::ContentAnalysisDelegate::SetFactoryForTesting(
        base::BindRepeating(
            &enterprise_connectors::test::FakeContentAnalysisDelegate::Create,
            base::DoNothing(), status_callback, "dm_token"));
  }

  void SetupDMToken() {
#if BUILDFLAG(IS_CHROMEOS)
    policy::SetDMTokenForTesting(policy::DMToken::CreateValidToken("dm_token"));
#else
    if (machine_scope()) {
      policy::SetDMTokenForTesting(
          policy::DMToken::CreateValidToken("dm_token"));
    } else {
      auto* manager = browser()->GetProfile()->GetUserCloudPolicyManager();
      if (manager && manager->core()->client()) {
        manager->core()->client()->SetupRegistration("dm_token", "client_id",
                                                     {});
      } else {
        enterprise_connectors::test::SetProfileDMToken(browser()->GetProfile(),
                                                       "dm_token");
      }
    }
#endif
  }

  bool machine_scope() const { return std::get<0>(GetParam()); }

  bool use_workspace_urls() const { return std::get<1>(GetParam()); }

  const char* test_url_0() const {
    return use_workspace_urls() ? kWorkspaceUrlForUser0 : kNonWorkspaceUrl;
  }

  const char* test_url_1() const {
    return use_workspace_urls() ? kWorkspaceUrlForUser1 : kNonWorkspaceUrl;
  }

  void SetUpOnMainThread() override {
    event_report_validator_helper_ = std::make_unique<
        enterprise_connectors::test::EventReportValidatorHelper>(
        browser()->GetProfile(), /*browser_test=*/true);

    MixinBasedInProcessBrowserTest::SetUpOnMainThread();
  }

  void TearDownOnMainThread() override {
    event_report_validator_helper_.reset();

    enterprise_connectors::ContentAnalysisDelegate::SetFactoryForTesting(
        enterprise_connectors::ContentAnalysisDelegate::Factory());
    policy::SetDMTokenForTesting(policy::DMToken::CreateEmptyToken());

    MixinBasedInProcessBrowserTest::TearDownOnMainThread();
  }

  content::WebContents* contents() {
    return browser()->GetTabStripModel()->GetActiveWebContents();
  }

  content::ClipboardEndpoint CreateURLClipboardEndpoint(const char* url) {
    return content::ClipboardEndpoint(ui::DataTransferEndpoint(GURL(url)),
                                      base::BindLambdaForTesting([this]() {
                                        return contents()->GetBrowserContext();
                                      }),
                                      *contents()->GetPrimaryMainFrame());
  }

  Profile* CreateAdditionalProfile() {
    ProfileManager* profile_manager = g_browser_process->profile_manager();

    base::FilePath new_path =
        profile_manager->GenerateNextProfileDirectoryPath();
    Profile& profile =
        profiles::testing::CreateProfileSync(profile_manager, new_path);
    return &profile;
  }

 protected:
  std::unique_ptr<enterprise_connectors::test::EventReportValidatorHelper>
      event_report_validator_helper_;
  base::test::ScopedFeatureList scoped_feature_list_;
  std::unique_ptr<enterprise_connectors::test::ActiveUserTestMixin>
      active_user_test_mixin_;
};

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       CopyContentAnalysisWarningCanceled) {
  active_user_test_mixin_->SetFakeCookieValue();
  SetupDMToken();

  enterprise_connectors::test::SetAnalysisConnector(
      browser()->GetProfile()->GetPrefs(),
      enterprise_connectors::AnalysisConnector::DATA_COPIED,
      R"(
        {
          "service_provider": "google",
          "enable": [
            {
              "url_list": ["*"],
              "tags": ["dlp"]
            }
          ],
          "block_until_verdict": 1
        })",
      machine_scope());
  enterprise_connectors::ContentAnalysisDelegate::SetFactoryForTesting(
      base::BindRepeating(
          &enterprise_connectors::test::FakeContentAnalysisDelegate::Create,
          base::DoNothing(),
          base::BindRepeating([](const std::string&, const base::FilePath&) {
            return enterprise_connectors::test::FakeContentAnalysisDelegate::
                DlpResponse(enterprise_connectors::ContentAnalysisResponse::
                                Result::SUCCESS,
                            "dlp",
                            enterprise_connectors::ContentAnalysisResponse::
                                Result::TriggeredRule::WARN);
          }),
          "dm_token"));

  ASSERT_TRUE(embedded_test_server()->Start());
  GURL url = embedded_test_server()->GetURL("/empty.html");
  ASSERT_TRUE(content::NavigateToURL(contents(), url));

  auto source = content::ClipboardEndpoint(
      ui::DataTransferEndpoint(url), base::BindLambdaForTesting([this]() {
        return contents()->GetBrowserContext();
      }),
      *contents()->GetPrimaryMainFrame());

  ui::ClipboardMetadata metadata = {
      .size = 100,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
  };
  content::ClipboardPasteData data;
  data.text = std::u16string(100, 'a');

  base::test::TestFuture<const ui::ClipboardFormatType&,
                         const content::ClipboardPasteData&,
                         std::optional<std::u16string>>
      future;

  data_controls::GetLastReplacedClipboardData() = {};
  ui::ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();

  IsClipboardCopyAllowedByPolicy(source, metadata, data, future.GetCallback());

  auto* toast_controller = browser()->GetFeatures().toast_controller();
  ASSERT_TRUE(toast_controller);

  // Wait until the warning creates the Toast.
  while (!toast_controller->IsShowingToast()) {
    base::RunLoop().RunUntilIdle();
  }

  EXPECT_EQ(toast_controller->GetCurrentToastId(),
            ToastId::kEnterpriseCopyWarning);

  toast_controller->GetToastWidgetForTesting()->CloseNow();
  enterprise_connectors::CopyWarningDelegateTracker::SetDelegate(contents(),
                                                                 nullptr);

  EXPECT_EQ(future.Get<0>().GetName(), metadata.format_type.GetName());

  EXPECT_TRUE(future.Get<1>().empty());

  auto replacement = future.Get<2>();
  EXPECT_TRUE(replacement.has_value());
  EXPECT_EQ(replacement.value(),
            l10n_util::GetStringUTF16(
                IDS_ENTERPRISE_CONTENT_ANALYSIS_COPY_BLOCKED_MESSAGE));

  {
    ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste);
    scw.WriteText(*replacement);
  }

  EXPECT_EQ(data_controls::GetLastReplacedClipboardData().restriction_level,
            data_controls::CopyRestrictionLevel::kBlocked);
}

INSTANTIATE_TEST_SUITE_P(All,
                         DataControlsClipboardUtilsBrowserTest,
                         testing::Combine(testing::Bool(), testing::Bool()));

}  // namespace

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       PasteAllowed_NoSource) {
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.ExpectNoReport();

  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardPasteBlock);
  base::test::TestFuture<std::optional<content::ClipboardPasteData>> future;
  auto source = content::ClipboardEndpoint(std::nullopt);
  auto destination = CreateURLClipboardEndpoint("https://google.com");
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
  };
  EXPECT_FALSE(IsPastePolicyCheckRequired(source, destination, metadata));
  PasteIfAllowedByPolicy(source, destination, metadata,
                         MakeClipboardPasteData("text", "image", {}),
                         future.GetCallback());

  auto paste_data = future.Get();
  EXPECT_TRUE(paste_data);
  EXPECT_EQ(paste_data->text, u"text");
  EXPECT_EQ(std::string(paste_data->png.begin(), paste_data->png.end()),
            "image");

  EXPECT_FALSE(helper.dialog());
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       PasteAllowed_SameSource) {
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.ExpectNoReport();

  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardPasteBlock);
  base::test::TestFuture<std::optional<content::ClipboardPasteData>> future;
  auto source = CreateURLClipboardEndpoint(test_url_0());
  auto destination = CreateURLClipboardEndpoint(test_url_0());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::HtmlType(),
  };
  EXPECT_FALSE(IsPastePolicyCheckRequired(source, destination, metadata));
  PasteIfAllowedByPolicy(source, destination, metadata,
                         MakeClipboardPasteData("text", "image", {}),
                         future.GetCallback());

  auto paste_data = future.Get();
  EXPECT_TRUE(paste_data);
  EXPECT_EQ(paste_data->text, u"text");
  EXPECT_EQ(std::string(paste_data->png.begin(), paste_data->png.end()),
            "image");

  EXPECT_FALSE(helper.dialog());
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       PasteBlockedByDataControls_DestinationRule) {
  active_user_test_mixin_->SetFakeCookieValue();

  base::RunLoop run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop.QuitClosure());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  if (use_workspace_urls()) {
    expected_event.set_web_app_signed_in_account(kContentAreaUser1);
  }
  expected_event.set_url(test_url_1());
  expected_event.set_tab_url(test_url_1());
  expected_event.set_source("CLIPBOARD");
  expected_event.set_destination(test_url_1());
  expected_event.set_content_type("text/plain");
  expected_event.set_content_size(1234);
  expected_event.set_trigger(chrome::cros::reporting::proto::
                                 DataTransferEventTrigger::WEB_CONTENT_UPLOAD);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BLOCKED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_id(222);
  triggered_rule.set_rule_name("rule_name");

  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "rule_name",
                                   "rule_id": "222",
                                   "destinations": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "BLOCK"}
                                   ]
                                 })"},
                                 machine_scope());
  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardPasteBlock);

  base::test::TestFuture<std::optional<content::ClipboardPasteData>> future;
  auto source = content::ClipboardEndpoint(std::nullopt);
  auto destination = CreateURLClipboardEndpoint(test_url_1());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
  };
  EXPECT_TRUE(IsPastePolicyCheckRequired(source, destination, metadata));
  PasteIfAllowedByPolicy(source, destination, metadata,
                         MakeClipboardPasteData("text", "image", {}),
                         future.GetCallback());

  auto paste_data = future.Get();
  EXPECT_FALSE(paste_data);

  helper.WaitForDialogToInitialize();
  helper.CloseDialogWithoutBypass();
  helper.WaitForDialogToClose();
  run_loop.Run();
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       PasteWarnedByDataControls_BypassedDestinationRule) {
  active_user_test_mixin_->SetFakeCookieValue();

  base::RunLoop run_loop_warn;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop_warn.QuitClosure());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent
      expected_warned_dlp_event;
  if (use_workspace_urls()) {
    expected_warned_dlp_event.set_web_app_signed_in_account(kContentAreaUser0);
  }
  expected_warned_dlp_event.set_url(test_url_0());
  expected_warned_dlp_event.set_tab_url(test_url_0());
  expected_warned_dlp_event.set_source("CLIPBOARD");
  expected_warned_dlp_event.set_destination(test_url_0());
  expected_warned_dlp_event.set_content_type("image/svg+xml");
  expected_warned_dlp_event.set_content_size(1234);
  expected_warned_dlp_event.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::
          WEB_CONTENT_UPLOAD);
  expected_warned_dlp_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_WARNED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_id(333);
  triggered_rule.set_rule_name("warn_rule_name");

  *expected_warned_dlp_event.add_triggered_rule_info() = triggered_rule;
  expected_warned_dlp_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_warned_dlp_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(
      std::move(expected_warned_dlp_event));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "warn_rule_name",
                                   "rule_id": "333",
                                   "destinations": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "WARN"}
                                   ]
                                 })"},
                                 machine_scope());
  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardPasteWarn);

  base::test::TestFuture<std::optional<content::ClipboardPasteData>> future;
  auto source = content::ClipboardEndpoint(std::nullopt);
  auto destination = CreateURLClipboardEndpoint(test_url_0());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::SvgType(),
  };
  EXPECT_TRUE(IsPastePolicyCheckRequired(source, destination, metadata));
  PasteIfAllowedByPolicy(source, destination, metadata,
                         MakeClipboardPasteData("text", "image", {}),
                         future.GetCallback());

  helper.WaitForDialogToInitialize();
  run_loop_warn.Run();

  // The first warn event should already be reported before the dialog has been
  // initialized, so it can be reassigned so that the bypass event can be
  // validated.
  base::RunLoop run_loop_bypass;
  event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop_bypass.QuitClosure());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent
      expected_bypassed_dlp_event;
  if (use_workspace_urls()) {
    expected_bypassed_dlp_event.set_web_app_signed_in_account(
        kContentAreaUser0);
  }
  expected_bypassed_dlp_event.set_url(test_url_0());
  expected_bypassed_dlp_event.set_tab_url(test_url_0());
  expected_bypassed_dlp_event.set_source("CLIPBOARD");
  expected_bypassed_dlp_event.set_destination(test_url_0());
  expected_bypassed_dlp_event.set_content_type("image/svg+xml");
  expected_bypassed_dlp_event.set_content_size(1234);
  expected_bypassed_dlp_event.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::
          WEB_CONTENT_UPLOAD);
  expected_bypassed_dlp_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BYPASSED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_bypassed_rule;
  triggered_bypassed_rule.set_rule_id(333);
  triggered_bypassed_rule.set_rule_name("warn_rule_name");

  *expected_bypassed_dlp_event.add_triggered_rule_info() =
      triggered_bypassed_rule;
  expected_bypassed_dlp_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_bypassed_dlp_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(
      std::move(expected_bypassed_dlp_event));

  // The dialog will stay up until a user action dismisses it, so `future`
  // shouldn't be ready yet.
  EXPECT_FALSE(future.IsReady());

  helper.BypassWarning();
  helper.WaitForDialogToClose();

  auto paste_data = future.Get();
  EXPECT_TRUE(paste_data);
  EXPECT_EQ(paste_data->text, u"text");
  EXPECT_EQ(std::string(paste_data->png.begin(), paste_data->png.end()),
            "image");
  run_loop_bypass.Run();
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       PasteWarnedByDataControls_CanceledDestinationRule) {
  active_user_test_mixin_->SetFakeCookieValue();

  base::RunLoop run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop.QuitClosure());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  if (use_workspace_urls()) {
    expected_event.set_web_app_signed_in_account(kContentAreaUser1);
  }
  expected_event.set_url(test_url_1());
  expected_event.set_tab_url(test_url_1());
  expected_event.set_source("CLIPBOARD");
  expected_event.set_destination(test_url_1());
  expected_event.set_content_type("image/png");
  expected_event.set_content_size(1234);
  expected_event.set_trigger(chrome::cros::reporting::proto::
                                 DataTransferEventTrigger::WEB_CONTENT_UPLOAD);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_WARNED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_id(1416);
  triggered_rule.set_rule_name("warn rule name");

  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "warn rule name",
                                   "rule_id": "1416",
                                   "destinations": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "WARN"}
                                   ]
                                 })"},
                                 machine_scope());
  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardPasteWarn);

  base::test::TestFuture<std::optional<content::ClipboardPasteData>> future;
  auto source = content::ClipboardEndpoint(std::nullopt);
  auto destination = CreateURLClipboardEndpoint(test_url_1());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::PngType(),
  };
  EXPECT_TRUE(IsPastePolicyCheckRequired(source, destination, metadata));
  PasteIfAllowedByPolicy(source, destination, metadata,
                         MakeClipboardPasteData("text", "image", {}),
                         future.GetCallback());

  helper.WaitForDialogToInitialize();

  // The dialog will stay up until a user action dismisses it, so `future`
  // shouldn't be ready yet.
  EXPECT_FALSE(future.IsReady());

  helper.CloseDialogWithoutBypass();
  helper.WaitForDialogToClose();

  auto paste_data = future.Get();
  EXPECT_FALSE(paste_data);
  run_loop.Run();
}

// ChromeOS requires extra boilerplate to run this test, and since copy-pasting
// between profiles on ChromeOS isn't a meaningful test it is simply omitted
// from running this.
#if !BUILDFLAG(IS_CHROMEOS)
IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       PasteBlockedByDataControls_SourceRule) {
  // By making a new profile for this test, we ensure we can prevent pasting to
  // it by having the rule set in the source profile only.
  Profile* source_profile = CreateAdditionalProfile();
  data_controls::SetDataControls(source_profile->GetPrefs(), {R"({
                                   "name": "report_rule_name",
                                   "rule_id": "4321",
                                   "destinations": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "BLOCK"}
                                   ]
                                 })"},
                                 machine_scope());

  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardPasteBlock);

  base::RunLoop report_run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();

  // The event should only be reported when the policies are set at the machine
  // level as we would otherwise be reporting from a different unmanaged or
  // unaffiliated profile.
  if (machine_scope()) {
    event_validator.SetDoneClosure(report_run_loop.QuitClosure());
    chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
    expected_event.set_url(test_url_1());
    expected_event.set_tab_url(test_url_1());
    expected_event.set_source("OTHER_PROFILE");
    expected_event.set_destination(test_url_1());
    expected_event.set_content_type("text/plain");
    expected_event.set_content_size(1234);
    expected_event.set_trigger(
        chrome::cros::reporting::proto::DataTransferEventTrigger::
            WEB_CONTENT_UPLOAD);
    expected_event.set_event_result(
        chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BLOCKED);

    ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
    triggered_rule.set_rule_id(4321);
    triggered_rule.set_rule_name("report_rule_name");

    *expected_event.add_triggered_rule_info() = triggered_rule;
    expected_event.set_profile_identifier(
        browser()->GetProfile()->GetPath().AsUTF8Unsafe());
    expected_event.set_profile_user_name(kUserName);

    event_validator.ExpectSensitiveDataEvent(std::move(expected_event));
  } else {
    event_validator.ExpectNoReport();
  }

  base::test::TestFuture<std::optional<content::ClipboardPasteData>> future;
  auto source = content::ClipboardEndpoint(
      ui::DataTransferEndpoint(GURL(test_url_0())),
      base::BindLambdaForTesting(
          [&source_profile]() -> content::BrowserContext* {
            return source_profile;
          }),
      *contents()->GetPrimaryMainFrame());
  auto destination =
      content::ClipboardEndpoint(ui::DataTransferEndpoint(GURL(test_url_1())),
                                 base::BindLambdaForTesting([this]() {
                                   return contents()->GetBrowserContext();
                                 }),
                                 *contents()->GetPrimaryMainFrame());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
  };
  EXPECT_TRUE(IsPastePolicyCheckRequired(source, destination, metadata));
  PasteIfAllowedByPolicy(source, destination, metadata,
                         MakeClipboardPasteData("text", "image", {}),
                         future.GetCallback());

  auto paste_data = future.Get();
  EXPECT_FALSE(paste_data);

  helper.WaitForDialogToInitialize();
  helper.CloseDialogWithoutBypass();
  helper.WaitForDialogToClose();

  if (machine_scope()) {
    report_run_loop.Run();
  }
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       PasteWarnedByDataControls_BypassedSourceRule) {
  // By making a new profile for this test, we ensure we can prevent pasting to
  // it by having the rule set in the source profile only.
  Profile* source_profile = CreateAdditionalProfile();
  data_controls::SetDataControls(source_profile->GetPrefs(), {R"({
                                   "name": "report_rule_name",
                                   "rule_id": "6543",
                                   "destinations": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "WARN"}
                                   ]
                                 })"},
                                 machine_scope());

  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardPasteWarn);

  base::RunLoop run_loop_warn;
  auto event_validator = event_report_validator_helper_->CreateValidator();

  // The event should only be reported when the policies are set at the machine
  // level as we would otherwise be reporting from a different unmanaged or
  // unaffiliated profile.
  if (machine_scope()) {
    event_validator.SetDoneClosure(run_loop_warn.QuitClosure());
    chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
    expected_event.set_url(test_url_1());
    expected_event.set_tab_url(test_url_1());
    expected_event.set_source("OTHER_PROFILE");
    expected_event.set_destination(test_url_1());
    expected_event.set_content_type("text/plain");
    expected_event.set_content_size(1234);
    expected_event.set_trigger(
        chrome::cros::reporting::proto::DataTransferEventTrigger::
            WEB_CONTENT_UPLOAD);
    expected_event.set_event_result(
        chrome::cros::reporting::proto::EventResult::EVENT_RESULT_WARNED);

    ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
    triggered_rule.set_rule_id(6543);
    triggered_rule.set_rule_name("report_rule_name");

    *expected_event.add_triggered_rule_info() = triggered_rule;
    expected_event.set_profile_identifier(
        browser()->GetProfile()->GetPath().AsUTF8Unsafe());
    expected_event.set_profile_user_name(kUserName);

    event_validator.ExpectSensitiveDataEvent(std::move(expected_event));
  } else {
    event_validator.ExpectNoReport();
  }

  base::test::TestFuture<std::optional<content::ClipboardPasteData>> future;
  auto source = content::ClipboardEndpoint(
      ui::DataTransferEndpoint(GURL(test_url_0())),
      base::BindLambdaForTesting(
          [&source_profile]() -> content::BrowserContext* {
            return source_profile;
          }),
      *contents()->GetPrimaryMainFrame());
  auto destination =
      content::ClipboardEndpoint(ui::DataTransferEndpoint(GURL(test_url_1())),
                                 base::BindLambdaForTesting([this]() {
                                   return contents()->GetBrowserContext();
                                 }),
                                 *contents()->GetPrimaryMainFrame());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
  };
  EXPECT_TRUE(IsPastePolicyCheckRequired(source, destination, metadata));
  PasteIfAllowedByPolicy(source, destination, metadata,
                         MakeClipboardPasteData("text", "image", {}),
                         future.GetCallback());

  // The dialog will stay up until a user action dismisses it, so `future`
  // shouldn't be ready yet.
  EXPECT_FALSE(future.IsReady());

  base::RunLoop run_loop_bypass;
  if (machine_scope()) {
    run_loop_warn.Run();

    // The first warn event should already be reported before the dialog has
    // been initialized, so it can be reassigned so that the bypass event can be
    // validated.
    event_validator = event_report_validator_helper_->CreateValidator();
    event_validator.SetDoneClosure(run_loop_bypass.QuitClosure());
    chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
    expected_event.set_url(test_url_1());
    expected_event.set_tab_url(test_url_1());
    expected_event.set_source("OTHER_PROFILE");
    expected_event.set_destination(test_url_1());
    expected_event.set_content_type("text/plain");
    expected_event.set_content_size(1234);
    expected_event.set_trigger(
        chrome::cros::reporting::proto::DataTransferEventTrigger::
            WEB_CONTENT_UPLOAD);
    expected_event.set_event_result(
        chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BYPASSED);

    ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
    triggered_rule.set_rule_id(6543);
    triggered_rule.set_rule_name("report_rule_name");

    *expected_event.add_triggered_rule_info() = triggered_rule;
    expected_event.set_profile_identifier(
        browser()->GetProfile()->GetPath().AsUTF8Unsafe());
    expected_event.set_profile_user_name(kUserName);

    event_validator.ExpectSensitiveDataEvent(std::move(expected_event));
  }

  helper.BypassWarning();
  helper.WaitForDialogToClose();

  auto paste_data = future.Get();
  EXPECT_TRUE(paste_data);
  EXPECT_EQ(paste_data->text, u"text");
  EXPECT_EQ(std::string(paste_data->png.begin(), paste_data->png.end()),
            "image");

  if (machine_scope()) {
    run_loop_bypass.Run();
  }
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       PasteWarnedByDataControls_CanceledSourceRule) {
  // By making a new profile for this test, we ensure we can prevent pasting to
  // it by having the rule set in the source profile only.
  Profile* source_profile = CreateAdditionalProfile();
  data_controls::SetDataControls(source_profile->GetPrefs(), {R"({
                                   "name": "report_rule_name",
                                   "rule_id": "7654",
                                   "destinations": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "WARN"}
                                   ]
                                 })"},
                                 machine_scope());

  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardPasteWarn);

  base::RunLoop report_run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();

  // The event should only be reported when the policies are set at the machine
  // level as we would otherwise be reporting from a different unmanaged or
  // unaffiliated profile.
  if (machine_scope()) {
    event_validator.SetDoneClosure(report_run_loop.QuitClosure());
    chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
    expected_event.set_url(test_url_1());
    expected_event.set_tab_url(test_url_1());
    expected_event.set_source("OTHER_PROFILE");
    expected_event.set_destination(test_url_1());
    expected_event.set_content_type("text/plain");
    expected_event.set_content_size(1234);
    expected_event.set_trigger(
        chrome::cros::reporting::proto::DataTransferEventTrigger::
            WEB_CONTENT_UPLOAD);
    expected_event.set_event_result(
        chrome::cros::reporting::proto::EventResult::EVENT_RESULT_WARNED);

    ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
    triggered_rule.set_rule_id(7654);
    triggered_rule.set_rule_name("report_rule_name");

    *expected_event.add_triggered_rule_info() = triggered_rule;
    expected_event.set_profile_identifier(
        browser()->GetProfile()->GetPath().AsUTF8Unsafe());
    expected_event.set_profile_user_name(kUserName);

    event_validator.ExpectSensitiveDataEvent(std::move(expected_event));
  } else {
    event_validator.ExpectNoReport();
  }

  base::test::TestFuture<std::optional<content::ClipboardPasteData>> future;
  auto source = content::ClipboardEndpoint(
      ui::DataTransferEndpoint(GURL(test_url_0())),
      base::BindLambdaForTesting(
          [&source_profile]() -> content::BrowserContext* {
            return source_profile;
          }),
      *contents()->GetPrimaryMainFrame());
  auto destination =
      content::ClipboardEndpoint(ui::DataTransferEndpoint(GURL(test_url_1())),
                                 base::BindLambdaForTesting([this]() {
                                   return contents()->GetBrowserContext();
                                 }),
                                 *contents()->GetPrimaryMainFrame());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
  };
  EXPECT_TRUE(IsPastePolicyCheckRequired(source, destination, metadata));
  PasteIfAllowedByPolicy(source, destination, metadata,
                         MakeClipboardPasteData("text", "image", {}),
                         future.GetCallback());

  // The dialog will stay up until a user action dismisses it, so `future`
  // shouldn't be ready yet.
  EXPECT_FALSE(future.IsReady());

  helper.CloseDialogWithoutBypass();
  helper.WaitForDialogToClose();

  auto paste_data = future.Get();
  EXPECT_FALSE(paste_data);

  if (machine_scope()) {
    report_run_loop.Run();
  }
}
#endif  // !BUILDFLAG(IS_CHROMEOS)

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       PasteReportedByDataControls_DestinationRule) {
  active_user_test_mixin_->SetFakeCookieValue();

  base::RunLoop run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop.QuitClosure());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  if (use_workspace_urls()) {
    expected_event.set_web_app_signed_in_account(kContentAreaUser0);
  }
  expected_event.set_url(test_url_0());
  expected_event.set_tab_url(test_url_0());
  expected_event.set_source("CLIPBOARD");
  expected_event.set_destination(test_url_0());
  expected_event.set_content_type("image/svg+xml");
  expected_event.set_content_size(1234);
  expected_event.set_trigger(chrome::cros::reporting::proto::
                                 DataTransferEventTrigger::WEB_CONTENT_UPLOAD);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_ALLOWED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_id(8765);
  triggered_rule.set_rule_name("report_rule_name");

  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "report_rule_name",
                                   "rule_id": "8765",
                                   "destinations": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "REPORT"}
                                   ]
                                 })"},
                                 machine_scope());
  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardPasteWarn);

  base::test::TestFuture<std::optional<content::ClipboardPasteData>> future;
  auto source = content::ClipboardEndpoint(std::nullopt);
  auto destination = CreateURLClipboardEndpoint(test_url_0());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::SvgType(),
  };
  EXPECT_TRUE(IsPastePolicyCheckRequired(source, destination, metadata));
  PasteIfAllowedByPolicy(source, destination, metadata,
                         MakeClipboardPasteData("text", "image", {}),
                         future.GetCallback());

  ASSERT_FALSE(helper.dialog());
  auto paste_data = future.Get();
  EXPECT_TRUE(paste_data);
  EXPECT_EQ(paste_data->text, u"text");
  EXPECT_EQ(std::string(paste_data->png.begin(), paste_data->png.end()),
            "image");
  run_loop.Run();
}

// ChromeOS requires extra boilerplate to run this test, and since copy-pasting
// between profiles on ChromeOS isn't a meaningful test it is simply omitted
// from running this.
#if !BUILDFLAG(IS_CHROMEOS)
IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       PasteReportedByDataControls_SourceRule) {
  // By making a new profile for this test, we ensure we can prevent pasting to
  // it by having the rule set in the source profile only.
  Profile* source_profile = CreateAdditionalProfile();
  data_controls::SetDataControls(source_profile->GetPrefs(), {R"({
                                   "name": "report_rule_name",
                                   "rule_id": "9753",
                                   "destinations": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "REPORT"}
                                   ]
                                 })"},
                                 machine_scope());

  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardPasteBlock);

  base::RunLoop report_run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();

  // The event should only be reported when the policies are set at the machine
  // level as we would otherwise be reporting from a different unmanaged or
  // unaffiliated profile.
  if (machine_scope()) {
    event_validator.SetDoneClosure(report_run_loop.QuitClosure());
    chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
    expected_event.set_url(test_url_1());
    expected_event.set_tab_url(test_url_1());
    expected_event.set_source("OTHER_PROFILE");
    expected_event.set_destination(test_url_1());
    expected_event.set_content_type("text/plain");
    expected_event.set_content_size(1234);
    expected_event.set_trigger(
        chrome::cros::reporting::proto::DataTransferEventTrigger::
            WEB_CONTENT_UPLOAD);
    expected_event.set_event_result(
        chrome::cros::reporting::proto::EventResult::EVENT_RESULT_ALLOWED);

    ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
    triggered_rule.set_rule_id(9753);
    triggered_rule.set_rule_name("report_rule_name");

    *expected_event.add_triggered_rule_info() = triggered_rule;
    expected_event.set_profile_identifier(
        browser()->GetProfile()->GetPath().AsUTF8Unsafe());
    expected_event.set_profile_user_name(kUserName);

    event_validator.ExpectSensitiveDataEvent(std::move(expected_event));
  } else {
    event_validator.ExpectNoReport();
  }

  base::test::TestFuture<std::optional<content::ClipboardPasteData>> future;
  auto source = content::ClipboardEndpoint(
      ui::DataTransferEndpoint(GURL(test_url_0())),
      base::BindLambdaForTesting(
          [&source_profile]() -> content::BrowserContext* {
            return source_profile;
          }),
      *contents()->GetPrimaryMainFrame());
  auto destination =
      content::ClipboardEndpoint(ui::DataTransferEndpoint(GURL(test_url_1())),
                                 base::BindLambdaForTesting([this]() {
                                   return contents()->GetBrowserContext();
                                 }),
                                 *contents()->GetPrimaryMainFrame());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
  };
  EXPECT_TRUE(IsPastePolicyCheckRequired(source, destination, metadata));
  PasteIfAllowedByPolicy(source, destination, metadata,
                         MakeClipboardPasteData("text", "image", {}),
                         future.GetCallback());

  ASSERT_FALSE(helper.dialog());
  auto paste_data = future.Get();
  EXPECT_TRUE(paste_data);
  EXPECT_EQ(paste_data->text, u"text");
  EXPECT_EQ(std::string(paste_data->png.begin(), paste_data->png.end()),
            "image");

  if (machine_scope()) {
    report_run_loop.Run();
  }
}
#endif  // !BUILDFLAG(IS_CHROMEOS)

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest, CopyAllowed) {
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.ExpectNoReport();

  auto source = content::ClipboardEndpoint(
      ui::DataTransferEndpoint(GURL("https://google.com")),
      base::BindLambdaForTesting(
          [this]() { return contents()->GetBrowserContext(); }),
      *contents()->GetPrimaryMainFrame());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
  };
  EXPECT_FALSE(IsCopyPolicyCheckRequired(source, metadata));

  base::test::TestFuture<const ui::ClipboardFormatType&,
                         const content::ClipboardPasteData&,
                         std::optional<std::u16string>>
      future;
  IsClipboardCopyAllowedByPolicy(source, metadata,
                                 MakeClipboardPasteData("foo", "", {}),
                                 future.GetCallback());

  auto data = future.Get<content::ClipboardPasteData>();
  EXPECT_EQ(data.text, u"foo");

  auto replacement = future.Get<std::optional<std::u16string>>();
  EXPECT_FALSE(replacement);
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest, CopyReported) {
  active_user_test_mixin_->SetFakeCookieValue();

  base::RunLoop run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop.QuitClosure());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  if (use_workspace_urls()) {
    expected_event.set_web_app_signed_in_account(kContentAreaUser1);
    expected_event.set_source_web_app_signed_in_account(kContentAreaUser1);
  }
  expected_event.set_url(test_url_1());
  expected_event.set_tab_url(test_url_1());
  expected_event.set_source(test_url_1());
  expected_event.set_destination("");
  expected_event.set_content_type("image/svg+xml");
  expected_event.set_content_size(1234);
  expected_event.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::CLIPBOARD_COPY);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_ALLOWED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_id(1248);
  triggered_rule.set_rule_name("report_only");

  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "report_only",
                                   "rule_id": "1248",
                                   "sources": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "REPORT"}
                                   ]
                                 })"},
                                 machine_scope());

  auto source = CreateURLClipboardEndpoint(test_url_1());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::SvgType(),
  };
  EXPECT_TRUE(IsCopyPolicyCheckRequired(source, metadata));

  base::test::TestFuture<const ui::ClipboardFormatType&,
                         const content::ClipboardPasteData&,
                         std::optional<std::u16string>>
      future;
  IsClipboardCopyAllowedByPolicy(source, metadata,
                                 MakeClipboardPasteData("foo", "", {}),
                                 future.GetCallback());

  auto data = future.Get<content::ClipboardPasteData>();
  EXPECT_EQ(data.text, u"foo");

  auto replacement = future.Get<std::optional<std::u16string>>();
  EXPECT_FALSE(replacement);
  run_loop.Run();
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest, CopyBlocked) {
  active_user_test_mixin_->SetFakeCookieValue();

  base::RunLoop run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop.QuitClosure());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  if (use_workspace_urls()) {
    expected_event.set_web_app_signed_in_account(kContentAreaUser0);
    expected_event.set_source_web_app_signed_in_account(kContentAreaUser0);
  }
  expected_event.set_url(test_url_0());
  expected_event.set_tab_url(test_url_0());
  expected_event.set_source(test_url_0());
  expected_event.set_destination("");
  expected_event.set_content_type("image/svg+xml");
  expected_event.set_content_size(1234);
  expected_event.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::CLIPBOARD_COPY);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BLOCKED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_id(987);
  triggered_rule.set_rule_name("block");

  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "block",
                                   "rule_id": "987",
                                   "sources": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "BLOCK"}
                                   ]
                                 })"},
                                 machine_scope());
  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardCopyBlock);

  auto source = CreateURLClipboardEndpoint(test_url_0());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::SvgType(),
  };
  EXPECT_TRUE(IsCopyPolicyCheckRequired(source, metadata));

  base::test::TestFuture<const ui::ClipboardFormatType&,
                         const content::ClipboardPasteData&,
                         std::optional<std::u16string>>
      future;
  IsClipboardCopyAllowedByPolicy(source, metadata,
                                 MakeClipboardPasteData("foo", "", {}),
                                 future.GetCallback());

  helper.WaitForDialogToInitialize();
  helper.CloseDialogWithoutBypass();
  helper.WaitForDialogToClose();

  EXPECT_TRUE(future.IsReady());
  auto data = future.Get<content::ClipboardPasteData>();
  EXPECT_EQ(data.text, u"");

  auto replacement = future.Get<std::optional<std::u16string>>();
  EXPECT_FALSE(replacement);
  run_loop.Run();
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       CopyWarnedThenCanceled) {
  active_user_test_mixin_->SetFakeCookieValue();

  base::RunLoop run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop.QuitClosure());
  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  if (use_workspace_urls()) {
    expected_event.set_web_app_signed_in_account(kContentAreaUser1);
    expected_event.set_source_web_app_signed_in_account(kContentAreaUser1);
  }
  expected_event.set_url(test_url_1());
  expected_event.set_tab_url(test_url_1());
  expected_event.set_source(test_url_1());
  expected_event.set_destination("");
  expected_event.set_content_type("image/png");
  expected_event.set_content_size(1234);
  expected_event.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::CLIPBOARD_COPY);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_WARNED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_id(3927);
  triggered_rule.set_rule_name("warn");

  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "warn",
                                   "rule_id": "3927",
                                   "sources": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "WARN"}
                                   ]
                                 })"},
                                 machine_scope());
  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardCopyWarn);

  auto source = CreateURLClipboardEndpoint(test_url_1());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::PngType(),
  };
  EXPECT_TRUE(IsCopyPolicyCheckRequired(source, metadata));

  base::test::TestFuture<const ui::ClipboardFormatType&,
                         const content::ClipboardPasteData&,
                         std::optional<std::u16string>>
      future;
  IsClipboardCopyAllowedByPolicy(source, metadata,
                                 MakeClipboardPasteData("foo", "", {}),
                                 future.GetCallback());

  helper.WaitForDialogToInitialize();

  // The dialog will stay up until a user action dismisses it, so `future`
  // shouldn't be ready yet.
  EXPECT_FALSE(future.IsReady());

  helper.CloseDialogWithoutBypass();
  helper.WaitForDialogToClose();

  auto data = future.Get<content::ClipboardPasteData>();
  EXPECT_EQ(data.text, u"");

  auto replacement = future.Get<std::optional<std::u16string>>();
  EXPECT_FALSE(replacement);
  run_loop.Run();
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       CopyWarnedThenCanceled_OsClipboardDestination) {
  active_user_test_mixin_->SetFakeCookieValue();

  base::RunLoop run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop.QuitClosure());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  if (use_workspace_urls()) {
    expected_event.set_web_app_signed_in_account(kContentAreaUser0);
    expected_event.set_source_web_app_signed_in_account(kContentAreaUser0);
  }
  expected_event.set_url(test_url_0());
  expected_event.set_tab_url(test_url_0());
  expected_event.set_source(test_url_0());
  expected_event.set_destination("");
  expected_event.set_content_type("text/plain");
  expected_event.set_content_size(1234);
  expected_event.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::CLIPBOARD_COPY);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_WARNED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_id(101);
  triggered_rule.set_rule_name("warn_cancel");

  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "warn_cancel",
                                   "rule_id": "101",
                                   "sources": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "destinations": {
                                     "os_clipboard": true
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "WARN"}
                                   ]
                                 })"},
                                 machine_scope());
  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardCopyWarn);

  auto source = CreateURLClipboardEndpoint(test_url_0());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
  };
  EXPECT_TRUE(IsCopyPolicyCheckRequired(source, metadata));

  base::test::TestFuture<const ui::ClipboardFormatType&,
                         const content::ClipboardPasteData&,
                         std::optional<std::u16string>>
      future;
  IsClipboardCopyAllowedByPolicy(source, metadata,
                                 MakeClipboardPasteData("foo", "", {}),
                                 future.GetCallback());

  helper.WaitForDialogToInitialize();

  // The dialog will stay up until a user action dismisses it, so `future`
  // shouldn't be ready yet.
  EXPECT_FALSE(future.IsReady());

  helper.CloseDialogWithoutBypass();
  helper.WaitForDialogToClose();

  auto data = future.Get<content::ClipboardPasteData>();
  EXPECT_EQ(data.text, u"");

  auto replacement = future.Get<std::optional<std::u16string>>();
  EXPECT_FALSE(replacement);
  run_loop.Run();
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       CopyWarnedThenBypassed) {
  active_user_test_mixin_->SetFakeCookieValue();

  base::RunLoop run_loop_warn;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop_warn.QuitClosure());

  {
    chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
    if (use_workspace_urls()) {
      expected_event.set_web_app_signed_in_account(kContentAreaUser1);
      expected_event.set_source_web_app_signed_in_account(kContentAreaUser1);
    }
    expected_event.set_url(test_url_1());
    expected_event.set_tab_url(test_url_1());
    expected_event.set_source(test_url_1());
    expected_event.set_destination("");
    expected_event.set_content_type("text/html");
    expected_event.set_content_size(1234);
    expected_event.set_trigger(chrome::cros::reporting::proto::
                                   DataTransferEventTrigger::CLIPBOARD_COPY);
    expected_event.set_event_result(
        chrome::cros::reporting::proto::EventResult::EVENT_RESULT_WARNED);

    ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
    triggered_rule.set_rule_id(12345);
    triggered_rule.set_rule_name("warn_bypass");

    *expected_event.add_triggered_rule_info() = triggered_rule;
    expected_event.set_profile_identifier(
        browser()->GetProfile()->GetPath().AsUTF8Unsafe());
    expected_event.set_profile_user_name(kUserName);

    event_validator.ExpectSensitiveDataEvent(std::move(expected_event));
  }

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "warn_bypass",
                                   "rule_id": "12345",
                                   "sources": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "WARN"}
                                   ]
                                 })"},
                                 machine_scope());
  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardCopyWarn);

  auto source = CreateURLClipboardEndpoint(test_url_1());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::HtmlType(),
  };
  EXPECT_TRUE(IsCopyPolicyCheckRequired(source, metadata));

  base::test::TestFuture<const ui::ClipboardFormatType&,
                         const content::ClipboardPasteData&,
                         std::optional<std::u16string>>
      future;
  IsClipboardCopyAllowedByPolicy(source, metadata,
                                 MakeClipboardPasteData("foo", "", {}),
                                 future.GetCallback());

  helper.WaitForDialogToInitialize();

  run_loop_warn.Run();

  // The dialog will stay up until a user action dismisses it, so `future`
  // shouldn't be ready yet.
  EXPECT_FALSE(future.IsReady());

  // The first warn event should already be reported before the dialog has been
  // initialized, so it can be reassigned so that the bypass event can be
  // validated.
  base::RunLoop run_loop_bypass;
  event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop_bypass.QuitClosure());
  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event_bypass;
  if (use_workspace_urls()) {
    expected_event_bypass.set_web_app_signed_in_account(kContentAreaUser1);
    expected_event_bypass.set_source_web_app_signed_in_account(
        kContentAreaUser1);
  }
  expected_event_bypass.set_url(test_url_1());
  expected_event_bypass.set_tab_url(test_url_1());
  expected_event_bypass.set_source(test_url_1());
  expected_event_bypass.set_destination("");
  expected_event_bypass.set_content_type("text/html");
  expected_event_bypass.set_content_size(1234);
  expected_event_bypass.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::CLIPBOARD_COPY);
  expected_event_bypass.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BYPASSED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule_bypass;
  triggered_rule_bypass.set_rule_id(12345);
  triggered_rule_bypass.set_rule_name("warn_bypass");

  *expected_event_bypass.add_triggered_rule_info() = triggered_rule_bypass;
  expected_event_bypass.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event_bypass.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event_bypass));

  helper.BypassWarning();
  helper.WaitForDialogToClose();

  auto data = future.Get<content::ClipboardPasteData>();
  EXPECT_EQ(data.text, u"foo");

  auto replacement = future.Get<std::optional<std::u16string>>();
  EXPECT_FALSE(replacement);
  run_loop_bypass.Run();
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       CopyWarnedThenBypassed_OsClipboardDestination) {
  active_user_test_mixin_->SetFakeCookieValue();

  base::RunLoop run_loop_warn;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop_warn.QuitClosure());

  {
    chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
    if (use_workspace_urls()) {
      expected_event.set_web_app_signed_in_account(kContentAreaUser0);
      expected_event.set_source_web_app_signed_in_account(kContentAreaUser0);
    }
    expected_event.set_url(test_url_0());
    expected_event.set_tab_url(test_url_0());
    expected_event.set_source(test_url_0());
    expected_event.set_destination("");
    expected_event.set_content_type("text/html");
    expected_event.set_content_size(1234);
    expected_event.set_trigger(chrome::cros::reporting::proto::
                                   DataTransferEventTrigger::CLIPBOARD_COPY);
    expected_event.set_event_result(
        chrome::cros::reporting::proto::EventResult::EVENT_RESULT_WARNED);

    ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
    triggered_rule.set_rule_id(111);
    triggered_rule.set_rule_name("warn_bypass_os");

    *expected_event.add_triggered_rule_info() = triggered_rule;
    expected_event.set_profile_identifier(
        browser()->GetProfile()->GetPath().AsUTF8Unsafe());
    expected_event.set_profile_user_name(kUserName);

    event_validator.ExpectSensitiveDataEvent(std::move(expected_event));
  }

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "warn_bypass_os",
                                   "rule_id": "111",
                                   "sources": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "destinations": {
                                     "os_clipboard": true
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "WARN"}
                                   ]
                                 })"},
                                 machine_scope());
  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardCopyWarn);

  auto source = CreateURLClipboardEndpoint(test_url_0());
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::HtmlType(),
  };
  EXPECT_TRUE(IsCopyPolicyCheckRequired(source, metadata));

  base::test::TestFuture<const ui::ClipboardFormatType&,
                         const content::ClipboardPasteData&,
                         std::optional<std::u16string>>
      future;
  IsClipboardCopyAllowedByPolicy(source, metadata,
                                 MakeClipboardPasteData("foo", "", {}),
                                 future.GetCallback());

  helper.WaitForDialogToInitialize();

  // The dialog will stay up until a user action dismisses it, so `future`
  // shouldn't be ready yet.
  EXPECT_FALSE(future.IsReady());
  run_loop_warn.Run();

  // The first warn event should already be reported before the dialog has been
  // initialized, so it can be reassigned so that the bypass event can be
  // validated.
  base::RunLoop run_loop_bypass;
  event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop_bypass.QuitClosure());

  {
    chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
    if (use_workspace_urls()) {
      expected_event.set_web_app_signed_in_account(kContentAreaUser0);
      expected_event.set_source_web_app_signed_in_account(kContentAreaUser0);
    }
    expected_event.set_url(test_url_0());
    expected_event.set_tab_url(test_url_0());
    expected_event.set_source(test_url_0());
    expected_event.set_destination("");
    expected_event.set_content_type("text/html");
    expected_event.set_content_size(1234);
    expected_event.set_trigger(chrome::cros::reporting::proto::
                                   DataTransferEventTrigger::CLIPBOARD_COPY);
    expected_event.set_event_result(
        chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BYPASSED);

    ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
    triggered_rule.set_rule_id(111);
    triggered_rule.set_rule_name("warn_bypass_os");

    *expected_event.add_triggered_rule_info() = triggered_rule;
    expected_event.set_profile_identifier(
        browser()->GetProfile()->GetPath().AsUTF8Unsafe());
    expected_event.set_profile_user_name(kUserName);

    event_validator.ExpectSensitiveDataEvent(std::move(expected_event));
  }

  helper.BypassWarning();
  helper.WaitForDialogToClose();

  auto data = future.Get<content::ClipboardPasteData>();
  EXPECT_EQ(data.text, u"foo");

  auto replacement = future.Get<std::optional<std::u16string>>();
  EXPECT_FALSE(replacement);
  run_loop_bypass.Run();
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       CopyBlockedOsClipboardThenPasteWarnedThenBypassed) {
  // Set up a block rule for copying to the OS clipboard and a warn rule for all
  // pastes.
  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(),
                                 {R"({
                                   "name": "block_os_clipboard",
                                   "rule_id": "121",
                                   "sources": {
                                     "urls": ["*"]
                                   },
                                   "destinations": {
                                     "os_clipboard": true
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "BLOCK"}
                                   ]
                                 })",
                                  R"({
                                   "name": "warn_on_all_pastes",
                                   "rule_id": "131",
                                   "sources": {
                                     "urls": ["*"]
                                   },
                                   "destinations": {
                                     "urls": ["*"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "WARN"}
                                   ]
                                 })"},
                                 machine_scope());

  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
      .seqno = ui::Clipboard::GetForCurrentThread()->GetSequenceNumber(
          ui::ClipboardBuffer::kCopyPaste),
  };

  auto source = CreateURLClipboardEndpoint("https://source.com");
  EXPECT_TRUE(IsCopyPolicyCheckRequired(source, metadata));

  base::test::TestFuture<const ui::ClipboardFormatType&,
                         const content::ClipboardPasteData&,
                         std::optional<std::u16string>>
      copy_future;
  IsClipboardCopyAllowedByPolicy(source, metadata,
                                 MakeClipboardPasteData("foo", "", {}),
                                 copy_future.GetCallback());

  ui::ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();

  // Check that replacement is populated as copying to the OS clipboard is
  // blocked.
  auto replacement = copy_future.Get<std::optional<std::u16string>>();
  EXPECT_TRUE(replacement);

  base::RunLoop run_loop_warn;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop_warn.QuitClosure());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent
      expected_warned_dlp_event;
  expected_warned_dlp_event.set_url("https://destination.com/");
  expected_warned_dlp_event.set_tab_url("https://destination.com/");
  expected_warned_dlp_event.set_source("https://source.com/");
  expected_warned_dlp_event.set_destination("https://destination.com/");
  expected_warned_dlp_event.set_content_type("text/plain");
  expected_warned_dlp_event.set_content_size(1234);
  expected_warned_dlp_event.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::
          WEB_CONTENT_UPLOAD);
  expected_warned_dlp_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_WARNED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_warned_rule;
  triggered_warned_rule.set_rule_id(131);
  triggered_warned_rule.set_rule_name("warn_on_all_pastes");

  *expected_warned_dlp_event.add_triggered_rule_info() = triggered_warned_rule;
  expected_warned_dlp_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_warned_dlp_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(
      std::move(expected_warned_dlp_event));

  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardPasteWarn);
  base::test::TestFuture<std::optional<content::ClipboardPasteData>>
      paste_future;
  auto paste_source = CreateURLClipboardEndpoint("https://source.com/");
  auto paste_destination =
      CreateURLClipboardEndpoint("https://destination.com");
  EXPECT_TRUE(
      IsPastePolicyCheckRequired(paste_source, paste_destination, metadata));
  // Simulate clipboard paste data being replaced.
  PasteIfAllowedByPolicy(paste_source, paste_destination, metadata,
                         MakeClipboardPasteData("replacement", "", {}),
                         paste_future.GetCallback());

  helper.WaitForDialogToInitialize();
  run_loop_warn.Run();

  base::RunLoop run_loop_bypass;
  event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop_bypass.QuitClosure());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent
      expected_bypassed_dlp_event;
  expected_bypassed_dlp_event.set_url("https://destination.com/");
  expected_bypassed_dlp_event.set_tab_url("https://destination.com/");
  expected_bypassed_dlp_event.set_source("https://source.com/");
  expected_bypassed_dlp_event.set_destination("https://destination.com/");
  expected_bypassed_dlp_event.set_content_type("text/plain");
  expected_bypassed_dlp_event.set_content_size(1234);
  expected_bypassed_dlp_event.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::
          WEB_CONTENT_UPLOAD);
  expected_bypassed_dlp_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BYPASSED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_bypassed_rule;
  triggered_bypassed_rule.set_rule_id(131);
  triggered_bypassed_rule.set_rule_name("warn_on_all_pastes");

  *expected_bypassed_dlp_event.add_triggered_rule_info() =
      triggered_bypassed_rule;
  expected_bypassed_dlp_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_bypassed_dlp_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(
      std::move(expected_bypassed_dlp_event));

  EXPECT_FALSE(paste_future.IsReady());

  helper.BypassWarning();
  helper.WaitForDialogToClose();

  // Check that the paste data is replaced back to the original data after the
  // bypass.
  auto paste_data = paste_future.Get();
  EXPECT_TRUE(paste_data);
  EXPECT_EQ(paste_data->text, u"foo");
  run_loop_bypass.Run();
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       FindBar_CopyAllowed) {
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.ExpectNoReport();

  // Without any restriction, selected text is allowed to reach the find bar.
  EXPECT_TRUE(CanPopulateFindBarFromSelection(contents()));

  // Without any restriction, text in the find bar is allowed to be copied and
  // isn't replaced.
  const std::u16string kText = u"foo";
  std::u16string copy_replacement;
  EXPECT_FALSE(ReplaceCopyFromFindBar(kText, contents(), &copy_replacement));
  EXPECT_TRUE(copy_replacement.empty());
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       FindBar_CopyBlocked) {
  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "block",
                                   "rule_id": "987",
                                   "destinations": {
                                     "os_clipboard": true
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "BLOCK"}
                                   ]
                                 })"},
                                 machine_scope());

  // With a blocking Data Controls rule, selected text is not allowed to reach
  // the find bar.
  EXPECT_FALSE(CanPopulateFindBarFromSelection(contents()));

  // With a blocking Data Controls rule, text is not allowed to be copied from
  // the find bar and is instead replaced by a warning message.
  const std::u16string kText = u"foo";
  std::u16string replacement;
  EXPECT_TRUE(ReplaceCopyFromFindBar(kText, contents(), &replacement));
  EXPECT_EQ(replacement,
            l10n_util::GetStringUTF16(
                IDS_ENTERPRISE_DATA_CONTROLS_COPY_PREVENTION_WARNING_MESSAGE));

  ui::ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();

  // Since the current rules don't restrict pasting inside the browser, the
  // original data is replaced back after pasting.
  base::test::TestFuture<std::optional<content::ClipboardPasteData>>
      paste_future;
  auto source = CreateURLClipboardEndpoint("https://source.com/");
  auto destination = CreateURLClipboardEndpoint("https://destination.com");
  ui::ClipboardMetadata metadata = {
      .size = 1234,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
      .seqno = ui::Clipboard::GetForCurrentThread()->GetSequenceNumber(
          ui::ClipboardBuffer::kCopyPaste),
  };
  // Even though no rule is triggered by the following `PasteIfAllowedByPolicy`
  // call, the policy check is still required to replace back the data.
  EXPECT_TRUE(IsPastePolicyCheckRequired(source, destination, metadata));
  PasteIfAllowedByPolicy(source, destination, metadata,
                         MakeClipboardPasteData("replacement", "", {}),
                         paste_future.GetCallback());
  auto paste_data = paste_future.Get();
  EXPECT_TRUE(paste_data);
  EXPECT_EQ(paste_data->text, kText);
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest, FindBar_Paste) {
  // Without any restriction, text pasted in the find bar will be replaced if
  // necessary.
  base::test::TestFuture<std::optional<std::u16string>> replace_future;
  ReplacePasteToFindBar(contents(), replace_future.GetCallback());
  EXPECT_FALSE(replace_future.Get());

  {
    ui::ScopedClipboardWriter writer(ui::ClipboardBuffer::kCopyPaste,
                                     std::make_unique<ui::DataTransferEndpoint>(
                                         contents()->GetLastCommittedURL()));
    content::AddSourceDataToClipboardWriter(writer,
                                            *contents()->GetPrimaryMainFrame());
    writer.WriteText(u"warning");
  }
  content::ClipboardPasteData data;
  data.text = u"replaced";
  data_controls::LastReplacedClipboardDataObserver::GetInstance()
      ->AddDataToNextSeqno(
          data, data_controls::CopyRestrictionLevel::kKeptInManagedChrome);
  ui::ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();

  base::test::TestFuture<std::optional<std::u16string>> replace_future2;
  ReplacePasteToFindBar(contents(), replace_future2.GetCallback());
  auto paste_replacement = replace_future2.Get();
  EXPECT_TRUE(paste_replacement);
  EXPECT_EQ(*paste_replacement, u"replaced");

  // With a triggered Data Controls rule, the data isn't replaced.
  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "block",
                                   "rule_id": "987",
                                   "destinations": {
                                     "urls": ["*"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "BLOCK"}
                                   ]
                                 })"},
                                 machine_scope());

  base::test::TestFuture<std::optional<std::u16string>> replace_future3;
  ReplacePasteToFindBar(contents(), replace_future3.GetCallback());
  EXPECT_FALSE(replace_future3.Get());
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest, DragAllowed) {
  base::HistogramTester histogram_tester;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.ExpectNoReport();

  bool allowed = IsDragAllowedByPolicy(
      /*source=*/CreateURLClipboardEndpoint("https://google.com"),
      /*drop_data=*/content::DropData());

  EXPECT_TRUE(allowed);
  histogram_tester.ExpectUniqueSample(
      "Enterprise.DataControls.DragAndDrop.Verdict", 0 /* Allowed */, 1);
  histogram_tester.ExpectTotalCount(
      "Enterprise.DataControls.DragAndDrop.EvaluationLatency", 1);
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest, DragBlocked) {
  base::HistogramTester histogram_tester;
  active_user_test_mixin_->SetFakeCookieValue();

  base::RunLoop run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop.QuitClosure());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  if (use_workspace_urls()) {
    expected_event.set_web_app_signed_in_account(kContentAreaUser0);
    expected_event.set_source_web_app_signed_in_account(kContentAreaUser0);
  }
  expected_event.set_url(test_url_0());
  expected_event.set_tab_url(test_url_0());
  expected_event.set_source(test_url_0());
  expected_event.set_destination("");
  expected_event.set_content_type("text/plain");
  expected_event.set_content_size(28);
  expected_event.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::CLIPBOARD_COPY);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BLOCKED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_id(987);
  triggered_rule.set_rule_name("block");

  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "block",
                                   "rule_id": "987",
                                   "sources": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "BLOCK"}
                                   ]
                                 })"},
                                 machine_scope());
  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardDragBlock);

  content::DropData drop_data;
  drop_data.text = u"Sensitive Data";

  bool allowed = IsDragAllowedByPolicy(
      /*source=*/CreateURLClipboardEndpoint(test_url_0()),
      /*drop_data=*/drop_data);

  EXPECT_FALSE(allowed);
  histogram_tester.ExpectUniqueSample(
      "Enterprise.DataControls.DragAndDrop.Verdict", 1 /* Blocked */, 1);
  histogram_tester.ExpectTotalCount(
      "Enterprise.DataControls.DragAndDrop.EvaluationLatency", 1);

  helper.WaitForDialogToInitialize();
  helper.CloseDialogWithoutBypass();
  helper.WaitForDialogToClose();
  run_loop.Run();
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       CopyAndDragConsistentSize) {
  active_user_test_mixin_->SetFakeCookieValue();

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "report_rule",
                                   "rule_id": "987",
                                   "sources": {
                                     "urls": ["google.com", "not.workspace.com"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "REPORT"}
                                   ]
                                 })"},
                                 machine_scope());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  if (use_workspace_urls()) {
    expected_event.set_web_app_signed_in_account(kContentAreaUser0);
    expected_event.set_source_web_app_signed_in_account(kContentAreaUser0);
  }
  expected_event.set_url(test_url_0());
  expected_event.set_tab_url(test_url_0());
  expected_event.set_source(test_url_0());
  expected_event.set_destination("");
  expected_event.set_content_type("text/html");
  expected_event.set_content_size(26);
  expected_event.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::CLIPBOARD_COPY);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_ALLOWED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_id(987);
  triggered_rule.set_rule_name("report_rule");

  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  // Both Copy and Drag should emit exactly the same report (same size, same
  // type).
  {
    base::RunLoop run_loop;
    auto event_validator = event_report_validator_helper_->CreateValidator();
    event_validator.SetDoneClosure(run_loop.QuitClosure());
    event_validator.ExpectSensitiveDataEvent(expected_event);

    content::ClipboardPasteData data;
    data.html = u"<html></html>";

    auto source = CreateURLClipboardEndpoint(test_url_0());
    ui::ClipboardMetadata metadata = {
        .size = 26,
        .format_type = ui::ClipboardFormatType::HtmlType(),
    };
    EXPECT_TRUE(IsCopyPolicyCheckRequired(source, metadata));

    base::test::TestFuture<const ui::ClipboardFormatType&,
                           const content::ClipboardPasteData&,
                           std::optional<std::u16string>>
        copy_future;
    IsClipboardCopyAllowedByPolicy(source, metadata,
                                   /*data=*/data,
                                   /*callback=*/copy_future.GetCallback());

    EXPECT_TRUE(copy_future.IsReady());
    run_loop.Run();
  }

  {
    base::RunLoop run_loop;
    auto event_validator = event_report_validator_helper_->CreateValidator();
    event_validator.SetDoneClosure(run_loop.QuitClosure());
    event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

    content::DropData drop_data;
    drop_data.html = u"<html></html>";

    EXPECT_TRUE(IsDragAllowedByPolicy(
        /*source=*/CreateURLClipboardEndpoint(test_url_0()),
        /*drop_data=*/drop_data));

    run_loop.Run();
  }
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       IsSearchWithAllowed_Allowed) {
  ASSERT_TRUE(content::NavigateToURL(contents(), GURL("about:blank")));
  EXPECT_TRUE(IsSearchWithAllowed(contents()));
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       IsSearchWithAllowed_Blocked) {
  ASSERT_TRUE(content::NavigateToURL(contents(), GURL("about:blank")));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "block_rule",
                                   "rule_id": "444",
                                   "sources": {
                                     "urls": ["*"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "BLOCK"}
                                   ]
                                 })"},
                                 machine_scope());

  EXPECT_FALSE(IsSearchWithAllowed(contents()));
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       IsSearchWithAllowed_Warned) {
  ASSERT_TRUE(content::NavigateToURL(contents(), GURL("about:blank")));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "warn_rule",
                                   "rule_id": "333",
                                   "sources": {
                                     "urls": ["*"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "WARN"}
                                   ]
                                 })"},
                                 machine_scope());

  EXPECT_TRUE(IsSearchWithAllowed(contents()));
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       IsClipboardCopyAllowedByPolicyForUI_Allowed) {
  ASSERT_TRUE(content::NavigateToURL(contents(), GURL("about:blank")));
  EXPECT_TRUE(IsClipboardCopyAllowedByPolicyForUI(contents()));
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       IsClipboardCopyAllowedByPolicyForUI_Blocked) {
  ASSERT_TRUE(content::NavigateToURL(contents(), GURL("about:blank")));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "block_rule",
                                   "rule_id": "444",
                                   "sources": {
                                     "urls": ["*"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "BLOCK"}
                                   ]
                                 })"},
                                 machine_scope());

  EXPECT_FALSE(IsClipboardCopyAllowedByPolicyForUI(contents()));
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       IsClipboardCopyAllowedByPolicyForUI_Warned) {
  ASSERT_TRUE(content::NavigateToURL(contents(), GURL("about:blank")));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "warn_rule",
                                   "rule_id": "333",
                                   "sources": {
                                     "urls": ["*"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "WARN"}
                                   ]
                                 })"},
                                 machine_scope());

  EXPECT_FALSE(IsClipboardCopyAllowedByPolicyForUI(contents()));
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       ShouldAllowSearchWith_Allowed) {
  base::HistogramTester histogram_tester;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.ExpectNoReport();

  base::test::TestFuture<void> callback_future;
  ShouldAllowSearchWith(contents(), 10, callback_future.GetCallback());
  EXPECT_TRUE(callback_future.Wait());

  histogram_tester.ExpectUniqueSample(
      "Enterprise.DataControls.SearchWith.Verdict",
      data_controls::Rule::Level::kNotSet, 1);
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       ShouldAllowSearchWith_WarnedBypassed) {
  base::HistogramTester histogram_tester;
  ASSERT_TRUE(content::NavigateToURL(contents(), GURL("about:blank")));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "warn_rule",
                                   "rule_id": "333",
                                   "sources": {
                                     "urls": ["*"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "WARN"}
                                   ]
                                 })"},
                                 machine_scope());

  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardActionWarn);

  base::RunLoop run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop.QuitClosure());
  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  expected_event.set_url("about:blank");
  expected_event.set_tab_url("about:blank");
  expected_event.set_source("about:blank");
  expected_event.set_destination("");
  expected_event.set_content_type("text/plain");
  expected_event.set_content_size(10);
  expected_event.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::CLIPBOARD_COPY);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BYPASSED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_id(333);
  triggered_rule.set_rule_name("warn_rule");

  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

  base::test::TestFuture<void> callback_future;
  ShouldAllowSearchWith(contents(), 10, callback_future.GetCallback());

  helper.WaitForDialogToInitialize();
  EXPECT_FALSE(callback_future.IsReady());

  helper.BypassWarning();
  helper.WaitForDialogToClose();

  run_loop.Run();

  EXPECT_TRUE(callback_future.Wait());

  histogram_tester.ExpectUniqueSample(
      "Enterprise.DataControls.SearchWith.Verdict",
      data_controls::Rule::Level::kWarn, 1);
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       ShouldAllowSearchWith_WarnedCanceled) {
  base::HistogramTester histogram_tester;
  ASSERT_TRUE(content::NavigateToURL(contents(), GURL("about:blank")));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
                                   "name": "warn_rule",
                                   "rule_id": "333",
                                   "sources": {
                                     "urls": ["*"]
                                   },
                                   "restrictions": [
                                     {"class": "CLIPBOARD", "level": "WARN"}
                                   ]
                                 })"},
                                 machine_scope());

  data_controls::DesktopDataControlsDialogTestHelper helper(
      data_controls::DataControlsDialog::Type::kClipboardActionWarn);

  base::RunLoop run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop.QuitClosure());
  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  expected_event.set_url("about:blank");
  expected_event.set_tab_url("about:blank");
  expected_event.set_source("about:blank");
  expected_event.set_destination("");
  expected_event.set_content_type("text/plain");
  expected_event.set_content_size(10);
  expected_event.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::CLIPBOARD_COPY);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_WARNED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_id(333);
  triggered_rule.set_rule_name("warn_rule");

  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

  base::test::TestFuture<void> callback_future;
  ShouldAllowSearchWith(contents(), 10, callback_future.GetCallback());

  helper.WaitForDialogToInitialize();
  EXPECT_FALSE(callback_future.IsReady());

  helper.CloseDialogWithoutBypass();
  helper.WaitForDialogToClose();

  run_loop.Run();

  EXPECT_FALSE(callback_future.IsReady());

  histogram_tester.ExpectUniqueSample(
      "Enterprise.DataControls.SearchWith.Verdict",
      data_controls::Rule::Level::kWarn, 1);
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       CopyContentAnalysisWarningBypassed) {
  active_user_test_mixin_->SetFakeCookieValue();
  SetupDMToken();

  enterprise_connectors::test::SetAnalysisConnector(
      browser()->GetProfile()->GetPrefs(),
      enterprise_connectors::AnalysisConnector::DATA_COPIED,
      R"(
        {
          "service_provider": "google",
          "enable": [
            {
              "url_list": ["*"],
              "tags": ["dlp"]
            }
          ],
          "block_until_verdict": 1
        })",
      machine_scope());
  enterprise_connectors::ContentAnalysisDelegate::SetFactoryForTesting(
      base::BindRepeating(
          &enterprise_connectors::test::FakeContentAnalysisDelegate::Create,
          base::DoNothing(),
          base::BindRepeating([](const std::string&, const base::FilePath&) {
            return enterprise_connectors::test::FakeContentAnalysisDelegate::
                DlpResponse(enterprise_connectors::ContentAnalysisResponse::
                                Result::SUCCESS,
                            "dlp",
                            enterprise_connectors::ContentAnalysisResponse::
                                Result::TriggeredRule::WARN);
          }),
          "dm_token"));

  ASSERT_TRUE(embedded_test_server()->Start());
  GURL url = embedded_test_server()->GetURL("/empty.html");
  ASSERT_TRUE(content::NavigateToURL(contents(), url));

  auto source = content::ClipboardEndpoint(
      ui::DataTransferEndpoint(url), base::BindLambdaForTesting([this]() {
        return contents()->GetBrowserContext();
      }),
      *contents()->GetPrimaryMainFrame());

  ui::ClipboardMetadata metadata = {
      .size = 100,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
  };
  content::ClipboardPasteData data;
  data.text = std::u16string(100, 'a');

  base::test::TestFuture<const ui::ClipboardFormatType&,
                         const content::ClipboardPasteData&,
                         std::optional<std::u16string>>
      future;

  data_controls::GetLastReplacedClipboardData() = {};
  ui::ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();

  IsClipboardCopyAllowedByPolicy(source, metadata, data, future.GetCallback());

  auto* toast_controller = browser()->GetFeatures().toast_controller();
  ASSERT_TRUE(toast_controller);

  // Wait until the warning creates the Toast.
  while (!toast_controller->IsShowingToast()) {
    base::RunLoop().RunUntilIdle();
  }

  EXPECT_EQ(toast_controller->GetCurrentToastId(),
            ToastId::kEnterpriseCopyWarning);

  enterprise_connectors::CopyWarningDelegateTracker::BypassAndClear(contents());

  EXPECT_EQ(data_controls::GetLastReplacedClipboardData().restriction_level,
            data_controls::CopyRestrictionLevel::kOngoingScan);

  EXPECT_EQ(future.Get<0>().GetName(), metadata.format_type.GetName());

  EXPECT_EQ(future.Get<1>().text, data.text);

  auto replacement = future.Get<2>();
  EXPECT_FALSE(replacement.has_value());

  {
    ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste);
    scw.WriteText(data.text);
  }

  // Bypassing successfully overwrites the physical OS clipboard with true data,
  // generating a new OS sequence number that outpaces the tracked placeholder.
  EXPECT_NE(data_controls::GetLastReplacedClipboardData().seqno,
            ui::Clipboard::GetForCurrentThread()->GetSequenceNumber(
                ui::ClipboardBuffer::kCopyPaste));

  base::test::TestFuture<std::u16string> text_future;
  ui::Clipboard::GetForCurrentThread()->ReadText(
      ui::ClipboardBuffer::kCopyPaste, /*data_dst=*/std::nullopt,
      text_future.GetCallback());
  EXPECT_EQ(text_future.Get(), data.text);
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       Copy_ContentAnalysisBlocked) {
  active_user_test_mixin_->SetFakeCookieValue();

  SetupDMToken();

  enterprise_connectors::test::SetAnalysisConnector(
      browser()->GetProfile()->GetPrefs(),
      enterprise_connectors::AnalysisConnector::DATA_COPIED,
      R"(
        {
          "service_provider": "google",
          "enable": [
            {
              "url_list": ["*"],
              "tags": ["dlp"]
            }
          ],
          "block_until_verdict": 1
        })",
      machine_scope());
  enterprise_connectors::ContentAnalysisDelegate::SetFactoryForTesting(
      base::BindRepeating(
          &enterprise_connectors::test::FakeContentAnalysisDelegate::Create,
          base::DoNothing(),
          base::BindRepeating([](const std::string&, const base::FilePath&) {
            return enterprise_connectors::test::FakeContentAnalysisDelegate::
                DlpResponse(enterprise_connectors::ContentAnalysisResponse::
                                Result::SUCCESS,
                            "dlp",
                            enterprise_connectors::ContentAnalysisResponse::
                                Result::TriggeredRule::BLOCK);
          }),
          "dm_token"));

  ASSERT_TRUE(embedded_test_server()->Start());
  GURL url = embedded_test_server()->GetURL("/empty.html");
  ASSERT_TRUE(content::NavigateToURL(contents(), url));

  auto source = content::ClipboardEndpoint(
      ui::DataTransferEndpoint(url), base::BindLambdaForTesting([this]() {
        return contents()->GetBrowserContext();
      }),
      *contents()->GetPrimaryMainFrame());

  ui::ClipboardMetadata metadata = {
      .size = 100,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
  };
  content::ClipboardPasteData data;
  data.text = std::u16string(100, 'a');

  base::test::TestFuture<const ui::ClipboardFormatType&,
                         const content::ClipboardPasteData&,
                         std::optional<std::u16string>>
      future;

  data_controls::GetLastReplacedClipboardData() = {};
  ui::ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();

  IsClipboardCopyAllowedByPolicy(source, metadata, data, future.GetCallback());

  EXPECT_EQ(data_controls::GetLastReplacedClipboardData().restriction_level,
            data_controls::CopyRestrictionLevel::kOngoingScan);

  EXPECT_EQ(future.Get<0>().GetName(), metadata.format_type.GetName());

  EXPECT_TRUE(future.Get<1>().empty());

  auto replacement = future.Get<2>();
  EXPECT_TRUE(replacement.has_value());

  {
    ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste);
    scw.WriteText(replacement.value_or(u""));
  }

  EXPECT_EQ(data_controls::GetLastReplacedClipboardData().restriction_level,
            data_controls::CopyRestrictionLevel::kBlocked);
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       Copy_ContentAnalysisKeptInManagedChrome) {
  active_user_test_mixin_->SetFakeCookieValue();

  SetupDMToken();

  enterprise_connectors::test::SetAnalysisConnector(
      browser()->GetProfile()->GetPrefs(),
      enterprise_connectors::AnalysisConnector::DATA_COPIED,
      R"(
        {
          "service_provider": "google",
          "enable": [
            {
              "url_list": ["*"],
              "tags": ["dlp"]
            }
          ],
          "block_until_verdict": 1
        })",
      machine_scope());
  enterprise_connectors::ContentAnalysisDelegate::SetFactoryForTesting(
      base::BindRepeating(
          &enterprise_connectors::test::FakeContentAnalysisDelegate::Create,
          base::DoNothing(),
          base::BindRepeating([](const std::string&, const base::FilePath&) {
            return enterprise_connectors::test::FakeContentAnalysisDelegate::
                DlpResponse(enterprise_connectors::ContentAnalysisResponse::
                                Result::SUCCESS,
                            "dlp",
                            enterprise_connectors::ContentAnalysisResponse::
                                Result::TriggeredRule::KEEP_IN_MANAGED_CHROME);
          }),
          "dm_token"));

  ASSERT_TRUE(embedded_test_server()->Start());
  GURL url = embedded_test_server()->GetURL("/empty.html");
  ASSERT_TRUE(content::NavigateToURL(contents(), url));

  auto source = content::ClipboardEndpoint(
      ui::DataTransferEndpoint(url), base::BindLambdaForTesting([this]() {
        return contents()->GetBrowserContext();
      }),
      *contents()->GetPrimaryMainFrame());

  ui::ClipboardMetadata metadata = {
      .size = 100,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
  };
  content::ClipboardPasteData data;
  data.text = std::u16string(100, 'a');

  base::test::TestFuture<const ui::ClipboardFormatType&,
                         const content::ClipboardPasteData&,
                         std::optional<std::u16string>>
      future;

  data_controls::GetLastReplacedClipboardData() = {};
  ui::ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();

  IsClipboardCopyAllowedByPolicy(source, metadata, data, future.GetCallback());

  EXPECT_EQ(data_controls::GetLastReplacedClipboardData().restriction_level,
            data_controls::CopyRestrictionLevel::kOngoingScan);

  EXPECT_EQ(future.Get<0>().GetName(), metadata.format_type.GetName());

  EXPECT_TRUE(future.Get<1>().empty());

  auto replacement = future.Get<2>();
  EXPECT_TRUE(replacement.has_value());

  {
    ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste);
    scw.WriteText(replacement.value_or(u""));
  }

  EXPECT_EQ(data_controls::GetLastReplacedClipboardData().restriction_level,
            data_controls::CopyRestrictionLevel::kKeptInManagedChrome);
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       Copy_ContentAnalysisAllowed) {
  active_user_test_mixin_->SetFakeCookieValue();

  SetupDMToken();

  enterprise_connectors::test::SetAnalysisConnector(
      browser()->GetProfile()->GetPrefs(),
      enterprise_connectors::AnalysisConnector::DATA_COPIED,
      R"(
        {
          "service_provider": "google",
          "enable": [
            {
              "url_list": ["*"],
              "tags": ["dlp"]
            }
          ],
          "block_until_verdict": 1
        })",
      machine_scope());
  enterprise_connectors::ContentAnalysisDelegate::SetFactoryForTesting(
      base::BindRepeating(
          &enterprise_connectors::test::FakeContentAnalysisDelegate::Create,
          base::DoNothing(),
          base::BindRepeating([](const std::string&, const base::FilePath&) {
            return enterprise_connectors::test::FakeContentAnalysisDelegate::
                SuccessfulResponse({"dlp"});
          }),
          "dm_token"));

  ASSERT_TRUE(embedded_test_server()->Start());
  GURL url = embedded_test_server()->GetURL("/empty.html");
  ASSERT_TRUE(content::NavigateToURL(contents(), url));

  auto source = content::ClipboardEndpoint(
      ui::DataTransferEndpoint(url), base::BindLambdaForTesting([this]() {
        return contents()->GetBrowserContext();
      }),
      *contents()->GetPrimaryMainFrame());

  ui::ClipboardMetadata metadata = {
      .size = 100,
      .format_type = ui::ClipboardFormatType::PlainTextType(),
  };
  content::ClipboardPasteData data;
  data.text = std::u16string(100, 'a');

  base::test::TestFuture<const ui::ClipboardFormatType&,
                         const content::ClipboardPasteData&,
                         std::optional<std::u16string>>
      future;

  data_controls::GetLastReplacedClipboardData() = {};
  ui::ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged();

  IsClipboardCopyAllowedByPolicy(source, metadata, data, future.GetCallback());

  EXPECT_EQ(data_controls::GetLastReplacedClipboardData().restriction_level,
            data_controls::CopyRestrictionLevel::kOngoingScan);

  EXPECT_EQ(future.Get<0>().GetName(), metadata.format_type.GetName());

  EXPECT_EQ(future.Get<1>().text, data.text);

  auto replacement = future.Get<2>();
  EXPECT_FALSE(replacement.has_value());
}

IN_PROC_BROWSER_TEST_P(
    DataControlsClipboardUtilsBrowserTest,
    PasteFromGeminiIfAllowedByPolicy_ContentAnalysisBlocked) {
  active_user_test_mixin_->SetFakeCookieValue();

  SetupDMToken();
  SetupContentAnalysisToBlock();

  ASSERT_TRUE(embedded_test_server()->Start());
  GURL url = embedded_test_server()->GetURL("/empty.html");
  ASSERT_TRUE(content::NavigateToURL(contents(), url));

  base::test::TestFuture<bool> future;
  base::HistogramTester histogram_tester;
  PasteFromGeminiIfAllowedByPolicy(contents()->GetPrimaryMainFrame(),
                                   std::string(1000, 'a'),
                                   future.GetCallback());

  EXPECT_FALSE(future.Get());
  histogram_tester.ExpectUniqueSample(
      "Enterprise.DataControls.GlicPaste.Verdict",
      data_controls::Rule::Level::kNotSet, 1);
  histogram_tester.ExpectTotalCount(
      "Enterprise.DataControls.GlicPaste.EvaluationLatency", 1);
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       PasteFromGeminiIfAllowedByPolicy_WarnedThenBlocked) {
  active_user_test_mixin_->SetFakeCookieValue();
  SetupDMToken();
  ASSERT_TRUE(embedded_test_server()->Start());
  GURL url = embedded_test_server()->GetURL("/empty.html");
  ASSERT_TRUE(content::NavigateToURL(contents(), url));

  base::RunLoop run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();

  event_validator.SetDoneClosure(run_loop.QuitClosure());
  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  expected_event.set_url(url.spec());
  expected_event.set_tab_url(url.spec());
  expected_event.set_source("GEMINI");
  expected_event.set_destination(url.spec());
  expected_event.set_content_type("text/plain");
  expected_event.set_content_size(1000);
  expected_event.set_trigger(chrome::cros::reporting::proto::
                                 DataTransferEventTrigger::WEB_CONTENT_UPLOAD);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_WARNED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_name("");
  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
        "restrictions": [
          {"class": "CLIPBOARD", "level": "WARN"}
        ],
        "sources": {
          "gemini_in_chrome": true
        }
      })"},
                                 machine_scope());

  SetupContentAnalysisToBlock();

  data_controls::DesktopDataControlsDialogTestHelper dialog_helper(
      data_controls::DataControlsDialog::Type::kClipboardPasteWarn);

  base::test::TestFuture<bool> future;
  PasteFromGeminiIfAllowedByPolicy(contents()->GetPrimaryMainFrame(),
                                   std::string(1000, 'a'),
                                   future.GetCallback());

  dialog_helper.WaitForDialogToInitialize();
  run_loop.Run();

  base::RunLoop run_loop_bypass;
  event_validator = event_report_validator_helper_->CreateValidator();

  event_validator.SetDoneClosure(run_loop_bypass.QuitClosure());
  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event_bypass;
  expected_event_bypass.set_url(url.spec());
  expected_event_bypass.set_tab_url(url.spec());
  expected_event_bypass.set_source("GEMINI");
  expected_event_bypass.set_destination(url.spec());
  expected_event_bypass.set_content_type("text/plain");
  expected_event_bypass.set_content_size(1000);
  expected_event_bypass.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::
          WEB_CONTENT_UPLOAD);
  expected_event_bypass.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BYPASSED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule_bypass;
  triggered_rule_bypass.set_rule_name("");
  *expected_event_bypass.add_triggered_rule_info() = triggered_rule_bypass;
  expected_event_bypass.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event_bypass.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event_bypass));

  dialog_helper.BypassWarning();
  dialog_helper.WaitForDialogToClose();

  EXPECT_FALSE(future.Get());
  run_loop_bypass.Run();
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       PasteFromGeminiIfAllowedByPolicy_DataControlsBlocked) {
  active_user_test_mixin_->SetFakeCookieValue();

  SetupDMToken();

  ASSERT_TRUE(embedded_test_server()->Start());
  GURL url = embedded_test_server()->GetURL("/empty.html");
  ASSERT_TRUE(content::NavigateToURL(contents(), url));

  base::RunLoop run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();

  event_validator.SetDoneClosure(run_loop.QuitClosure());
  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  expected_event.set_url(url.spec());
  expected_event.set_tab_url(url.spec());
  expected_event.set_source("GEMINI");
  expected_event.set_destination(url.spec());
  expected_event.set_content_type("text/plain");
  expected_event.set_content_size(1000);
  expected_event.set_trigger(chrome::cros::reporting::proto::
                                 DataTransferEventTrigger::WEB_CONTENT_UPLOAD);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BLOCKED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_name("");
  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
        "restrictions": [
          {"class": "CLIPBOARD", "level": "BLOCK"}
        ],
        "sources": {
          "gemini_in_chrome": true
        }
      })"},
                                 machine_scope());

  base::test::TestFuture<bool> future;
  base::HistogramTester histogram_tester;
  PasteFromGeminiIfAllowedByPolicy(contents()->GetPrimaryMainFrame(),
                                   std::string(1000, 'a'),
                                   future.GetCallback());

  EXPECT_FALSE(future.Get());
  run_loop.Run();
  histogram_tester.ExpectUniqueSample(
      "Enterprise.DataControls.GlicPaste.Verdict",
      data_controls::Rule::Level::kBlock, 1);
  histogram_tester.ExpectTotalCount(
      "Enterprise.DataControls.GlicPaste.EvaluationLatency", 1);
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       PasteFromGeminiIfAllowedByPolicy_DataControlsWarned) {
  active_user_test_mixin_->SetFakeCookieValue();

  SetupDMToken();

  ASSERT_TRUE(embedded_test_server()->Start());
  GURL url = embedded_test_server()->GetURL("/empty.html");
  ASSERT_TRUE(content::NavigateToURL(contents(), url));

  base::RunLoop run_loop;
  auto event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop.QuitClosure());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event;
  expected_event.set_url(url.spec());
  expected_event.set_tab_url(url.spec());
  expected_event.set_source("GEMINI");
  expected_event.set_destination(url.spec());
  expected_event.set_content_type("text/plain");
  expected_event.set_content_size(1000);
  expected_event.set_trigger(chrome::cros::reporting::proto::
                                 DataTransferEventTrigger::WEB_CONTENT_UPLOAD);
  expected_event.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_WARNED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule;
  triggered_rule.set_rule_name("");
  *expected_event.add_triggered_rule_info() = triggered_rule;
  expected_event.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event));

  data_controls::SetDataControls(browser()->GetProfile()->GetPrefs(), {R"({
        "restrictions": [
          {"class": "CLIPBOARD", "level": "WARN"}
        ],
        "sources": {
          "gemini_in_chrome": true
        }
      })"},
                                 machine_scope());

  data_controls::DesktopDataControlsDialogTestHelper dialog_helper(
      data_controls::DataControlsDialog::Type::kClipboardPasteWarn);

  base::test::TestFuture<bool> future;
  base::HistogramTester histogram_tester;
  PasteFromGeminiIfAllowedByPolicy(contents()->GetPrimaryMainFrame(),
                                   std::string(1000, 'a'),
                                   future.GetCallback());

  dialog_helper.WaitForDialogToInitialize();
  run_loop.Run();
  histogram_tester.ExpectUniqueSample(
      "Enterprise.DataControls.GlicPaste.Verdict",
      data_controls::Rule::Level::kWarn, 1);
  histogram_tester.ExpectTotalCount(
      "Enterprise.DataControls.GlicPaste.EvaluationLatency", 1);

  base::RunLoop run_loop_bypass;
  event_validator = event_report_validator_helper_->CreateValidator();
  event_validator.SetDoneClosure(run_loop_bypass.QuitClosure());

  chrome::cros::reporting::proto::DlpSensitiveDataEvent expected_event_bypass;
  expected_event_bypass.set_url(url.spec());
  expected_event_bypass.set_tab_url(url.spec());
  expected_event_bypass.set_source("GEMINI");
  expected_event_bypass.set_destination(url.spec());
  expected_event_bypass.set_content_type("text/plain");
  expected_event_bypass.set_content_size(1000);
  expected_event_bypass.set_trigger(
      chrome::cros::reporting::proto::DataTransferEventTrigger::
          WEB_CONTENT_UPLOAD);
  expected_event_bypass.set_event_result(
      chrome::cros::reporting::proto::EventResult::EVENT_RESULT_BYPASSED);

  ::chrome::cros::reporting::proto::TriggeredRuleInfo triggered_rule_bypass;
  triggered_rule_bypass.set_rule_name("");
  *expected_event_bypass.add_triggered_rule_info() = triggered_rule_bypass;
  expected_event_bypass.set_profile_identifier(
      browser()->GetProfile()->GetPath().AsUTF8Unsafe());
  expected_event_bypass.set_profile_user_name(kUserName);

  event_validator.ExpectSensitiveDataEvent(std::move(expected_event_bypass));

  dialog_helper.BypassWarning();
  dialog_helper.WaitForDialogToClose();

  EXPECT_TRUE(future.Get());
  run_loop_bypass.Run();
}

class ClipboardEnterpriseMessageObserver : public ui::ClipboardObserver {
 public:
  ClipboardEnterpriseMessageObserver(const std::u16string& expected_text,
                                     base::OnceClosure callback)
      : expected_text_(expected_text), callback_(std::move(callback)) {
    ui::ClipboardMonitor::GetInstance()->AddObserver(this);
  }
  ~ClipboardEnterpriseMessageObserver() override {
    ui::ClipboardMonitor::GetInstance()->RemoveObserver(this);
  }

  void OnClipboardDataChanged() override {
    if (ui::clipboard_test_util::ReadText(ui::Clipboard::GetForCurrentThread(),
                                          ui::ClipboardBuffer::kCopyPaste,
                                          /*data_dst=*/nullptr) ==
        expected_text_) {
      if (callback_) {
        std::move(callback_).Run();
      }
    }
  }

 private:
  std::u16string expected_text_;
  base::OnceClosure callback_;
};

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       Copy_SafebrowsingAndContentAnalysis_Blocked) {
  SetupDMToken();
  SetupContentAnalysisToBlockCopy();

  // Enable Safe Browsing Enhanced Protection to ensure it would normally fire.
  safe_browsing::SetSafeBrowsingState(
      browser()->GetProfile()->GetPrefs(),
      safe_browsing::SafeBrowsingState::ENHANCED_PROTECTION);

  ASSERT_TRUE(embedded_test_server()->Start());
  GURL url = embedded_test_server()->GetURL("/title1.html");
  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));

  content::PermissionController* permission_controller =
      browser()->GetProfile()->GetPermissionController();
  url::Origin origin = url::Origin::Create(url);
  content::SetPermissionControllerOverride(
      permission_controller, origin, origin,
      blink::PermissionType::CLIPBOARD_READ_WRITE,
      blink::mojom::PermissionStatus::GRANTED);

  auto* web_contents = browser()->GetTabStripModel()->GetActiveWebContents();

  // Create a waiter to wait for the clipboard to be successfully written with
  // the OS-level replacement string.
  base::test::TestFuture<void> future;
  ClipboardEnterpriseMessageObserver waiter(
      l10n_util::GetStringUTF16(
          IDS_ENTERPRISE_CONTENT_ANALYSIS_COPY_BLOCKED_MESSAGE),
      future.GetCallback());
  base::HistogramTester histogram_tester;

  // We write generic "sensitive data" because ContentAnalysisFake returns a
  // strict BLOCK verdict for everything.
  ASSERT_TRUE(content::ExecJs(
      web_contents,
      "document.body.innerText = 'a'.repeat(100);"
      "let range = document.createRange();"
      "range.selectNodeContents(document.body);"
      "let selection = window.getSelection();"
      "selection.removeAllRanges();"
      "selection.addRange(range);"));

  web_contents->Copy();

  // Wait for OS clipboard write
  EXPECT_TRUE(future.Wait());

  EXPECT_GT(enterprise_connectors::test::FakeContentAnalysisDelegate::
                GetTotalAnalysisRequestsCount(),
            0);

  EXPECT_EQ(ui::clipboard_test_util::ReadText(
                ui::Clipboard::GetForCurrentThread(),
                ui::ClipboardBuffer::kCopyPaste, /*data_dst=*/nullptr),
            l10n_util::GetStringUTF16(
                IDS_ENTERPRISE_CONTENT_ANALYSIS_COPY_BLOCKED_MESSAGE));

  // Assert that Safe Browsing was completely skipped and did not mistakenly
  // process the "Blocked" warning string natively.
  histogram_tester.ExpectTotalCount(
      "SBClientPhishing.ClipboardCopyApi.PayloadLength", 0);
}

IN_PROC_BROWSER_TEST_P(DataControlsClipboardUtilsBrowserTest,
                       Copy_SafebrowsingAndContentAnalysis_Allowed) {
  SetupDMToken();
  enterprise_connectors::test::SetAnalysisConnector(
      browser()->GetProfile()->GetPrefs(),
      enterprise_connectors::AnalysisConnector::DATA_COPIED,
      R"(
        {
          "service_provider": "google",
          "enable": [
            {
              "url_list": ["*"],
              "tags": ["dlp"]
            }
          ],
          "block_until_verdict": 1
        })",
      machine_scope());

  enterprise_connectors::ContentAnalysisDelegate::SetFactoryForTesting(
      base::BindRepeating(
          &enterprise_connectors::test::FakeContentAnalysisDelegate::Create,
          base::DoNothing(),
          base::BindRepeating([](const std::string&, const base::FilePath&) {
            return enterprise_connectors::test::FakeContentAnalysisDelegate::
                SuccessfulResponse({"dlp"});
          }),
          "dm_token"));

  // Enable Safe Browsing Enhanced Protection to ensure it would normally fire.
  safe_browsing::SetSafeBrowsingState(
      browser()->GetProfile()->GetPrefs(),
      safe_browsing::SafeBrowsingState::ENHANCED_PROTECTION);

  ASSERT_TRUE(embedded_test_server()->Start());
  GURL url = embedded_test_server()->GetURL("/title1.html");
  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));

  content::PermissionController* permission_controller =
      browser()->GetProfile()->GetPermissionController();
  url::Origin origin = url::Origin::Create(url);
  content::SetPermissionControllerOverride(
      permission_controller, origin, origin,
      blink::PermissionType::CLIPBOARD_READ_WRITE,
      blink::mojom::PermissionStatus::GRANTED);

  auto* web_contents = browser()->GetTabStripModel()->GetActiveWebContents();

  base::test::TestFuture<void> future;
  // In the allowed scenario, we expect the original text (100 'a's) to make it
  // to the OS clipboard.
  std::u16string expected_clipboard_text(100, 'a');
  ClipboardEnterpriseMessageObserver waiter(expected_clipboard_text,
                                            future.GetCallback());
  base::HistogramTester histogram_tester;

  ASSERT_TRUE(content::ExecJs(
      web_contents,
      "document.body.innerText = 'a'.repeat(100);"
      "let range = document.createRange();"
      "range.selectNodeContents(document.body);"
      "let selection = window.getSelection();"
      "selection.removeAllRanges();"
      "selection.addRange(range);"));

  web_contents->Copy();

  // Wait for OS clipboard write
  EXPECT_TRUE(future.Wait());

  // Assert that Safe Browsing was executed cleanly, firing the expected metrics
  // because Content Analysis allowed the string payload through.
  histogram_tester.ExpectTotalCount(
      "SBClientPhishing.ClipboardCopyApi.PayloadLength", 1);
}
}  // namespace enterprise_data_protection
