1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
6 
7 #include <map>
8 #include <utility>
9 #include <vector>
10 
11 #include "base/base64.h"
12 #include "base/containers/flat_set.h"
13 #include "base/i18n/number_formatting.h"
14 #include "base/json/json_reader.h"
15 #include "base/json/json_writer.h"
16 #include "base/memory/ref_counted_memory.h"
17 #include "base/optional.h"
18 #include "base/run_loop.h"
19 #include "base/stl_util.h"
20 #include "base/strings/string16.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/test/icu_test_util.h"
23 #include "base/test/metrics/histogram_tester.h"
24 #include "base/values.h"
25 #include "chrome/browser/printing/print_test_utils.h"
26 #include "chrome/browser/printing/print_view_manager.h"
27 #include "chrome/browser/ui/webui/print_preview/fake_print_render_frame.h"
28 #include "chrome/browser/ui/webui/print_preview/policy_settings.h"
29 #include "chrome/browser/ui/webui/print_preview/print_preview_metrics.h"
30 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
31 #include "chrome/browser/ui/webui/print_preview/printer_handler.h"
32 #include "chrome/common/pref_names.h"
33 #include "chrome/test/base/testing_browser_process.h"
34 #include "chrome/test/base/testing_profile.h"
35 #include "components/prefs/pref_service.h"
36 #include "components/sync_preferences/testing_pref_service_syncable.h"
37 #include "content/public/browser/render_frame_host.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/browser/web_ui_controller.h"
40 #include "content/public/test/browser_task_environment.h"
41 #include "content/public/test/test_renderer_host.h"
42 #include "content/public/test/test_web_ui.h"
43 #include "testing/gtest/include/gtest/gtest.h"
44 
45 namespace printing {
46 
47 namespace {
48 
49 const char kDummyInitiatorName[] = "TestInitiator";
50 const char kEmptyPrinterName[] = "EmptyPrinter";
51 const char kTestData[] = "abc";
52 
53 // Array of all PrinterTypes.
54 constexpr PrinterType kAllTypes[] = {PrinterType::kPrivet,
55                                      PrinterType::kExtension, PrinterType::kPdf,
56                                      PrinterType::kLocal, PrinterType::kCloud};
57 
58 // Array of all PrinterTypes that have working PrinterHandlers.
59 constexpr PrinterType kAllSupportedTypes[] = {
60     PrinterType::kPrivet, PrinterType::kExtension, PrinterType::kPdf,
61     PrinterType::kLocal};
62 
63 // All three printer types that implement PrinterHandler::StartGetPrinters().
64 constexpr PrinterType kFetchableTypes[] = {
65     PrinterType::kPrivet, PrinterType::kExtension, PrinterType::kLocal};
66 
67 struct PrinterInfo {
68   std::string id;
69   bool is_default;
70   base::Value basic_info = base::Value(base::Value::Type::DICTIONARY);
71   base::Value capabilities = base::Value(base::Value::Type::DICTIONARY);
72 };
73 
GetSimplePrinterInfo(const std::string & name,bool is_default)74 PrinterInfo GetSimplePrinterInfo(const std::string& name, bool is_default) {
75   PrinterInfo simple_printer;
76   simple_printer.id = name;
77   simple_printer.is_default = is_default;
78   simple_printer.basic_info.SetKey("printer_name",
79                                    base::Value(simple_printer.id));
80   simple_printer.basic_info.SetKey("printer_description",
81                                    base::Value("Printer for test"));
82   simple_printer.basic_info.SetKey("printer_status", base::Value(1));
83   base::Value cdd(base::Value::Type::DICTIONARY);
84   base::Value capabilities(base::Value::Type::DICTIONARY);
85   simple_printer.capabilities.SetKey("printer",
86                                      simple_printer.basic_info.Clone());
87   simple_printer.capabilities.SetKey("capabilities", cdd.Clone());
88   return simple_printer;
89 }
90 
GetEmptyPrinterInfo()91 PrinterInfo GetEmptyPrinterInfo() {
92   PrinterInfo empty_printer;
93   empty_printer.id = kEmptyPrinterName;
94   empty_printer.is_default = false;
95   empty_printer.basic_info.SetKey("printer_name",
96                                   base::Value(empty_printer.id));
97   empty_printer.basic_info.SetKey("printer_description",
98                                   base::Value("Printer with no capabilities"));
99   empty_printer.basic_info.SetKey("printer_status", base::Value(0));
100   empty_printer.capabilities.SetKey("printer",
101                                     empty_printer.basic_info.Clone());
102   return empty_printer;
103 }
104 
GetPrintPreviewTicket()105 base::Value GetPrintPreviewTicket() {
106   base::Value print_ticket = GetPrintTicket(PrinterType::kLocal);
107 
108   // Make some modifications to match a preview print ticket.
109   print_ticket.SetKey(kSettingPageRange, base::Value());
110   print_ticket.SetBoolKey(kIsFirstRequest, true);
111   print_ticket.SetIntKey(kPreviewRequestID, 0);
112   print_ticket.SetBoolKey(kSettingPreviewModifiable, false);
113   print_ticket.SetBoolKey(kSettingPreviewIsPdf, true);
114   print_ticket.RemoveKey(kSettingPageWidth);
115   print_ticket.RemoveKey(kSettingPageHeight);
116   print_ticket.RemoveKey(kSettingShowSystemDialog);
117 
118   return print_ticket;
119 }
120 
ConstructPreviewArgs(base::StringPiece callback_id,const base::Value & print_ticket)121 std::unique_ptr<base::ListValue> ConstructPreviewArgs(
122     base::StringPiece callback_id,
123     const base::Value& print_ticket) {
124   base::Value args(base::Value::Type::LIST);
125   args.Append(callback_id);
126   std::string json;
127   base::JSONWriter::Write(print_ticket, &json);
128   args.Append(json);
129   return base::ListValue::From(base::Value::ToUniquePtrValue(std::move(args)));
130 }
131 
GetUserActionForPrinterType(PrinterType type)132 UserActionBuckets GetUserActionForPrinterType(PrinterType type) {
133   switch (type) {
134     case PrinterType::kPrivet:
135       return UserActionBuckets::kPrintWithPrivet;
136     case PrinterType::kExtension:
137       return UserActionBuckets::kPrintWithExtension;
138     case PrinterType::kPdf:
139       return UserActionBuckets::kPrintToPdf;
140     case PrinterType::kLocal:
141       return UserActionBuckets::kPrintToPrinter;
142     case PrinterType::kCloud:
143       return UserActionBuckets::kPrintWithCloudPrint;
144   }
145 }
146 
147 // Checks whether |histograms| was updated correctly by a job with a printer
148 // type |type| with arguments generated by GetPrintTicket().
CheckHistograms(const base::HistogramTester & histograms,PrinterType type)149 void CheckHistograms(const base::HistogramTester& histograms,
150                      PrinterType type) {
151   static constexpr PrintSettingsBuckets kPopulatedPrintSettingsBuckets[] = {
152       PrintSettingsBuckets::kPortrait, PrintSettingsBuckets::kColor,
153       PrintSettingsBuckets::kCollate,  PrintSettingsBuckets::kDuplex,
154       PrintSettingsBuckets::kTotal,    PrintSettingsBuckets::kDefaultMedia,
155   };
156 
157   for (auto bucket : kPopulatedPrintSettingsBuckets)
158     histograms.ExpectBucketCount("PrintPreview.PrintSettings", bucket, 1);
159 
160   // All other PrintPreview.PrintSettings buckets should be empty.
161   histograms.ExpectTotalCount("PrintPreview.PrintSettings",
162                               base::size(kPopulatedPrintSettingsBuckets));
163 
164   const UserActionBuckets user_action = GetUserActionForPrinterType(type);
165   histograms.ExpectBucketCount("PrintPreview.UserAction", user_action, 1);
166   // Only one PrintPreview.UserAction bucket should have been populated.
167   histograms.ExpectTotalCount("PrintPreview.UserAction", 1);
168 
169   histograms.ExpectTotalCount("PrintPreview.PrintDocumentSize.HTML", 1);
170   histograms.ExpectTotalCount("PrintPreview.PrintDocumentSize.PDF", 0);
171   histograms.ExpectBucketCount("PrintPreview.PrintDocumentType",
172                                PrintDocumentTypeBuckets::kHtmlDocument, 1);
173   histograms.ExpectBucketCount("PrintPreview.PrintDocumentType",
174                                PrintDocumentTypeBuckets::kPdfDocument, 0);
175 }
176 
177 class TestPrinterHandler : public PrinterHandler {
178  public:
TestPrinterHandler(const std::vector<PrinterInfo> & printers)179   explicit TestPrinterHandler(const std::vector<PrinterInfo>& printers) {
180     SetPrinters(printers);
181   }
182 
~TestPrinterHandler()183   ~TestPrinterHandler() override {}
184 
Reset()185   void Reset() override {}
186 
GetDefaultPrinter(DefaultPrinterCallback cb)187   void GetDefaultPrinter(DefaultPrinterCallback cb) override {
188     std::move(cb).Run(default_printer_);
189   }
190 
StartGetPrinters(AddedPrintersCallback added_printers_callback,GetPrintersDoneCallback done_callback)191   void StartGetPrinters(AddedPrintersCallback added_printers_callback,
192                         GetPrintersDoneCallback done_callback) override {
193     if (!printers_.empty())
194       added_printers_callback.Run(printers_);
195     std::move(done_callback).Run();
196   }
197 
StartGetCapability(const std::string & destination_id,GetCapabilityCallback callback)198   void StartGetCapability(const std::string& destination_id,
199                           GetCapabilityCallback callback) override {
200     std::move(callback).Run(printer_capabilities_[destination_id]->Clone());
201   }
202 
StartGrantPrinterAccess(const std::string & printer_id,GetPrinterInfoCallback callback)203   void StartGrantPrinterAccess(const std::string& printer_id,
204                                GetPrinterInfoCallback callback) override {}
205 
StartPrint(const base::string16 & job_title,base::Value settings,scoped_refptr<base::RefCountedMemory> print_data,PrintCallback callback)206   void StartPrint(const base::string16& job_title,
207                   base::Value settings,
208                   scoped_refptr<base::RefCountedMemory> print_data,
209                   PrintCallback callback) override {
210     std::move(callback).Run(base::Value());
211   }
212 
SetPrinters(const std::vector<PrinterInfo> & printers)213   void SetPrinters(const std::vector<PrinterInfo>& printers) {
214     base::Value::ListStorage printer_list;
215     for (const auto& printer : printers) {
216       if (printer.is_default)
217         default_printer_ = printer.id;
218       printer_list.push_back(printer.basic_info.Clone());
219       printer_capabilities_[printer.id] = base::DictionaryValue::From(
220           std::make_unique<base::Value>(printer.capabilities.Clone()));
221     }
222     printers_ = base::ListValue(printer_list);
223   }
224 
225  private:
226   std::string default_printer_;
227   base::ListValue printers_;
228   std::map<std::string, std::unique_ptr<base::DictionaryValue>>
229       printer_capabilities_;
230 
231   DISALLOW_COPY_AND_ASSIGN(TestPrinterHandler);
232 };
233 
234 class FakePrintPreviewUI : public PrintPreviewUI {
235  public:
FakePrintPreviewUI(content::WebUI * web_ui,std::unique_ptr<PrintPreviewHandler> handler)236   FakePrintPreviewUI(content::WebUI* web_ui,
237                      std::unique_ptr<PrintPreviewHandler> handler)
238       : PrintPreviewUI(web_ui, std::move(handler)) {}
239 
~FakePrintPreviewUI()240   ~FakePrintPreviewUI() override {}
241 
GetPrintPreviewDataForIndex(int index,scoped_refptr<base::RefCountedMemory> * data) const242   void GetPrintPreviewDataForIndex(
243       int index,
244       scoped_refptr<base::RefCountedMemory>* data) const override {
245     *data = base::MakeRefCounted<base::RefCountedStaticMemory>(
246         reinterpret_cast<const unsigned char*>(kTestData),
247         sizeof(kTestData) - 1);
248   }
249 
OnPrintPreviewRequest(int request_id)250   void OnPrintPreviewRequest(int request_id) override {}
OnCancelPendingPreviewRequest()251   void OnCancelPendingPreviewRequest() override {}
OnHidePreviewDialog()252   void OnHidePreviewDialog() override {}
OnClosePrintPreviewDialog()253   void OnClosePrintPreviewDialog() override {}
254 
255  private:
256   DISALLOW_COPY_AND_ASSIGN(FakePrintPreviewUI);
257 };
258 
259 class TestPrintPreviewPrintRenderFrame : public FakePrintRenderFrame {
260  public:
TestPrintPreviewPrintRenderFrame(blink::AssociatedInterfaceProvider * provider)261   explicit TestPrintPreviewPrintRenderFrame(
262       blink::AssociatedInterfaceProvider* provider)
263       : FakePrintRenderFrame(provider) {}
264 
265   ~TestPrintPreviewPrintRenderFrame() final = default;
266 
GetSettings()267   const base::Value& GetSettings() { return settings_; }
268 
SetCompletionClosure(base::OnceClosure closure)269   void SetCompletionClosure(base::OnceClosure closure) {
270     closure_ = std::move(closure);
271   }
272 
273  private:
274   // FakePrintRenderFrame:
PrintPreview(base::Value settings)275   void PrintPreview(base::Value settings) final {
276     settings_ = std::move(settings);
277     std::move(closure_).Run();
278   }
279 
280   base::OnceClosure closure_;
281   base::Value settings_;
282 };
283 
284 class TestPrintPreviewHandler : public PrintPreviewHandler {
285  public:
TestPrintPreviewHandler(std::unique_ptr<PrinterHandler> printer_handler,content::WebContents * initiator)286   TestPrintPreviewHandler(std::unique_ptr<PrinterHandler> printer_handler,
287                           content::WebContents* initiator)
288       : bad_messages_(0),
289         test_printer_handler_(std::move(printer_handler)),
290         initiator_(initiator) {}
291 
GetPrinterHandler(PrinterType printer_type)292   PrinterHandler* GetPrinterHandler(PrinterType printer_type) override {
293     called_for_type_.insert(printer_type);
294     return test_printer_handler_.get();
295   }
296 
IsCloudPrintEnabled()297   bool IsCloudPrintEnabled() override { return true; }
298 
RegisterForGaiaCookieChanges()299   void RegisterForGaiaCookieChanges() override {}
UnregisterForGaiaCookieChanges()300   void UnregisterForGaiaCookieChanges() override {}
301 
BadMessageReceived()302   void BadMessageReceived() override { bad_messages_++; }
303 
GetInitiator() const304   content::WebContents* GetInitiator() const override { return initiator_; }
305 
CalledOnlyForType(PrinterType printer_type)306   bool CalledOnlyForType(PrinterType printer_type) {
307     return (called_for_type_.size() == 1 &&
308             *called_for_type_.begin() == printer_type);
309   }
310 
NotCalled()311   bool NotCalled() { return called_for_type_.empty(); }
312 
reset_calls()313   void reset_calls() { called_for_type_.clear(); }
314 
bad_messages()315   int bad_messages() { return bad_messages_; }
316 
317  private:
318   int bad_messages_;
319   base::flat_set<PrinterType> called_for_type_;
320   std::unique_ptr<PrinterHandler> test_printer_handler_;
321   content::WebContents* const initiator_;
322 
323   DISALLOW_COPY_AND_ASSIGN(TestPrintPreviewHandler);
324 };
325 
326 }  // namespace
327 
328 class PrintPreviewHandlerTest : public testing::Test {
329  public:
330   PrintPreviewHandlerTest() = default;
331   ~PrintPreviewHandlerTest() override = default;
332 
SetUp()333   void SetUp() override {
334     TestingProfile::Builder builder;
335     profile_ = builder.Build();
336     initiator_web_contents_ = content::WebContents::Create(
337         content::WebContents::CreateParams(profile_.get()));
338     content::WebContents* initiator = initiator_web_contents_.get();
339     preview_web_contents_ = content::WebContents::Create(
340         content::WebContents::CreateParams(profile_.get()));
341     PrintViewManager::CreateForWebContents(initiator);
342     PrintViewManager::FromWebContents(initiator)->PrintPreviewNow(
343         initiator->GetMainFrame(), false);
344     web_ui_ = std::make_unique<content::TestWebUI>();
345     web_ui_->set_web_contents(preview_web_contents_.get());
346 
347     printers_.push_back(GetSimplePrinterInfo(kDummyPrinterName, true));
348     auto printer_handler = CreatePrinterHandler(printers_);
349     printer_handler_ = printer_handler.get();
350 
351     auto preview_handler = std::make_unique<TestPrintPreviewHandler>(
352         std::move(printer_handler), initiator);
353     preview_handler->set_web_ui(web_ui());
354     handler_ = preview_handler.get();
355 
356     auto preview_ui = std::make_unique<FakePrintPreviewUI>(
357         web_ui(), std::move(preview_handler));
358     preview_ui->SetInitiatorTitle(base::ASCIIToUTF16(kDummyInitiatorName));
359     web_ui()->SetController(std::move(preview_ui));
360   }
361 
TearDown()362   void TearDown() override {
363     PrintViewManager::FromWebContents(initiator_web_contents_.get())
364         ->PrintPreviewDone();
365   }
366 
CreatePrinterHandler(const std::vector<PrinterInfo> & printers)367   virtual std::unique_ptr<TestPrinterHandler> CreatePrinterHandler(
368       const std::vector<PrinterInfo>& printers) {
369     return std::make_unique<TestPrinterHandler>(printers);
370   }
371 
Initialize()372   void Initialize() { InitializeWithLocale("en"); }
373 
InitializeWithLocale(const std::string & locale)374   void InitializeWithLocale(const std::string& locale) {
375     // Sending this message will enable javascript, so it must always be called
376     // before any other messages are sent.
377     base::Value args(base::Value::Type::LIST);
378     args.Append("test-callback-id-0");
379     std::unique_ptr<base::ListValue> list_args =
380         base::ListValue::From(base::Value::ToUniquePtrValue(std::move(args)));
381 
382     auto* browser_process = TestingBrowserProcess::GetGlobal();
383     std::string original_locale = browser_process->GetApplicationLocale();
384     {
385       // Set locale since the delimiters checked in VerifyInitialSettings()
386       // depend on it. This has to be done in several ways to make various
387       // locale code sync up correctly.
388       browser_process->SetApplicationLocale(locale);
389       base::test::ScopedRestoreICUDefaultLocale scoped_locale(locale);
390       base::ResetFormattersForTesting();
391       handler()->HandleGetInitialSettings(list_args.get());
392     }
393     // Reset again now that |scoped_locale| has been destroyed.
394     browser_process->SetApplicationLocale(original_locale);
395     base::ResetFormattersForTesting();
396 
397     // In response to get initial settings, the initial settings are sent back.
398     ASSERT_EQ(1u, web_ui()->call_data().size());
399   }
400 
AssertWebUIEventFired(const content::TestWebUI::CallData & data,const std::string & event_id)401   void AssertWebUIEventFired(const content::TestWebUI::CallData& data,
402                              const std::string& event_id) {
403     EXPECT_EQ("cr.webUIListenerCallback", data.function_name());
404     std::string event_fired;
405     ASSERT_TRUE(data.arg1()->GetAsString(&event_fired));
406     EXPECT_EQ(event_id, event_fired);
407   }
408 
CheckWebUIResponse(const content::TestWebUI::CallData & data,const std::string & callback_id_in,bool expect_success)409   void CheckWebUIResponse(const content::TestWebUI::CallData& data,
410                           const std::string& callback_id_in,
411                           bool expect_success) {
412     EXPECT_EQ("cr.webUIResponse", data.function_name());
413     std::string callback_id;
414     ASSERT_TRUE(data.arg1()->GetAsString(&callback_id));
415     EXPECT_EQ(callback_id_in, callback_id);
416     bool success = false;
417     ASSERT_TRUE(data.arg2()->GetAsBoolean(&success));
418     EXPECT_EQ(expect_success, success);
419   }
420 
ValidateInitialSettings(const content::TestWebUI::CallData & data,const std::string & default_printer_name,const std::string & initiator_title)421   void ValidateInitialSettings(const content::TestWebUI::CallData& data,
422                                const std::string& default_printer_name,
423                                const std::string& initiator_title) {
424     ValidateInitialSettingsForLocale(data, default_printer_name,
425                                      initiator_title, "en", ",", ".");
426   }
427 
428   // Validates the initial settings structure in the response matches the
429   // print_preview.NativeInitialSettings type in
430   // chrome/browser/resources/print_preview/native_layer.js. Checks that:
431   //   - |default_printer_name| is the printer name returned
432   //   - |initiator_title| is the initiator title returned
433   // Also validates that delimiters are correct for |locale| (set in
434   // InitializeWithLocale()) with the associated |thousands_delimiter| and
435   // |decimal_delimiter|.
436   // Assumes "test-callback-id-0" was used as the callback id.
ValidateInitialSettingsForLocale(const content::TestWebUI::CallData & data,const std::string & default_printer_name,const std::string & initiator_title,const std::string & locale,const std::string & thousands_delimiter,const std::string & decimal_delimiter)437   void ValidateInitialSettingsForLocale(
438       const content::TestWebUI::CallData& data,
439       const std::string& default_printer_name,
440       const std::string& initiator_title,
441       const std::string& locale,
442       const std::string& thousands_delimiter,
443       const std::string& decimal_delimiter) {
444     CheckWebUIResponse(data, "test-callback-id-0", true);
445     const base::Value* settings = data.arg3();
446     ASSERT_TRUE(settings->FindKeyOfType("isInKioskAutoPrintMode",
447                                         base::Value::Type::BOOLEAN));
448     ASSERT_TRUE(settings->FindKeyOfType("isInAppKioskMode",
449                                         base::Value::Type::BOOLEAN));
450 
451     const std::string* actual_locale = settings->FindStringKey("uiLocale");
452     ASSERT_TRUE(actual_locale);
453     EXPECT_EQ(locale, *actual_locale);
454     const std::string* actual_thousands_delimiter =
455         settings->FindStringKey("thousandsDelimiter");
456     ASSERT_TRUE(actual_thousands_delimiter);
457     EXPECT_EQ(thousands_delimiter, *actual_thousands_delimiter);
458     const std::string* actual_decimal_delimiter =
459         settings->FindStringKey("decimalDelimiter");
460     ASSERT_TRUE(actual_decimal_delimiter);
461     EXPECT_EQ(decimal_delimiter, *actual_decimal_delimiter);
462 
463     ASSERT_TRUE(
464         settings->FindKeyOfType("unitType", base::Value::Type::INTEGER));
465     ASSERT_TRUE(settings->FindKeyOfType("previewModifiable",
466                                         base::Value::Type::BOOLEAN));
467     const base::Value* title =
468         settings->FindKeyOfType("documentTitle", base::Value::Type::STRING);
469     ASSERT_TRUE(title);
470     EXPECT_EQ(initiator_title, title->GetString());
471     ASSERT_TRUE(settings->FindKeyOfType("documentHasSelection",
472                                         base::Value::Type::BOOLEAN));
473     ASSERT_TRUE(settings->FindKeyOfType("shouldPrintSelectionOnly",
474                                         base::Value::Type::BOOLEAN));
475     const base::Value* printer =
476         settings->FindKeyOfType("printerName", base::Value::Type::STRING);
477     ASSERT_TRUE(printer);
478     EXPECT_EQ(default_printer_name, printer->GetString());
479 
480     ASSERT_TRUE(settings->FindKeyOfType("pdfPrinterDisabled",
481                                         base::Value::Type::BOOLEAN));
482     ASSERT_TRUE(settings->FindKeyOfType("destinationsManaged",
483                                         base::Value::Type::BOOLEAN));
484     ASSERT_TRUE(
485         settings->FindKeyOfType("cloudPrintURL", base::Value::Type::STRING));
486     ASSERT_TRUE(
487         settings->FindKeyOfType("userAccounts", base::Value::Type::LIST));
488     ASSERT_TRUE(
489         settings->FindKeyOfType("syncAvailable", base::Value::Type::BOOLEAN));
490   }
491 
492   // Returns |policy_name| entry from initial settings policies.
GetInitialSettingsPolicy(const base::Value & settings,const std::string & policy_name)493   const base::Value* GetInitialSettingsPolicy(const base::Value& settings,
494                                               const std::string& policy_name) {
495     const base::Value* policies =
496         settings.FindKeyOfType("policies", base::Value::Type::DICTIONARY);
497     if (!policies)
498       return nullptr;
499     return policies->FindKeyOfType(policy_name, base::Value::Type::DICTIONARY);
500   }
501 
502   // Validates the initial settings value policies structure in the response
503   // matches the print_preview.Policies type in
504   // chrome/browser/resources/print_preview/native_layer.js.
505   // Assumes "test-callback-id-0" was used as the callback id.
ValidateInitialSettingsValuePolicy(const content::TestWebUI::CallData & data,const std::string & policy_name,base::Optional<base::Value> expected_policy_value)506   void ValidateInitialSettingsValuePolicy(
507       const content::TestWebUI::CallData& data,
508       const std::string& policy_name,
509       base::Optional<base::Value> expected_policy_value) {
510     CheckWebUIResponse(data, "test-callback-id-0", true);
511     const base::Value* settings = data.arg3();
512 
513     const base::Value* policy =
514         GetInitialSettingsPolicy(*settings, policy_name);
515     const base::Value* policy_value =
516         policy ? policy->FindKey("value") : nullptr;
517 
518     ASSERT_EQ(expected_policy_value.has_value(), !!policy_value);
519     if (expected_policy_value.has_value())
520       EXPECT_EQ(expected_policy_value.value(), *policy_value);
521   }
522 
523   // Validates the initial settings allowed/default mode policies structure in
524   // the response matches the print_preview.Policies type in
525   // chrome/browser/resources/print_preview/native_layer.js.
526   // Assumes "test-callback-id-0" was used as the callback id.
ValidateInitialSettingsAllowedDefaultModePolicy(const content::TestWebUI::CallData & data,const std::string & policy_name,base::Optional<base::Value> expected_allowed_mode,base::Optional<base::Value> expected_default_mode)527   void ValidateInitialSettingsAllowedDefaultModePolicy(
528       const content::TestWebUI::CallData& data,
529       const std::string& policy_name,
530       base::Optional<base::Value> expected_allowed_mode,
531       base::Optional<base::Value> expected_default_mode) {
532     CheckWebUIResponse(data, "test-callback-id-0", true);
533     const base::Value* settings = data.arg3();
534 
535     const base::Value* policy =
536         GetInitialSettingsPolicy(*settings, policy_name);
537     const base::Value* allowed_mode =
538         policy ? policy->FindKey("allowedMode") : nullptr;
539     const base::Value* default_mode =
540         policy ? policy->FindKey("defaultMode") : nullptr;
541 
542     ASSERT_EQ(expected_allowed_mode.has_value(), !!allowed_mode);
543     if (expected_allowed_mode.has_value())
544       EXPECT_EQ(expected_allowed_mode.value(), *allowed_mode);
545 
546     ASSERT_EQ(expected_default_mode.has_value(), !!default_mode);
547     if (expected_default_mode.has_value())
548       EXPECT_EQ(expected_default_mode.value(), *default_mode);
549   }
550 
551   // Simulates a 'getPrinters' Web UI message by constructing the arguments and
552   // making the call to the handler.
SendGetPrinters(PrinterType type,const std::string & callback_id_in)553   void SendGetPrinters(PrinterType type, const std::string& callback_id_in) {
554     base::Value args(base::Value::Type::LIST);
555     args.Append(callback_id_in);
556     args.Append(static_cast<int>(type));
557     handler()->HandleGetPrinters(&base::Value::AsListValue(args));
558   }
559 
560   // Validates that the printers-added Web UI event has been fired for
561   // |expected-type| with 1 printer. This should be the second most recent call,
562   // as the resolution of the getPrinters() promise will be the most recent.
ValidatePrinterTypeAdded(PrinterType expected_type)563   void ValidatePrinterTypeAdded(PrinterType expected_type) {
564     const size_t call_data_size = web_ui()->call_data().size();
565     ASSERT_GE(call_data_size, 2u);
566     const content::TestWebUI::CallData& add_data =
567         *web_ui()->call_data()[call_data_size - 2];
568     AssertWebUIEventFired(add_data, "printers-added");
569     const auto type = static_cast<PrinterType>(add_data.arg2()->GetInt());
570     EXPECT_EQ(expected_type, type);
571     ASSERT_TRUE(add_data.arg3());
572     base::Value::ConstListView printer_list = add_data.arg3()->GetList();
573     ASSERT_EQ(printer_list.size(), 1u);
574     EXPECT_TRUE(printer_list[0].FindKeyOfType("printer_name",
575                                               base::Value::Type::STRING));
576   }
577 
578   // Simulates a 'getPrinterCapabilities' Web UI message by constructing the
579   // arguments and making the call to the handler.
SendGetPrinterCapabilities(PrinterType type,const std::string & callback_id_in,const std::string & printer_name)580   void SendGetPrinterCapabilities(PrinterType type,
581                                   const std::string& callback_id_in,
582                                   const std::string& printer_name) {
583     base::Value args(base::Value::Type::LIST);
584     args.Append(callback_id_in);
585     args.Append(printer_name);
586     args.Append(static_cast<int>(type));
587     handler()->HandleGetPrinterCapabilities(&base::Value::AsListValue(args));
588   }
589 
590   // Validates that a printer capabilities promise was resolved/rejected.
ValidatePrinterCapabilities(const std::string & callback_id_in,bool expect_resolved)591   void ValidatePrinterCapabilities(const std::string& callback_id_in,
592                                    bool expect_resolved) {
593     const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
594     CheckWebUIResponse(data, callback_id_in, expect_resolved);
595     if (expect_resolved) {
596       const base::Value* settings = data.arg3();
597       ASSERT_TRUE(settings);
598       EXPECT_TRUE(settings->FindKeyOfType(kSettingCapabilities,
599                                           base::Value::Type::DICTIONARY));
600     }
601   }
602 
603   blink::AssociatedInterfaceProvider*
GetInitiatorAssociatedInterfaceProvider()604   GetInitiatorAssociatedInterfaceProvider() {
605     return initiator_web_contents_->GetMainFrame()
606         ->GetRemoteAssociatedInterfaces();
607   }
608 
profile()609   const Profile* profile() { return profile_.get(); }
prefs()610   sync_preferences::TestingPrefServiceSyncable* prefs() {
611     return profile_->GetTestingPrefService();
612   }
web_ui()613   content::TestWebUI* web_ui() { return web_ui_.get(); }
handler()614   TestPrintPreviewHandler* handler() { return handler_; }
printer_handler()615   TestPrinterHandler* printer_handler() { return printer_handler_; }
printers()616   std::vector<PrinterInfo>& printers() { return printers_; }
617 
618  private:
619   content::BrowserTaskEnvironment task_environment_;
620   std::unique_ptr<TestingProfile> profile_;
621   std::unique_ptr<content::TestWebUI> web_ui_;
622   content::RenderViewHostTestEnabler rvh_test_enabler_;
623   std::unique_ptr<content::WebContents> preview_web_contents_;
624   std::unique_ptr<content::WebContents> initiator_web_contents_;
625   std::vector<PrinterInfo> printers_;
626   TestPrinterHandler* printer_handler_;
627   TestPrintPreviewHandler* handler_;
628 
629   DISALLOW_COPY_AND_ASSIGN(PrintPreviewHandlerTest);
630 };
631 
TEST_F(PrintPreviewHandlerTest,InitialSettingsSimple)632 TEST_F(PrintPreviewHandlerTest, InitialSettingsSimple) {
633   Initialize();
634 
635   // Verify initial settings were sent.
636   ValidateInitialSettings(*web_ui()->call_data().back(), kDummyPrinterName,
637                           kDummyInitiatorName);
638 }
639 
TEST_F(PrintPreviewHandlerTest,InitialSettingsHiLocale)640 TEST_F(PrintPreviewHandlerTest, InitialSettingsHiLocale) {
641   InitializeWithLocale("hi");
642 
643   // Verify initial settings were sent for Hindi.
644   ValidateInitialSettingsForLocale(*web_ui()->call_data().back(),
645                                    kDummyPrinterName, kDummyInitiatorName, "hi",
646                                    ",", ".");
647 }
648 
TEST_F(PrintPreviewHandlerTest,InitialSettingsRuLocale)649 TEST_F(PrintPreviewHandlerTest, InitialSettingsRuLocale) {
650   InitializeWithLocale("ru");
651 
652   // Verify initial settings were sent for Russian.
653   ValidateInitialSettingsForLocale(*web_ui()->call_data().back(),
654                                    kDummyPrinterName, kDummyInitiatorName, "ru",
655                                    "\xC2\xA0", ",");
656 }
657 
TEST_F(PrintPreviewHandlerTest,InitialSettingsNoPolicies)658 TEST_F(PrintPreviewHandlerTest, InitialSettingsNoPolicies) {
659   Initialize();
660   ValidateInitialSettingsAllowedDefaultModePolicy(*web_ui()->call_data().back(),
661                                                   "headerFooter", base::nullopt,
662                                                   base::nullopt);
663   ValidateInitialSettingsAllowedDefaultModePolicy(*web_ui()->call_data().back(),
664                                                   "cssBackground",
665                                                   base::nullopt, base::nullopt);
666   ValidateInitialSettingsAllowedDefaultModePolicy(
667       *web_ui()->call_data().back(), "mediaSize", base::nullopt, base::nullopt);
668   ValidateInitialSettingsValuePolicy(*web_ui()->call_data().back(), "sheets",
669                                      base::nullopt);
670 }
671 
TEST_F(PrintPreviewHandlerTest,InitialSettingsRestrictHeaderFooterEnabled)672 TEST_F(PrintPreviewHandlerTest, InitialSettingsRestrictHeaderFooterEnabled) {
673   // Set a pref with allowed value.
674   prefs()->SetManagedPref(prefs::kPrintHeaderFooter,
675                           std::make_unique<base::Value>(true));
676   Initialize();
677   ValidateInitialSettingsAllowedDefaultModePolicy(
678       *web_ui()->call_data().back(), "headerFooter", base::Value(true),
679       base::nullopt);
680 }
681 
TEST_F(PrintPreviewHandlerTest,InitialSettingsRestrictHeaderFooterDisabled)682 TEST_F(PrintPreviewHandlerTest, InitialSettingsRestrictHeaderFooterDisabled) {
683   // Set a pref with allowed value.
684   prefs()->SetManagedPref(prefs::kPrintHeaderFooter,
685                           std::make_unique<base::Value>(false));
686   Initialize();
687   ValidateInitialSettingsAllowedDefaultModePolicy(
688       *web_ui()->call_data().back(), "headerFooter", base::Value(false),
689       base::nullopt);
690 }
691 
TEST_F(PrintPreviewHandlerTest,InitialSettingsEnableHeaderFooter)692 TEST_F(PrintPreviewHandlerTest, InitialSettingsEnableHeaderFooter) {
693   // Set a pref that should take priority over StickySettings.
694   prefs()->SetBoolean(prefs::kPrintHeaderFooter, true);
695   Initialize();
696   ValidateInitialSettingsAllowedDefaultModePolicy(*web_ui()->call_data().back(),
697                                                   "headerFooter", base::nullopt,
698                                                   base::Value(true));
699 }
700 
TEST_F(PrintPreviewHandlerTest,InitialSettingsDisableHeaderFooter)701 TEST_F(PrintPreviewHandlerTest, InitialSettingsDisableHeaderFooter) {
702   // Set a pref that should take priority over StickySettings.
703   prefs()->SetBoolean(prefs::kPrintHeaderFooter, false);
704   Initialize();
705   ValidateInitialSettingsAllowedDefaultModePolicy(*web_ui()->call_data().back(),
706                                                   "headerFooter", base::nullopt,
707                                                   base::Value(false));
708 }
709 
TEST_F(PrintPreviewHandlerTest,InitialSettingsRestrictBackgroundGraphicsEnabled)710 TEST_F(PrintPreviewHandlerTest,
711        InitialSettingsRestrictBackgroundGraphicsEnabled) {
712   // Set a pref with allowed value.
713   prefs()->SetInteger(prefs::kPrintingAllowedBackgroundGraphicsModes, 1);
714   Initialize();
715   ValidateInitialSettingsAllowedDefaultModePolicy(
716       *web_ui()->call_data().back(), "cssBackground", base::Value(1),
717       base::nullopt);
718 }
719 
TEST_F(PrintPreviewHandlerTest,InitialSettingsRestrictBackgroundGraphicsDisabled)720 TEST_F(PrintPreviewHandlerTest,
721        InitialSettingsRestrictBackgroundGraphicsDisabled) {
722   // Set a pref with allowed value.
723   prefs()->SetInteger(prefs::kPrintingAllowedBackgroundGraphicsModes, 2);
724   Initialize();
725   ValidateInitialSettingsAllowedDefaultModePolicy(
726       *web_ui()->call_data().back(), "cssBackground", base::Value(2),
727       base::nullopt);
728 }
729 
TEST_F(PrintPreviewHandlerTest,InitialSettingsEnableBackgroundGraphics)730 TEST_F(PrintPreviewHandlerTest, InitialSettingsEnableBackgroundGraphics) {
731   // Set a pref that should take priority over StickySettings.
732   prefs()->SetInteger(prefs::kPrintingBackgroundGraphicsDefault, 1);
733   Initialize();
734   ValidateInitialSettingsAllowedDefaultModePolicy(
735       *web_ui()->call_data().back(), "cssBackground", base::nullopt,
736       base::Value(1));
737 }
738 
TEST_F(PrintPreviewHandlerTest,InitialSettingsDisableBackgroundGraphics)739 TEST_F(PrintPreviewHandlerTest, InitialSettingsDisableBackgroundGraphics) {
740   // Set a pref that should take priority over StickySettings.
741   prefs()->SetInteger(prefs::kPrintingBackgroundGraphicsDefault, 2);
742   Initialize();
743   ValidateInitialSettingsAllowedDefaultModePolicy(
744       *web_ui()->call_data().back(), "cssBackground", base::nullopt,
745       base::Value(2));
746 }
747 
TEST_F(PrintPreviewHandlerTest,InitialSettingsDefaultPaperSizeName)748 TEST_F(PrintPreviewHandlerTest, InitialSettingsDefaultPaperSizeName) {
749   const char kPrintingPaperSizeDefaultName[] = R"(
750     {
751       "name": "iso_a5_148x210mm"
752     })";
753   const char kExpectedInitialSettingsPolicy[] = R"(
754     {
755       "width": 148000,
756       "height": 210000
757     })";
758 
759   base::Optional<base::Value> default_paper_size =
760       base::JSONReader::Read(kPrintingPaperSizeDefaultName);
761   ASSERT_TRUE(default_paper_size.has_value());
762   // Set a pref that should take priority over StickySettings.
763   prefs()->Set(prefs::kPrintingPaperSizeDefault, default_paper_size.value());
764   Initialize();
765 
766   base::Optional<base::Value> expected_initial_settings_policy =
767       base::JSONReader::Read(kExpectedInitialSettingsPolicy);
768   ASSERT_TRUE(expected_initial_settings_policy.has_value());
769 
770   ValidateInitialSettingsAllowedDefaultModePolicy(
771       *web_ui()->call_data().back(), "mediaSize", base::nullopt,
772       std::move(expected_initial_settings_policy));
773 }
774 
TEST_F(PrintPreviewHandlerTest,InitialSettingsDefaultPaperSizeCustomSize)775 TEST_F(PrintPreviewHandlerTest, InitialSettingsDefaultPaperSizeCustomSize) {
776   const char kPrintingPaperSizeDefaultCustomSize[] = R"(
777     {
778       "name": "custom",
779       "custom_size": {
780         "width": 148000,
781         "height": 210000
782       }
783     })";
784   const char kExpectedInitialSettingsPolicy[] = R"(
785     {
786       "width": 148000,
787       "height": 210000
788     })";
789 
790   base::Optional<base::Value> default_paper_size =
791       base::JSONReader::Read(kPrintingPaperSizeDefaultCustomSize);
792   ASSERT_TRUE(default_paper_size.has_value());
793   // Set a pref that should take priority over StickySettings.
794   prefs()->Set(prefs::kPrintingPaperSizeDefault, default_paper_size.value());
795   Initialize();
796 
797   base::Optional<base::Value> expected_initial_settings_policy =
798       base::JSONReader::Read(kExpectedInitialSettingsPolicy);
799   ASSERT_TRUE(expected_initial_settings_policy.has_value());
800 
801   ValidateInitialSettingsAllowedDefaultModePolicy(
802       *web_ui()->call_data().back(), "mediaSize", base::nullopt,
803       std::move(expected_initial_settings_policy));
804 }
805 
806 #if defined(OS_CHROMEOS)
TEST_F(PrintPreviewHandlerTest,InitialSettingsMaxSheetsAllowedPolicy)807 TEST_F(PrintPreviewHandlerTest, InitialSettingsMaxSheetsAllowedPolicy) {
808   prefs()->SetInteger(prefs::kPrintingMaxSheetsAllowed, 2);
809   Initialize();
810   ValidateInitialSettingsValuePolicy(*web_ui()->call_data().back(), "sheets",
811                                      base::Value(2));
812 }
813 #endif  // defined(OS_CHROMEOS)
814 
TEST_F(PrintPreviewHandlerTest,GetPrinters)815 TEST_F(PrintPreviewHandlerTest, GetPrinters) {
816   Initialize();
817 
818   // Check all three printer types that implement
819   for (size_t i = 0; i < base::size(kFetchableTypes); i++) {
820     PrinterType type = kFetchableTypes[i];
821     std::string callback_id_in =
822         "test-callback-id-" + base::NumberToString(i + 1);
823     handler()->reset_calls();
824     SendGetPrinters(type, callback_id_in);
825 
826     EXPECT_TRUE(handler()->CalledOnlyForType(type));
827 
828     // Start with 1 call from initial settings, then add 2 more for each loop
829     // iteration (one for printers-added, and one for the response).
830     ASSERT_EQ(1u + 2 * (i + 1), web_ui()->call_data().size());
831 
832     ValidatePrinterTypeAdded(type);
833 
834     // Verify getPrinters promise was resolved successfully.
835     const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
836     CheckWebUIResponse(data, callback_id_in, true);
837   }
838 }
839 
840 // Validates the 'printing.printer_type_deny_list' pref by placing the extension
841 // and privet printer types on a deny list. A 'getPrinters' Web UI message is
842 // then called for all three fetchable printer types; only local printers should
843 // be successfully fetched.
TEST_F(PrintPreviewHandlerTest,GetNoDenyListPrinters)844 TEST_F(PrintPreviewHandlerTest, GetNoDenyListPrinters) {
845   base::Value::ListStorage deny_list;
846   deny_list.push_back(base::Value("extension"));
847   deny_list.push_back(base::Value("privet"));
848   prefs()->Set(prefs::kPrinterTypeDenyList, base::Value(std::move(deny_list)));
849   Initialize();
850 
851   size_t expected_callbacks = 1;
852   for (size_t i = 0; i < base::size(kFetchableTypes); i++) {
853     PrinterType type = kFetchableTypes[i];
854     std::string callback_id_in =
855         "test-callback-id-" + base::NumberToString(i + 1);
856     handler()->reset_calls();
857     SendGetPrinters(type, callback_id_in);
858 
859     // Start with 1 call from initial settings, then add 2 more for each printer
860     // type that isn't on the deny list (one for printers-added, and one for the
861     // response), and only 1 more for each type on the deny list (just for
862     // response).
863     const bool is_allowed_type = type == PrinterType::kLocal;
864     EXPECT_EQ(is_allowed_type, handler()->CalledOnlyForType(type));
865     expected_callbacks += is_allowed_type ? 2 : 1;
866     ASSERT_EQ(expected_callbacks, web_ui()->call_data().size());
867 
868     if (is_allowed_type) {
869       ValidatePrinterTypeAdded(type);
870     }
871 
872     // Verify getPrinters promise was resolved successfully.
873     const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
874     CheckWebUIResponse(data, callback_id_in, true);
875   }
876 }
877 
TEST_F(PrintPreviewHandlerTest,GetPrinterCapabilities)878 TEST_F(PrintPreviewHandlerTest, GetPrinterCapabilities) {
879   // Add an empty printer to the handler.
880   printers().push_back(GetEmptyPrinterInfo());
881   printer_handler()->SetPrinters(printers());
882 
883   // Initial settings first to enable javascript.
884   Initialize();
885 
886   // Check all four printer types that implement
887   // PrinterHandler::StartGetCapability().
888   for (size_t i = 0; i < base::size(kAllSupportedTypes); i++) {
889     PrinterType type = kAllSupportedTypes[i];
890     std::string callback_id_in =
891         "test-callback-id-" + base::NumberToString(i + 1);
892     handler()->reset_calls();
893     SendGetPrinterCapabilities(type, callback_id_in, kDummyPrinterName);
894     EXPECT_TRUE(handler()->CalledOnlyForType(type));
895 
896     // Start with 1 call from initial settings, then add 1 more for each loop
897     // iteration.
898     ASSERT_EQ(1u + (i + 1), web_ui()->call_data().size());
899 
900     ValidatePrinterCapabilities(callback_id_in, /*expect_resolved=*/true);
901   }
902 
903   // Run through the loop again, this time with a printer that has no
904   // capabilities.
905   for (size_t i = 0; i < base::size(kAllSupportedTypes); i++) {
906     PrinterType type = kAllSupportedTypes[i];
907     std::string callback_id_in =
908         "test-callback-id-" +
909         base::NumberToString(i + base::size(kAllSupportedTypes) + 1);
910     handler()->reset_calls();
911     SendGetPrinterCapabilities(type, callback_id_in, kEmptyPrinterName);
912     EXPECT_TRUE(handler()->CalledOnlyForType(type));
913 
914     // Start with 1 call from initial settings plus
915     // base::size(kAllSupportedTypes) from first loop, then add 1 more for each
916     // loop iteration.
917     ASSERT_EQ(1u + base::size(kAllSupportedTypes) + (i + 1),
918               web_ui()->call_data().size());
919 
920     ValidatePrinterCapabilities(callback_id_in, /*expect_resolved=*/false);
921   }
922 }
923 
924 // Validates the 'printing.printer_type_deny_list' pref by placing the local and
925 // PDF printer types on the deny list. A 'getPrinterCapabilities' Web UI message
926 // is then called for all supported printer types; only privet and extension
927 // printer capabilties should be successfully fetched.
TEST_F(PrintPreviewHandlerTest,GetNoDenyListPrinterCapabilities)928 TEST_F(PrintPreviewHandlerTest, GetNoDenyListPrinterCapabilities) {
929   base::Value::ListStorage deny_list;
930   deny_list.push_back(base::Value("local"));
931   deny_list.push_back(base::Value("pdf"));
932   prefs()->Set(prefs::kPrinterTypeDenyList, base::Value(std::move(deny_list)));
933   Initialize();
934 
935   // Check all four printer types that implement
936   // PrinterHandler::StartGetCapability().
937   for (size_t i = 0; i < base::size(kAllSupportedTypes); i++) {
938     PrinterType type = kAllSupportedTypes[i];
939     std::string callback_id_in =
940         "test-callback-id-" + base::NumberToString(i + 1);
941     handler()->reset_calls();
942     SendGetPrinterCapabilities(type, callback_id_in, kDummyPrinterName);
943 
944     const bool is_allowed_type =
945         type == PrinterType::kPrivet || type == PrinterType::kExtension;
946     EXPECT_EQ(is_allowed_type, handler()->CalledOnlyForType(type));
947 
948     // Start with 1 call from initial settings, then add 1 more for each loop
949     // iteration.
950     ASSERT_EQ(1u + (i + 1), web_ui()->call_data().size());
951 
952     ValidatePrinterCapabilities(callback_id_in, is_allowed_type);
953   }
954 }
955 
TEST_F(PrintPreviewHandlerTest,Print)956 TEST_F(PrintPreviewHandlerTest, Print) {
957   Initialize();
958 
959   // All printer types can print.
960   for (size_t i = 0; i < base::size(kAllTypes); i++) {
961     base::HistogramTester histograms;
962     handler()->reset_calls();
963 
964     // Send print preview request.
965     base::Value preview_ticket = GetPrintPreviewTicket();
966     preview_ticket.SetIntKey(kPreviewRequestID, i);
967     std::string preview_callback_id =
968         "test-callback-id-" + base::NumberToString(2 * i + 1);
969     std::unique_ptr<base::ListValue> preview_list_args =
970         ConstructPreviewArgs(preview_callback_id, preview_ticket);
971     handler()->HandleGetPreview(preview_list_args.get());
972 
973     // Send printing request.
974     PrinterType type = kAllTypes[i];
975     base::Value print_args(base::Value::Type::LIST);
976     std::string print_callback_id =
977         "test-callback-id-" + base::NumberToString(2 * (i + 1));
978     print_args.Append(print_callback_id);
979     base::Value print_ticket = GetPrintTicket(type);
980     std::string json;
981     base::JSONWriter::Write(print_ticket, &json);
982     print_args.Append(json);
983     std::unique_ptr<base::ListValue> print_list_args = base::ListValue::From(
984         base::Value::ToUniquePtrValue(std::move(print_args)));
985     handler()->HandlePrint(print_list_args.get());
986 
987     CheckHistograms(histograms, type);
988 
989     // Verify correct PrinterHandler was called or that no handler was requested
990     // for cloud printers.
991     if (type == PrinterType::kCloud) {
992       EXPECT_TRUE(handler()->NotCalled());
993     } else {
994       EXPECT_TRUE(handler()->CalledOnlyForType(type));
995     }
996 
997     // Verify print promise was resolved successfully.
998     const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
999     CheckWebUIResponse(data, print_callback_id, true);
1000 
1001     // For cloud print, should also get the encoded data back as a string.
1002     if (type == PrinterType::kCloud) {
1003       std::string print_data;
1004       ASSERT_TRUE(data.arg3()->GetAsString(&print_data));
1005       std::string expected_data;
1006       base::Base64Encode(kTestData, &expected_data);
1007       EXPECT_EQ(print_data, expected_data);
1008     }
1009   }
1010 }
1011 
TEST_F(PrintPreviewHandlerTest,GetPreview)1012 TEST_F(PrintPreviewHandlerTest, GetPreview) {
1013   Initialize();
1014 
1015   base::RunLoop run_loop;
1016   TestPrintPreviewPrintRenderFrame print_render_frame(
1017       GetInitiatorAssociatedInterfaceProvider());
1018   print_render_frame.SetCompletionClosure(run_loop.QuitClosure());
1019 
1020   base::Value print_ticket = GetPrintPreviewTicket();
1021   std::unique_ptr<base::ListValue> list_args =
1022       ConstructPreviewArgs("test-callback-id-1", print_ticket);
1023   handler()->HandleGetPreview(list_args.get());
1024   run_loop.Run();
1025 
1026   // Verify that the preview was requested from the renderer with the
1027   // appropriate settings.
1028   const base::Value& preview_params = print_render_frame.GetSettings();
1029   bool preview_id_found = false;
1030   for (const auto& it : preview_params.DictItems()) {
1031     if (it.first == kPreviewUIID) {  // This is added by the handler.
1032       preview_id_found = true;
1033       continue;
1034     }
1035     const base::Value* value_in = print_ticket.FindKey(it.first);
1036     ASSERT_TRUE(value_in);
1037     EXPECT_EQ(*value_in, it.second);
1038   }
1039   EXPECT_TRUE(preview_id_found);
1040 }
1041 
TEST_F(PrintPreviewHandlerTest,SendPreviewUpdates)1042 TEST_F(PrintPreviewHandlerTest, SendPreviewUpdates) {
1043   Initialize();
1044 
1045   base::RunLoop run_loop;
1046   TestPrintPreviewPrintRenderFrame print_render_frame(
1047       GetInitiatorAssociatedInterfaceProvider());
1048   print_render_frame.SetCompletionClosure(run_loop.QuitClosure());
1049 
1050   const char callback_id_in[] = "test-callback-id-1";
1051   base::Value print_ticket = GetPrintPreviewTicket();
1052   std::unique_ptr<base::ListValue> list_args =
1053       ConstructPreviewArgs(callback_id_in, print_ticket);
1054   handler()->HandleGetPreview(list_args.get());
1055   run_loop.Run();
1056   const base::Value& preview_params = print_render_frame.GetSettings();
1057 
1058   // Read the preview UI ID and request ID
1059   base::Optional<int> request_value =
1060       preview_params.FindIntKey(kPreviewRequestID);
1061   ASSERT_TRUE(request_value.has_value());
1062   int preview_request_id = request_value.value();
1063 
1064   base::Optional<int> ui_value = preview_params.FindIntKey(kPreviewUIID);
1065   ASSERT_TRUE(ui_value.has_value());
1066   int preview_ui_id = ui_value.value();
1067 
1068   // Simulate renderer responses: PageLayoutReady, PageCountReady,
1069   // PagePreviewReady, and OnPrintPreviewReady will be called in that order.
1070   base::Value layout(base::Value::Type::DICTIONARY);
1071   layout.SetDoubleKey(kSettingMarginTop, 34.0);
1072   layout.SetDoubleKey(kSettingMarginLeft, 34.0);
1073   layout.SetDoubleKey(kSettingMarginBottom, 34.0);
1074   layout.SetDoubleKey(kSettingMarginRight, 34.0);
1075   layout.SetDoubleKey(kSettingContentWidth, 544.0);
1076   layout.SetDoubleKey(kSettingContentHeight, 700.0);
1077   layout.SetIntKey(kSettingPrintableAreaX, 17);
1078   layout.SetIntKey(kSettingPrintableAreaY, 17);
1079   layout.SetIntKey(kSettingPrintableAreaWidth, 578);
1080   layout.SetIntKey(kSettingPrintableAreaHeight, 734);
1081   handler()->SendPageLayoutReady(base::Value::AsDictionaryValue(layout),
1082                                  /*has_custom_page_size_style,=*/false,
1083                                  preview_request_id);
1084 
1085   // Verify that page-layout-ready webUI event was fired.
1086   AssertWebUIEventFired(*web_ui()->call_data().back(), "page-layout-ready");
1087 
1088   // 1 page document. Modifiable so send default 100 scaling.
1089   handler()->SendPageCountReady(1, 100, preview_request_id);
1090   AssertWebUIEventFired(*web_ui()->call_data().back(), "page-count-ready");
1091 
1092   // Page at index 0 is ready.
1093   handler()->SendPagePreviewReady(0, preview_ui_id, preview_request_id);
1094   AssertWebUIEventFired(*web_ui()->call_data().back(), "page-preview-ready");
1095 
1096   // Print preview is ready.
1097   handler()->OnPrintPreviewReady(preview_ui_id, preview_request_id);
1098   CheckWebUIResponse(*web_ui()->call_data().back(), callback_id_in, true);
1099 
1100   // Renderer responses have been as expected.
1101   EXPECT_EQ(handler()->bad_messages(), 0);
1102 
1103   // None of these should work since there has been no new preview request.
1104   // Check that there are no new web UI messages sent.
1105   size_t message_count = web_ui()->call_data().size();
1106   handler()->SendPageLayoutReady(base::DictionaryValue(),
1107                                  /*has_custom_page_size_style,=*/false,
1108                                  preview_request_id);
1109   EXPECT_EQ(message_count, web_ui()->call_data().size());
1110   handler()->SendPageCountReady(1, -1, 0);
1111   EXPECT_EQ(message_count, web_ui()->call_data().size());
1112   handler()->OnPrintPreviewReady(0, 0);
1113   EXPECT_EQ(message_count, web_ui()->call_data().size());
1114 
1115   // Handler should have tried to kill the renderer for each of these.
1116   EXPECT_EQ(handler()->bad_messages(), 3);
1117 }
1118 
1119 class FailingTestPrinterHandler : public TestPrinterHandler {
1120  public:
FailingTestPrinterHandler(const std::vector<PrinterInfo> & printers)1121   explicit FailingTestPrinterHandler(const std::vector<PrinterInfo>& printers)
1122       : TestPrinterHandler(printers) {}
1123 
1124   ~FailingTestPrinterHandler() override = default;
1125 
StartGetCapability(const std::string & destination_id,GetCapabilityCallback callback)1126   void StartGetCapability(const std::string& destination_id,
1127                           GetCapabilityCallback callback) override {
1128     std::move(callback).Run(base::Value());
1129   }
1130 
1131  private:
1132   DISALLOW_COPY_AND_ASSIGN(FailingTestPrinterHandler);
1133 };
1134 
1135 class PrintPreviewHandlerFailingTest : public PrintPreviewHandlerTest {
1136  public:
1137   PrintPreviewHandlerFailingTest() = default;
1138   ~PrintPreviewHandlerFailingTest() override = default;
1139 
CreatePrinterHandler(const std::vector<PrinterInfo> & printers)1140   std::unique_ptr<TestPrinterHandler> CreatePrinterHandler(
1141       const std::vector<PrinterInfo>& printers) override {
1142     return std::make_unique<FailingTestPrinterHandler>(printers);
1143   }
1144 
1145  private:
1146   DISALLOW_COPY_AND_ASSIGN(PrintPreviewHandlerFailingTest);
1147 };
1148 
1149 // This test is similar to PrintPreviewHandlerTest.GetPrinterCapabilities, but
1150 // uses FailingTestPrinterHandler instead of TestPrinterHandler. As a result,
1151 // StartGetCapability() always fails, to exercise its callback's failure
1152 // handling path. Failure is different from getting no capabilities.
TEST_F(PrintPreviewHandlerFailingTest,GetPrinterCapabilities)1153 TEST_F(PrintPreviewHandlerFailingTest, GetPrinterCapabilities) {
1154   // Add an empty printer to the handler.
1155   printers().push_back(GetEmptyPrinterInfo());
1156   printer_handler()->SetPrinters(printers());
1157 
1158   // Initial settings first to enable javascript.
1159   Initialize();
1160 
1161   // Check all four printer types that implement
1162   // PrinterHandler::StartGetCapability().
1163   for (size_t i = 0; i < base::size(kAllSupportedTypes); i++) {
1164     PrinterType type = kAllSupportedTypes[i];
1165     handler()->reset_calls();
1166     base::Value args(base::Value::Type::LIST);
1167     std::string callback_id_in =
1168         "test-callback-id-" + base::NumberToString(i + 1);
1169     args.Append(callback_id_in);
1170     args.Append(kDummyPrinterName);
1171     args.Append(static_cast<int>(type));
1172     std::unique_ptr<base::ListValue> list_args =
1173         base::ListValue::From(base::Value::ToUniquePtrValue(std::move(args)));
1174     handler()->HandleGetPrinterCapabilities(list_args.get());
1175     EXPECT_TRUE(handler()->CalledOnlyForType(type));
1176 
1177     // Start with 1 call from initial settings, then add 1 more for each loop
1178     // iteration.
1179     ASSERT_EQ(1u + (i + 1), web_ui()->call_data().size());
1180 
1181     // Verify printer capabilities promise was rejected.
1182     const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
1183     CheckWebUIResponse(data, callback_id_in, false);
1184     const base::Value* settings = data.arg3();
1185     ASSERT_TRUE(settings);
1186     EXPECT_TRUE(settings->is_none());
1187   }
1188 }
1189 
1190 }  // namespace printing
1191