1 // Copyright 2016 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 <memory>
6 
7 #include "base/stl_util.h"
8 #include "base/test/values_test_util.h"
9 #include "chrome/browser/ui/webui/print_preview/print_preview_utils.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "ui/gfx/geometry/size.h"
12 
13 namespace printing {
14 
15 namespace {
16 
17 const char kCollate[] = "collate";
18 const char kDisplayName[] = "display_name";
19 const char kDpi[] = "dpi";
20 const char kId[] = "id";
21 const char kIsDefault[] = "is_default";
22 const char kMediaSizes[] = "media_sizes";
23 const char kPagesPerSheet[] = "Pages per sheet";
24 const char kPaperType[] = "Paper Type";
25 const char kPrinter[] = "printer";
26 const char kValue[] = "value";
27 const char kVendorCapability[] = "vendor_capability";
28 
GetCapabilitiesFull()29 base::DictionaryValue GetCapabilitiesFull() {
30   base::DictionaryValue printer;
31 
32   base::Value::ListStorage list_media;
33   list_media.push_back(base::Value("Letter"));
34   list_media.push_back(base::Value("A4"));
35   printer.SetKey(kMediaSizes, base::Value(list_media));
36 
37   base::Value::ListStorage list_dpi;
38   list_dpi.push_back(base::Value(300));
39   list_dpi.push_back(base::Value(600));
40 
41   base::Value options(base::Value::Type::DICTIONARY);
42   options.SetKey(kOptionKey, base::Value(list_dpi));
43   printer.SetKey(kDpi, std::move(options));
44 
45   printer.SetKey(kCollate, base::Value(true));
46 
47   base::Value::ListStorage pages_per_sheet;
48   for (int i = 1; i <= 8; i *= 2) {
49     base::Value option(base::Value::Type::DICTIONARY);
50     option.SetKey(kDisplayName, base::Value(std::to_string(i)));
51     option.SetKey(kValue, base::Value(i));
52     if (i == 1)
53       option.SetKey(kIsDefault, base::Value(true));
54     pages_per_sheet.push_back(std::move(option));
55   }
56   base::Value pages_per_sheet_option(base::Value::Type::DICTIONARY);
57   pages_per_sheet_option.SetKey(kOptionKey, base::Value(pages_per_sheet));
58   base::Value pages_per_sheet_capability(base::Value::Type::DICTIONARY);
59   pages_per_sheet_capability.SetKey(kDisplayName, base::Value(kPagesPerSheet));
60   pages_per_sheet_capability.SetKey(kId, base::Value(kPagesPerSheet));
61   pages_per_sheet_capability.SetKey(kTypeKey, base::Value(kSelectString));
62   pages_per_sheet_capability.SetKey(kSelectCapKey,
63                                     std::move(pages_per_sheet_option));
64 
65   base::Value::ListStorage paper_types;
66   base::Value option1(base::Value::Type::DICTIONARY);
67   option1.SetKey(kDisplayName, base::Value("Plain"));
68   option1.SetKey(kValue, base::Value("Plain"));
69   option1.SetKey(kIsDefault, base::Value(true));
70   base::Value option2(base::Value::Type::DICTIONARY);
71   option2.SetKey(kDisplayName, base::Value("Photo"));
72   option2.SetKey(kValue, base::Value("Photo"));
73   paper_types.push_back(std::move(option1));
74   paper_types.push_back(std::move(option2));
75   base::Value paper_type_option(base::Value::Type::DICTIONARY);
76   paper_type_option.SetKey(kOptionKey, base::Value(paper_types));
77   base::Value paper_type_capability(base::Value::Type::DICTIONARY);
78   paper_type_capability.SetKey(kDisplayName, base::Value(kPaperType));
79   paper_type_capability.SetKey(kId, base::Value(kPaperType));
80   paper_type_capability.SetKey(kTypeKey, base::Value(kSelectString));
81   paper_type_capability.SetKey(kSelectCapKey, std::move(paper_type_option));
82 
83   base::Value::ListStorage vendor_capabilities;
84   vendor_capabilities.push_back(std::move(pages_per_sheet_capability));
85   vendor_capabilities.push_back(std::move(paper_type_capability));
86   printer.SetKey(kVendorCapability, base::Value(vendor_capabilities));
87 
88   return printer;
89 }
90 
ValidList(const base::Value * list)91 base::Value ValidList(const base::Value* list) {
92   auto out_list = list->Clone();
93   out_list.EraseListValueIf([](const base::Value& v) { return v.is_none(); });
94   return out_list;
95 }
96 
HasValidEntry(const base::Value * list)97 bool HasValidEntry(const base::Value* list) {
98   return list && !list->GetList().empty() && !ValidList(list).GetList().empty();
99 }
100 
CompareStringKeys(const base::Value & expected,const base::Value & actual,base::StringPiece key)101 void CompareStringKeys(const base::Value& expected,
102                        const base::Value& actual,
103                        base::StringPiece key) {
104   EXPECT_EQ(*(expected.FindKeyOfType(key, base::Value::Type::STRING)),
105             *(actual.FindKeyOfType(key, base::Value::Type::STRING)));
106 }
107 
ValidateList(const base::Value * list_out,const base::Value * input_list)108 void ValidateList(const base::Value* list_out, const base::Value* input_list) {
109   auto input_list_valid = ValidList(input_list);
110   ASSERT_EQ(list_out->GetList().size(), input_list_valid.GetList().size());
111   for (size_t index = 0; index < list_out->GetList().size(); index++) {
112     EXPECT_EQ(list_out->GetList()[index], input_list_valid.GetList()[index]);
113   }
114 }
115 
ValidateMedia(const base::Value * printer_out,const base::Value * expected_list)116 void ValidateMedia(const base::Value* printer_out,
117                    const base::Value* expected_list) {
118   const base::Value* media_out =
119       printer_out->FindKeyOfType(kMediaSizes, base::Value::Type::LIST);
120   if (!HasValidEntry(expected_list)) {
121     EXPECT_FALSE(media_out);
122     return;
123   }
124   ValidateList(media_out, expected_list);
125 }
126 
ValidateDpi(const base::Value * printer_out,const base::Value * expected_dpi)127 void ValidateDpi(const base::Value* printer_out,
128                  const base::Value* expected_dpi) {
129   const base::Value* dpi_option_out =
130       printer_out->FindKeyOfType(kDpi, base::Value::Type::DICTIONARY);
131   if (!expected_dpi) {
132     EXPECT_FALSE(dpi_option_out);
133     return;
134   }
135   const base::Value* dpi_list =
136       expected_dpi->FindKeyOfType(kOptionKey, base::Value::Type::LIST);
137   if (!HasValidEntry(dpi_list)) {
138     EXPECT_FALSE(dpi_option_out);
139     return;
140   }
141   ASSERT_TRUE(dpi_option_out);
142   const base::Value* dpi_list_out =
143       dpi_option_out->FindKeyOfType(kOptionKey, base::Value::Type::LIST);
144   ASSERT_TRUE(dpi_list_out);
145   ValidateList(dpi_list_out, dpi_list);
146 }
147 
ValidateCollate(const base::Value * printer_out)148 void ValidateCollate(const base::Value* printer_out) {
149   const base::Value* collate_out =
150       printer_out->FindKeyOfType(kCollate, base::Value::Type::BOOLEAN);
151   ASSERT_TRUE(collate_out);
152 }
153 
ValidateVendorCaps(const base::Value * printer_out,const base::Value * input_vendor_caps)154 void ValidateVendorCaps(const base::Value* printer_out,
155                         const base::Value* input_vendor_caps) {
156   const base::Value* vendor_capability_out =
157       printer_out->FindKeyOfType(kVendorCapability, base::Value::Type::LIST);
158   if (!HasValidEntry(input_vendor_caps)) {
159     ASSERT_FALSE(vendor_capability_out);
160     return;
161   }
162 
163   ASSERT_TRUE(vendor_capability_out);
164   size_t index = 0;
165   base::Value::ConstListView output_list = vendor_capability_out->GetList();
166   for (const auto& input_entry : input_vendor_caps->GetList()) {
167     if (!HasValidEntry(
168             input_entry
169                 .FindKeyOfType(kSelectCapKey, base::Value::Type::DICTIONARY)
170                 ->FindKeyOfType(kOptionKey, base::Value::Type::LIST))) {
171       continue;
172     }
173     CompareStringKeys(input_entry, output_list[index], kDisplayName);
174     CompareStringKeys(input_entry, output_list[index], kId);
175     CompareStringKeys(input_entry, output_list[index], kTypeKey);
176     const base::Value* select_cap = output_list[index].FindKeyOfType(
177         kSelectCapKey, base::Value::Type::DICTIONARY);
178     ASSERT_TRUE(select_cap);
179     const base::Value* list =
180         select_cap->FindKeyOfType(kOptionKey, base::Value::Type::LIST);
181     ASSERT_TRUE(list);
182     ValidateList(
183         list,
184         input_entry.FindKeyOfType(kSelectCapKey, base::Value::Type::DICTIONARY)
185             ->FindKeyOfType(kOptionKey, base::Value::Type::LIST));
186     index++;
187   }
188 }
189 
ValidatePrinter(const base::Value * cdd_out,const base::DictionaryValue & printer)190 void ValidatePrinter(const base::Value* cdd_out,
191                      const base::DictionaryValue& printer) {
192   const base::Value* printer_out =
193       cdd_out->FindKeyOfType(kPrinter, base::Value::Type::DICTIONARY);
194   ASSERT_TRUE(printer_out);
195 
196   const base::Value* media =
197       printer.FindKeyOfType(kMediaSizes, base::Value::Type::LIST);
198   ValidateMedia(printer_out, media);
199 
200   const base::Value* dpi_dict =
201       printer.FindKeyOfType(kDpi, base::Value::Type::DICTIONARY);
202   ValidateDpi(printer_out, dpi_dict);
203   ValidateCollate(printer_out);
204 
205   const base::Value* capabilities_list =
206       printer.FindKeyOfType(kVendorCapability, base::Value::Type::LIST);
207   ValidateVendorCaps(printer_out, capabilities_list);
208 }
209 
210 }  // namespace
211 
212 using PrintPreviewUtilsTest = testing::Test;
213 
TEST_F(PrintPreviewUtilsTest,FullCddPassthrough)214 TEST_F(PrintPreviewUtilsTest, FullCddPassthrough) {
215   base::DictionaryValue printer = GetCapabilitiesFull();
216   base::DictionaryValue cdd;
217   cdd.SetKey(kPrinter, printer.Clone());
218   auto cdd_out = ValidateCddForPrintPreview(std::move(cdd));
219   ValidatePrinter(&cdd_out, printer);
220 }
221 
TEST_F(PrintPreviewUtilsTest,FilterBadList)222 TEST_F(PrintPreviewUtilsTest, FilterBadList) {
223   base::DictionaryValue printer = GetCapabilitiesFull();
224   printer.RemoveKey(kMediaSizes);
225   base::Value::ListStorage list_media;
226   list_media.push_back(base::Value());
227   list_media.push_back(base::Value());
228   printer.SetKey(kMediaSizes, base::Value(list_media));
229   base::DictionaryValue cdd;
230   cdd.SetKey(kPrinter, printer.Clone());
231   auto cdd_out = ValidateCddForPrintPreview(std::move(cdd));
232   ValidatePrinter(&cdd_out, printer);
233 }
234 
TEST_F(PrintPreviewUtilsTest,FilterBadOptionOneElement)235 TEST_F(PrintPreviewUtilsTest, FilterBadOptionOneElement) {
236   base::DictionaryValue printer = GetCapabilitiesFull();
237   printer.RemoveKey(kDpi);
238   base::Value options(base::Value::Type::DICTIONARY);
239   base::Value::ListStorage list_dpi;
240   list_dpi.push_back(base::Value());
241   list_dpi.push_back(base::Value(600));
242   options.SetKey(kOptionKey, base::Value(list_dpi));
243   printer.SetKey(kDpi, std::move(options));
244   base::DictionaryValue cdd;
245   cdd.SetKey(kPrinter, printer.Clone());
246   auto cdd_out = ValidateCddForPrintPreview(std::move(cdd));
247   ValidatePrinter(&cdd_out, printer);
248 }
249 
TEST_F(PrintPreviewUtilsTest,FilterBadOptionAllElement)250 TEST_F(PrintPreviewUtilsTest, FilterBadOptionAllElement) {
251   base::DictionaryValue printer = GetCapabilitiesFull();
252   printer.RemoveKey(kDpi);
253   base::Value options(base::Value::Type::DICTIONARY);
254   base::Value::ListStorage list_dpi;
255   list_dpi.push_back(base::Value());
256   list_dpi.push_back(base::Value());
257   options.SetKey(kOptionKey, base::Value(list_dpi));
258   printer.SetKey(kDpi, std::move(options));
259   base::DictionaryValue cdd;
260   cdd.SetKey(kPrinter, printer.Clone());
261   auto cdd_out = ValidateCddForPrintPreview(std::move(cdd));
262   ValidatePrinter(&cdd_out, printer);
263 }
264 
TEST_F(PrintPreviewUtilsTest,FilterBadVendorCapabilityAllElement)265 TEST_F(PrintPreviewUtilsTest, FilterBadVendorCapabilityAllElement) {
266   base::DictionaryValue printer = GetCapabilitiesFull();
267   base::Value* select_cap_0 =
268       printer.FindKeyOfType(kVendorCapability, base::Value::Type::LIST)
269           ->GetList()[0]
270           .FindKeyOfType(kSelectCapKey, base::Value::Type::DICTIONARY);
271   select_cap_0->RemoveKey(kOptionKey);
272   base::Value::ListStorage option_list;
273   option_list.push_back(base::Value());
274   option_list.push_back(base::Value());
275   select_cap_0->SetKey(kOptionKey, base::Value(option_list));
276   base::DictionaryValue cdd;
277   cdd.SetKey(kPrinter, printer.Clone());
278   auto cdd_out = ValidateCddForPrintPreview(std::move(cdd));
279   ValidatePrinter(&cdd_out, printer);
280 }
281 
TEST_F(PrintPreviewUtilsTest,FilterBadVendorCapabilityOneElement)282 TEST_F(PrintPreviewUtilsTest, FilterBadVendorCapabilityOneElement) {
283   base::DictionaryValue printer = GetCapabilitiesFull();
284   base::Value* vendor_dictionary =
285       printer.FindKeyOfType(kVendorCapability, base::Value::Type::LIST)
286           ->GetList()[0]
287           .FindKeyOfType(kSelectCapKey, base::Value::Type::DICTIONARY);
288   vendor_dictionary->RemoveKey(kOptionKey);
289   base::Value::ListStorage pages_per_sheet;
290   for (int i = 1; i <= 8; i *= 2) {
291     if (i == 2) {
292       pages_per_sheet.push_back(base::Value());
293       continue;
294     }
295     base::Value option(base::Value::Type::DICTIONARY);
296     option.SetKey(kDisplayName, base::Value(std::to_string(i)));
297     option.SetKey(kValue, base::Value(i));
298     if (i == 1)
299       option.SetKey(kIsDefault, base::Value(true));
300     pages_per_sheet.push_back(std::move(option));
301   }
302   vendor_dictionary->SetKey(kOptionKey, base::Value(pages_per_sheet));
303 
304   base::DictionaryValue cdd;
305   cdd.SetKey(kPrinter, printer.Clone());
306   auto cdd_out = ValidateCddForPrintPreview(std::move(cdd));
307   ValidatePrinter(&cdd_out, printer);
308 }
309 
310 }  // namespace printing
311