From 2c411892e273c564dfb6650dcee8fea458849178 Mon Sep 17 00:00:00 2001 From: Tom Crowley Date: Thu, 29 May 2025 16:55:50 +0000 Subject: [PATCH] ceftests: Add tests for PrintToPdf --- cef_paths2.gypi | 1 + tests/ceftests/print_to_pdf_unittest.cc | 290 ++++++++++++++++++++++++ 2 files changed, 291 insertions(+) create mode 100644 tests/ceftests/print_to_pdf_unittest.cc diff --git a/cef_paths2.gypi b/cef_paths2.gypi index 767c6f252..8cd27a603 100644 --- a/cef_paths2.gypi +++ b/cef_paths2.gypi @@ -540,6 +540,7 @@ 'tests/ceftests/permission_prompt_unittest.cc', 'tests/ceftests/preference_unittest.cc', 'tests/ceftests/print_unittest.cc', + 'tests/ceftests/print_to_pdf_unittest.cc', 'tests/ceftests/process_message_unittest.cc', 'tests/ceftests/request_context_unittest.cc', 'tests/ceftests/request_handler_unittest.cc', diff --git a/tests/ceftests/print_to_pdf_unittest.cc b/tests/ceftests/print_to_pdf_unittest.cc new file mode 100644 index 000000000..1de61e0c0 --- /dev/null +++ b/tests/ceftests/print_to_pdf_unittest.cc @@ -0,0 +1,290 @@ +// Copyright (c) 2025 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include + +#include "include/base/cef_callback.h" +#include "include/wrapper/cef_closure_task.h" +#include "include/wrapper/cef_scoped_temp_dir.h" +#include "tests/ceftests/test_handler.h" +#include "tests/ceftests/test_util.h" +#include "tests/gtest/include/gtest/gtest.h" +#include "tests/shared/browser/file_util.h" + +namespace { + +const char kPrintHtmlUrl[] = "https://tests/print.html"; +const char kTestFileName[] = "print.pdf"; +#if defined(OS_WIN) +const char kTestFileNameInvalid[] = "print.pdf?"; +#endif // defined(OS_WIN) +const char kTestHtml[] = + "\n" + "\n" + "\n" + " \n" + " \n" + " Print Test\n" + " \n" + "\n" + "\n" + "

Print Test Document

\n" + "

This is a simple test document to check printing " + "functionality.

