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