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