chromium/chrome/browser/printing/print_backend_browsertest.cc

// 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 "printing/backend/print_backend.h"

#include <stdint.h>

#include <algorithm>
#include <memory>
#include <optional>
#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/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"

#if BUILDFLAG(IS_WIN)
#include "printing/emf_win.h"
#else
#include "printing/metafile_skia.h"
#endif

namespace printing {

UnorderedElementsAreArray;

namespace {

constexpr char kDefaultPrinterName[] =;
constexpr char16_t kDefaultPrinterName16[] =;
constexpr char kAnotherPrinterName[] =;
constexpr char kInvalidPrinterName[] =;
constexpr char16_t kInvalidPrinterName16[] =;
constexpr char kAccessDeniedPrinterName[] =;

const PrinterBasicInfoOptions kDefaultPrintInfoOptions{};

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 =;
constexpr int kPrintSettingsCopies =;
constexpr int kPrintSettingsDefaultDpi =;
constexpr int kPrintSettingsOverrideDpi =;

const int32_t kTestDocumentCookie =;

bool LoadMetafileDataFromFile(const std::string& file_name,
                              Metafile& metafile) {}

}  // namespace

class PrintBackendBrowserTest : public InProcessBrowserTest {};

IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, EnumeratePrinters) {}

IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, GetDefaultPrinterName) {}

#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) {}

IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, FetchCapabilitiesAccessDenied) {}

#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());
  std::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) {}

#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) {}

IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, StartPrinting) {}

#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);

  std::optional<mojom::ResultCode> result = RenderPageAndWait();
  EXPECT_EQ(result, mojom::ResultCode::kSuccess);
}
#endif  // BUILDFLAG(IS_WIN)

// TODO(crbug.com/40100562)  Include Windows for this test once XPS print
// pipeline is enabled.
#if !BUILDFLAG(IS_WIN)
IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, RenderPrintedDocument) {}
#endif  // !BUILDFLAG(IS_WIN)

IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, DocumentDone) {}

IN_PROC_BROWSER_TEST_F(PrintBackendBrowserTest, Cancel) {}

}  // namespace printing