#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/containers/flat_set.h"
#include "base/containers/span.h"
#include "base/i18n/number_formatting.h"
#include "base/json/json_writer.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted_memory.h"
#include "base/notreached.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/icu_test_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/values_test_util.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/printing/print_preview_dialog_controller.h"
#include "chrome/browser/printing/print_test_utils.h"
#include "chrome/browser/printing/print_view_manager.h"
#include "chrome/browser/ui/webui/print_preview/fake_print_render_frame.h"
#include "chrome/browser/ui/webui/print_preview/policy_settings.h"
#include "chrome/browser/ui/webui/print_preview/print_preview_metrics.h"
#include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
#include "chrome/browser/ui/webui/print_preview/print_preview_utils.h"
#include "chrome/browser/ui/webui/print_preview/printer_handler.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "components/enterprise/buildflags/buildflags.h"
#include "components/prefs/pref_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/test_web_ui.h"
#include "printing/buildflags/buildflags.h"
#include "printing/mojom/print.mojom.h"
#include "printing/printing_features.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
#include "chrome/browser/enterprise/connectors/common.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/policy/dm_token_utils.h"
#if BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS)
#include "chrome/browser/enterprise/connectors/test/fake_content_analysis_sdk_manager.h"
#endif
#endif
#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
#include "chrome/test/base/testing_profile_manager.h"
#endif
#if BUILDFLAG(IS_CHROMEOS)
#include "chromeos/crosapi/mojom/local_printer.mojom.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/crosapi/crosapi_manager.h"
#include "chrome/browser/ash/crosapi/idle_service_ash.h"
#include "chrome/browser/ash/crosapi/test_crosapi_dependency_registry.h"
#include "chrome/browser/ash/crosapi/test_local_printer_ash.h"
#include "chromeos/ash/components/login/login_state/login_state.h"
#elif BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/test/chromeos/printing/fake_local_printer_chromeos.h"
#endif
namespace printing {
namespace {
const char kDummyInitiatorName[] = …;
const char16_t kDummyInitiatorName16[] = …;
const char kEmptyPrinterName[] = …;
const char kTestData[] = …;
#if BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS)
constexpr char kFakeDmToken[] = …;
constexpr char kCallbackId[] = …;
#endif
constexpr mojom::PrinterType kAllTypes[] = …;
constexpr mojom::PrinterType kAllSupportedTypes[] = …;
constexpr mojom::PrinterType kFetchableTypes[] = …;
struct PrinterInfo { … };
PrinterInfo GetSimplePrinterInfo(const std::string& name, bool is_default) { … }
PrinterInfo GetEmptyPrinterInfo() { … }
base::Value::Dict GetPrintPreviewTicket() { … }
base::Value::List ConstructPreviewArgs(std::string_view callback_id,
const base::Value::Dict& print_ticket) { … }
UserActionBuckets GetUserActionForPrinterType(mojom::PrinterType type) { … }
void CheckHistograms(const base::HistogramTester& histograms,
mojom::PrinterType type) { … }
class TestPrinterHandler : public PrinterHandler { … };
class FakePrintPreviewUI : public PrintPreviewUI { … };
class TestPrintPreviewPrintRenderFrame final : public FakePrintRenderFrame { … };
#if BUILDFLAG(IS_CHROMEOS_LACROS)
class TestLocalPrinter : public FakeLocalPrinter {
public:
TestLocalPrinter() : policies_(crosapi::mojom::Policies()) {}
TestLocalPrinter(const TestLocalPrinter&) = delete;
TestLocalPrinter& operator=(const TestLocalPrinter&) = delete;
~TestLocalPrinter() override = default;
void set_policies(const crosapi::mojom::Policies& policies) {
policies_ = policies;
}
void add_to_deny_list(const mojom::PrinterType& printer_type) {
deny_list_.push_back(printer_type);
}
void GetPolicies(GetPoliciesCallback callback) override {
ASSERT_TRUE(policies_);
std::move(callback).Run(policies_->Clone());
policies_.reset();
}
void GetPrinterTypeDenyList(
GetPrinterTypeDenyListCallback callback) override {
std::move(callback).Run(deny_list_);
}
private:
std::optional<crosapi::mojom::Policies> policies_;
std::vector<mojom::PrinterType> deny_list_;
};
#endif
class TestPrintPreviewHandler : public PrintPreviewHandler { … };
#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
class TestPrintPreviewHandlerForContentAnalysis
: public TestPrintPreviewHandler { … };
#endif
}
class PrintPreviewHandlerTest : public testing::Test { … };
TEST_F(PrintPreviewHandlerTest, InitialSettingsSimple) { … }
TEST_F(PrintPreviewHandlerTest, InitialSettingsHiLocale) { … }
TEST_F(PrintPreviewHandlerTest, InitialSettingsRuLocale) { … }
TEST_F(PrintPreviewHandlerTest, InitialSettingsNoPolicies) { … }
#if BUILDFLAG(IS_CHROMEOS)
TEST_F(PrintPreviewHandlerTest, InitialSettingsNoAsh) {
DisableAshChrome();
Initialize();
ValidateInitialSettings(*web_ui()->call_data().back(), test::kPrinterName,
kDummyInitiatorName);
ValidateInitialSettingsAllowedDefaultModePolicy(*web_ui()->call_data().back(),
"headerFooter", std::nullopt,
std::nullopt);
ValidateInitialSettingsAllowedDefaultModePolicy(*web_ui()->call_data().back(),
"cssBackground", std::nullopt,
std::nullopt);
ValidateInitialSettingsAllowedDefaultModePolicy(
*web_ui()->call_data().back(), "mediaSize", std::nullopt, std::nullopt);
ValidateInitialSettingsValuePolicy(*web_ui()->call_data().back(), "sheets",
std::nullopt);
}
#endif
TEST_F(PrintPreviewHandlerTest, InitialSettingsRestrictHeaderFooterEnabled) { … }
TEST_F(PrintPreviewHandlerTest, InitialSettingsRestrictHeaderFooterDisabled) { … }
TEST_F(PrintPreviewHandlerTest, InitialSettingsEnableHeaderFooter) { … }
TEST_F(PrintPreviewHandlerTest, InitialSettingsDisableHeaderFooter) { … }
TEST_F(PrintPreviewHandlerTest,
InitialSettingsRestrictBackgroundGraphicsEnabled) { … }
TEST_F(PrintPreviewHandlerTest,
InitialSettingsRestrictBackgroundGraphicsDisabled) { … }
TEST_F(PrintPreviewHandlerTest, InitialSettingsEnableBackgroundGraphics) { … }
TEST_F(PrintPreviewHandlerTest, InitialSettingsDisableBackgroundGraphics) { … }
TEST_F(PrintPreviewHandlerTest, InitialSettingsDefaultPaperSizeName) { … }
TEST_F(PrintPreviewHandlerTest, InitialSettingsDefaultPaperSizeCustomSize) { … }
#if BUILDFLAG(IS_CHROMEOS)
TEST_F(PrintPreviewHandlerTest, InitialSettingsMaxSheetsAllowedPolicy) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::Policies policies;
policies.max_sheets_allowed = 2;
policies.max_sheets_allowed_has_value = true;
SetPolicies(policies);
#else
prefs()->SetInteger(prefs::kPrintingMaxSheetsAllowed, 2);
#endif
Initialize();
ValidateInitialSettingsValuePolicy(*web_ui()->call_data().back(), "sheets",
base::Value(2));
}
TEST_F(PrintPreviewHandlerTest, InitialSettingsEnableColorAndMonochrome) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::Policies policies;
policies.allowed_color_modes = 3;
SetPolicies(policies);
#else
prefs()->SetInteger(prefs::kPrintingAllowedColorModes, 3);
#endif
Initialize();
ValidateInitialSettingsAllowedDefaultModePolicy(
*web_ui()->call_data().back(), "color", base::Value(3), std::nullopt);
}
TEST_F(PrintPreviewHandlerTest, InitialSettingsDefaultColor) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::Policies policies;
policies.default_color_mode = printing::mojom::ColorModeRestriction::kColor;
SetPolicies(policies);
#else
prefs()->SetInteger(prefs::kPrintingColorDefault, 2);
#endif
Initialize();
ValidateInitialSettingsAllowedDefaultModePolicy(
*web_ui()->call_data().back(), "color", std::nullopt, base::Value(2));
}
TEST_F(PrintPreviewHandlerTest, InitialSettingsEnableSimplexAndDuplex) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::Policies policies;
policies.allowed_duplex_modes = 7;
SetPolicies(policies);
#else
prefs()->SetInteger(prefs::kPrintingAllowedDuplexModes, 7);
#endif
Initialize();
ValidateInitialSettingsAllowedDefaultModePolicy(
*web_ui()->call_data().back(), "duplex", base::Value(7), std::nullopt);
}
TEST_F(PrintPreviewHandlerTest, InitialSettingsDefaultSimplex) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::Policies policies;
policies.default_duplex_mode =
printing::mojom::DuplexModeRestriction::kSimplex;
SetPolicies(policies);
#else
prefs()->SetInteger(prefs::kPrintingDuplexDefault, 1);
#endif
Initialize();
ValidateInitialSettingsAllowedDefaultModePolicy(
*web_ui()->call_data().back(), "duplex", std::nullopt, base::Value(1));
}
TEST_F(PrintPreviewHandlerTest, InitialSettingsRestrictPin) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::Policies policies;
policies.allowed_pin_modes = printing::mojom::PinModeRestriction::kPin;
SetPolicies(policies);
#else
prefs()->SetInteger(prefs::kPrintingAllowedPinModes, 1);
#endif
Initialize();
ValidateInitialSettingsAllowedDefaultModePolicy(
*web_ui()->call_data().back(), "pin", base::Value(1), std::nullopt);
}
TEST_F(PrintPreviewHandlerTest, InitialSettingsDefaultNoPin) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::Policies policies;
policies.default_pin_mode = printing::mojom::PinModeRestriction::kNoPin;
SetPolicies(policies);
#else
prefs()->SetInteger(prefs::kPrintingPinDefault, 2);
#endif
Initialize();
ValidateInitialSettingsAllowedDefaultModePolicy(
*web_ui()->call_data().back(), "pin", std::nullopt, base::Value(2));
}
#endif
TEST_F(PrintPreviewHandlerTest, GetPrinters) { … }
TEST_F(PrintPreviewHandlerTest, GetNoDenyListPrinters) { … }
TEST_F(PrintPreviewHandlerTest, GetPrinterCapabilities) { … }
TEST_F(PrintPreviewHandlerTest, GetNoDenyListPrinterCapabilities) { … }
TEST_F(PrintPreviewHandlerTest, GetPrinterCapabilitiesContinuousMedia) { … }
TEST_F(PrintPreviewHandlerTest, Print) { … }
TEST_F(PrintPreviewHandlerTest, GetPreview) { … }
TEST_F(PrintPreviewHandlerTest, SendPreviewUpdates) { … }
#if BUILDFLAG(IS_CHROMEOS_LACROS)
TEST_F(PrintPreviewHandlerTest, SaveToDriveLacrosPrimaryProfile) {
crosapi::mojom::Policies policies;
SetPolicies(policies);
TestingProfile* main_profile =
testing_profile_manager()->CreateTestingProfile("Main Profile",
true);
SetProfileForInitialSettings(main_profile);
Initialize();
const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
const base::Value::Dict& settings = data.arg3()->GetDict();
EXPECT_TRUE(settings.FindBool("isDriveMounted").has_value());
}
TEST_F(PrintPreviewHandlerTest, SaveToDriveLacrosNonPrimaryProfile) {
crosapi::mojom::Policies policies;
SetPolicies(policies);
TestingProfile* secondary_profile =
testing_profile_manager()->CreateTestingProfile(
"Secondary Profile",
false);
SetProfileForInitialSettings(secondary_profile);
Initialize();
const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
const base::Value::Dict& settings = data.arg3()->GetDict();
EXPECT_FALSE(settings.FindBool("isDriveMounted").has_value());
}
#endif
class FailingTestPrinterHandler : public TestPrinterHandler { … };
class PrintPreviewHandlerFailingTest : public PrintPreviewHandlerTest { … };
TEST_F(PrintPreviewHandlerFailingTest, GetPrinterCapabilities) { … }
#if BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS)
class ContentAnalysisPrintPreviewHandlerTest
: public PrintPreviewHandlerTest,
public testing::WithParamInterface<bool> { … };
TEST_P(ContentAnalysisPrintPreviewHandlerTest, LocalScanBeforePrinting) { … }
INSTANTIATE_TEST_SUITE_P(…);
#endif
}