[go: nahoru, domu]

blob: 479631fa18421a3dad856b8819189c96f30d915c [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include "base/check_op.h"
#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/printing/print_backend_service_manager.h"
#include "chrome/browser/printing/print_backend_service_test_impl.h"
#include "chrome/browser/printing/print_test_utils.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/services/printing/public/mojom/print_backend_service.mojom.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/test/browser_test.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "printing/backend/print_backend.h"
#include "printing/backend/test_print_backend.h"
#include "printing/buildflags/buildflags.h"
#include "printing/metafile.h"
#include "printing/mojom/print.mojom.h"
#include "printing/print_job_constants.h"
#include "printing/print_settings.h"
#include "printing/print_settings_conversion.h"
#include "printing/printing_context.h"
#include "printing/printing_context_factory_for_test.h"
#include "printing/printing_features.h"
#include "printing/test_printing_context.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#if BUILDFLAG(IS_WIN)
#include "printing/emf_win.h"
#else
#include "printing/metafile_skia.h"
#endif
namespace printing {
using ::testing::UnorderedElementsAreArray;
namespace {
constexpr char kDefaultPrinterName[] = "default-test-printer";
constexpr char16_t kDefaultPrinterName16[] = u"default-test-printer";
constexpr char kAnotherPrinterName[] = "another-test-printer";
constexpr char kInvalidPrinterName[] = "invalid-test-printer";
constexpr char16_t kInvalidPrinterName16[] = u"invalid-test-printer";
constexpr char kAccessDeniedPrinterName[] = "access-denied-test-printer";
const PrinterBasicInfoOptions kDefaultPrintInfoOptions{{"opt1", "123"},
{"opt2", "456"}};
const PrinterBasicInfo kDefaultPrinterInfo(
/*printer_name=*/kDefaultPrinterName,
/*display_name=*/"default test printer",
/*printer_description=*/"Default printer for testing.",
/*printer_status=*/0,
/*is_default=*/true,
kDefaultPrintInfoOptions);
const PrinterBasicInfo kAnotherPrinterInfo(
/*printer_name=*/kAnotherPrinterName,
/*display_name=*/"another test printer",
/*printer_description=*/"Another printer for testing.",
/*printer_status=*/5,
/*is_default=*/false,
/*options=*/{});
constexpr int32_t kCopiesMax = 123;
constexpr int kPrintSettingsCopies = 42;
constexpr int kPrintSettingsDefaultDpi = 300;
constexpr int kPrintSettingsOverrideDpi = 150;
const int32_t kTestDocumentCookie = PrintSettings::NewCookie();
bool LoadMetafileDataFromFile(const std::string& file_name,
Metafile& metafile) {
base::FilePath data_file;
if (!base::PathService::Get(chrome::DIR_TEST_DATA, &data_file))
return false;
data_file =
data_file.Append(FILE_PATH_LITERAL("printing")).AppendASCII(file_name);
std::string data;
{
base::ScopedAllowBlockingForTesting allow_block;
if (!base::ReadFileToString(data_file, &data))
return false;
}
return metafile.InitFromData(base::as_bytes(base::make_span(data)));
}
} // namespace
class PrintBackendBrowserTest : public InProcessBrowserTest {
public:
PrintBackendBrowserTest() = default;
~PrintBackendBrowserTest() override = default;
void SetUp() override {
// Tests of the Print Backend service always imply out-of-process.
feature_list_.InitAndEnableFeatureWithParameters(
features::kEnableOopPrintDrivers,
{{features::kEnableOopPrintDriversJobPrint.name, "true"}});
// Do local setup before calling base class, since the base class enters
// the main run loop.
PrintBackend::SetPrintBackendForTesting(test_print_backend_.get());
PrintingContext::SetPrintingContextFactoryForTest(
&test_printing_context_factory_);
InProcessBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
LaunchService();
InProcessBrowserTest::SetUpOnMainThread();
}
void TearDown() override {
// Call base class teardown before local teardown, to be in opposite order
// of `SetUp`.
InProcessBrowserTest::TearDown();
PrintingContext::SetPrintingContextFactoryForTest(/*factory=*/nullptr);
PrintBackend::SetPrintBackendForTesting(/*print_backend=*/nullptr);
}
void TearDownOnMainThread() override {
InProcessBrowserTest::TearDownOnMainThread();
PrintBackendServiceManager::ResetForTesting();
}
// Load the test backend with a default printer driver.
void AddDefaultPrinter() {
// Only explicitly specify capabilities that we pay attention to in the
// tests.
auto default_caps = std::make_unique<PrinterSemanticCapsAndDefaults>();
default_caps->copies_max = kCopiesMax;
default_caps->default_paper = test::kPaperLetter;
default_caps->papers.push_back(test::kPaperLetter);
default_caps->papers.push_back(test::kPaperLegal);
test_print_backend_->AddValidPrinter(
kDefaultPrinterName, std::move(default_caps),
std::make_unique<PrinterBasicInfo>(kDefaultPrinterInfo));
}
// Load the test backend with another (non-default) printer.
void AddAnotherPrinter() {
test_print_backend_->AddValidPrinter(
kAnotherPrinterName, std::make_unique<PrinterSemanticCapsAndDefaults>(),
std::make_unique<PrinterBasicInfo>(kAnotherPrinterInfo));
}
void AddAccessDeniedPrinter() {
test_print_backend_->AddAccessDeniedPrinter(kAccessDeniedPrinterName);
}
void SetPrinterNameForSubsequentContexts(const std::string& printer_name) {
test_printing_context_factory_.SetPrinterNameForSubsequentContexts(
printer_name);
}
// `PrintBackendServiceTestImpl` does a debug check on shutdown that there
// are no residual persistent printing contexts left in the service. For
// tests which are known to break this (either by design, for test simplicity
// or because a related change is only partly implemented), use this method
// to notify the service to not DCHECK on such a condition.
void SkipPersistentContextsCheckOnShutdown() {
print_backend_service_->SkipPersistentContextsCheckOnShutdown();
}
// Common helpers to perform particular stages of printing a document.
uint32_t EstablishPrintingContextAndWait() {
constexpr uint32_t kContextId = 7;
#if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
constexpr uint32_t kParentWindowId = 8;
#endif
GetPrintBackendService()->EstablishPrintingContext(kContextId
#if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
,
kParentWindowId
#endif
);
return kContextId;
}
mojom::PrintSettingsResultPtr UpdatePrintSettingsAndWait(
uint32_t context_id,
const PrintSettings& print_settings) {
base::Value::Dict job_settings =
PrintSettingsToJobSettingsDebug(print_settings);
job_settings.Set(kSettingPrinterType,
static_cast<int>(mojom::PrinterType::kLocal));
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
mojom::PrintSettingsResultPtr settings;
GetPrintBackendService()->UpdatePrintSettings(
context_id, std::move(job_settings),
base::BindOnce(&PrintBackendBrowserTest::CapturePrintSettings,
base::Unretained(this), std::ref(settings)));
WaitUntilCallbackReceived();
return settings;
}
mojom::ResultCode StartPrintingAndWait(uint32_t context_id,
const PrintSettings& print_settings) {
UpdatePrintSettingsAndWait(context_id, print_settings);
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
mojom::ResultCode result;
GetPrintBackendService()->StartPrinting(
context_id, kTestDocumentCookie, u"document name",
#if !BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
/*settings=*/absl::nullopt,
#endif
base::BindOnce(&PrintBackendBrowserTest::CaptureResult,
base::Unretained(this), std::ref(result)));
WaitUntilCallbackReceived();
return result;
}
#if BUILDFLAG(IS_WIN)
absl::optional<mojom::ResultCode> RenderPageAndWait() {
// Load a sample EMF file for a single page for testing handling.
Emf metafile;
if (!LoadMetafileDataFromFile("test1.emf", metafile))
return absl::nullopt;
base::MappedReadOnlyRegion region_mapping =
metafile.GetDataAsSharedMemoryRegion();
if (!region_mapping.IsValid())
return absl::nullopt;
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
mojom::ResultCode result;
GetPrintBackendService()->RenderPrintedPage(
kTestDocumentCookie,
/*page_index=*/0, metafile.GetDataType(),
std::move(region_mapping.region),
/*page_size=*/gfx::Size(200, 200),
/*page_content_rect=*/gfx::Rect(0, 0, 200, 200),
/*shrink_factor=*/1.0f,
base::BindOnce(&PrintBackendBrowserTest::CaptureResult,
base::Unretained(this), std::ref(result)));
WaitUntilCallbackReceived();
return result;
}
#endif // BUILDFLAG(IS_WIN)
// TODO(crbug.com/1008222) Include Windows once XPS print pipeline is enabled.
#if !BUILDFLAG(IS_WIN)
absl::optional<mojom::ResultCode> RenderDocumentAndWait() {
// Load a sample PDF file for a single page for testing handling.
MetafileSkia metafile;
if (!LoadMetafileDataFromFile("embedded_images.pdf", metafile))
return absl::nullopt;
base::MappedReadOnlyRegion region_mapping =
metafile.GetDataAsSharedMemoryRegion();
if (!region_mapping.IsValid())
return absl::nullopt;
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
mojom::ResultCode result;
GetPrintBackendService()->RenderPrintedDocument(
kTestDocumentCookie, /*page_count=*/1u, metafile.GetDataType(),
std::move(region_mapping.region),
base::BindOnce(&PrintBackendBrowserTest::CaptureResult,
base::Unretained(this), std::ref(result)));
WaitUntilCallbackReceived();
return result;
}
#endif // !BUILDFLAG(IS_WIN)
mojom::ResultCode DocumentDoneAndWait() {
mojom::ResultCode result;
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
GetPrintBackendService()->DocumentDone(
kTestDocumentCookie,
base::BindOnce(&PrintBackendBrowserTest::CaptureResult,
base::Unretained(this), std::ref(result)));
WaitUntilCallbackReceived();
return result;
}
void CancelAndWait() {
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
GetPrintBackendService()->Cancel(
kTestDocumentCookie,
base::BindOnce(&PrintBackendBrowserTest::CheckForQuit,
base::Unretained(this)));
WaitUntilCallbackReceived();
}
// Public callbacks used by tests.
void OnDidEnumeratePrinters(mojom::PrinterListResultPtr& capture_printer_list,
mojom::PrinterListResultPtr printer_list) {
capture_printer_list = std::move(printer_list);
CheckForQuit();
}
void OnDidGetDefaultPrinterName(
mojom::DefaultPrinterNameResultPtr& capture_printer_name,
mojom::DefaultPrinterNameResultPtr printer_name) {
capture_printer_name = std::move(printer_name);
CheckForQuit();
}
void OnDidGetPrinterSemanticCapsAndDefaults(
mojom::PrinterSemanticCapsAndDefaultsResultPtr& capture_printer_caps,
mojom::PrinterSemanticCapsAndDefaultsResultPtr printer_caps) {
capture_printer_caps = std::move(printer_caps);
CheckForQuit();
}
void OnDidFetchCapabilities(
mojom::PrinterCapsAndInfoResultPtr& capture_caps_and_info,
mojom::PrinterCapsAndInfoResultPtr caps_and_info) {
capture_caps_and_info = std::move(caps_and_info);
CheckForQuit();
}
#if BUILDFLAG(IS_WIN)
void OnDidGetPaperPrintableArea(gfx::Rect& capture_printable_area_um,
const gfx::Rect& printable_area_um) {
capture_printable_area_um = printable_area_um;
CheckForQuit();
}
#endif
void CapturePrintSettings(
mojom::PrintSettingsResultPtr& capture_print_settings,
mojom::PrintSettingsResultPtr print_settings) {
capture_print_settings = std::move(print_settings);
CheckForQuit();
}
void CaptureResult(mojom::ResultCode& capture_result,
mojom::ResultCode result) {
capture_result = result;
CheckForQuit();
}
// The following are helper functions for having a wait loop in the test and
// exit when expected messages are received. Expect to only have to wait for
// one message.
void WaitUntilCallbackReceived() {
// If callback happened before getting here, then no need to wait.
if (!received_message_) {
base::RunLoop run_loop;
quit_callback_ = run_loop.QuitClosure();
run_loop.Run();
}
// Reset for possible subsequent test.
received_message_ = false;
}
void CheckForQuit() {
received_message_ = true;
if (quit_callback_)
std::move(quit_callback_).Run();
}
// Get the print backend service being tested.
mojom::PrintBackendService* GetPrintBackendService() const {
return print_backend_service_.get();
}
private:
class PrintBackendPrintingContextFactoryForTest
: public PrintingContextFactoryForTest {
public:
std::unique_ptr<PrintingContext> CreatePrintingContext(
PrintingContext::Delegate* delegate,
PrintingContext::ProcessBehavior process_behavior) override {
auto context =
std::make_unique<TestPrintingContext>(delegate, process_behavior);
auto settings = std::make_unique<PrintSettings>();
settings->set_copies(kPrintSettingsCopies);
settings->set_dpi(kPrintSettingsDefaultDpi);
settings->set_device_name(base::ASCIIToUTF16(printer_name_));
context->SetDeviceSettings(printer_name_, std::move(settings));
return std::move(context);
}
void SetPrinterNameForSubsequentContexts(const std::string& printer_name) {
printer_name_ = printer_name;
}
private:
std::string printer_name_;
};
// Initialize and load the backend service with some test print drivers.
void LaunchService() {
print_backend_service_ = PrintBackendServiceTestImpl::LaunchForTesting(
remote_, test_print_backend_, /*sandboxed=*/true);
}
base::test::ScopedFeatureList feature_list_;
bool received_message_ = false;
base::OnceClosure quit_callback_;
mojo::Remote<mojom::PrintBackendService> remote_;
scoped_refptr<TestPrintBackend> test_print_backend_ =
base::MakeRefCounted<TestPrintBackend>();
TestPrintingContextDelegate test_printing_context_delegate_;
PrintBackendPrintingContextFactoryForTest test_printing_context_factory_;
std::unique_ptr<PrintBackendServiceTestImpl> print_backend_service_;
};
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, EnumeratePrinters) {
AddDefaultPrinter();
AddAnotherPrinter();
const PrinterList kPrinterListExpected = {kDefaultPrinterInfo,
kAnotherPrinterInfo};
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
mojom::PrinterListResultPtr printer_list;
GetPrintBackendService()->EnumeratePrinters(
base::BindOnce(&PrintBackendBrowserTest::OnDidEnumeratePrinters,
base::Unretained(this), std::ref(printer_list)));
WaitUntilCallbackReceived();
ASSERT_TRUE(printer_list->is_printer_list());
EXPECT_THAT(printer_list->get_printer_list(),
UnorderedElementsAreArray(kPrinterListExpected));
}
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, GetDefaultPrinterName) {
AddDefaultPrinter();
mojom::DefaultPrinterNameResultPtr default_printer_name;
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
GetPrintBackendService()->GetDefaultPrinterName(
base::BindOnce(&PrintBackendBrowserTest::OnDidGetDefaultPrinterName,
base::Unretained(this), std::ref(default_printer_name)));
WaitUntilCallbackReceived();
ASSERT_TRUE(default_printer_name->is_default_printer_name());
EXPECT_EQ(default_printer_name->get_default_printer_name(),
kDefaultPrinterName);
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest,
GetPrinterSemanticCapsAndDefaults) {
AddDefaultPrinter();
mojom::PrinterSemanticCapsAndDefaultsResultPtr printer_caps;
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
GetPrintBackendService()->GetPrinterSemanticCapsAndDefaults(
kDefaultPrinterName,
base::BindOnce(
&PrintBackendBrowserTest::OnDidGetPrinterSemanticCapsAndDefaults,
base::Unretained(this), std::ref(printer_caps)));
WaitUntilCallbackReceived();
ASSERT_TRUE(printer_caps->is_printer_caps());
EXPECT_EQ(printer_caps->get_printer_caps().copies_max, kCopiesMax);
// Requesting for an invalid printer should not return capabilities.
GetPrintBackendService()->GetPrinterSemanticCapsAndDefaults(
kInvalidPrinterName,
base::BindOnce(
&PrintBackendBrowserTest::OnDidGetPrinterSemanticCapsAndDefaults,
base::Unretained(this), std::ref(printer_caps)));
WaitUntilCallbackReceived();
ASSERT_TRUE(printer_caps->is_result_code());
EXPECT_EQ(printer_caps->get_result_code(), mojom::ResultCode::kFailed);
}
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest,
GetPrinterSemanticCapsAndDefaultsAccessDenied) {
AddAccessDeniedPrinter();
mojom::PrinterSemanticCapsAndDefaultsResultPtr printer_caps;
// Requesting for a printer which requires elevated privileges should not
// return capabilities, and should indicate that access was denied.
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
GetPrintBackendService()->GetPrinterSemanticCapsAndDefaults(
kAccessDeniedPrinterName,
base::BindOnce(
&PrintBackendBrowserTest::OnDidGetPrinterSemanticCapsAndDefaults,
base::Unretained(this), std::ref(printer_caps)));
WaitUntilCallbackReceived();
ASSERT_TRUE(printer_caps->is_result_code());
EXPECT_EQ(printer_caps->get_result_code(), mojom::ResultCode::kAccessDenied);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, FetchCapabilities) {
AddDefaultPrinter();
mojom::PrinterCapsAndInfoResultPtr caps_and_info;
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
GetPrintBackendService()->FetchCapabilities(
kDefaultPrinterName,
base::BindOnce(&PrintBackendBrowserTest::OnDidFetchCapabilities,
base::Unretained(this), std::ref(caps_and_info)));
WaitUntilCallbackReceived();
ASSERT_TRUE(caps_and_info->is_printer_caps_and_info());
EXPECT_EQ(caps_and_info->get_printer_caps_and_info()->printer_caps.copies_max,
kCopiesMax);
// Requesting for an invalid printer should not return capabilities.
GetPrintBackendService()->FetchCapabilities(
kInvalidPrinterName,
base::BindOnce(&PrintBackendBrowserTest::OnDidFetchCapabilities,
base::Unretained(this), std::ref(caps_and_info)));
WaitUntilCallbackReceived();
ASSERT_TRUE(caps_and_info->is_result_code());
EXPECT_EQ(caps_and_info->get_result_code(), mojom::ResultCode::kFailed);
}
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, FetchCapabilitiesAccessDenied) {
AddAccessDeniedPrinter();
mojom::PrinterCapsAndInfoResultPtr caps_and_info;
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
GetPrintBackendService()->FetchCapabilities(
kAccessDeniedPrinterName,
base::BindOnce(&PrintBackendBrowserTest::OnDidFetchCapabilities,
base::Unretained(this), std::ref(caps_and_info)));
WaitUntilCallbackReceived();
ASSERT_TRUE(caps_and_info->is_result_code());
EXPECT_EQ(caps_and_info->get_result_code(), mojom::ResultCode::kAccessDenied);
}
#if BUILDFLAG(IS_WIN)
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, GetPaperPrintableArea) {
AddDefaultPrinter();
mojom::PrinterCapsAndInfoResultPtr caps_and_info;
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
GetPrintBackendService()->FetchCapabilities(
kDefaultPrinterName,
base::BindOnce(&PrintBackendBrowserTest::OnDidFetchCapabilities,
base::Unretained(this), std::ref(caps_and_info)));
WaitUntilCallbackReceived();
// Fetching capabiliities only provides the paper printable area for the
// default paper size. Find a paper which is not the default, which should
// have been given an incorrect printable area that matches the paper size.
ASSERT_TRUE(caps_and_info->is_printer_caps_and_info());
absl::optional<PrinterSemanticCapsAndDefaults::Paper> non_default_paper;
const PrinterSemanticCapsAndDefaults::Paper& default_paper =
caps_and_info->get_printer_caps_and_info()->printer_caps.default_paper;
const PrinterSemanticCapsAndDefaults::Papers& papers =
caps_and_info->get_printer_caps_and_info()->printer_caps.papers;
for (const auto& paper : papers) {
if (paper != default_paper) {
non_default_paper = paper;
break;
}
}
ASSERT_TRUE(non_default_paper.has_value());
EXPECT_EQ(non_default_paper->printable_area_um(),
gfx::Rect(non_default_paper->size_um()));
// Request the printable area for this paper size, which should no longer
// match the physical size but have real printable area values.
gfx::Rect printable_area_um;
PrintSettings::RequestedMedia media(
/*.size_microns =*/non_default_paper->size_um(),
/*.vendor_id = */ non_default_paper->vendor_id());
GetPrintBackendService()->GetPaperPrintableArea(
kDefaultPrinterName, media,
base::BindOnce(&PrintBackendBrowserTest::OnDidGetPaperPrintableArea,
base::Unretained(this), std::ref(printable_area_um)));
WaitUntilCallbackReceived();
ASSERT_TRUE(!printable_area_um.IsEmpty());
EXPECT_NE(printable_area_um, non_default_paper->printable_area_um());
}
#endif // BUILDFLAG(IS_WIN)
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, UseDefaultSettings) {
AddDefaultPrinter();
SetPrinterNameForSubsequentContexts(kDefaultPrinterName);
// Isolated call has no corresponding cleanup of the printing context.
SkipPersistentContextsCheckOnShutdown();
const uint32_t context_id = EstablishPrintingContextAndWait();
mojom::PrintSettingsResultPtr settings;
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
GetPrintBackendService()->UseDefaultSettings(
context_id, base::BindOnce(&PrintBackendBrowserTest::CapturePrintSettings,
base::Unretained(this), std::ref(settings)));
WaitUntilCallbackReceived();
ASSERT_TRUE(settings->is_settings());
EXPECT_EQ(settings->get_settings().copies(), kPrintSettingsCopies);
EXPECT_EQ(settings->get_settings().dpi(), kPrintSettingsDefaultDpi);
}
#if BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, AskUserForSettings) {
AddDefaultPrinter();
SetPrinterNameForSubsequentContexts(kDefaultPrinterName);
// Isolated call has no corresponding cleanup of the printing context.
SkipPersistentContextsCheckOnShutdown();
const uint32_t context_id = EstablishPrintingContextAndWait();
mojom::PrintSettingsResultPtr settings;
// Safe to use base::Unretained(this) since waiting locally on the callback
// forces a shorter lifetime than `this`.
GetPrintBackendService()->AskUserForSettings(
context_id,
/*max_pages=*/1, /*has_selection=*/false, /*is_scripted=*/false,
base::BindOnce(&PrintBackendBrowserTest::CapturePrintSettings,
base::Unretained(this), std::ref(settings)));
WaitUntilCallbackReceived();
ASSERT_TRUE(settings->is_settings());
EXPECT_EQ(settings->get_settings().copies(), kPrintSettingsCopies);
EXPECT_EQ(settings->get_settings().dpi(), kPrintSettingsDefaultDpi);
}
#endif // BUILDFLAG(ENABLE_OOP_BASIC_PRINT_DIALOG)
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, UpdatePrintSettings) {
AddDefaultPrinter();
SetPrinterNameForSubsequentContexts(kDefaultPrinterName);
// Isolated call has no corresponding cleanup of the printing context.
SkipPersistentContextsCheckOnShutdown();
const uint32_t context_id = EstablishPrintingContextAndWait();
PrintSettings print_settings;
print_settings.set_device_name(kDefaultPrinterName16);
print_settings.set_dpi(kPrintSettingsOverrideDpi);
mojom::PrintSettingsResultPtr settings =
UpdatePrintSettingsAndWait(context_id, print_settings);
ASSERT_TRUE(settings->is_settings());
EXPECT_EQ(settings->get_settings().copies(), kPrintSettingsCopies);
EXPECT_EQ(settings->get_settings().dpi(), kPrintSettingsOverrideDpi);
#if BUILDFLAG(IS_LINUX) && BUILDFLAG(USE_CUPS)
const PrintSettings::AdvancedSettings& advanced_settings =
settings->get_settings().advanced_settings();
EXPECT_EQ(advanced_settings.size(), kDefaultPrintInfoOptions.size());
for (const auto& advanced_setting : advanced_settings) {
auto option = kDefaultPrintInfoOptions.find(advanced_setting.first);
ASSERT_NE(option, kDefaultPrintInfoOptions.end());
EXPECT_EQ(option->second, advanced_setting.second.GetString());
}
#endif // BUILDFLAG(IS_LINUX) && BUILDFLAG(USE_CUPS)
// Updating for an invalid printer should not return print settings.
print_settings.set_device_name(kInvalidPrinterName16);
settings = UpdatePrintSettingsAndWait(context_id, print_settings);
ASSERT_TRUE(settings->is_result_code());
EXPECT_EQ(settings->get_result_code(), mojom::ResultCode::kFailed);
}
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, StartPrinting) {
AddDefaultPrinter();
SetPrinterNameForSubsequentContexts(kDefaultPrinterName);
const uint32_t context_id = EstablishPrintingContextAndWait();
PrintSettings print_settings;
print_settings.set_device_name(kDefaultPrinterName16);
ASSERT_TRUE(UpdatePrintSettingsAndWait(context_id, print_settings));
EXPECT_EQ(StartPrintingAndWait(context_id, print_settings),
mojom::ResultCode::kSuccess);
}
#if BUILDFLAG(IS_WIN)
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, RenderPrintedPage) {
AddDefaultPrinter();
SetPrinterNameForSubsequentContexts(kDefaultPrinterName);
const uint32_t context_id = EstablishPrintingContextAndWait();
PrintSettings print_settings;
print_settings.set_device_name(kDefaultPrinterName16);
ASSERT_TRUE(UpdatePrintSettingsAndWait(context_id, print_settings));
ASSERT_EQ(StartPrintingAndWait(context_id, print_settings),
mojom::ResultCode::kSuccess);
absl::optional<mojom::ResultCode> result = RenderPageAndWait();
EXPECT_EQ(result, mojom::ResultCode::kSuccess);
}
#endif // BUILDFLAG(IS_WIN)
// TODO(crbug.com/1008222) Include Windows for this test once XPS print
// pipeline is enabled.
#if !BUILDFLAG(IS_WIN)
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, RenderPrintedDocument) {
AddDefaultPrinter();
SetPrinterNameForSubsequentContexts(kDefaultPrinterName);
const uint32_t context_id = EstablishPrintingContextAndWait();
PrintSettings print_settings;
print_settings.set_device_name(kDefaultPrinterName16);
ASSERT_TRUE(UpdatePrintSettingsAndWait(context_id, print_settings));
ASSERT_EQ(StartPrintingAndWait(context_id, print_settings),
mojom::ResultCode::kSuccess);
absl::optional<mojom::ResultCode> result = RenderDocumentAndWait();
EXPECT_EQ(result, mojom::ResultCode::kSuccess);
}
#endif // !BUILDFLAG(IS_WIN)
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, DocumentDone) {
AddDefaultPrinter();
SetPrinterNameForSubsequentContexts(kDefaultPrinterName);
const uint32_t context_id = EstablishPrintingContextAndWait();
PrintSettings print_settings;
print_settings.set_device_name(kDefaultPrinterName16);
ASSERT_TRUE(UpdatePrintSettingsAndWait(context_id, print_settings));
ASSERT_EQ(StartPrintingAndWait(context_id, print_settings),
mojom::ResultCode::kSuccess);
// TODO(crbug.com/1008222) Include Windows coverage for RenderDocument()
// path once XPS print pipeline is enabled.
#if BUILDFLAG(IS_WIN)
absl::optional<mojom::ResultCode> result = RenderPageAndWait();
#else
absl::optional<mojom::ResultCode> result = RenderDocumentAndWait();
#endif
EXPECT_EQ(result, mojom::ResultCode::kSuccess);
EXPECT_EQ(DocumentDoneAndWait(), mojom::ResultCode::kSuccess);
}
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, Cancel) {
AddDefaultPrinter();
SetPrinterNameForSubsequentContexts(kDefaultPrinterName);
const uint32_t context_id = EstablishPrintingContextAndWait();
PrintSettings print_settings;
print_settings.set_device_name(kDefaultPrinterName16);
ASSERT_TRUE(UpdatePrintSettingsAndWait(context_id, print_settings));
EXPECT_EQ(StartPrintingAndWait(context_id, print_settings),
mojom::ResultCode::kSuccess);
CancelAndWait();
}
} // namespace printing