// Copyright 2023 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/ash/policy/dlp/dialogs/files_policy_dialog.h"
#include <tuple>
#include "base/files/file_path.h"
#include "base/functional/callback_helpers.h"
#include "base/rand_util.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "chrome/browser/ash/file_manager/file_manager_test_util.h"
#include "chrome/browser/ash/file_manager/open_util.h"
#include "chrome/browser/ash/file_manager/path_util.h"
#include "chrome/browser/ash/policy/dlp/dialogs/files_policy_error_dialog.h"
#include "chrome/browser/ash/policy/dlp/dialogs/files_policy_warn_dialog.h"
#include "chrome/browser/ash/policy/dlp/files_policy_string_util.h"
#include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_confidential_file.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_file_destination.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_files_utils.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_policy_constants.h"
#include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/enterprise/data_controls/core/browser/component.h"
#include "components/enterprise/data_controls/core/browser/dlp_histogram_helper.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/test/browser_test.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/mojom/dialog_button.mojom.h"
#include "ui/base/mojom/ui_base_types.mojom-shared.h"
#include "ui/base/ui_base_types.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/textarea/textarea.h"
namespace policy {
namespace {
// Generate a random string with the given `length`.
std::u16string GenerateText(size_t length) {
std::u16string random_string;
for (size_t index = 0; index < length; ++index) {
random_string += static_cast<char16_t>(base::RandInt('A', 'Z'));
}
return random_string;
}
} // namespace
class FilesPolicyDialogBrowserTest
: public InProcessBrowserTest,
public ::testing::WithParamInterface<dlp::FileAction> {
public:
FilesPolicyDialogBrowserTest() {
scoped_feature_list_.InitAndEnableFeature(features::kNewFilesPolicyUX);
}
FilesPolicyDialogBrowserTest(const FilesPolicyDialogBrowserTest&) = delete;
FilesPolicyDialogBrowserTest& operator=(const FilesPolicyDialogBrowserTest&) =
delete;
~FilesPolicyDialogBrowserTest() override = default;
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
// Setup the Files app.
ash::SystemWebAppManager::GetForTest(browser()->profile())
->InstallSystemAppsForTesting();
file_manager::test::AddDefaultComponentExtensionsOnMainThread(
browser()->profile());
}
protected:
Browser* FindFilesApp() {
return FindSystemWebAppBrowser(browser()->profile(),
ash::SystemWebAppType::FILE_MANAGER);
}
Browser* OpenFilesApp() {
base::RunLoop run_loop;
file_manager::util::ShowItemInFolder(
browser()->profile(),
file_manager::util::GetDownloadsFolderForProfile(browser()->profile()),
base::BindLambdaForTesting(
[&run_loop](platform_util::OpenOperationResult result) {
EXPECT_EQ(platform_util::OpenOperationResult::OPEN_SUCCEEDED,
result);
run_loop.Quit();
}));
run_loop.Run();
return ui_test_utils::WaitForBrowserToOpen();
}
base::test::ScopedFeatureList scoped_feature_list_;
const base::HistogramTester histogram_tester_;
};
class WarningDialogBrowserTest : public FilesPolicyDialogBrowserTest {
public:
void SetUpOnMainThread() override {
FilesPolicyDialogBrowserTest::SetUpOnMainThread();
warning_paths_.emplace_back("file1.txt");
warning_paths_.emplace_back("file2.txt");
}
protected:
std::vector<base::FilePath> warning_paths_;
base::MockCallback<WarningWithJustificationCallback> cb_;
};
// Tests that the warning dialog is created as a system modal if no parent is
// passed, and that accepting the dialog runs the callback with true.
IN_PROC_BROWSER_TEST_P(WarningDialogBrowserTest, NoParent) {
dlp::FileAction action = GetParam();
auto* widget = FilesPolicyDialog::CreateWarnDialog(
cb_.Get(), action,
/*modal_parent=*/nullptr,
FilesPolicyDialog::Info::Warn(FilesPolicyDialog::BlockReason::kDlp,
warning_paths_));
ASSERT_TRUE(widget);
FilesPolicyWarnDialog* dialog = static_cast<FilesPolicyWarnDialog*>(
widget->widget_delegate()->AsDialogDelegate());
ASSERT_TRUE(dialog);
// There should be no justification text area since it's not set in the
// FilesPolicyDialog::Info above.
ASSERT_EQ(widget->GetRootView()->GetViewByID(
PolicyDialogBase::kEnterpriseConnectorsJustificationTextareaId),
nullptr);
EXPECT_EQ(dialog->GetModalType(), ui::mojom::ModalType::kSystem);
// Proceed.
EXPECT_CALL(cb_, Run(/*user_justification=*/std::optional<std::u16string>(),
/*should_proceed=*/true))
.Times(1);
dialog->AcceptDialog();
EXPECT_TRUE(widget->IsClosed());
EXPECT_THAT(histogram_tester_.GetAllSamples(
data_controls::GetDlpHistogramPrefix() +
std::string(data_controls::dlp::kFileActionWarnReviewedUMA)),
base::BucketsAre(base::Bucket(action, 1)));
}
// Tests that the warning dialog is created as a window modal if a Files app
// window is passed as the parent, and that cancelling the dialog runs the
// callback with false.
IN_PROC_BROWSER_TEST_P(WarningDialogBrowserTest, WithParent) {
dlp::FileAction action = GetParam();
ASSERT_FALSE(FindFilesApp());
Browser* files_app = OpenFilesApp();
ASSERT_TRUE(files_app);
ASSERT_EQ(files_app, FindFilesApp());
auto* widget = FilesPolicyDialog::CreateWarnDialog(
cb_.Get(), action, files_app->window()->GetNativeWindow(),
FilesPolicyDialog::Info::Warn(FilesPolicyDialog::BlockReason::kDlp,
warning_paths_));
ASSERT_TRUE(widget);
FilesPolicyWarnDialog* dialog = static_cast<FilesPolicyWarnDialog*>(
widget->widget_delegate()->AsDialogDelegate());
ASSERT_TRUE(dialog);
EXPECT_EQ(dialog->GetModalType(), ui::mojom::ModalType::kWindow);
EXPECT_EQ(widget->parent()->GetNativeWindow(),
files_app->window()->GetNativeWindow());
// Cancel.
EXPECT_CALL(cb_, Run(/*user_justification=*/std::optional<std::u16string>(),
/*should_proceed=*/false))
.Times(1);
dialog->CancelDialog();
EXPECT_TRUE(widget->IsClosed());
EXPECT_THAT(histogram_tester_.GetAllSamples(
data_controls::GetDlpHistogramPrefix() +
std::string(data_controls::dlp::kFileActionWarnReviewedUMA)),
base::BucketsAre(base::Bucket(action, 1)));
}
// Tests that the warning dialog contains a justification textarea and when the
// warning is proceeded the user justification is forwarded to the continue
// callback.
IN_PROC_BROWSER_TEST_P(WarningDialogBrowserTest, JustificationTextarea) {
dlp::FileAction action = GetParam();
auto dialog_info = FilesPolicyDialog::Info::Warn(
FilesPolicyDialog::BlockReason::kEnterpriseConnectorsSensitiveData,
warning_paths_);
dialog_info.SetBypassRequiresJustification(true);
auto* widget = FilesPolicyDialog::CreateWarnDialog(
cb_.Get(), action, /*modal_parent=*/nullptr, std::move(dialog_info));
ASSERT_TRUE(widget);
FilesPolicyWarnDialog* dialog = static_cast<FilesPolicyWarnDialog*>(
widget->widget_delegate()->AsDialogDelegate());
ASSERT_TRUE(dialog);
views::Textarea* justification_area =
static_cast<views::Textarea*>(widget->GetRootView()->GetViewByID(
PolicyDialogBase::kEnterpriseConnectorsJustificationTextareaId));
ASSERT_TRUE(justification_area);
// The OK button should be disabled if there is no text in the justification
// area.
EXPECT_FALSE(dialog->IsDialogButtonEnabled(ui::mojom::DialogButton::kOk));
const size_t max_chars = dialog->GetMaxBypassJustificationLengthForTesting();
const std::u16string valid_justification = GenerateText(max_chars);
// The OK button should be enable if the max amount of char is inserted.
justification_area->SetText(u"");
justification_area->InsertText(
valid_justification,
ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
EXPECT_TRUE(dialog->IsDialogButtonEnabled(ui::mojom::DialogButton::kOk));
// The OK button should also be disabled if an extra char is added.
justification_area->InsertText(
GenerateText(1),
ui::TextInputClient::InsertTextCursorBehavior::kMoveCursorAfterText);
EXPECT_FALSE(dialog->IsDialogButtonEnabled(ui::mojom::DialogButton::kOk));
// Reset a valid justification by deleting the extra char to proceed the
// warning.
justification_area->DeleteRange(gfx::Range(max_chars, max_chars + 1));
EXPECT_TRUE(dialog->IsDialogButtonEnabled(ui::mojom::DialogButton::kOk));
EXPECT_EQ(dialog->GetModalType(), ui::mojom::ModalType::kSystem);
// Proceed.
EXPECT_CALL(cb_, Run({valid_justification}, /*should_proceed=*/true))
.Times(1);
dialog->AcceptDialog();
EXPECT_TRUE(widget->IsClosed());
EXPECT_THAT(histogram_tester_.GetAllSamples(
data_controls::GetDlpHistogramPrefix() +
std::string(data_controls::dlp::kFileActionWarnReviewedUMA)),
base::BucketsAre(base::Bucket(action, 1)));
}
INSTANTIATE_TEST_SUITE_P(FilesPolicyDialog,
WarningDialogBrowserTest,
::testing::Values(dlp::FileAction::kDownload,
dlp::FileAction::kTransfer,
dlp::FileAction::kUpload,
dlp::FileAction::kCopy,
dlp::FileAction::kMove,
dlp::FileAction::kOpen,
dlp::FileAction::kShare));
class ErrorDialogBrowserTest : public FilesPolicyDialogBrowserTest {
public:
void SetUpOnMainThread() override {
FilesPolicyDialogBrowserTest::SetUpOnMainThread();
const std::vector<base::FilePath> paths = {base::FilePath("file1.txt"),
base::FilePath("file2.txt")};
dialog_info_map_.insert({FilesPolicyDialog::BlockReason::kDlp,
FilesPolicyDialog::Info::Error(
FilesPolicyDialog::BlockReason::kDlp, paths)});
}
// Checks that a error dialog with mixed errors only contains the sections for
// the given `reasons`.
void ContainMixedErrorSections(
FilesPolicyErrorDialog* dialog,
const std::vector<FilesPolicyDialog::BlockReason>& reasons) {
std::set<FilesPolicyDialog::BlockReason> reasons_without_sections(
std::begin(FilesPolicyDialog::available_reasons),
std::end(FilesPolicyDialog::available_reasons));
for (FilesPolicyDialog::BlockReason reason : reasons) {
// The view ID is attached to the title label.
views::View* title_label = dialog->GetViewByID(
FilesPolicyDialog::MapBlockReasonToViewID(reason));
EXPECT_TRUE(title_label);
reasons_without_sections.erase(reason);
}
for (FilesPolicyDialog::BlockReason reason : reasons_without_sections) {
EXPECT_FALSE(dialog->GetViewByID(
FilesPolicyDialog::MapBlockReasonToViewID(reason)));
}
}
std::u16string GetTitle(FilesPolicyErrorDialog* dialog,
FilesPolicyDialog::BlockReason reason) {
views::View* title_label =
dialog->GetViewByID(FilesPolicyDialog::MapBlockReasonToViewID(reason));
if (!title_label) {
return u"";
}
// The view ID is attached to the title label.
return static_cast<views::Label*>(title_label)->GetText();
}
protected:
std::map<FilesPolicyDialog::BlockReason, FilesPolicyDialog::Info>
dialog_info_map_;
};
// Tests that the error dialog is created as a system modal if no parent is
// passed, and that accepting the dialog dismisses it without any other action.
IN_PROC_BROWSER_TEST_P(ErrorDialogBrowserTest, NoParent) {
dlp::FileAction action = GetParam();
// Add another blocked file to test the mixed error case.
const std::vector<base::FilePath> paths = {base::FilePath("file3.txt")};
auto dialog_settings = FilesPolicyDialog::Info::Error(
FilesPolicyDialog::BlockReason::kEnterpriseConnectorsSensitiveData,
paths);
// Override default dialog settings.
dialog_settings.SetMessage(u"Custom message");
dialog_settings.SetLearnMoreURL(GURL("https://learnmore.com"));
dialog_info_map_.insert(
{FilesPolicyDialog::BlockReason::kEnterpriseConnectorsSensitiveData,
std::move(dialog_settings)});
auto* widget = FilesPolicyDialog::CreateErrorDialog(dialog_info_map_, action,
/*modal_parent=*/nullptr);
ASSERT_TRUE(widget);
FilesPolicyErrorDialog* dialog = static_cast<FilesPolicyErrorDialog*>(
widget->widget_delegate()->AsDialogDelegate());
ASSERT_TRUE(dialog);
EXPECT_EQ(dialog->GetModalType(), ui::mojom::ModalType::kSystem);
// Accept -> dismiss.
dialog->AcceptDialog();
EXPECT_TRUE(widget->IsClosed());
EXPECT_THAT(histogram_tester_.GetAllSamples(
data_controls::GetDlpHistogramPrefix() +
std::string(data_controls::dlp::kFileActionBlockReviewedUMA)),
base::BucketsAre(base::Bucket(action, 1)));
}
// Tests that the error dialog is created as a window modal if a Files app
// window is passed as the parent, and that accepting the dialog dismisses it
// without any other action.
IN_PROC_BROWSER_TEST_P(ErrorDialogBrowserTest, WithParent) {
dlp::FileAction action = GetParam();
ASSERT_FALSE(FindFilesApp());
Browser* files_app = OpenFilesApp();
ASSERT_TRUE(files_app);
ASSERT_EQ(files_app, FindFilesApp());
auto* widget = FilesPolicyDialog::CreateErrorDialog(
dialog_info_map_, action, files_app->window()->GetNativeWindow());
ASSERT_TRUE(widget);
FilesPolicyErrorDialog* dialog = static_cast<FilesPolicyErrorDialog*>(
widget->widget_delegate()->AsDialogDelegate());
ASSERT_TRUE(dialog);
EXPECT_EQ(dialog->GetModalType(), ui::mojom::ModalType::kWindow);
EXPECT_EQ(widget->parent()->GetNativeWindow(),
files_app->window()->GetNativeWindow());
// Accept -> dismiss.
dialog->AcceptDialog();
EXPECT_TRUE(widget->IsClosed());
EXPECT_THAT(histogram_tester_.GetAllSamples(
data_controls::GetDlpHistogramPrefix() +
std::string(data_controls::dlp::kFileActionBlockReviewedUMA)),
base::BucketsAre(base::Bucket(action, 1)));
}
// Tests that the error dialog is populated with one section for every available
// block reason.
IN_PROC_BROWSER_TEST_P(ErrorDialogBrowserTest, AllErrorSections) {
dlp::FileAction action = GetParam();
std::map<FilesPolicyDialog::BlockReason, FilesPolicyDialog::Info> info_map;
size_t count = 0;
for (FilesPolicyDialog::BlockReason reason :
FilesPolicyDialog::available_reasons) {
const base::FilePath path1("file" + base::NumberToString(count++) + ".txt");
const base::FilePath path2("file" + base::NumberToString(count++) + ".txt");
auto dialog_settings =
FilesPolicyDialog::Info::Error(reason, {path1, path2});
info_map.insert({reason, std::move(dialog_settings)});
}
// Sensitive data and malware have their own section only when a custom
// message is defined.
const std::u16string sensitive_data_message =
u"Sensitive data custom message";
info_map
.at(FilesPolicyDialog::BlockReason::kEnterpriseConnectorsSensitiveData)
.SetMessage(sensitive_data_message);
const std::u16string malware_message = u"Malware data custom message";
info_map.at(FilesPolicyDialog::BlockReason::kEnterpriseConnectorsMalware)
.SetMessage(malware_message);
auto* widget = FilesPolicyDialog::CreateErrorDialog(info_map, action,
/*modal_parent=*/nullptr);
ASSERT_TRUE(widget);
FilesPolicyErrorDialog* dialog = static_cast<FilesPolicyErrorDialog*>(
widget->widget_delegate()->AsDialogDelegate());
ASSERT_TRUE(dialog);
std::vector<FilesPolicyDialog::BlockReason> expected_sections = {
FilesPolicyDialog::BlockReason::kDlp,
FilesPolicyDialog::BlockReason::kEnterpriseConnectorsSensitiveData,
FilesPolicyDialog::BlockReason::kEnterpriseConnectorsMalware,
FilesPolicyDialog::BlockReason::kEnterpriseConnectorsScanFailed,
FilesPolicyDialog::BlockReason::kEnterpriseConnectorsEncryptedFile,
FilesPolicyDialog::BlockReason::kEnterpriseConnectorsLargeFile,
FilesPolicyDialog::BlockReason::kEnterpriseConnectors};
ContainMixedErrorSections(dialog, expected_sections);
for (FilesPolicyDialog::BlockReason reason : expected_sections) {
if (reason == FilesPolicyDialog::BlockReason::kEnterpriseConnectors) {
// In this case we also expect files with
// FilesPolicyDialog::BlockReason::kEnterpriseConnectorsUnknownScanResult
// block reason.
size_t files_num = info_map.at(reason).GetFiles().size() +
info_map
.at(FilesPolicyDialog::BlockReason::
kEnterpriseConnectorsUnknownScanResult)
.GetFiles()
.size();
ASSERT_EQ(GetTitle(dialog, reason),
files_string_util::GetBlockReasonMessage(reason, files_num));
continue;
}
ASSERT_EQ(GetTitle(dialog, reason), info_map.at(reason).GetMessage());
}
}
// Tests that when no custom message is specified for Enterprise Connectors
// malware and sensitive data, the error dialog is a single error dialog.
IN_PROC_BROWSER_TEST_P(ErrorDialogBrowserTest,
NoEnterpriseConnectorsCustomMessage) {
dlp::FileAction action = GetParam();
std::map<FilesPolicyDialog::BlockReason, FilesPolicyDialog::Info> info_map;
auto sensitive_data_file_dialog_settings = FilesPolicyDialog::Info::Error(
FilesPolicyDialog::BlockReason::kEnterpriseConnectorsSensitiveData,
{base::FilePath("file1.txt"), base::FilePath("file2.txt")});
auto malware_file_dialog_settings = FilesPolicyDialog::Info::Error(
FilesPolicyDialog::BlockReason::kEnterpriseConnectorsMalware,
{base::FilePath("file3.txt"), base::FilePath("file4.txt")});
info_map.insert(
{FilesPolicyDialog::BlockReason::kEnterpriseConnectorsSensitiveData,
std::move(sensitive_data_file_dialog_settings)});
info_map.insert({FilesPolicyDialog::BlockReason::kEnterpriseConnectorsMalware,
std::move(malware_file_dialog_settings)});
auto* widget = FilesPolicyDialog::CreateErrorDialog(info_map, action,
/*modal_parent=*/nullptr);
ASSERT_TRUE(widget);
FilesPolicyErrorDialog* dialog = static_cast<FilesPolicyErrorDialog*>(
widget->widget_delegate()->AsDialogDelegate());
ASSERT_TRUE(dialog);
// The dialog is a single error dialog, and thus it does not contain mixed
// error sections.
ContainMixedErrorSections(dialog, {});
}
// Tests that when files are blocked because of Enterprise Connectors malware
// and sensitive data reasons, but a custom message is only defined for one of
// them, e.g., malware, the error dialog should have two sections: one for
// malware with the custom message, and a generic one section with a default
// message for the other files.
IN_PROC_BROWSER_TEST_P(ErrorDialogBrowserTest,
EnterpriseConnectorsCustomMessage) {
dlp::FileAction action = GetParam();
std::map<FilesPolicyDialog::BlockReason, FilesPolicyDialog::Info> info_map;
std::vector<base::FilePath> sensitive_data_paths = {
base::FilePath("file1.txt"), base::FilePath("file2.txt")};
auto sensitive_data_file_dialog_settings = FilesPolicyDialog::Info::Error(
FilesPolicyDialog::BlockReason::kEnterpriseConnectorsSensitiveData,
sensitive_data_paths);
auto malware_file_dialog_settings = FilesPolicyDialog::Info::Error(
FilesPolicyDialog::BlockReason::kEnterpriseConnectorsMalware,
{base::FilePath("file3.txt"), base::FilePath("file4.txt")});
const std::u16string malware_message = u"Malware data custom message";
malware_file_dialog_settings.SetMessage(malware_message);
info_map.insert(
{FilesPolicyDialog::BlockReason::kEnterpriseConnectorsSensitiveData,
std::move(sensitive_data_file_dialog_settings)});
info_map.insert({FilesPolicyDialog::BlockReason::kEnterpriseConnectorsMalware,
std::move(malware_file_dialog_settings)});
auto* widget = FilesPolicyDialog::CreateErrorDialog(info_map, action,
/*modal_parent=*/nullptr);
ASSERT_TRUE(widget);
FilesPolicyErrorDialog* dialog = static_cast<FilesPolicyErrorDialog*>(
widget->widget_delegate()->AsDialogDelegate());
ASSERT_TRUE(dialog);
ContainMixedErrorSections(
dialog, {FilesPolicyDialog::BlockReason::kEnterpriseConnectorsMalware,
FilesPolicyDialog::BlockReason::kEnterpriseConnectors});
ASSERT_EQ(
GetTitle(dialog,
FilesPolicyDialog::BlockReason::kEnterpriseConnectorsMalware),
l10n_util::GetStringFUTF16(IDS_POLICY_DLP_FROM_YOUR_ADMIN_MESSAGE,
malware_message));
ASSERT_EQ(
GetTitle(dialog, FilesPolicyDialog::BlockReason::kEnterpriseConnectors),
files_string_util::GetBlockReasonMessage(
FilesPolicyDialog::BlockReason::kEnterpriseConnectors,
sensitive_data_paths.size()));
}
INSTANTIATE_TEST_SUITE_P(FilesPolicyDialog,
ErrorDialogBrowserTest,
::testing::Values(dlp::FileAction::kDownload,
dlp::FileAction::kTransfer,
dlp::FileAction::kUpload,
dlp::FileAction::kCopy,
dlp::FileAction::kMove,
dlp::FileAction::kOpen,
dlp::FileAction::kShare));
// Class to test "old" DLP Files restriction warning dialogs.
class DlpWarningDialogDestinationBrowserTest : public InProcessBrowserTest {
public:
DlpWarningDialogDestinationBrowserTest() = default;
DlpWarningDialogDestinationBrowserTest(
const DlpWarningDialogDestinationBrowserTest&) = delete;
DlpWarningDialogDestinationBrowserTest& operator=(
const DlpWarningDialogDestinationBrowserTest&) = delete;
~DlpWarningDialogDestinationBrowserTest() override = default;
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
warning_paths_.emplace_back("file1.txt");
warning_paths_.emplace_back("file2.txt");
}
protected:
std::vector<base::FilePath> warning_paths_;
};
// (b/281495499): This is a test for the crash that happens upon showing a
// warning dialog for downloads.
IN_PROC_BROWSER_TEST_F(DlpWarningDialogDestinationBrowserTest, Download) {
auto paths = std::vector<base::FilePath>({base::FilePath("file1.txt")});
ASSERT_TRUE(FilesPolicyDialog::CreateWarnDialog(
base::DoNothing(), dlp::FileAction::kDownload,
/*modal_parent=*/nullptr,
FilesPolicyDialog::Info::Warn(FilesPolicyDialog::BlockReason::kDlp,
paths),
DlpFileDestination(data_controls::Component::kDrive)));
}
class DestinationBrowserTest
: public DlpWarningDialogDestinationBrowserTest,
public ::testing::WithParamInterface<
std::tuple<dlp::FileAction, DlpFileDestination>> {};
IN_PROC_BROWSER_TEST_P(DestinationBrowserTest, CreateDialog) {
auto [action, destination] = GetParam();
ASSERT_TRUE(FilesPolicyDialog::CreateWarnDialog(
base::DoNothing(), action,
/*modal_parent=*/nullptr,
FilesPolicyDialog::Info::Warn(FilesPolicyDialog::BlockReason::kDlp,
warning_paths_),
destination));
}
INSTANTIATE_TEST_SUITE_P(
FilesPolicyDialog,
DestinationBrowserTest,
::testing::Values(
// (b/277594200): This is a test for the crash that happens upon showing
// a warning dialog when a file is dragged to a webpage.
std::make_tuple(dlp::FileAction::kCopy,
DlpFileDestination(GURL("https://example.com"))),
std::make_tuple(dlp::FileAction::kUpload,
DlpFileDestination(GURL("https://example.com"))),
// (b/273269211): This is a test for the crash that happens upon showing
// a warning dialog when a file is moved to Google Drive.
std::make_tuple(dlp::FileAction::kMove,
DlpFileDestination(data_controls::Component::kDrive)),
std::make_tuple(dlp::FileAction::kTransfer,
DlpFileDestination(data_controls::Component::kArc)),
std::make_tuple(
dlp::FileAction::kUnknown,
DlpFileDestination(data_controls::Component::kCrostini)),
std::make_tuple(dlp::FileAction::kOpen,
DlpFileDestination(data_controls::Component::kUsb)),
std::make_tuple(
dlp::FileAction::kMove,
DlpFileDestination(data_controls::Component::kPluginVm)),
std::make_tuple(
dlp::FileAction::kShare,
DlpFileDestination(data_controls::Component::kOneDrive))));
} // namespace policy