chromium/chrome/browser/download/download_target_determiner_unittest.cc

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

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "chrome/browser/download/download_target_determiner.h"

#include <stddef.h>
#include <stdint.h>

#include <optional>
#include <string>
#include <vector>

#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/json/values_util.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/observer_list.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/test_future.h"
#include "build/build_config.h"
#include "chrome/browser/download/chrome_download_manager_delegate.h"
#include "chrome/browser/download/download_confirmation_result.h"
#include "chrome/browser/download/download_crx_util.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/download/download_prompt_status.h"
#include "chrome/browser/download/download_stats.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/common/buildflags.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "components/download/public/common/download_interrupt_reasons.h"
#include "components/download/public/common/download_target_info.h"
#include "components/download/public/common/mock_download_item.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_types.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/content/common/file_type_policies.h"
#include "components/safe_browsing/content/common/file_type_policies_test_util.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/user_manager/scoped_user_manager.h"
#include "content/public/browser/download_item_utils.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
#include "extensions/buildflags/buildflags.h"
#include "net/base/mime_util.h"
#include "ppapi/buildflags/buildflags.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/shell_dialogs/selected_file_info.h"
#include "url/origin.h"

#if BUILDFLAG(ENABLE_PLUGINS)
#include "content/public/browser/plugin_service.h"
#include "content/public/browser/plugin_service_filter.h"
#include "content/public/common/webplugininfo.h"
#endif

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

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/ash/policy/dlp/dlp_files_controller_ash.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_file_destination.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.h"
#include "chrome/browser/chromeos/policy/dlp/test/mock_dlp_rules_manager.h"
#endif

DownloadItem;
DownloadPathReservationTracker;
_;
AnyNumber;
Invoke;
Ref;
Return;
ReturnRef;
ReturnRefOfCopy;
Truly;
WithArg;
ConflictAction;
DownloadFileType;
FileTypePolicies;