\n" + "\n" + ""; + +// Browser-side test handler. +class PrintToPdfTestHandler : public TestHandler, public CefPdfPrintCallback { + public: + PrintToPdfTestHandler(const std::string& url, bool expect_ok) + : url_(url), expect_ok_(expect_ok) {} + + virtual std::string GetTestFileName() { return kTestFileName; } + + void RunTest() override { + EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); + + test_path_ = + client::file_util::JoinPath(temp_dir_.GetPath(), GetTestFileName()); + + // Add the resource. + AddResource(url_, kTestHtml, "text/html"); + + // Create the browser. + CreateBrowser(url_); + + // Time out the test after a reasonable period of time. + SetTestTimeout(5000); + } + + void OnLoadEnd(CefRefPtr browser, + CefRefPtr frame, + int httpStatusCode) override { + const std::string& url = frame->GetURL(); + if (url == "about:blank" || url.find("chrome-extension://") == 0) { + return; + } + + if (url == kPrintHtmlUrl) { + EXPECT_FALSE(got_on_load_end_html_); + got_on_load_end_html_.yes(); + } else { + NOTREACHED() << "url=" << url; + } + + PrintToPDF(browser); + } + + void OnPdfPrintFinished(const CefString& path, bool ok) override { + EXPECT_EQ(expect_ok_, ok); + + if (ok) { + EXPECT_EQ(test_path_, path); + } + + EXPECT_FALSE(got_on_pdf_print_finished_); + got_on_pdf_print_finished_.yes(); + + CompleteTest(); + } + + void VerifyResultsOnFileThread() { + EXPECT_TRUE(CefCurrentlyOn(TID_FILE_USER_VISIBLE)); + + // Verify the file contents. + std::string contents; + bool ok = client::file_util::ReadFileToString(test_path_, &contents); + EXPECT_EQ(ok, expect_ok_); + if (expect_ok_) { + EXPECT_GT(contents.size(), 1024U); + // https://en.wikipedia.org/wiki/PDF + // The file starts with a header containing a magic number (as a readable + // string) and the version of the format, for example %PDF-1.7 + if (contents.size() >= 4U) { + EXPECT_EQ(contents[0], '%'); + EXPECT_EQ(contents[1], 'P'); + EXPECT_EQ(contents[2], 'D'); + EXPECT_EQ(contents[3], 'F'); + } + } + + EXPECT_TRUE(temp_dir_.Delete()); + EXPECT_TRUE(temp_dir_.IsEmpty()); + + CefPostTask(TID_UI, + base::BindOnce(&PrintToPdfTestHandler::CompleteTest, this)); + } + + void CompleteTest() { + if (!verified_results_ && !temp_dir_.IsEmpty()) { + verified_results_ = true; + CefPostTask(TID_FILE_USER_VISIBLE, + base::BindOnce( + &PrintToPdfTestHandler::VerifyResultsOnFileThread, this)); + return; + } + + DestroyTest(); + } + + void DestroyTest() override { + EXPECT_TRUE(got_on_load_end_html_); + EXPECT_TRUE(got_on_pdf_print_finished_); + EXPECT_TRUE(verified_results_); + + if (temp_dir_.IsValid()) { + ASSERT_TRUE(temp_dir_.Delete()); + } + + TestHandler::DestroyTest(); + } + + virtual void PrintToPDF(CefRefPtr browser) { + CefPdfPrintSettings settings; + browser->GetHost()->PrintToPDF(test_path_, settings, this); + } + + protected: + CefScopedTempDir temp_dir_; + + const std::string url_; + CefString test_path_; + const bool expect_ok_; + bool verified_results_ = false; + + TrackCallback got_on_load_end_html_; + TrackCallback got_on_pdf_print_finished_; + + IMPLEMENT_REFCOUNTING(PrintToPdfTestHandler); +}; + +class PrintToPdfInvalidMarginTestHandler : public PrintToPdfTestHandler { + public: + PrintToPdfInvalidMarginTestHandler(const std::string& url, bool expect_ok) + : PrintToPdfTestHandler(url, expect_ok) {} + + virtual void PrintToPDF(CefRefPtr browser) override { + CefPdfPrintSettings settings; + settings.margin_left = -1; + settings.margin_type = cef_pdf_print_margin_type_t::PDF_PRINT_MARGIN_CUSTOM; + browser->GetHost()->PrintToPDF(test_path_, settings, this); + } + + protected: + IMPLEMENT_REFCOUNTING(PrintToPdfInvalidMarginTestHandler); +}; + +class PrintToPdfInvalidPaperDimTestHandler : public PrintToPdfTestHandler { + public: + PrintToPdfInvalidPaperDimTestHandler(const std::string& url, bool expect_ok) + : PrintToPdfTestHandler(url, expect_ok) {} + + virtual void PrintToPDF(CefRefPtr browser) override { + CefPdfPrintSettings settings; + settings.paper_width = -1; + settings.paper_height = -1; + browser->GetHost()->PrintToPDF(test_path_, settings, this); + } + + protected: + IMPLEMENT_REFCOUNTING(PrintToPdfInvalidPaperDimTestHandler); +}; + +class PrintToPdfInvalidScaleTestHandler : public PrintToPdfTestHandler { + public: + PrintToPdfInvalidScaleTestHandler(const std::string& url, bool expect_ok) + : PrintToPdfTestHandler(url, expect_ok) {} + + virtual void PrintToPDF(CefRefPtr browser) override { + CefPdfPrintSettings settings; + settings.scale = 999999999; + browser->GetHost()->PrintToPDF(test_path_, settings, this); + } + + protected: + IMPLEMENT_REFCOUNTING(PrintToPdfInvalidScaleTestHandler); +}; + +#if defined(OS_WIN) +class PrintToPdfInvalidFileNameTestHandler : public PrintToPdfTestHandler { + public: + PrintToPdfInvalidFileNameTestHandler(const std::string& url, bool expect_ok) + : PrintToPdfTestHandler(url, expect_ok) {} + + std::string GetTestFileName() override { return kTestFileNameInvalid; } + + protected: + IMPLEMENT_REFCOUNTING(PrintToPdfInvalidFileNameTestHandler); +}; +#endif // defined(OS_WIN) + +} // namespace + +TEST(PdfPrintTest, DefaultSettings) { + CefRefPtr handler = + new PrintToPdfTestHandler(kPrintHtmlUrl, true); + handler->ExecuteTest(); + ReleaseAndWaitForDestructor(handler); +} + +TEST(PdfPrintTest, InvalidMargin) { + // Should still pass as settings are validated + CefRefPtr handler = + new PrintToPdfInvalidMarginTestHandler(kPrintHtmlUrl, true); + handler->ExecuteTest(); + ReleaseAndWaitForDestructor(handler); +} + +TEST(PdfPrintTest, InvalidPageDim) { + // Should still pass as settings are validated + CefRefPtr handler = + new PrintToPdfInvalidPaperDimTestHandler(kPrintHtmlUrl, true); + handler->ExecuteTest(); + ReleaseAndWaitForDestructor(handler); +} + +TEST(PdfPrintTest, InvalidScale) { + CefRefPtr handler = + new PrintToPdfInvalidScaleTestHandler(kPrintHtmlUrl, false); + handler->ExecuteTest(); + ReleaseAndWaitForDestructor(handler); +} + +#if defined(OS_WIN) +TEST(PdfPrintTest, InvalidFileName) { + CefRefPtr handler = + new PrintToPdfInvalidFileNameTestHandler(kPrintHtmlUrl, false); + handler->ExecuteTest(); + ReleaseAndWaitForDestructor(handler); +} +#endif // defined(OS_WIN)