chromium/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc

// Copyright 2017 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/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"  // nogncheck
#endif  // BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS)
#endif  // BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)

#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  // BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS)

// Array of all mojom::PrinterTypes.
constexpr mojom::PrinterType kAllTypes[] =;

// Array of all mojom::PrinterTypes that have working PrinterHandlers.
constexpr mojom::PrinterType kAllSupportedTypes[] =;

// Both printer types that implement PrinterHandler::StartGetPrinters().
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) {}

// Checks whether |histograms| was updated correctly by a job with a printer
// type |type| with arguments generated by GetPrintTicket().
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);
  }

  // crosapi::mojom::LocalPrinter:
  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  // BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)

}  // namespace

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();
  // Verify initial settings were sent.
  ValidateInitialSettings(*web_ui()->call_data().back(), test::kPrinterName,
                          kDummyInitiatorName);
  // Verify policy settings are empty.
  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
  // Set a pref that should take priority over StickySettings.
  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
  // Set a pref that should take priority over StickySettings.
  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
  // Set a pref that should take priority over StickySettings.
  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
  // Set a pref that should take priority over StickySettings.
  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
  // Set a pref that should take priority over StickySettings.
  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
  // Set a pref that should take priority over StickySettings.
  prefs()->SetInteger(prefs::kPrintingPinDefault, 2);
#endif
  Initialize();
  ValidateInitialSettingsAllowedDefaultModePolicy(
      *web_ui()->call_data().back(), "pin", std::nullopt, base::Value(2));
}
#endif  // BUILDFLAG(IS_CHROMEOS)

TEST_F(PrintPreviewHandlerTest, GetPrinters) {}

// Validates the 'printing.printer_type_deny_list' pref by placing the extension
// printer type on a deny list. A 'getPrinters' Web UI message is
// then called both fetchable printer types; only local printers should
// be successfully fetched.
TEST_F(PrintPreviewHandlerTest, GetNoDenyListPrinters) {}

TEST_F(PrintPreviewHandlerTest, GetPrinterCapabilities) {}

// Validates the 'printing.printer_type_deny_list' pref by placing the local and
// PDF printer types on the deny list. A 'getPrinterCapabilities' Web UI message
// is then called for all supported printer types; only extension
// printer capabilities should be successfully fetched.
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)
// Tests that the `isDriveMounted` setting is only included for the primary
// profile on Lacros.
TEST_F(PrintPreviewHandlerTest, SaveToDriveLacrosPrimaryProfile) {
  crosapi::mojom::Policies policies;
  SetPolicies(policies);
  TestingProfile* main_profile =
      testing_profile_manager()->CreateTestingProfile("Main Profile",
                                                      /*is_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());
}

// Tests that the `isDriveMounted` setting is not included for a non-primary
// profile on Lacros.
TEST_F(PrintPreviewHandlerTest, SaveToDriveLacrosNonPrimaryProfile) {
  crosapi::mojom::Policies policies;
  SetPolicies(policies);
  TestingProfile* secondary_profile =
      testing_profile_manager()->CreateTestingProfile(
          "Secondary Profile",
          /*is_main_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 {};

// This test is similar to PrintPreviewHandlerTest.GetPrinterCapabilities, but
// uses FailingTestPrinterHandler instead of TestPrinterHandler. As a result,
// StartGetCapability() always fails, to exercise its callback's failure
// handling path. Failure is different from getting no capabilities.
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  // BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS)

}  // namespace printing