namespace {

const char kTransientPathGenerationHistogram[] =;

const char kTransientPathValidationHistogram[] =;

template <typename T>
base::HistogramBase::Sample ToHistogramSample(T t) {}

// No-op delegate.
class NullWebContentsDelegate : public content::WebContentsDelegate {};

// Google Mock action that posts a task to the current message loop that invokes
// the first argument of the mocked method as a callback. Said argument must be
// a base::OnceCallback<void(ParamType)>&. |result| must be of |ParamType| and
// is bound as that parameter. Example:
//   class FooClass {
//    public:
//     virtual void Foo(base::OnceCallback<void(bool)> callback);
//   };
//   ...
//   EXPECT_CALL(mock_fooclass_instance, Foo(callback))
//     .WillOnce(ScheduleCallback(false));
ACTION_P(ScheduleCallback, result0) {}

ACTION_P2(ScheduleCallback2, result0, result1) {}

// Used with DownloadTestCase. Indicates the type of test case. The expectations
// for the test is set based on the type.
enum TestCaseType {};

// Used with DownloadTestCase. Type of intermediate filename to expect.
enum TestCaseExpectIntermediate {};

// Typical download test case. Used with
// DownloadTargetDeterminerTest::RunTestCase().
struct DownloadTestCase {};

// In this class, overridden methods thunk to mocked methods (names ending with
// underscore) because WithArgs doesn't support moving. The mocked methods thus
// take a reference to the callback.
class MockDownloadTargetDeterminerDelegate
    : public DownloadTargetDeterminerDelegate {};

class DownloadTargetDeterminerTest : public ChromeRenderViewHostTestHarness {};

void DownloadTargetDeterminerTest::SetUp() {}

void DownloadTargetDeterminerTest::TearDown() {}

std::unique_ptr<download::MockDownloadItem>
DownloadTargetDeterminerTest::CreateActiveDownloadItem(
    int32_t id,
    const DownloadTestCase& test_case) {}

void DownloadTargetDeterminerTest::EnableAutoOpenByUserBasedOnExtension(
    const base::FilePath& path) {}

void DownloadTargetDeterminerTest::SetManagedDownloadPath(
    const base::FilePath& path) {}

void DownloadTargetDeterminerTest::SetPromptForDownload(bool prompt) {}

base::FilePath DownloadTargetDeterminerTest::GetPathInDownloadDir(
    const base::FilePath::StringType& relative_path) {}

void DownloadTargetDeterminerTest::RunTestCase(
    const DownloadTestCase& test_case,
    const base::FilePath& initial_virtual_path,
    download::MockDownloadItem* item) {}

DownloadTargetDeterminerTest::TargetInfoAndDangerLevel
DownloadTargetDeterminerTest::RunDownloadTargetDeterminer(
    const base::FilePath& initial_virtual_path,
    download::MockDownloadItem* item) {}

void DownloadTargetDeterminerTest::RunTestCasesWithActiveItem(
    const DownloadTestCase test_cases[],
    size_t test_case_count) {}

void DownloadTargetDeterminerTest::VerifyDownloadTarget(
    const DownloadTestCase& test_case,
    TargetInfoAndDangerLevel info) {}

void DownloadTargetDeterminerTest::SetUpFileTypePolicies() {}

// static
void MockDownloadTargetDeterminerDelegate::NullPromptUser(
    DownloadItem* download,
    const base::FilePath& suggested_path,
    DownloadConfirmationReason reason,
    ConfirmationCallback& callback) {}

// static
void MockDownloadTargetDeterminerDelegate::NullDetermineLocalPath(
    DownloadItem* download,
    const base::FilePath& virtual_path,
    download::LocalPathCallback& callback) {}

// NotifyExtensions implementation that overrides the path so that the target
// file is in a subdirectory called 'overridden'. If the extension is '.remove',
// the extension is removed.
void NotifyExtensionsOverridePath(
    download::DownloadItem* download,
    const base::FilePath& path,
    DownloadTargetDeterminerDelegate::NotifyExtensionsCallback& callback) {}

TEST_F(DownloadTargetDeterminerTest, Basic) {}

TEST_F(DownloadTargetDeterminerTest, CancelSaveAs) {}

// The SafeBrowsing check is performed early. Make sure that a download item
// that has been marked as DANGEROUS_URL behaves correctly.
TEST_F(DownloadTargetDeterminerTest, DangerousUrl) {}

// The SafeBrowsing check is performed early. Make sure that a download item
// that has been marked as MAYBE_DANGEROUS_CONTENT behaves correctly.
TEST_F(DownloadTargetDeterminerTest, MaybeDangerousContent) {}

// Test whether the last saved directory is used for 'Save As' downloads.
TEST_F(DownloadTargetDeterminerTest, LastSavePath) {}

// These tests are run with the default downloads folder set to a virtual
// directory.
TEST_F(DownloadTargetDeterminerTest, DefaultVirtual) {}

#if BUILDFLAG(ENABLE_PLUGINS)
TEST_F(DownloadTargetDeterminerTest,
       DetermineIfHandledSafelyHelperSynchronous) {}
#endif

// Test that an inactive download will still get a virtual or local download
// path.
TEST_F(DownloadTargetDeterminerTest, InactiveDownload) {}

// If the reserved path could not be verified, then the user should see a
// prompt.
TEST_F(DownloadTargetDeterminerTest, ReservationFailed_Confirmation) {}

// If the local path could not be determined, the download should be cancelled.
TEST_F(DownloadTargetDeterminerTest, LocalPathFailed) {}

// Downloads that have a danger level of ALLOW_ON_USER_GESTURE should be marked
// as safe depending on whether there was a user gesture associated with the
// download and whether the referrer was visited prior to today.
TEST_F(DownloadTargetDeterminerTest, VisitedReferrer) {}

TEST_F(DownloadTargetDeterminerTest, TransitionType) {}

// These test cases are run with "Prompt for download" user preference set to
// true.
TEST_F(DownloadTargetDeterminerTest, PromptAlways_SafeAutomatic) {}

TEST_F(DownloadTargetDeterminerTest, PromptAlways_SafeSaveAs) {}

TEST_F(DownloadTargetDeterminerTest, PromptAlways_SafeForced) {}

TEST_F(DownloadTargetDeterminerTest, PromptAlways_AutoOpen) {}

// If an embedder responds to a RequestConfirmation with a new path and a
// CONTINUE_WITHOUT_CONFIRMATION, then we shouldn't consider the file as safe.
TEST_F(DownloadTargetDeterminerTest, ContinueWithoutConfirmation_SaveAs) {}

// Same as ContinueWithoutConfirmation_SaveAs, but the embedder response
// indicates that the user confirmed the path. Hence the danger level of the
// download and the disposition should be updated accordingly.
TEST_F(DownloadTargetDeterminerTest, ContinueWithConfirmation_SaveAs) {}

#if BUILDFLAG(ENABLE_EXTENSIONS)
// These test cases are run with "Prompt for download" user preference set to
// true. For non-trusted extensions, download should cause prompting.
// Android doesn't support extensions.
TEST_F(DownloadTargetDeterminerTest, PromptAlways_NonTrustedExtension) {}

// Trusted extension download should not cause prompting.
TEST_F(DownloadTargetDeterminerTest, PromptAlways_TrustedExtension) {}
#endif  // BUILDFLAG(ENABLE_EXTENSIONS)

// If the download path is managed, then we don't show any prompts.
// Note that if the download path is managed, then PromptForDownload() is false.
TEST_F(DownloadTargetDeterminerTest, ManagedPath) {}

// Test basic blocking functionality via GetInsecureDownloadStatus.
TEST_F(DownloadTargetDeterminerTest, BlockDownloads) {}

// Test basic functionality supporting extensions that want to override download
// filenames.
TEST_F(DownloadTargetDeterminerTest, NotifyExtensionsSafe) {}

// Test that filenames provided by extensions are passed into SafeBrowsing
// checks and dangerous download checks.
TEST_F(DownloadTargetDeterminerTest, NotifyExtensionsUnsafe) {}

// Test that conflict actions set by extensions are passed correctly into
// ReserveVirtualPath.
TEST_F(DownloadTargetDeterminerTest, NotifyExtensionsConflict) {}

// Test that relative paths returned by extensions are always relative to the
// default downloads path.
TEST_F(DownloadTargetDeterminerTest, NotifyExtensionsDefaultPath) {}

// Test that relative paths returned by extensions are always relative to the
// default downloads path.
TEST_F(DownloadTargetDeterminerTest, NotifyExtensionsLocalFile) {}

TEST_F(DownloadTargetDeterminerTest, InitialVirtualPathUnsafe) {}

// Prompting behavior for resumed downloads is based on the last interrupt
// reason. If the reason indicates that the target path may not be suitable for
// the download (ACCESS_DENIED, NO_SPACE, etc..), then the user should be
// prompted, and not otherwise. These test cases shouldn't result in prompting
// since the error is set to NETWORK_FAILED.
TEST_F(DownloadTargetDeterminerTest, ResumedNoPrompt) {}

// Test that a forced download doesn't prompt, even if the interrupt reason
// suggests that the target path may not be suitable for downloads.
TEST_F(DownloadTargetDeterminerTest, ResumedForcedDownload) {}

// Prompting behavior for resumed downloads is based on the last interrupt
// reason. If the reason indicates that the target path may not be suitable for
// the download (ACCESS_DENIED, NO_SPACE, etc..), then the user should be
// prompted, and not otherwise. These test cases result in prompting since the
// error is set to NO_SPACE.
TEST_F(DownloadTargetDeterminerTest, ResumedWithPrompt) {}

// Test intermediate filename generation for resumed downloads.
TEST_F(DownloadTargetDeterminerTest, IntermediateNameForResumed) {}

// Test MIME type determination based on the target filename.
TEST_F(DownloadTargetDeterminerTest, MIMETypeDetermination) {}

// Test that the mime type given by the server may determine the target file
// extension.
// The file extension is generated through mime type when:
// 1. Content-Type header is not empty.
// 2. No suggested file name, which has higher priority than mime type to
// generate file name.
// 3. No force file name, which has higher priority.
// 4. The extension generated from the URL is considered safe by safe browsing,
// and it's not required to do security check by safe browsing. No matter the
// new extension is safe or unsafe, we never decrease the number of safe
// browsing checks.
TEST_F(DownloadTargetDeterminerTest, MimeTypeFileExtension) {}

// Test that a user validated download won't be treated as dangerous.
TEST_F(DownloadTargetDeterminerTest, ResumedWithUserValidatedDownload) {}

// Test that verifies transient download target determination.
TEST_F(DownloadTargetDeterminerTest, TransientDownload) {}

// Simulate resumption on transient download. The download item does not provide
// forced path in this case.
TEST_F(DownloadTargetDeterminerTest, TransientDownloadResumption) {}

#if BUILDFLAG(IS_WIN)
// Test that env variables will be removed from file name before prompting Save
// As dialog.
TEST_F(DownloadTargetDeterminerTest, TestSanitizeEnvVariable) {
  const DownloadTestCase kSaveEnvPathTestCases[] = {
      {// 0: File name contains env var delimits.
       SAVE_AS, download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
       DownloadFileType::NOT_DANGEROUS, "http://example.com/f%oo%.tx%xyz%t",
       "text/plain", FILE_PATH_LITERAL(""),

       FILE_PATH_LITERAL("f.txt"), DownloadItem::TARGET_DISPOSITION_PROMPT,

       EXPECT_CRDOWNLOAD},

      {// 1: File name contains dangerous extensions after removing env var.
       SAVE_AS, download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
       DownloadFileType::NOT_DANGEROUS, "http://example.com/foo.ln%xyz%k",
       "application/octet-stream", FILE_PATH_LITERAL(""),

       FILE_PATH_LITERAL("foo.download"),
       DownloadItem::TARGET_DISPOSITION_PROMPT,

       EXPECT_CRDOWNLOAD},
      {// 2: File name falling back to dangerous extensions after removing env var.
       SAVE_AS, download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
       DownloadFileType::NOT_DANGEROUS, "http://example.com/foo2.lnk.%%",
       "application/octet-stream", FILE_PATH_LITERAL(""),

       FILE_PATH_LITERAL("foo2.download"),
       DownloadItem::TARGET_DISPOSITION_PROMPT,

       EXPECT_CRDOWNLOAD},
      {// 3: File name is an env var.
       SAVE_AS, download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
       DownloadFileType::NOT_DANGEROUS, "http://example.com/%foo.txt%",
       "text/plain", FILE_PATH_LITERAL(""),

       FILE_PATH_LITERAL("download"), DownloadItem::TARGET_DISPOSITION_PROMPT,

       EXPECT_CRDOWNLOAD}};

  RunTestCasesWithActiveItem(kSaveEnvPathTestCases,
                             std::size(kSaveEnvPathTestCases));
}
#endif  // BUILDFLAG(IS_WIN)

#if BUILDFLAG(ENABLE_PLUGINS)

void DummyGetPluginsCallback(
    base::OnceClosure closure,
    const std::vector<content::WebPluginInfo>& plugins) {}

void ForceRefreshOfPlugins() {}

class MockPluginServiceFilter : public content::PluginServiceFilter {};

class ScopedRegisterInternalPlugin {};

// We use a slightly different test fixture for tests that touch plugins. SetUp
// needs to disable plugin discovery.
class DownloadTargetDeterminerTestWithPlugin
    : public DownloadTargetDeterminerTest {};

// Check if secure handling of filetypes is determined correctly for PPAPI
// plugins.
TEST_F(DownloadTargetDeterminerTestWithPlugin, CheckForSecureHandling_PPAPI) {}

// Check if secure handling of filetypes is determined correctly for
// BrowserPlugins.
TEST_F(DownloadTargetDeterminerTestWithPlugin,
       CheckForSecureHandling_BrowserPlugin) {}

#endif  // BUILDFLAG(ENABLE_PLUGINS)

#if BUILDFLAG(IS_ANDROID)
// If a content URI is returned when determining local path, virtual path
// is updated.
TEST_F(DownloadTargetDeterminerTest, DetermineLocalPathReturnsContentUri) {
  const DownloadTestCase kLocalPathContentUriCase = {
      AUTOMATIC,
      download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
      DownloadFileType::NOT_DANGEROUS,
      "http://example.com/foo.txt",
      "text/plain",
      FILE_PATH_LITERAL(""),
      FILE_PATH_LITERAL("content://media/123"),
      DownloadItem::TARGET_DISPOSITION_OVERWRITE,
      EXPECT_LOCAL_PATH};

  std::unique_ptr<download::MockDownloadItem> item =
      CreateActiveDownloadItem(0, kLocalPathContentUriCase);
  // The default download directory is the virtual path.
  download_prefs()->SetDownloadPath(test_virtual_dir());

  EXPECT_CALL(
      *delegate(),
      DetermineLocalPath_(
          _, GetPathInDownloadDir(FILE_PATH_LITERAL("virtual/foo.txt")), _))
      .WillOnce(WithArg<2>(ScheduleCallback2(
          base::FilePath("content://media/123"), base::FilePath("foor.txt"))));
  TargetInfoAndDangerLevel info =
      RunDownloadTargetDeterminer(base::FilePath(), item.get());

  EXPECT_EQ(info.target_info.display_name.value(), "foor.txt");
  EXPECT_EQ(info.target_info.target_path.value(), "content://media/123");
}
#endif  // BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(IS_CHROMEOS_ASH)
// Tests that DLP policies are checked before determining the download path.
class DownloadTargetDeterminerDlpTest : public DownloadTargetDeterminerTest {
 protected:
  DownloadTargetDeterminerDlpTest()
      : profile_(std::make_unique<TestingProfile>()),
        user_manager_(new ash::FakeChromeUserManager()),
        scoped_user_manager_(std::make_unique<user_manager::ScopedUserManager>(
            base::WrapUnique(user_manager_.get()))) {}

