1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.print.cts;
18 
19 import android.os.ParcelFileDescriptor;
20 import android.print.PageRange;
21 import android.print.PrintAttributes;
22 import android.print.PrintAttributes.Margins;
23 import android.print.PrintAttributes.MediaSize;
24 import android.print.PrintAttributes.Resolution;
25 import android.print.PrintDocumentAdapter;
26 import android.print.PrintDocumentAdapter.LayoutResultCallback;
27 import android.print.PrintDocumentAdapter.WriteResultCallback;
28 import android.print.PrintDocumentInfo;
29 import android.print.PrinterCapabilitiesInfo;
30 import android.print.PrinterId;
31 import android.print.PrinterInfo;
32 import android.print.cts.services.FirstPrintService;
33 import android.print.cts.services.PrintServiceCallbacks;
34 import android.print.cts.services.PrinterDiscoverySessionCallbacks;
35 import android.print.cts.services.SecondPrintService;
36 import android.print.cts.services.StubbablePrinterDiscoverySession;
37 import android.printservice.PrintJob;
38 
39 import android.util.Log;
40 import org.mockito.invocation.InvocationOnMock;
41 import org.mockito.stubbing.Answer;
42 
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.List;
46 
47 /**
48  * Test that the print attributes are correctly propagated through the print framework
49  */
50 public class PrintAttributesTest extends BasePrintTest {
51     private static final String LOG_TAG = "PrintAttributesTest";
52     private final String PRINTER_NAME = "Test printer";
53 
54     private final Margins[] MIN_MARGINS = {
55             new Margins(0, 0, 0, 0), new Margins(10, 10, 10, 10), new Margins(20, 20, 20, 20),
56     };
57 
58     private final MediaSize MEDIA_SIZES[] = {
59             MediaSize.ISO_A3, MediaSize.ISO_A4, MediaSize.ISO_A5
60     };
61 
62     private final int COLOR_MODES[] = {
63             PrintAttributes.COLOR_MODE_MONOCHROME, PrintAttributes.COLOR_MODE_COLOR
64     };
65 
66     private final int DUPLEX_MODES[] = {
67             PrintAttributes.DUPLEX_MODE_NONE, PrintAttributes.DUPLEX_MODE_LONG_EDGE,
68             PrintAttributes.DUPLEX_MODE_SHORT_EDGE
69     };
70 
71     private final Resolution RESOLUTIONS[] = {
72             new Resolution("300x300", "300x300", 300, 300),
73             new Resolution("600x600", "600x600", 600, 600),
74             new Resolution("1200x1200", "1200x1200", 1200, 1200)
75     };
76 
77     /**
78      * Stores the {@link PrintAttributes} passed to the layout method
79      */
80     private PrintAttributes mLayoutAttributes;
81 
82     /**
83      * Create a new {@link PrintAttributes} object with the given properties.
84      *
85      * All properties can be null/0 to remain unset.
86      *
87      * @param mediaSize {@link MediaSize} to use
88      * @param colorMode Color mode to use
89      * @param duplexMode Duplex mode to use
90      * @param resolution {@link Resolution} to use
91      *
92      * @return The newly created object or null if no properties are set
93      */
createAttributes(MediaSize mediaSize, int colorMode, int duplexMode, Resolution resolution)94     private PrintAttributes createAttributes(MediaSize mediaSize, int colorMode, int duplexMode,
95             Resolution resolution) {
96         if (mediaSize == null && colorMode == 0 && duplexMode == 0 && resolution == null) {
97             return null;
98         }
99 
100         PrintAttributes.Builder builder = new PrintAttributes.Builder();
101 
102         if (mediaSize != null) {
103             builder.setMediaSize(mediaSize);
104         }
105 
106         if (colorMode != 0) {
107             builder.setColorMode(colorMode);
108         }
109 
110         if (duplexMode != 0) {
111             builder.setDuplexMode(duplexMode);
112         }
113 
114         if (resolution != null) {
115             builder.setResolution(resolution);
116         }
117 
118         return builder.build();
119     }
120 
121     /**
122      * Create {@link PrinterDiscoverySessionCallbacks} with a single printer that has the given
123      * capabilities
124      *
125      * @param minMargins The minMargins of the printer
126      * @param mediaSizes The {@link MediaSize media sizes} supported by the printer
127      * @param defaultMediaSize The default {@link MediaSize}
128      * @param colorModes The color modes supported by the printer
129      * @param defaultColorMode The default color mode
130      * @param duplexModes The duplex modes supported by the printer
131      * @param defaultDuplexMode The default duplex mode
132      * @param resolutions The {@link Resolution resolutions} supported by the printer
133      * @param defaultResolution The default {@link Resolution} to use
134      *
135      * @return New {@link PrinterDiscoverySessionCallbacks} with a single printer that has the
136      *         given capabilities
137      */
createMockPrinterDiscoverySessionCallbacks( final Margins minMargins, final MediaSize mediaSizes[], final MediaSize defaultMediaSize, final int colorModes[], final int defaultColorMode, final int duplexModes[], final int defaultDuplexMode, final Resolution resolutions[], final Resolution defaultResolution)138     private PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
139             final Margins minMargins, final MediaSize mediaSizes[],
140             final MediaSize defaultMediaSize, final int colorModes[], final int defaultColorMode,
141             final int duplexModes[], final int defaultDuplexMode, final Resolution resolutions[],
142             final Resolution defaultResolution) {
143         return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
144             @Override
145             public Void answer(InvocationOnMock invocation) {
146                 StubbablePrinterDiscoverySession session =
147                         ((PrinterDiscoverySessionCallbacks) invocation.getMock()).getSession();
148 
149                 if (session.getPrinters().isEmpty()) {
150                     List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
151                     PrinterId printerId = session.getService().generatePrinterId(PRINTER_NAME);
152 
153                     PrinterCapabilitiesInfo.Builder builder =
154                             new PrinterCapabilitiesInfo.Builder(printerId);
155 
156                     builder.setMinMargins(minMargins);
157 
158                     int mediaSizesLength = mediaSizes.length;
159                     for (int i = 0; i < mediaSizesLength; i++) {
160                         if (mediaSizes[i].equals(defaultMediaSize)) {
161                             builder.addMediaSize(mediaSizes[i], true);
162                         } else {
163                             builder.addMediaSize(mediaSizes[i], false);
164                         }
165                     }
166 
167                     int colorModesMask = 0;
168                     int colorModesLength = colorModes.length;
169                     for (int i = 0; i < colorModesLength; i++) {
170                         colorModesMask |= colorModes[i];
171                     }
172                     builder.setColorModes(colorModesMask, defaultColorMode);
173 
174                     int duplexModesMask = 0;
175                     int duplexModeLength = duplexModes.length;
176                     for (int i = 0; i < duplexModeLength; i++) {
177                         duplexModesMask |= duplexModes[i];
178                     }
179                     builder.setDuplexModes(duplexModesMask, defaultDuplexMode);
180 
181                     int resolutionsLength = resolutions.length;
182                     for (int i = 0; i < resolutionsLength; i++) {
183                         if (resolutions[i].equals(defaultResolution)) {
184                             builder.addResolution(resolutions[i], true);
185                         } else {
186                             builder.addResolution(resolutions[i], false);
187                         }
188                     }
189 
190                     PrinterInfo printer = new PrinterInfo.Builder(printerId, PRINTER_NAME,
191                             PrinterInfo.STATUS_IDLE).setCapabilities(builder.build()).build();
192                     printers.add(printer);
193 
194                     session.addPrinters(printers);
195                 }
196                 return null;
197             }
198         }, null, null, new Answer<Void>() {
199             @Override
200             public Void answer(InvocationOnMock invocation) throws Throwable {
201                 return null;
202             }
203         }, null, null, new Answer<Void>() {
204             @Override
205             public Void answer(InvocationOnMock invocation) throws Throwable {
206                 // Take a note onDestroy was called.
207                 onPrinterDiscoverySessionDestroyCalled();
208                 return null;
209             }
210         });
211     }
212 
213     /**
214      * Create dummy {@link PrintServiceCallbacks}
215      *
216      * This is needed to as the print framework is trying to talk to any printer even if is not set
217      * up.
218      *
219      * @return Dummy {@link PrintServiceCallbacks}
220      */
221     private PrintServiceCallbacks createDummyMockPrintServiceCallbacks() {
222         return createMockPrintServiceCallbacks(null, null, null);
223     }
224 
225     /**
226      * Create a {@link PrintDocumentAdapter} that serves empty pages
227      *
228      * @return A new {@link PrintDocumentAdapter}
229      */
230     private PrintDocumentAdapter createMockPrintDocumentAdapter() {
231         return createMockPrintDocumentAdapter(
232                 new Answer<Void>() {
233                     @Override
234                     public Void answer(InvocationOnMock invocation) throws Throwable {
235                         mLayoutAttributes = (PrintAttributes) invocation.getArguments()[1];
236                         LayoutResultCallback callback =
237                                 (LayoutResultCallback) invocation.getArguments()[3];
238                         PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
239                                 .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
240                                 .setPageCount(1)
241                                 .build();
242                         callback.onLayoutFinished(info, false);
243                         // Mark layout was called.
244                         onLayoutCalled();
245                         return null;
246                     }
247                 }, new Answer<Void>() {
248                     @Override
249                     public Void answer(InvocationOnMock invocation) throws Throwable {
250                         Object[] args = invocation.getArguments();
251                         PageRange[] pages = (PageRange[]) args[0];
252                         ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
253                         WriteResultCallback callback = (WriteResultCallback) args[3];
254                         writeBlankPages(mLayoutAttributes, fd, pages[0].getStart(),
255                                 pages[0].getEnd());
256                         fd.close();
257                         callback.onWriteFinished(pages);
258                         // Mark write was called.
259                         onWriteCalled();
260                         return null;
261                     }
262                 }, new Answer<Void>() {
263                     @Override
264                     public Void answer(InvocationOnMock invocation) throws Throwable {
265                         // Mark finish was called.
266                         onFinishCalled();
267                         return null;
268                     }
269                 });
270     }
271 
272     /**
273      * Set up a single printer with the given capabilities
274      *
275      * @param minMargins The minMargins of the printer
276      * @param mediaSizes The {@link MediaSize media sizes} supported by the printer
277      * @param defaultMediaSize The default {@link MediaSize}
278      * @param colorModes The color modes supported by the printer
279      * @param defaultColorMode The default color mode
280      * @param duplexModes The duplex modes supported by the printer
281      * @param defaultDuplexMode The default duplex mode
282      * @param resolutions The {@link Resolution resolutions} supported by the printer
283      * @param defaultResolution The default {@link Resolution} to use
284      *
285      * @return A {@link PrintDocumentAdapter} that can be used for the new printer
286      */
287     private PrintDocumentAdapter setUpPrinter(Margins minMargins, MediaSize mediaSizes[],
288             MediaSize defaultMediaSize, int colorModes[], int defaultColorMode, int duplexModes[],
289             int defaultDuplexMode, Resolution resolutions[], Resolution defaultResolution) {
290         final PrinterDiscoverySessionCallbacks sessionCallbacks =
291                 createMockPrinterDiscoverySessionCallbacks(minMargins, mediaSizes,
292                         defaultMediaSize, colorModes, defaultColorMode, duplexModes,
293                         defaultDuplexMode, resolutions, defaultResolution);
294 
295         PrintServiceCallbacks serviceCallbacks = createMockPrintServiceCallbacks(
296                 new Answer<PrinterDiscoverySessionCallbacks>() {
297                     @Override
298                     public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
299                         return sessionCallbacks;
300                     }
301                 },
302                 new Answer<Void>() {
303                     @Override
304                     public Void answer(InvocationOnMock invocation) {
305                         PrintJob printJob = (PrintJob) invocation.getArguments()[0];
306                         // We pretend the job is handled immediately.
307                         printJob.complete();
308                         return null;
309                     }
310                 }, null);
311 
312         // Configure the print services.
313         FirstPrintService.setCallbacks(serviceCallbacks);
314 
315         // We need to set up the second print service too, otherwise we get a null pointer in the
316         // print framework
317         SecondPrintService.setCallbacks(createDummyMockPrintServiceCallbacks());
318 
319         // Create a print adapter that respects the print contract.
320         return createMockPrintDocumentAdapter();
321     }
322 
323     /**
324      * Check if a value is in an array.
325      *
326      * To be use instead of Arrays.asList(array).contains(value) for ints.
327      *
328      * @param array The array the value might be in
329      * @param value The value to search for
330      *
331      * @return true iff the value is in the array
332      */
333     private boolean isInArray(final int array[], int value) {
334         int arrayLength = array.length;
335         for (int i = 0; i < arrayLength; i++) {
336             if (array[i] == value) {
337                 return true;
338             }
339         }
340 
341         return false;
342     }
343 
344     /**
345      * Flexible base test for all print attribute tests.
346      *
347      * Asserts that the default and suggested attributes are properly honored by the print
348      * framework.
349      *
350      * @param minMargins The minMargins of the printer
351      * @param mediaSizes The {@link MediaSize media sizes} supported by the printer
352      * @param defaultMediaSize The default {@link MediaSize}
353      * @param colorModes The color modes supported by the printer
354      * @param defaultColorMode The default color mode
355      * @param duplexModes The duplex modes supported by the printer
356      * @param defaultDuplexMode The default duplex mode
357      * @param resolutions The {@link Resolution resolutions} supported by the printer
358      * @param defaultResolution The default {@link Resolution} to use
359      * @param suggestedMediaSize The suggested {@link MediaSize} for the print job
360      * @param suggestedColorMode The suggested color mode for the print job
361      * @param suggestedDuplexMode The suggested duplex mode for the print job
362      * @param suggestedResolution The suggested resolution for the print job
363      *
364      * @throws Exception If anything is unexpected
365      */
366     private void baseTest(Margins minMargins, MediaSize mediaSizes[],
367             MediaSize defaultMediaSize, MediaSize suggestedMediaSize, int colorModes[],
368             int defaultColorMode, int suggestedColorMode, int duplexModes[],
369             int defaultDuplexMode, int suggestedDuplexMode, Resolution resolutions[],
370             Resolution defaultResolution, Resolution suggestedResolution) throws Exception {
371         if (!supportsPrinting()) {
372             return;
373         }
374 
375         // Set up printer with supported and default attributes
376         PrintDocumentAdapter adapter =
377                 setUpPrinter(minMargins, mediaSizes, defaultMediaSize, colorModes, defaultColorMode,
378                         duplexModes, defaultDuplexMode, resolutions, defaultResolution);
379 
380         Log.d(LOG_TAG, "makeDefaultPrinter");
381         // Make printer default. This is necessary as a different default printer might pre-select
382         // its default attributes and thereby overrides the defaults of the tested printer.
383         makeDefaultPrinter(adapter, PRINTER_NAME);
384 
385         // Select suggested attributes
386         PrintAttributes suggestedAttributes = createAttributes(suggestedMediaSize,
387                 suggestedColorMode, suggestedDuplexMode, suggestedResolution);
388 
389         // Start print action and wait for layout, the result is stored in #layoutAttributes,
390         // @see createMockPrintDocumentAdapter
391         Log.d(LOG_TAG, "print");
392         print(adapter, suggestedAttributes);
393         Log.d(LOG_TAG, "waitForWriteAdapterCallback");
394         waitForWriteAdapterCallback(2);
395         Log.d(LOG_TAG, "clickPrintButton");
396         clickPrintButton();
397         Log.d(LOG_TAG, "waitForPrinterDiscoverySessionDestroyCallbackCalled");
398         waitForPrinterDiscoverySessionDestroyCallbackCalled(2);
399 
400         // It does not make sense to suggest minMargins, hence the print framework always picks
401         // the one set up for the printer.
402         assertEquals("Min margins not as expected", minMargins, mLayoutAttributes.getMinMargins());
403 
404         // Verify that the attributes are honored properly
405         if (suggestedMediaSize != null && Arrays.asList(mediaSizes).contains(suggestedMediaSize)) {
406             assertEquals("Media size not as suggested", suggestedMediaSize,
407                     mLayoutAttributes.getMediaSize());
408         } else {
409             assertEquals("Media size not default", defaultMediaSize,
410                     mLayoutAttributes.getMediaSize());
411         }
412 
413         if (suggestedColorMode != 0 && isInArray(colorModes, suggestedColorMode)) {
414             assertEquals("Color mode not as suggested", suggestedColorMode,
415                     mLayoutAttributes.getColorMode());
416         } else {
417             assertEquals("Color mode not default", defaultColorMode,
418                     mLayoutAttributes.getColorMode());
419         }
420 
421         if (suggestedDuplexMode != 0 && isInArray(duplexModes, suggestedDuplexMode)) {
422             assertEquals("Duplex mode not as suggested", suggestedDuplexMode,
423                     mLayoutAttributes.getDuplexMode());
424         } else {
425             assertEquals("Duplex mode not default", defaultDuplexMode,
426                     mLayoutAttributes.getDuplexMode());
427         }
428 
429         if (suggestedResolution != null
430                 && Arrays.asList(resolutions).contains(suggestedResolution)) {
431             assertEquals("Resolution not as suggested", suggestedResolution,
432                     mLayoutAttributes.getResolution());
433         } else {
434             assertEquals("Resolution not default", defaultResolution,
435                     mLayoutAttributes.getResolution());
436         }
437     }
438 
439     /**
440      * Test that attributes are as expected if the default attributes match the suggested ones.
441      *
442      * This test sets the default and suggested attributes to the first selection.
443      *
444      * @throws Exception If anything is unexpected
445      */
446     public void testDefaultMatchesSuggested0() throws Exception {
447         //       available     default          suggestion
448         baseTest(              MIN_MARGINS[0],
449                  MEDIA_SIZES,  MEDIA_SIZES[0],  MEDIA_SIZES[0],
450                  COLOR_MODES,  COLOR_MODES[0],  COLOR_MODES[0],
451                  DUPLEX_MODES, DUPLEX_MODES[0], DUPLEX_MODES[0],
452                  RESOLUTIONS,  RESOLUTIONS[0],  RESOLUTIONS[0]);
453     }
454 
455     /**
456      * Test that attributes are as expected if the default attributes match the suggested ones.
457      *
458      * This test sets the default and suggested attributes to the second selection.
459      *
460      * @throws Exception If anything is unexpected
461      */
462     public void testDefaultMatchesSuggested1() throws Exception {
463         //       available     default          suggestion
464         baseTest(              MIN_MARGINS[1],
465                  MEDIA_SIZES,  MEDIA_SIZES[1],  MEDIA_SIZES[1],
466                  COLOR_MODES,  COLOR_MODES[1],  COLOR_MODES[1],
467                  DUPLEX_MODES, DUPLEX_MODES[1], DUPLEX_MODES[1],
468                  RESOLUTIONS,  RESOLUTIONS[1],  RESOLUTIONS[1]);
469     }
470 
471     /**
472      * Test that attributes are as expected if the default attributes match the suggested ones.
473      *
474      * This test sets the default and suggested attributes to the third selection.
475      *
476      * @throws Exception If anything is unexpected
477      */
478     public void testDefaultMatchesSuggested2() throws Exception {
479         //       available     default          suggestion
480         baseTest(              MIN_MARGINS[2],
481                  MEDIA_SIZES,  MEDIA_SIZES[2],  MEDIA_SIZES[2],
482                  // There are only two color modes, hence pick [1]
483                  COLOR_MODES,  COLOR_MODES[1],  COLOR_MODES[1],
484                  DUPLEX_MODES, DUPLEX_MODES[2], DUPLEX_MODES[2],
485                  RESOLUTIONS,  RESOLUTIONS[2],  RESOLUTIONS[2]);
486     }
487 
488     /**
489      * Test that attributes are as expected if the no suggestion is given.
490      *
491      * This test sets the default attributes to the first selection.
492      *
493      * @throws Exception If anything is unexpected
494      */
495     public void testNoSuggestion0() throws Exception {
496         //       available     default          suggestion
497         baseTest(              MIN_MARGINS[0],
498                  MEDIA_SIZES,  MEDIA_SIZES[0],  null,
499                  COLOR_MODES,  COLOR_MODES[0],  0,
500                  DUPLEX_MODES, DUPLEX_MODES[0], 0,
501                  RESOLUTIONS,  RESOLUTIONS[0],  null);
502     }
503 
504     /**
505      * Test that attributes are as expected if the no suggestion is given.
506      *
507      * This test sets the default attributes to the second selection.
508      *
509      * @throws Exception If anything is unexpected
510      */
511     public void testNoSuggestion1() throws Exception {
512         //       available     default          suggestion
513         baseTest(              MIN_MARGINS[1],
514                  MEDIA_SIZES,  MEDIA_SIZES[1],  null,
515                  COLOR_MODES,  COLOR_MODES[1],  0,
516                  DUPLEX_MODES, DUPLEX_MODES[1], 0,
517                  RESOLUTIONS,  RESOLUTIONS[1],  null);
518     }
519 
520     /**
521      * Test that attributes are as expected if the no suggestion is given.
522      *
523      * This test sets the default attributes to the third selection.
524      *
525      * @throws Exception If anything is unexpected
526      */
527     public void testNoSuggestion2() throws Exception {
528         //       available     default          suggestion
529         baseTest(              MIN_MARGINS[2],
530                  MEDIA_SIZES,  MEDIA_SIZES[2],  null,
531                  // There are only two color modes, hence pick [1]
532                  COLOR_MODES,  COLOR_MODES[1],  0,
533                  DUPLEX_MODES, DUPLEX_MODES[2], 0,
534                  RESOLUTIONS,  RESOLUTIONS[2],  null);
535     }
536 
537     /**
538      * Test that attributes are as expected if only the {@link MediaSize} is suggested.
539      *
540      * This test sets the default attributes to the first selection, but the {@link MediaSize} is
541      * suggested to be the second selection.
542      *
543      * @throws Exception If anything is unexpected
544      */
545     public void testMediaSizeSuggestion0() throws Exception {
546         //       available     default          suggestion
547         baseTest(              MIN_MARGINS[0],
548                  MEDIA_SIZES,  MEDIA_SIZES[0],  MEDIA_SIZES[1],
549                  COLOR_MODES,  COLOR_MODES[0],  0,
550                  DUPLEX_MODES, DUPLEX_MODES[0], 0,
551                  RESOLUTIONS,  RESOLUTIONS[0],  null);
552     }
553 
554     /**
555      * Test that attributes are as expected if only the {@link MediaSize} is suggested.
556      *
557      * This test sets the default attributes to the second selection, but the {@link MediaSize} is
558      * suggested to be the first selection.
559      *
560      * @throws Exception If anything is unexpected
561      */
562     public void testMediaSizeSuggestion1() throws Exception {
563         //       available     default          suggestion
564         baseTest(              MIN_MARGINS[1],
565                  MEDIA_SIZES,  MEDIA_SIZES[1],  MEDIA_SIZES[0],
566                  COLOR_MODES,  COLOR_MODES[1],  0,
567                  DUPLEX_MODES, DUPLEX_MODES[1], 0,
568                  RESOLUTIONS,  RESOLUTIONS[1],  null);
569     }
570 
571     /**
572      * Test that attributes are as expected if only the duplex mode is suggested.
573      *
574      * This test sets the default attributes to the first selection, but the duplex mode is
575      * suggested to be the second selection.
576      *
577      * @throws Exception If anything is unexpected
578      */
579     public void testDuplexModeSuggestion0() throws Exception {
580         //       available     default          suggestion
581         baseTest(              MIN_MARGINS[0],
582                  MEDIA_SIZES,  MEDIA_SIZES[0],  null,
583                  COLOR_MODES,  COLOR_MODES[0],  0,
584                  DUPLEX_MODES, DUPLEX_MODES[0], DUPLEX_MODES[1],
585                  RESOLUTIONS,  RESOLUTIONS[0],  null);
586     }
587 
588     /**
589      * Test that attributes are as expected if only the duplex mode is suggested.
590      *
591      * This test sets the default attributes to the second selection, but the duplex mode is
592      * suggested to be the first selection.
593      *
594      * @throws Exception If anything is unexpected
595      */
596     public void testDuplexModeSuggestion1() throws Exception {
597         //       available     default          suggestion
598         baseTest(              MIN_MARGINS[1],
599                  MEDIA_SIZES,  MEDIA_SIZES[1],  null,
600                  COLOR_MODES,  COLOR_MODES[1],  0,
601                  DUPLEX_MODES, DUPLEX_MODES[1], DUPLEX_MODES[0],
602                  RESOLUTIONS,  RESOLUTIONS[1],  null);
603     }
604 
605     /**
606      * Test that attributes are as expected if all attributes are suggested and different from the
607      * default attributes.
608      *
609      * @throws Exception If anything is unexpected
610      */
611     public void testSuggestedDifferentFromDefault() throws Exception {
612         //       available     default          suggestion
613         baseTest(              MIN_MARGINS[0],
614                  MEDIA_SIZES,  MEDIA_SIZES[0],  MEDIA_SIZES[1],
615                  COLOR_MODES,  COLOR_MODES[0],  COLOR_MODES[1],
616                  DUPLEX_MODES, DUPLEX_MODES[0], DUPLEX_MODES[1],
617                  RESOLUTIONS,  RESOLUTIONS[0],  RESOLUTIONS[1]);
618     }
619 
620     /**
621      * Test that attributes are as expected if all attributes are suggested but all of them are not
622      * supported by the printer.
623      *
624      * @throws Exception If anything is unexpected
625      */
626     public void testUnsupportedSuggested() throws Exception {
627         //       available                               default          suggestion
628         baseTest(                                        MIN_MARGINS[0],
629                  Arrays.copyOfRange(MEDIA_SIZES, 0, 1),  MEDIA_SIZES[0],  MEDIA_SIZES[1],
630                  Arrays.copyOfRange(COLOR_MODES, 0, 1),  COLOR_MODES[0],  COLOR_MODES[1],
631                  Arrays.copyOfRange(DUPLEX_MODES, 0, 1), DUPLEX_MODES[0], DUPLEX_MODES[1],
632                  Arrays.copyOfRange(RESOLUTIONS, 0, 1),  RESOLUTIONS[0],  RESOLUTIONS[1]);
633     }
634 
635     /**
636      * Test that negative Margins do not cause issues in the print print spooler. Negative margins
637      * are allowed because of historical reasons.
638      *
639      * @throws Exception If anything is unexpected
640      */
641     public void testNegativeMargins() throws Exception {
642         //       available     default                          suggestion
643         baseTest(              new Margins(-10, -10, -10, -10),
644                  MEDIA_SIZES,  MEDIA_SIZES[1],                  null,
645                  COLOR_MODES,  COLOR_MODES[1],                  0,
646                  DUPLEX_MODES, DUPLEX_MODES[1],                 0,
647                  RESOLUTIONS,  RESOLUTIONS[1],                  null);
648     }
649 }
650