1 // Copyright (c) 2012 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 "printing/backend/cups_helper.h"
6 
7 #include "base/strings/stringprintf.h"
8 #include "build/build_config.h"
9 #include "printing/backend/print_backend.h"
10 #include "printing/mojom/print.mojom.h"
11 #include "printing/print_settings.h"
12 #include "printing/printing_utils.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 
16 namespace printing {
17 
18 namespace {
19 
20 // Returns true if the papers have the same name, vendor ID, and size.
PapersEqual(const PrinterSemanticCapsAndDefaults::Paper & lhs,const PrinterSemanticCapsAndDefaults::Paper & rhs)21 bool PapersEqual(const PrinterSemanticCapsAndDefaults::Paper& lhs,
22                  const PrinterSemanticCapsAndDefaults::Paper& rhs) {
23   return lhs.display_name == rhs.display_name &&
24          lhs.vendor_id == rhs.vendor_id && lhs.size_um == rhs.size_um;
25 }
26 
VerifyCapabilityColorModels(const PrinterSemanticCapsAndDefaults & caps)27 void VerifyCapabilityColorModels(const PrinterSemanticCapsAndDefaults& caps) {
28   base::Optional<bool> maybe_color = IsColorModelSelected(caps.color_model);
29   ASSERT_TRUE(maybe_color.has_value());
30   EXPECT_TRUE(maybe_color.value());
31   maybe_color = IsColorModelSelected(caps.bw_model);
32   ASSERT_TRUE(maybe_color.has_value());
33   EXPECT_FALSE(maybe_color.value());
34 }
35 
GeneratePpdResolutionTestData(const char * res_name)36 std::string GeneratePpdResolutionTestData(const char* res_name) {
37   return base::StringPrintf(R"(*PPD-Adobe: 4.3
38 *OpenUI *%1$s/%1$s: PickOne
39 *%1$s 600dpi/600 dpi: " "
40 *Default%1$s: 600dpi
41 *CloseUI: *%1$s)",
42                             res_name);
43 }
44 
45 }  // namespace
46 
TEST(PrintBackendCupsHelperTest,TestPpdParsingNoColorDuplexShortEdge)47 TEST(PrintBackendCupsHelperTest, TestPpdParsingNoColorDuplexShortEdge) {
48   constexpr char kTestPpdData[] =
49       R"(*PPD-Adobe: "4.3"
50 *OpenGroup: General/General
51 *OpenUI *ColorModel/Color Model: PickOne
52 *DefaultColorModel: Gray
53 *ColorModel Gray/Grayscale: "
54   <</cupsColorSpace 0/cupsColorOrder 0>>setpagedevice"
55 *ColorModel Black/Inverted Grayscale: "
56   <</cupsColorSpace 3/cupsColorOrder 0>>setpagedevice"
57 *CloseUI: *ColorModel
58 *OpenUI *Duplex/2-Sided Printing: PickOne
59 *DefaultDuplex: DuplexTumble
60 *Duplex None/Off: "
61   <</Duplex false>>setpagedevice"
62 *Duplex DuplexNoTumble/LongEdge: "
63   </Duplex true/Tumble false>>setpagedevice"
64 *Duplex DuplexTumble/ShortEdge: "
65   <</Duplex true/Tumble true>>setpagedevice"
66 *CloseUI: *Duplex
67 *CloseGroup: General)";
68 
69   PrinterSemanticCapsAndDefaults caps;
70   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
71                                    kTestPpdData, &caps));
72   EXPECT_TRUE(caps.collate_capable);
73   EXPECT_TRUE(caps.collate_default);
74   EXPECT_EQ(caps.copies_max, 9999);
75   EXPECT_THAT(caps.duplex_modes,
76               testing::UnorderedElementsAre(mojom::DuplexMode::kSimplex,
77                                             mojom::DuplexMode::kLongEdge,
78                                             mojom::DuplexMode::kShortEdge));
79   EXPECT_EQ(mojom::DuplexMode::kShortEdge, caps.duplex_default);
80   EXPECT_FALSE(caps.color_changeable);
81   EXPECT_FALSE(caps.color_default);
82 }
83 
84 // Test duplex detection code, which regressed in http://crbug.com/103999.
TEST(PrintBackendCupsHelperTest,TestPpdParsingNoColorDuplexSimples)85 TEST(PrintBackendCupsHelperTest, TestPpdParsingNoColorDuplexSimples) {
86   constexpr char kTestPpdData[] =
87       R"(*PPD-Adobe: "4.3"
88 *OpenGroup: General/General
89 *OpenUI *Duplex/Double-Sided Printing: PickOne
90 *DefaultDuplex: None
91 *Duplex None/Off: "
92   <</Duplex false>>setpagedevice"
93 *Duplex DuplexNoTumble/Long Edge (Standard): "
94   <</Duplex true/Tumble false>>setpagedevice"
95 *Duplex DuplexTumble/Short Edge (Flip): "
96   <</Duplex true/Tumble true>>setpagedevice"
97 *CloseUI: *Duplex
98 *CloseGroup: General)";
99 
100   PrinterSemanticCapsAndDefaults caps;
101   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
102                                    kTestPpdData, &caps));
103   EXPECT_TRUE(caps.collate_capable);
104   EXPECT_TRUE(caps.collate_default);
105   EXPECT_EQ(caps.copies_max, 9999);
106   EXPECT_THAT(caps.duplex_modes,
107               testing::UnorderedElementsAre(mojom::DuplexMode::kSimplex,
108                                             mojom::DuplexMode::kLongEdge,
109                                             mojom::DuplexMode::kShortEdge));
110   EXPECT_EQ(mojom::DuplexMode::kSimplex, caps.duplex_default);
111   EXPECT_FALSE(caps.color_changeable);
112   EXPECT_FALSE(caps.color_default);
113 }
114 
TEST(PrintBackendCupsHelperTest,TestPpdParsingNoColorNoDuplex)115 TEST(PrintBackendCupsHelperTest, TestPpdParsingNoColorNoDuplex) {
116   constexpr char kTestPpdData[] =
117       R"(*PPD-Adobe: "4.3"
118 *OpenGroup: General/General
119 *OpenUI *ColorModel/Color Model: PickOne
120 *DefaultColorModel: Gray
121 *ColorModel Gray/Grayscale: "
122   <</cupsColorSpace 0/cupsColorOrder 0>>setpagedevice"
123 *ColorModel Black/Inverted Grayscale: "
124   <</cupsColorSpace 3/cupsColorOrder 0>>setpagedevice"
125 *CloseUI: *ColorModel
126 *CloseGroup: General)";
127 
128   PrinterSemanticCapsAndDefaults caps;
129   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
130                                    kTestPpdData, &caps));
131   EXPECT_TRUE(caps.collate_capable);
132   EXPECT_TRUE(caps.collate_default);
133   EXPECT_EQ(caps.copies_max, 9999);
134   EXPECT_THAT(caps.duplex_modes, testing::UnorderedElementsAre());
135   EXPECT_EQ(mojom::DuplexMode::kUnknownDuplexMode, caps.duplex_default);
136   EXPECT_FALSE(caps.color_changeable);
137   EXPECT_FALSE(caps.color_default);
138 }
139 
TEST(PrintBackendCupsHelperTest,TestPpdParsingColorTrueDuplexShortEdge)140 TEST(PrintBackendCupsHelperTest, TestPpdParsingColorTrueDuplexShortEdge) {
141   constexpr char kTestPpdData[] =
142       R"(*PPD-Adobe: "4.3"
143 *ColorDevice: True
144 *DefaultColorSpace: CMYK
145 *OpenGroup: General/General
146 *OpenUI *ColorModel/Color Model: PickOne
147 *DefaultColorModel: CMYK
148 *ColorModel CMYK/Color: "(cmyk) RCsetdevicecolor"
149 *ColorModel Gray/Black and White: "(gray) RCsetdevicecolor"
150 *CloseUI: *ColorModel
151 *OpenUI *Duplex/2-Sided Printing: PickOne
152 *DefaultDuplex: DuplexTumble
153 *Duplex None/Off: "
154   <</Duplex false>>setpagedevice"
155 *Duplex DuplexNoTumble/LongEdge: "
156   <</Duplex true/Tumble false>>setpagedevice"
157 *Duplex DuplexTumble/ShortEdge: "
158   <</Duplex true/Tumble true>>setpagedevice"
159 *CloseUI: *Duplex
160 *CloseGroup: General)";
161 
162   PrinterSemanticCapsAndDefaults caps;
163   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
164                                    kTestPpdData, &caps));
165   EXPECT_TRUE(caps.collate_capable);
166   EXPECT_TRUE(caps.collate_default);
167   EXPECT_EQ(caps.copies_max, 9999);
168   EXPECT_THAT(caps.duplex_modes,
169               testing::UnorderedElementsAre(mojom::DuplexMode::kSimplex,
170                                             mojom::DuplexMode::kLongEdge,
171                                             mojom::DuplexMode::kShortEdge));
172   EXPECT_EQ(mojom::DuplexMode::kShortEdge, caps.duplex_default);
173   EXPECT_TRUE(caps.color_changeable);
174   EXPECT_TRUE(caps.color_default);
175 }
176 
TEST(PrintBackendCupsHelperTest,TestPpdParsingColorFalseDuplexLongEdge)177 TEST(PrintBackendCupsHelperTest, TestPpdParsingColorFalseDuplexLongEdge) {
178   constexpr char kTestPpdData[] =
179       R"(*PPD-Adobe: "4.3"
180 *ColorDevice: True
181 *DefaultColorSpace: CMYK
182 *OpenGroup: General/General
183 *OpenUI *ColorModel/Color Model: PickOne
184 *DefaultColorModel: Grayscale
185 *ColorModel Color/Color: "
186   %% FoomaticRIPOptionSetting: ColorModel=Color"
187 *FoomaticRIPOptionSetting ColorModel=Color: "
188   JCLDatamode=Color GSCmdLine=Color"
189 *ColorModel Grayscale/Grayscale: "
190   %% FoomaticRIPOptionSetting: ColorModel=Grayscale"
191 *FoomaticRIPOptionSetting ColorModel=Grayscale: "
192   JCLDatamode=Grayscale GSCmdLine=Grayscale"
193 *CloseUI: *ColorModel
194 *OpenUI *Duplex/2-Sided Printing: PickOne
195 *DefaultDuplex: DuplexNoTumble
196 *Duplex None/Off: "
197   <</Duplex false>>setpagedevice"
198 *Duplex DuplexNoTumble/LongEdge: "
199   <</Duplex true/Tumble false>>setpagedevice"
200 *Duplex DuplexTumble/ShortEdge: "
201   <</Duplex true/Tumble true>>setpagedevice"
202 *CloseUI: *Duplex
203 *CloseGroup: General)";
204 
205   PrinterSemanticCapsAndDefaults caps;
206   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
207                                    kTestPpdData, &caps));
208   EXPECT_TRUE(caps.collate_capable);
209   EXPECT_TRUE(caps.collate_default);
210   EXPECT_EQ(caps.copies_max, 9999);
211   EXPECT_THAT(caps.duplex_modes,
212               testing::UnorderedElementsAre(mojom::DuplexMode::kSimplex,
213                                             mojom::DuplexMode::kLongEdge,
214                                             mojom::DuplexMode::kShortEdge));
215   EXPECT_EQ(mojom::DuplexMode::kLongEdge, caps.duplex_default);
216   EXPECT_TRUE(caps.color_changeable);
217   EXPECT_FALSE(caps.color_default);
218 }
219 
TEST(PrintBackendCupsHelperTest,TestPpdParsingPageSize)220 TEST(PrintBackendCupsHelperTest, TestPpdParsingPageSize) {
221   constexpr char kTestPpdData[] =
222       R"(*PPD-Adobe: "4.3"
223 *OpenUI *PageSize: PickOne
224 *DefaultPageSize: Legal
225 *PageSize Letter/US Letter: "
226   <</DeferredMediaSelection true /PageSize [612 792]
227   /ImagingBBox null /MediaClass null >> setpagedevice"
228 *End
229 *PageSize Legal/US Legal: "
230   <</DeferredMediaSelection true /PageSize [612 1008]
231   /ImagingBBox null /MediaClass null >> setpagedevice"
232 *End
233 *DefaultPaperDimension: Legal
234 *PaperDimension Letter/US Letter: "612   792"
235 *PaperDimension Legal/US Legal: "612  1008"
236 *CloseUI: *PageSize)";
237 
238   PrinterSemanticCapsAndDefaults caps;
239   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
240                                    kTestPpdData, &caps));
241   ASSERT_EQ(2UL, caps.papers.size());
242   EXPECT_EQ("Letter", caps.papers[0].vendor_id);
243   EXPECT_EQ("US Letter", caps.papers[0].display_name);
244   EXPECT_EQ(215900, caps.papers[0].size_um.width());
245   EXPECT_EQ(279400, caps.papers[0].size_um.height());
246   EXPECT_EQ("Legal", caps.papers[1].vendor_id);
247   EXPECT_EQ("US Legal", caps.papers[1].display_name);
248   EXPECT_EQ(215900, caps.papers[1].size_um.width());
249   EXPECT_EQ(355600, caps.papers[1].size_um.height());
250   EXPECT_TRUE(PapersEqual(caps.papers[1], caps.default_paper));
251 }
252 
TEST(PrintBackendCupsHelperTest,TestPpdParsingPageSizeNoDefaultSpecified)253 TEST(PrintBackendCupsHelperTest, TestPpdParsingPageSizeNoDefaultSpecified) {
254   constexpr char kTestPpdData[] =
255       R"(*PPD-Adobe: "4.3"
256 *OpenUI *PageSize: PickOne
257 *PageSize A3/ISO A3: "
258   << /DeferredMediaSelection true /PageSize [842 1191]
259   /ImagingBBox null >> setpagedevice"
260 *End
261 *PageSize A4/ISO A4: "
262   << /DeferredMediaSelection true /PageSize [595 842]
263   /ImagingBBox null >> setpagedevice"
264 *End
265 *PageSize Legal/US Legal: "
266   << /DeferredMediaSelection true /PageSize [612 1008]
267   /ImagingBBox null >> setpagedevice"
268 *End
269 *PageSize Letter/US Letter: "
270   << /DeferredMediaSelection true /PageSize [612 792]
271   /ImagingBBox null >> setpagedevice"
272 *End
273 *PaperDimension A3/ISO A3: "842 1191"
274 *PaperDimension A4/ISO A4: "595 842"
275 *PaperDimension Legal/US Legal: "612 1008"
276 *PaperDimension Letter/US Letter: "612 792"
277 *CloseUI: *PageSize)";
278 
279   {
280     PrinterSemanticCapsAndDefaults caps;
281     EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"en-US",
282                                      kTestPpdData, &caps));
283     ASSERT_EQ(4UL, caps.papers.size());
284     EXPECT_EQ("Letter", caps.papers[3].vendor_id);
285     EXPECT_EQ("US Letter", caps.papers[3].display_name);
286     EXPECT_EQ(215900, caps.papers[3].size_um.width());
287     EXPECT_EQ(279400, caps.papers[3].size_um.height());
288     EXPECT_TRUE(PapersEqual(caps.papers[3], caps.default_paper));
289   }
290   {
291     PrinterSemanticCapsAndDefaults caps;
292     EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"en-UK",
293                                      kTestPpdData, &caps));
294     ASSERT_EQ(4UL, caps.papers.size());
295     EXPECT_EQ("A4", caps.papers[1].vendor_id);
296     EXPECT_EQ("ISO A4", caps.papers[1].display_name);
297     EXPECT_EQ(209903, caps.papers[1].size_um.width());
298     EXPECT_EQ(297039, caps.papers[1].size_um.height());
299     EXPECT_TRUE(PapersEqual(caps.papers[1], caps.default_paper));
300   }
301 }
302 
TEST(PrintBackendCupsHelperTest,TestPpdParsingBrotherPrinters)303 TEST(PrintBackendCupsHelperTest, TestPpdParsingBrotherPrinters) {
304   {
305     constexpr char kTestPpdData[] =
306         R"(*PPD-Adobe: "4.3"
307 *ColorDevice: True
308 *OpenUI *BRPrintQuality/Color/Mono: PickOne
309 *DefaultBRPrintQuality: Auto
310 *BRPrintQuality Auto/Auto: ""
311 *BRPrintQuality Color/Color: ""
312 *BRPrintQuality Black/Mono: ""
313 *CloseUI: *BRPrintQuality)";
314 
315     PrinterSemanticCapsAndDefaults caps;
316     EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
317                                      kTestPpdData, &caps));
318     EXPECT_TRUE(caps.color_changeable);
319     EXPECT_TRUE(caps.color_default);
320     EXPECT_EQ(mojom::ColorModel::kBrotherBRScript3Color, caps.color_model);
321     EXPECT_EQ(mojom::ColorModel::kBrotherBRScript3Black, caps.bw_model);
322     VerifyCapabilityColorModels(caps);
323   }
324   {
325     constexpr char kTestPpdData[] =
326         R"(*PPD-Adobe: "4.3"
327 *ColorDevice: True
328 *OpenUI *BRMonoColor/Color / Mono: PickOne
329 *DefaultBRMonoColor: Auto
330 *BRMonoColor Auto/Auto: ""
331 *BRMonoColor FullColor/Color: ""
332 *BRMonoColor Mono/Mono: ""
333 *CloseUI: *BRMonoColor)";
334 
335     PrinterSemanticCapsAndDefaults caps;
336     EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
337                                      kTestPpdData, &caps));
338     EXPECT_TRUE(caps.color_changeable);
339     EXPECT_TRUE(caps.color_default);
340     EXPECT_EQ(mojom::ColorModel::kBrotherCUPSColor, caps.color_model);
341     EXPECT_EQ(mojom::ColorModel::kBrotherCUPSMono, caps.bw_model);
342     VerifyCapabilityColorModels(caps);
343   }
344   {
345     constexpr char kTestPpdData[] =
346         R"(*PPD-Adobe: "4.3"
347 *ColorDevice: True
348 *OpenUI *BRDuplex/Two-Sided Printing: PickOne
349 *DefaultBRDuplex: DuplexTumble
350 *BRDuplex DuplexTumble/Short-Edge Binding: ""
351 *BRDuplex DuplexNoTumble/Long-Edge Binding: ""
352 *BRDuplex None/Off: ""
353 *CloseUI: *BRDuplex)";
354 
355     PrinterSemanticCapsAndDefaults caps;
356     EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
357                                      kTestPpdData, &caps));
358     EXPECT_THAT(caps.duplex_modes,
359                 testing::UnorderedElementsAre(mojom::DuplexMode::kSimplex,
360                                               mojom::DuplexMode::kLongEdge,
361                                               mojom::DuplexMode::kShortEdge));
362     EXPECT_EQ(mojom::DuplexMode::kShortEdge, caps.duplex_default);
363   }
364 }
365 
TEST(PrintBackendCupsHelperTest,TestPpdParsingHpPrinters)366 TEST(PrintBackendCupsHelperTest, TestPpdParsingHpPrinters) {
367   constexpr char kTestPpdData[] =
368       R"(*PPD-Adobe: "4.3"
369 *ColorDevice: True
370 *OpenUI *HPColorMode/Mode: PickOne
371 *DefaultHPColorMode: ColorPrint
372 *HPColorMode ColorPrint/Color: "
373   << /ProcessColorModel /DeviceCMYK >> setpagedevice"
374 *HPColorMode GrayscalePrint/Grayscale: "
375   << /ProcessColorModel /DeviceGray >> setpagedevice"
376 *CloseUI: *HPColorMode)";
377 
378   PrinterSemanticCapsAndDefaults caps;
379   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
380                                    kTestPpdData, &caps));
381   EXPECT_TRUE(caps.color_changeable);
382   EXPECT_TRUE(caps.color_default);
383   EXPECT_EQ(mojom::ColorModel::kHPColorColor, caps.color_model);
384   EXPECT_EQ(mojom::ColorModel::kHPColorBlack, caps.bw_model);
385   VerifyCapabilityColorModels(caps);
386 }
387 
TEST(PrintBackendCupsHelperTest,TestPpdParsingEpsonPrinters)388 TEST(PrintBackendCupsHelperTest, TestPpdParsingEpsonPrinters) {
389   constexpr char kTestPpdData[] =
390       R"(*PPD-Adobe: "4.3"
391 *ColorDevice: True
392 *OpenUI *Ink/Ink: PickOne
393 *DefaultInk: COLOR
394 *Ink COLOR/Color: "
395   <</cupsBitsPerColor 8 /cupsColorOrder 0
396   /cupsColorSpace 1 /cupsCompression 1>> setpagedevice"
397 *Ink MONO/Monochrome: "
398   <</cupsBitsPerColor 8 /cupsColorOrder 0
399   /cupsColorSpace 0 /cupsCompression 1>> setpagedevice"
400 *CloseUI: *Ink)";
401 
402   PrinterSemanticCapsAndDefaults caps;
403   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
404                                    kTestPpdData, &caps));
405   EXPECT_TRUE(caps.color_changeable);
406   EXPECT_TRUE(caps.color_default);
407   EXPECT_EQ(mojom::ColorModel::kEpsonInkColor, caps.color_model);
408   EXPECT_EQ(mojom::ColorModel::kEpsonInkMono, caps.bw_model);
409   VerifyCapabilityColorModels(caps);
410 }
411 
TEST(PrintBackendCupsHelperTest,TestPpdParsingSamsungPrinters)412 TEST(PrintBackendCupsHelperTest, TestPpdParsingSamsungPrinters) {
413   constexpr char kTestPpdData[] =
414       R"(*PPD-Adobe: "4.3"
415 *ColorDevice: True
416 *OpenUI *ColorMode/Color Mode:  Boolean
417 *DefaultColorMode: True
418 *ColorMode False/Grayscale: ""
419 *ColorMode True/Color: ""
420 *CloseUI: *ColorMode)";
421 
422   PrinterSemanticCapsAndDefaults caps;
423   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
424                                    kTestPpdData, &caps));
425   EXPECT_TRUE(caps.color_changeable);
426   EXPECT_TRUE(caps.color_default);
427   EXPECT_EQ(mojom::ColorModel::kColorModeColor, caps.color_model);
428   EXPECT_EQ(mojom::ColorModel::kColorModeMonochrome, caps.bw_model);
429   VerifyCapabilityColorModels(caps);
430 }
431 
TEST(PrintBackendCupsHelperTest,TestPpdParsingSharpPrinters)432 TEST(PrintBackendCupsHelperTest, TestPpdParsingSharpPrinters) {
433   constexpr char kTestPpdData[] =
434       R"(*PPD-Adobe: "4.3"
435 *ColorDevice: True
436 *OpenUI *ARCMode/Color Mode: PickOne
437 *OrderDependency: 180 AnySetup *ARCMode
438 *DefaultARCMode: CMAuto
439 *ARCMode CMAuto/Automatic: ""
440 *End
441 *ARCMode CMColor/Color: ""
442 *End
443 *ARCMode CMBW/Black and White: ""
444 *End
445 *CloseUI: *ARCMode)";
446 
447   PrinterSemanticCapsAndDefaults caps;
448   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
449                                    kTestPpdData, &caps));
450   EXPECT_TRUE(caps.color_changeable);
451   EXPECT_TRUE(caps.color_default);
452   EXPECT_EQ(mojom::ColorModel::kSharpARCModeCMColor, caps.color_model);
453   EXPECT_EQ(mojom::ColorModel::kSharpARCModeCMBW, caps.bw_model);
454   VerifyCapabilityColorModels(caps);
455 }
456 
TEST(PrintBackendCupsHelperTest,TestPpdParsingXeroxPrinters)457 TEST(PrintBackendCupsHelperTest, TestPpdParsingXeroxPrinters) {
458   constexpr char kTestPpdData[] =
459       R"(*PPD-Adobe: "4.3"
460 *ColorDevice: True
461 *OpenUI *XRXColor/Color Correction: PickOne
462 *OrderDependency: 48.0 AnySetup *XRXColor
463 *DefaultXRXColor: Automatic
464 *XRXColor Automatic/Automatic: "
465   <</ProcessColorModel /DeviceCMYK>> setpagedevice"
466 *XRXColor BW/Black and White:  "
467   <</ProcessColorModel /DeviceGray>> setpagedevice"
468 *CloseUI: *XRXColor)";
469 
470   PrinterSemanticCapsAndDefaults caps;
471   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
472                                    kTestPpdData, &caps));
473   EXPECT_TRUE(caps.color_changeable);
474   EXPECT_TRUE(caps.color_default);
475   EXPECT_EQ(mojom::ColorModel::kXeroxXRXColorAutomatic, caps.color_model);
476   EXPECT_EQ(mojom::ColorModel::kXeroxXRXColorBW, caps.bw_model);
477   VerifyCapabilityColorModels(caps);
478 }
479 
TEST(PrintBackendCupsHelperTest,TestPpdParsingCupsMaxCopies)480 TEST(PrintBackendCupsHelperTest, TestPpdParsingCupsMaxCopies) {
481   {
482     constexpr char kTestPpdData[] =
483         R"(*PPD-Adobe: "4.3"
484 *cupsMaxCopies: 99
485 *OpenUI *ColorMode/Color Mode:  Boolean
486 *DefaultColorMode: True
487 *CloseUI: *ColorMode)";
488 
489     PrinterSemanticCapsAndDefaults caps;
490     EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
491                                      kTestPpdData, &caps));
492     EXPECT_EQ(99, caps.copies_max);
493   }
494 
495   {
496     constexpr char kTestPpdData[] =
497         R"(*PPD-Adobe: "4.3"
498 *cupsMaxCopies: notavalidnumber
499 *OpenUI *ColorMode/Color Mode:  Boolean
500 *DefaultColorMode: True
501 *CloseUI: *ColorMode)";
502 
503     PrinterSemanticCapsAndDefaults caps;
504     EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
505                                      kTestPpdData, &caps));
506     EXPECT_EQ(9999, caps.copies_max);
507   }
508 }
509 
TEST(PrintBackendCupsHelperTest,TestPpdParsingResolutionTagNames)510 TEST(PrintBackendCupsHelperTest, TestPpdParsingResolutionTagNames) {
511   constexpr const char* kTestResNames[] = {"Resolution",     "JCLResolution",
512                                            "SetResolution",  "CNRes_PGP",
513                                            "HPPrintQuality", "LXResolution"};
514   const std::vector<gfx::Size> kExpectedResolutions = {gfx::Size(600, 600)};
515   PrinterSemanticCapsAndDefaults caps;
516   for (const char* res_name : kTestResNames) {
517     EXPECT_TRUE(ParsePpdCapabilities(
518         /*dest=*/nullptr, /*locale=*/"",
519         GeneratePpdResolutionTestData(res_name).c_str(), &caps));
520     EXPECT_EQ(kExpectedResolutions, caps.dpis);
521     EXPECT_EQ(kExpectedResolutions[0], caps.default_dpi);
522   }
523 }
524 
TEST(PrintBackendCupsHelperTest,TestPpdParsingResolutionInvalidDefaultResolution)525 TEST(PrintBackendCupsHelperTest,
526      TestPpdParsingResolutionInvalidDefaultResolution) {
527   constexpr char kTestPpdData[] =
528       R"(*PPD-Adobe: "4.3"
529 *OpenUI *Resolution/Resolution: PickOne
530 *DefaultResolution: 500dpi
531 *Resolution 600dpi/600 dpi: ""
532 *CloseUI: *Resolution)";
533 
534   PrinterSemanticCapsAndDefaults caps;
535   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
536                                    kTestPpdData, &caps));
537   EXPECT_EQ(std::vector<gfx::Size>{gfx::Size(600, 600)}, caps.dpis);
538   EXPECT_TRUE(caps.default_dpi.IsEmpty());
539 }
540 
TEST(PrintBackendCupsHelperTest,TestPpdParsingResolutionNoResolution)541 TEST(PrintBackendCupsHelperTest, TestPpdParsingResolutionNoResolution) {
542   constexpr char kTestPpdData[] =
543       R"(*PPD-Adobe: "4.3"
544 *OpenUI *Resolution/Resolution: PickOne
545 *CloseUI: *Resolution)";
546 
547   PrinterSemanticCapsAndDefaults caps;
548   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
549                                    kTestPpdData, &caps));
550   EXPECT_TRUE(caps.dpis.empty());
551   EXPECT_TRUE(caps.default_dpi.IsEmpty());
552   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
553                                    "*PPD-Adobe: \"4.3\"", &caps));
554   EXPECT_TRUE(caps.dpis.empty());
555   EXPECT_TRUE(caps.default_dpi.IsEmpty());
556 }
557 
TEST(PrintBackendCupsHelperTest,TestPpdParsingResolutionNoDefaultResolution)558 TEST(PrintBackendCupsHelperTest, TestPpdParsingResolutionNoDefaultResolution) {
559   constexpr char kTestPpdData[] =
560       R"(*PPD-Adobe: "4.3"
561 *OpenUI *Resolution/Resolution: PickOne
562 *Resolution 600dpi/600 dpi: ""
563 *CloseUI: *Resolution)";
564 
565   PrinterSemanticCapsAndDefaults caps;
566   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
567                                    kTestPpdData, &caps));
568   EXPECT_EQ(std::vector<gfx::Size>{gfx::Size(600, 600)}, caps.dpis);
569   EXPECT_TRUE(caps.default_dpi.IsEmpty());
570 }
571 
TEST(PrintBackendCupsHelperTest,TestPpdParsingResolutionDpiFormat)572 TEST(PrintBackendCupsHelperTest, TestPpdParsingResolutionDpiFormat) {
573   constexpr char kTestPpdData[] =
574       R"(*PPD-Adobe: "4.3"
575 *JCLOpenUI *Resolution/Resolution: PickOne
576 *OrderDependency: 100 JCLSetup *Resolution
577 *DefaultResolution: 600dpi
578 *Resolution 500x500dpi/500 dpi: " "
579 *Resolution 0.5dpi/0.5 dpi: " "
580 *Resolution 5.0dpi/5 dpi: " "
581 *Resolution 600dpi/600 dpi: " "
582 *Resolution 0dpi/0 dpi: " "
583 *Resolution 1e1dpi/10 dpi: " "
584 *Resolution -3dpi/-3 dpi: " "
585 *Resolution -3x300dpi/dpi: " "
586 *Resolution 300x0dpi/dpi: " "
587 *Resolution 50/50: " "
588 *Resolution 50dpis/50 dpis: " "
589 *Resolution 30x30dpis/30 dpis: " "
590 *Resolution 2400x600dpi/HQ1200: " "
591 *JCLCloseUI: *Resolution)";
592 
593   const std::vector<gfx::Size> kExpectedResolutions = {
594       gfx::Size(500, 500), gfx::Size(600, 600), gfx::Size(2400, 600)};
595   PrinterSemanticCapsAndDefaults caps;
596   EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
597                                    kTestPpdData, &caps));
598   EXPECT_EQ(kExpectedResolutions, caps.dpis);
599   EXPECT_EQ(kExpectedResolutions[1], caps.default_dpi);
600 }
601 
TEST(PrintBackendCupsHelperTest,TestPpdSetsDestOptions)602 TEST(PrintBackendCupsHelperTest, TestPpdSetsDestOptions) {
603   constexpr char kTestPpdData[] =
604       R"(*PPD-Adobe: "4.3"
605 *OpenUI *Duplex/2-Sided Printing: PickOne
606 *DefaultDuplex: DuplexTumble
607 *Duplex None/Off: "
608   <</Duplex false>>setpagedevice"
609 *Duplex DuplexNoTumble/LongEdge: "
610   </Duplex true/Tumble false>>setpagedevice"
611 *Duplex DuplexTumble/ShortEdge: "
612   <</Duplex true/Tumble true>>setpagedevice"
613 *CloseUI: *Duplex)";
614 
615   cups_dest_t* dest;
616   int num_dests = 0;
617   num_dests =
618       cupsAddDest(/*name=*/"test_dest", /*instance=*/nullptr, num_dests, &dest);
619   ASSERT_EQ(1, num_dests);
620 
621   // Set long edge duplex mode in the destination options even though the PPD
622   // sets short edge duplex mode as the default.
623   cups_option_t* options = nullptr;
624   int num_options = 0;
625   num_options =
626       cupsAddOption("Duplex", "DuplexNoTumble", num_options, &options);
627   dest->num_options = num_options;
628   dest->options = options;
629 
630   PrinterSemanticCapsAndDefaults caps;
631   EXPECT_TRUE(ParsePpdCapabilities(dest, /*locale=*/"", kTestPpdData, &caps));
632   EXPECT_THAT(caps.duplex_modes,
633               testing::UnorderedElementsAre(mojom::DuplexMode::kSimplex,
634                                             mojom::DuplexMode::kLongEdge,
635                                             mojom::DuplexMode::kShortEdge));
636   EXPECT_EQ(mojom::DuplexMode::kLongEdge, caps.duplex_default);
637 
638   cupsFreeDests(num_dests, dest);
639 }
640 
641 }  // namespace printing
642