  class MockFilesController : public policy::DlpFilesControllerAsh {
   public:
    explicit MockFilesController(const policy::DlpRulesManager& rules_manager,
                                 Profile* profile)
        : DlpFilesControllerAsh(rules_manager, profile) {}
    ~MockFilesController() override = default;

    MOCK_METHOD(bool,
                ShouldPromptBeforeDownload,
                (const policy::DlpFileDestination&, const base::FilePath&),
                (override));
  };

  void SetUp() override {
    DownloadTargetDeterminerTest::SetUp();

    AccountId account_id =
        AccountId::FromUserEmailGaiaId("[email protected]", "12345");
    profile_->SetIsNewProfile(true);
    user_manager::User* user =
        user_manager_->AddUserWithAffiliationAndTypeAndProfile(
            account_id, /*is_affiliated=*/false,
            user_manager::UserType::kRegular, profile_.get());
    user_manager_->UserLoggedIn(account_id, user->username_hash(),
                                /*browser_restart=*/false,
                                /*is_child=*/false);
    user_manager_->SimulateUserProfileLoad(account_id);
  }

  void TearDown() override {
    mock_files_controller_.reset();
    scoped_user_manager_.reset();
    profile_.reset();

    DownloadTargetDeterminerTest::TearDown();
  }

  std::unique_ptr<KeyedService> SetDlpRulesManager(
      content::BrowserContext* context) {
    auto dlp_rules_manager =
        std::make_unique<testing::NiceMock<policy::MockDlpRulesManager>>(
            Profile::FromBrowserContext(context));
    rules_manager_ = dlp_rules_manager.get();
    return dlp_rules_manager;
  }

  void SetupRulesManager() {
    policy::DlpRulesManagerFactory::GetInstance()->SetTestingFactory(
        profile_.get(),
        base::BindRepeating(
            &DownloadTargetDeterminerDlpTest::SetDlpRulesManager,
            base::Unretained(this)));
    ASSERT_TRUE(policy::DlpRulesManagerFactory::GetForPrimaryProfile());

    ON_CALL(*rules_manager_, IsFilesPolicyEnabled)
        .WillByDefault(testing::Return(true));
    mock_files_controller_ =
        std::make_unique<MockFilesController>(*rules_manager_, profile_.get());
    ON_CALL(*rules_manager_, GetDlpFilesController)
        .WillByDefault(testing::Return(mock_files_controller_.get()));
  }

  std::unique_ptr<TestingProfile> profile_;
  raw_ptr<ash::FakeChromeUserManager, DanglingUntriaged> user_manager_;
  std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
  raw_ptr<policy::MockDlpRulesManager, DanglingUntriaged> rules_manager_ =
      nullptr;
  std::unique_ptr<MockFilesController> mock_files_controller_ = nullptr;
};

// Download URL might be invalid. Dlp must not crash in that case
// (b/300605501).
TEST_F(DownloadTargetDeterminerDlpTest, InvalidUrl) {
  SetupRulesManager();

  const DownloadTestCase kManagedPathTestCase = {
      AUTOMATIC,
      download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
      DownloadFileType::NOT_DANGEROUS,
      "",
      "text/plain",
      FILE_PATH_LITERAL(""),

      FILE_PATH_LITERAL("download.txt"),
      DownloadItem::TARGET_DISPOSITION_PROMPT,

      EXPECT_CRDOWNLOAD};

  SetManagedDownloadPath(test_download_dir());
  ASSERT_TRUE(download_prefs()->IsDownloadPathManaged());
  EXPECT_CALL(*delegate(),
              RequestConfirmation_(
                  _, GetPathInDownloadDir(FILE_PATH_LITERAL("download.txt")),
                  DownloadConfirmationReason::DLP_BLOCKED, _));
  EXPECT_CALL(*mock_files_controller_, ShouldPromptBeforeDownload).Times(0);
  RunTestCasesWithActiveItem(&kManagedPathTestCase, 1);
}

// Even if the download path is managed, we should prompt if the download path
// is blocked by DLP.
TEST_F(DownloadTargetDeterminerDlpTest, ManagedPath_ShouldPrompt) {
  SetupRulesManager();

  const DownloadTestCase kManagedPathTestCase = {
      AUTOMATIC,
      download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
      DownloadFileType::NOT_DANGEROUS,
      "http://example.com/foo.txt",
      "text/plain",
      FILE_PATH_LITERAL(""),

      FILE_PATH_LITERAL("foo.txt"),
      DownloadItem::TARGET_DISPOSITION_PROMPT,

      EXPECT_CRDOWNLOAD};

  SetManagedDownloadPath(test_download_dir());
  ASSERT_TRUE(download_prefs()->IsDownloadPathManaged());
  EXPECT_CALL(*delegate(),
              RequestConfirmation_(
                  _, GetPathInDownloadDir(FILE_PATH_LITERAL("foo.txt")),
                  DownloadConfirmationReason::DLP_BLOCKED, _));
  EXPECT_CALL(*mock_files_controller_, ShouldPromptBeforeDownload)
      .WillOnce(testing::Return(true));
  RunTestCasesWithActiveItem(&kManagedPathTestCase, 1);
}

// Even if "Prompt for download" user preference is set to false, we should
// prompt if the download path is blocked by DLP.
TEST_F(DownloadTargetDeterminerDlpTest, PromptAlways_SafeAutomatic) {
  SetupRulesManager();

  const DownloadTestCase kSafeAutomatic = {
      AUTOMATIC,
      download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
      DownloadFileType::NOT_DANGEROUS,
      "http://example.com/automatic.txt",
      "text/plain",
      FILE_PATH_LITERAL(""),

      FILE_PATH_LITERAL("automatic.txt"),
      DownloadItem::TARGET_DISPOSITION_PROMPT,

      EXPECT_CRDOWNLOAD};

  SetPromptForDownload(false);
  EXPECT_CALL(*mock_files_controller_, ShouldPromptBeforeDownload)
      .WillOnce(testing::Return(true));
  EXPECT_CALL(*delegate(),
              RequestConfirmation_(
                  _, GetPathInDownloadDir(FILE_PATH_LITERAL("automatic.txt")),
                  DownloadConfirmationReason::DLP_BLOCKED, _));
  RunTestCasesWithActiveItem(&kSafeAutomatic, 1);
}
#endif

}  // namespace