1 /*
2  * Copyright 2014 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.hardware.camera2.cts.helpers;
18 
19 import android.graphics.Rect;
20 import android.hardware.camera2.CameraCharacteristics;
21 import android.hardware.camera2.CaptureRequest;
22 import android.hardware.camera2.CaptureRequest.Builder;
23 import android.hardware.camera2.CaptureResult;
24 import android.hardware.camera2.params.MeteringRectangle;
25 import android.media.Image;
26 import android.util.Log;
27 import android.util.Size;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Objects;
33 import java.util.Set;
34 import org.hamcrest.CoreMatchers;
35 import org.hamcrest.Matcher;
36 import org.junit.rules.ErrorCollector;
37 
38 /**
39  * A camera test ErrorCollector class to gather the test failures during a test,
40  * instead of failing the test immediately for each failure.
41  */
42 public class CameraErrorCollector extends ErrorCollector {
43 
44     private static final String TAG = "CameraErrorCollector";
45     private static final boolean LOG_ERRORS = Log.isLoggable(TAG, Log.ERROR);
46 
47     private String mCameraMsg = "";
48 
49     @Override
verify()50     public void verify() throws Throwable {
51         // Do not remove if using JUnit 3 test runners. super.verify() is protected.
52         super.verify();
53     }
54 
55     /**
56      * Adds an unconditional error to the table.
57      *
58      * <p>Execution continues, but test will fail at the end.</p>
59      *
60      * @param message A string containing the failure reason.
61      */
addMessage(String message)62     public void addMessage(String message) {
63         addErrorSuper(new Throwable(mCameraMsg + message));
64     }
65 
66     /**
67      * Adds a Throwable to the table. <p>Execution continues, but the test will fail at the end.</p>
68      */
69     @Override
addError(Throwable error)70     public void addError(Throwable error) {
71         addErrorSuper(new Throwable(mCameraMsg + error.getMessage(), error));
72     }
73 
addErrorSuper(Throwable error)74     private void addErrorSuper(Throwable error) {
75         if (LOG_ERRORS) Log.e(TAG, error.getMessage());
76         super.addError(error);
77     }
78 
79     /**
80      * Adds a failure to the table if {@code matcher} does not match {@code value}.
81      * Execution continues, but the test will fail at the end if the match fails.
82      * The camera id is included into the failure log.
83      */
84     @Override
checkThat(final T value, final Matcher<T> matcher)85     public <T> void checkThat(final T value, final Matcher<T> matcher) {
86         super.checkThat(mCameraMsg, value, matcher);
87     }
88 
89     /**
90      * Adds a failure with the given {@code reason} to the table if
91      * {@code matcher} does not match {@code value}. Execution continues, but
92      * the test will fail at the end if the match fails. The camera id is
93      * included into the failure log.
94      */
95     @Override
checkThat(final String reason, final T value, final Matcher<T> matcher)96     public <T> void checkThat(final String reason, final T value, final Matcher<T> matcher) {
97         super.checkThat(mCameraMsg + reason, value, matcher);
98     }
99 
100     /**
101      * Set the camera id to this error collector object for logging purpose.
102      *
103      * @param id The camera id to be set.
104      */
setCameraId(String id)105     public void setCameraId(String id) {
106         if (id != null) {
107             mCameraMsg = "Test failed for camera " + id + ": ";
108         } else {
109             mCameraMsg = "";
110         }
111     }
112 
113     /**
114      * Adds a failure to the table if {@code condition} is not {@code true}.
115      * <p>
116      * Execution continues, but the test will fail at the end if the condition
117      * failed.
118      * </p>
119      *
120      * @param msg Message to be logged when check fails.
121      * @param condition Log the failure if it is not true.
122      */
expectTrue(String msg, boolean condition)123     public boolean expectTrue(String msg, boolean condition) {
124         if (!condition) {
125             addMessage(msg);
126         }
127 
128         return condition;
129     }
130 
131     /**
132      * Check if the two values are equal.
133      *
134      * @param msg Message to be logged when check fails.
135      * @param expected Expected value to be checked against.
136      * @param actual Actual value to be checked.
137      * @return {@code true} if the two values are equal, {@code false} otherwise.
138      *
139      * @throws IllegalArgumentException if {@code expected} was {@code null}
140      */
expectEquals(String msg, T expected, T actual)141     public <T> boolean expectEquals(String msg, T expected, T actual) {
142         if (expected == null) {
143             throw new IllegalArgumentException("expected value shouldn't be null");
144         }
145 
146         if (!Objects.equals(expected, actual)) {
147             addMessage(String.format("%s (expected = %s, actual = %s) ", msg, expected,
148                     actual));
149             return false;
150         }
151 
152         return true;
153     }
154 
155     /**
156      * Check if the two values are not equal.
157      *
158      * @param msg Message to be logged when check fails.
159      * @param expected Expected value to be checked against.
160      * @param actual Actual value to be checked.
161      * @return {@code true} if the two values are not equal, {@code false} otherwise.
162      */
expectNotEquals(String msg, T expected, T actual)163     public <T> boolean expectNotEquals(String msg, T expected, T actual) {
164         if (Objects.equals(expected, actual)) {
165             addMessage(String.format("%s (expected = %s, actual = %s) ", msg, expected,
166                     actual));
167             return false;
168         }
169 
170         return true;
171     }
172 
173     /**
174      * Check if the two arrays of values are deeply equal.
175      *
176      * @param msg Message to be logged when check fails.
177      * @param expected Expected array of values to be checked against.
178      * @param actual Actual array of values to be checked.
179      * @return {@code true} if the two arrays of values are deeply equal, {@code false} otherwise.
180      *
181      * @throws IllegalArgumentException if {@code expected} was {@code null}
182      */
expectEquals(String msg, T[] expected, T[] actual)183     public <T> boolean expectEquals(String msg, T[] expected, T[] actual) {
184         if (expected == null) {
185             throw new IllegalArgumentException("expected value shouldn't be null");
186         }
187 
188         if (!Arrays.deepEquals(expected, actual)) {
189             addMessage(String.format("%s (expected = %s, actual = %s) ", msg,
190                     Arrays.deepToString(expected), Arrays.deepToString(actual)));
191             return false;
192         }
193 
194         return true;
195     }
196 
197     /**
198      * Check if the two arrays of values are not deeply equal.
199      *
200      * @param msg Message to be logged when check fails.
201      * @param expected Expected array of values to be checked against.
202      * @param actual Actual array of values to be checked.
203      * @return {@code true} if the two arrays of values are not deeply equal, {@code false}
204      *          otherwise.
205      *
206      * @throws IllegalArgumentException if {@code expected} was {@code null}
207      */
expectNotEquals(String msg, T[] expected, T[] actual)208     public <T> boolean expectNotEquals(String msg, T[] expected, T[] actual) {
209         if (expected == null) {
210             throw new IllegalArgumentException("expected value shouldn't be null");
211         }
212 
213         if (Arrays.deepEquals(expected, actual)) {
214             addMessage(String.format("%s (expected = %s, actual = %s) ", msg,
215                     Arrays.deepToString(expected), Arrays.deepToString(actual)));
216             return false;
217         }
218 
219         return true;
220     }
221 
222     /**
223      * Check that the {@code actual} value is greater than the {@code expected} value.
224      *
225      * @param msg Message to be logged when check fails.
226      * @param expected The expected value to check that the actual value is larger than.
227      * @param actual Actual value to check.
228      * @return {@code true} if {@code actual} is greater than {@code expected}.
229      */
expectGreater(String msg, T expected, T actual)230     public <T extends Comparable<? super T>> boolean expectGreater(String msg, T expected,
231             T actual) {
232         return expectTrue(String.format("%s: (expected = %s was not greater than actual = %s) ",
233                 msg, expected, actual), actual.compareTo(expected) > 0);
234     }
235 
236     /**
237      * Check that the {@code actual} value is greater than or equal to the {@code expected} value.
238      *
239      * @param msg Message to be logged when check fails.
240      * @param expected The expected value to check that the actual value is larger than or equal to.
241      * @param actual Actual value to check.
242      * @return {@code true} if {@code actual} is greater than or equal to {@code expected}.
243      */
expectGreaterOrEqual(String msg, T expected, T actual)244     public <T extends Comparable<? super T>> boolean expectGreaterOrEqual(String msg, T expected,
245                                                                        T actual) {
246         return expectTrue(String.format("%s: (expected = %s was not greater than actual = %s) ",
247                 msg, expected, actual), actual.compareTo(expected) >= 0);
248     }
249 
250     /**
251      * Check that the {@code actual} value is less than the {@code expected} value.
252      *
253      * @param msg Message to be logged when check fails.
254      * @param expected The expected value to check that the actual value is less than.
255      * @param actual Actual value to check.
256      * @return {@code true} if {@code actual} is less than {@code expected}.
257      */
expectLess(String msg, T expected, T actual)258     public <T extends Comparable<? super T>> boolean expectLess(String msg, T expected,
259             T actual) {
260         return expectTrue(String.format("%s: (expected = %s was not greater than actual = %s) ",
261                 msg, expected, actual), actual.compareTo(expected) < 0);
262     }
263 
264     /**
265      * Check that the {@code actual} value is less than or equal to the {@code expected} value.
266      *
267      * @param msg Message to be logged when check fails.
268      * @param expected The expected value to check that the actual value is less than or equal to.
269      * @param actual Actual value to check.
270      * @return {@code true} if {@code actual} is less than or equal to {@code expected}.
271      */
expectLessOrEqual(String msg, T expected, T actual)272     public <T extends Comparable<? super T>> boolean expectLessOrEqual(String msg, T expected,
273             T actual) {
274         return expectTrue(String.format("%s: (expected = %s was not greater than actual = %s) ",
275                 msg, expected, actual), actual.compareTo(expected) <= 0);
276     }
277 
278     /**
279      * Check if the two float values are equal with given error tolerance.
280      *
281      * @param msg Message to be logged when check fails.
282      * @param expected Expected value to be checked against.
283      * @param actual Actual value to be checked.
284      * @param tolerance The error margin for the equality check.
285      * @return {@code true} if the two values are equal, {@code false} otherwise.
286      */
expectEquals(String msg, float expected, float actual, float tolerance)287     public <T> boolean expectEquals(String msg, float expected, float actual, float tolerance) {
288         if (expected == actual) {
289             return true;
290         }
291 
292         if (!(Math.abs(expected - actual) <= tolerance)) {
293             addMessage(String.format("%s (expected = %s, actual = %s, tolerance = %s) ", msg,
294                     expected, actual, tolerance));
295             return false;
296         }
297 
298         return true;
299     }
300 
301     /**
302      * Check if the two double values are equal with given error tolerance.
303      *
304      * @param msg Message to be logged when check fails.
305      * @param expected Expected value to be checked against.
306      * @param actual Actual value to be checked.
307      * @param tolerance The error margin for the equality check
308      * @return {@code true} if the two values are equal, {@code false} otherwise.
309      */
expectEquals(String msg, double expected, double actual, double tolerance)310     public <T> boolean expectEquals(String msg, double expected, double actual, double tolerance) {
311         if (expected == actual) {
312             return true;
313         }
314 
315         if (!(Math.abs(expected - actual) <= tolerance)) {
316             addMessage(String.format("%s (expected = %s, actual = %s, tolerance = %s) ", msg,
317                     expected, actual, tolerance));
318             return false;
319         }
320 
321         return true;
322     }
323 
324     /**
325      * Check that all values in the list are greater than or equal to the min value.
326      *
327      * @param msg Message to be logged when check fails
328      * @param list The list of values to be checked
329      * @param min The smallest allowed value
330      */
expectValuesGreaterOrEqual(String msg, List<T> list, T min)331     public <T extends Comparable<? super T>> void expectValuesGreaterOrEqual(String msg,
332             List<T> list, T min) {
333         for (T value : list) {
334             expectTrue(msg + String.format(", array value " + value.toString() +
335                                     " is less than %s",
336                             min.toString()), value.compareTo(min) >= 0);
337         }
338     }
339 
340     /**
341      * Check that all values in the array are greater than or equal to the min value.
342      *
343      * @param msg Message to be logged when check fails
344      * @param array The array of values to be checked
345      * @param min The smallest allowed value
346      */
expectValuesGreaterOrEqual(String msg, T[] array, T min)347     public <T extends Comparable<? super T>> void expectValuesGreaterOrEqual(String msg,
348                                                                              T[] array, T min) {
349         expectValuesGreaterOrEqual(msg, Arrays.asList(array), min);
350     }
351 
352     /**
353      * Expect the list of values are in the range.
354      *
355      * @param msg Message to be logged
356      * @param list The list of values to be checked
357      * @param min The min value of the range
358      * @param max The max value of the range
359      */
expectValuesInRange(String msg, List<T> list, T min, T max)360     public <T extends Comparable<? super T>> void expectValuesInRange(String msg, List<T> list,
361             T min, T max) {
362         for (T value : list) {
363             expectTrue(msg + String.format(", array value " + value.toString() +
364                     " is out of range [%s, %s]",
365                     min.toString(), max.toString()),
366                     value.compareTo(max)<= 0 && value.compareTo(min) >= 0);
367         }
368     }
369 
370     /**
371      * Expect the array of values are in the range.
372      *
373      * @param msg Message to be logged
374      * @param array The array of values to be checked
375      * @param min The min value of the range
376      * @param max The max value of the range
377      */
expectValuesInRange(String msg, T[] array, T min, T max)378     public <T extends Comparable<? super T>> void expectValuesInRange(String msg, T[] array,
379             T min, T max) {
380         expectValuesInRange(msg, Arrays.asList(array), min, max);
381     }
382 
383     /**
384      * Expect the array of values are in the range.
385      *
386      * @param msg Message to be logged
387      * @param array The array of values to be checked
388      * @param min The min value of the range
389      * @param max The max value of the range
390      */
expectValuesInRange(String msg, int[] array, int min, int max)391     public void expectValuesInRange(String msg, int[] array, int min, int max) {
392         ArrayList<Integer> l = new ArrayList<>(array.length);
393         for (int i : array) {
394             l.add(i);
395         }
396         expectValuesInRange(msg, l, min, max);
397     }
398 
399     /**
400      * Expect the value is in the range.
401      *
402      * @param msg Message to be logged
403      * @param value The value to be checked
404      * @param min The min value of the range
405      * @param max The max value of the range
406      *
407      * @return {@code true} if the value was in range, {@code false} otherwise
408      */
expectInRange(String msg, T value, T min, T max)409     public <T extends Comparable<? super T>> boolean expectInRange(String msg, T value,
410             T min, T max) {
411         return expectTrue(msg + String.format(", value " + value.toString()
412                 + " is out of range [%s, %s]",
413                 min.toString(), max.toString()),
414                 value.compareTo(max)<= 0 && value.compareTo(min) >= 0);
415     }
416 
417 
418     /**
419      * Check that two metering region arrays are similar enough by ensuring that each of their width,
420      * height, and all corners are within {@code errorPercent} of each other.
421      *
422      * <p>Note that the length of the arrays must be the same, and each weight must be the same
423      * as well. We assume the order is also equivalent.</p>
424      *
425      * <p>At most 1 error per each dissimilar metering region is collected.</p>
426      *
427      * @param msg Message to be logged
428      * @param expected The reference 'expected' values to be used to check against
429      * @param actual The actual values that were received
430      * @param errorPercent Within how many percent the components should be
431      *
432      * @return {@code true} if all expects passed, {@code false} otherwise
433      */
expectMeteringRegionsAreSimilar(String msg, MeteringRectangle[] expected, MeteringRectangle[] actual, float errorPercent)434     public boolean expectMeteringRegionsAreSimilar(String msg,
435             MeteringRectangle[] expected, MeteringRectangle[] actual,
436             float errorPercent) {
437         String expectedActualMsg = String.format("expected (%s), actual (%s)",
438                 Arrays.deepToString(expected), Arrays.deepToString(actual));
439 
440         String differentSizesMsg = String.format(
441                 "%s: rect lists are different sizes; %s",
442                 msg, expectedActualMsg);
443 
444         String differentWeightsMsg = String.format(
445                 "%s: rect weights are different; %s",
446                 msg, expectedActualMsg);
447 
448         if (!expectTrue(differentSizesMsg, actual != null)) {
449             return false;
450         }
451 
452         if (!expectEquals(differentSizesMsg, expected.length, actual.length)) return false;
453 
454         boolean succ = true;
455         for (int i = 0; i < expected.length; ++i) {
456             if (i < actual.length) {
457                 // Avoid printing multiple errors for the same rectangle
458                 if (!expectRectsAreSimilar(
459                         msg, expected[i].getRect(), actual[i].getRect(), errorPercent)) {
460                     succ = false;
461                     continue;
462                 }
463                 if (!expectEquals(differentWeightsMsg,
464                         expected[i].getMeteringWeight(), actual[i].getMeteringWeight())) {
465                     succ = false;
466                     continue;
467                 }
468             }
469         }
470 
471         return succ;
472     }
473 
474     /**
475      * Check that two rectangles are similar enough by ensuring that their width, height,
476      * and all corners are within {@code errorPercent} of each other.
477      *
478      * <p>Only the first error is collected, to avoid spamming several error messages when
479      * the rectangle is hugely dissimilar.</p>
480      *
481      * @param msg Message to be logged
482      * @param expected The reference 'expected' value to be used to check against
483      * @param actual The actual value that was received
484      * @param errorPercent Within how many percent the components should be
485      *
486      * @return {@code true} if all expects passed, {@code false} otherwise
487      */
expectRectsAreSimilar(String msg, Rect expected, Rect actual, float errorPercent)488     public boolean expectRectsAreSimilar(String msg, Rect expected, Rect actual,
489             float errorPercent) {
490         String formattedMsg = String.format("%s: rects are not similar enough; expected (%s), " +
491                 "actual (%s), error percent (%s), reason: ",
492                 msg, expected, actual, errorPercent);
493 
494         if (!expectSimilarValues(
495                 formattedMsg, "too wide", "too narrow", actual.width(), expected.width(),
496                 errorPercent)) return false;
497 
498         if (!expectSimilarValues(
499                 formattedMsg, "too tall", "too short", actual.height(), expected.height(),
500                 errorPercent)) return false;
501 
502         if (!expectSimilarValues(
503                 formattedMsg, "too low", "too high", actual.centerY(), expected.centerY(),
504                 errorPercent)) return false;
505 
506         if (!expectSimilarValues(
507                 formattedMsg, "too right", "too left", actual.centerX(), expected.centerX(),
508                 errorPercent)) return false;
509 
510         return true;
511     }
512 
513     /**
514      * Check that two sizes are similar enough by ensuring that their width and height
515      * are within {@code errorPercent} of each other.
516      *
517      * <p>Only the first error is collected, to avoid spamming several error messages when
518      * the rectangle is hugely dissimilar.</p>
519      *
520      * @param msg Message to be logged
521      * @param expected The reference 'expected' value to be used to check against
522      * @param actual The actual value that was received
523      * @param errorPercent Within how many percent the components should be
524      *
525      * @return {@code true} if all expects passed, {@code false} otherwise
526      */
expectSizesAreSimilar(String msg, Size expected, Size actual, float errorPercent)527     public boolean expectSizesAreSimilar(String msg, Size expected, Size actual,
528             float errorPercent) {
529         String formattedMsg = String.format("%s: rects are not similar enough; expected (%s), " +
530                 "actual (%s), error percent (%s), reason: ",
531                 msg, expected, actual, errorPercent);
532 
533         if (!expectSimilarValues(
534                 formattedMsg, "too wide", "too narrow", actual.getWidth(), expected.getWidth(),
535                 errorPercent)) return false;
536 
537         if (!expectSimilarValues(
538                 formattedMsg, "too tall", "too short", actual.getHeight(), expected.getHeight(),
539                 errorPercent)) return false;
540 
541         return true;
542     }
543 
544     /**
545      * Check that the rectangle is centered within a certain tolerance of {@code errorPercent},
546      * with respect to the {@code bounds} bounding rectangle.
547      *
548      * @param msg Message to be logged
549      * @param expectedBounds The width/height of the bounding rectangle
550      * @param actual The actual value that was received
551      * @param errorPercent Within how many percent the centering should be
552      */
expectRectCentered(String msg, Size expectedBounds, Rect actual, float errorPercent)553     public void expectRectCentered(String msg, Size expectedBounds, Rect actual,
554             float errorPercent) {
555         String formattedMsg = String.format("%s: rect should be centered; expected bounds (%s), " +
556                 "actual (%s), error percent (%s), reason: ",
557                 msg, expectedBounds, actual, errorPercent);
558 
559         int centerBoundX = expectedBounds.getWidth() / 2;
560         int centerBoundY = expectedBounds.getHeight() / 2;
561 
562         expectSimilarValues(
563                 formattedMsg, "too low", "too high", actual.centerY(), centerBoundY,
564                 errorPercent);
565 
566         expectSimilarValues(
567                 formattedMsg, "too right", "too left", actual.centerX(), centerBoundX,
568                 errorPercent);
569     }
570 
expectSimilarValues( String formattedMsg, String tooSmall, String tooLarge, int actualValue, int expectedValue, float errorPercent)571     private boolean expectSimilarValues(
572             String formattedMsg, String tooSmall, String tooLarge, int actualValue,
573             int expectedValue, float errorPercent) {
574         boolean succ = true;
575         succ = expectTrue(formattedMsg + tooLarge,
576                 actualValue <= (expectedValue * (1.0f + errorPercent))) && succ;
577         succ = expectTrue(formattedMsg + tooSmall,
578                 actualValue >= (expectedValue * (1.0f - errorPercent))) && succ;
579 
580         return succ;
581     }
582 
expectNotNull(String msg, Object obj)583     public void expectNotNull(String msg, Object obj) {
584         checkThat(msg, obj, CoreMatchers.notNullValue());
585     }
586 
expectNull(String msg, Object obj)587     public void expectNull(String msg, Object obj) {
588         if (obj != null) {
589             addMessage(msg);
590         }
591     }
592 
593     /**
594      * Check if the values in the array are monotonically increasing (decreasing) and not all
595      * equal.
596      *
597      * @param array The array of values to be checked
598      * @param ascendingOrder The monotonicity ordering to be checked with
599      */
checkArrayMonotonicityAndNotAllEqual(T[] array, boolean ascendingOrder)600     public <T extends Comparable<? super T>>  void checkArrayMonotonicityAndNotAllEqual(T[] array,
601             boolean ascendingOrder) {
602         String orderMsg = ascendingOrder ? ("increasing order") : ("decreasing order");
603         for (int i = 0; i < array.length - 1; i++) {
604             int compareResult = array[i + 1].compareTo(array[i]);
605             boolean condition = compareResult >= 0;
606             if (!ascendingOrder) {
607                 condition = compareResult <= 0;
608             }
609 
610             expectTrue(String.format("Adjacent values (%s and %s) %s monotonicity is broken",
611                     array[i].toString(), array[i + 1].toString(), orderMsg), condition);
612         }
613 
614         expectTrue("All values of this array are equal: " + array[0].toString(),
615                 array[0].compareTo(array[array.length - 1]) != 0);
616     }
617 
618     /**
619      * Check if the key value is not null and return the value.
620      *
621      * @param characteristics The {@link CameraCharacteristics} to get the key from.
622      * @param key The {@link CameraCharacteristics} key to be checked.
623      *
624      * @return The value of the key.
625      */
expectKeyValueNotNull(CameraCharacteristics characteristics, CameraCharacteristics.Key<T> key)626     public <T> T expectKeyValueNotNull(CameraCharacteristics characteristics,
627             CameraCharacteristics.Key<T> key) {
628 
629         T value = characteristics.get(key);
630         if (value == null) {
631             addMessage("Key " + key.getName() + " shouldn't be null");
632         }
633 
634         return value;
635     }
636 
637     /**
638      * Check if the key value is not null and return the value.
639      *
640      * @param request The {@link CaptureRequest} to get the key from.
641      * @param key The {@link CaptureRequest} key to be checked.
642      *
643      * @return The value of the key.
644      */
expectKeyValueNotNull(CaptureRequest request, CaptureRequest.Key<T> key)645     public <T> T expectKeyValueNotNull(CaptureRequest request,
646                                        CaptureRequest.Key<T> key) {
647 
648         T value = request.get(key);
649         if (value == null) {
650             addMessage("Key " + key.getName() + " shouldn't be null");
651         }
652 
653         return value;
654     }
655 
656     /**
657      * Check if the key value is not null and return the value.
658      *
659      * @param request The {@link CaptureRequest#Builder} to get the key from.
660      * @param key The {@link CaptureRequest} key to be checked.
661      * @return The value of the key.
662      */
expectKeyValueNotNull(Builder request, CaptureRequest.Key<T> key)663     public <T> T expectKeyValueNotNull(Builder request, CaptureRequest.Key<T> key) {
664 
665         T value = request.get(key);
666         if (value == null) {
667             addMessage("Key " + key.getName() + " shouldn't be null");
668         }
669 
670         return value;
671     }
672 
673     /**
674      * Check if the key value is not null and return the value.
675      *
676      * @param result The {@link CaptureResult} to get the key from.
677      * @param key The {@link CaptureResult} key to be checked.
678      * @return The value of the key.
679      */
expectKeyValueNotNull(CaptureResult result, CaptureResult.Key<T> key)680     public <T> T expectKeyValueNotNull(CaptureResult result, CaptureResult.Key<T> key) {
681         return expectKeyValueNotNull("", result, key);
682     }
683 
684     /**
685      * Check if the key value is not null and return the value.
686      *
687      * @param msg The message to be logged.
688      * @param result The {@link CaptureResult} to get the key from.
689      * @param key The {@link CaptureResult} key to be checked.
690      * @return The value of the key.
691      */
expectKeyValueNotNull(String msg, CaptureResult result, CaptureResult.Key<T> key)692     public <T> T expectKeyValueNotNull(String msg, CaptureResult result, CaptureResult.Key<T> key) {
693 
694         T value = result.get(key);
695         if (value == null) {
696             addMessage(msg + " Key " + key.getName() + " shouldn't be null");
697         }
698 
699         return value;
700     }
701 
702     /**
703      * Check if the key is non-null and the value is not equal to target.
704      *
705      * @param request The The {@link CaptureRequest#Builder} to get the key from.
706      * @param key The {@link CaptureRequest} key to be checked.
707      * @param expected The expected value of the CaptureRequest key.
708      */
expectKeyValueNotEquals( Builder request, CaptureRequest.Key<T> key, T expected)709     public <T> void expectKeyValueNotEquals(
710             Builder request, CaptureRequest.Key<T> key, T expected) {
711         if (request == null || key == null || expected == null) {
712             throw new IllegalArgumentException("request, key and expected shouldn't be null");
713         }
714 
715         T value;
716         if ((value = expectKeyValueNotNull(request, key)) == null) {
717             return;
718         }
719 
720         String reason = "Key " + key.getName() + " shouldn't have value " + value.toString();
721         checkThat(reason, value, CoreMatchers.not(expected));
722     }
723 
724     /**
725      * Check if the key is non-null and the value is not equal to target.
726      *
727      * @param result The {@link CaptureResult} to get the key from.
728      * @param key The {@link CaptureResult} key to be checked.
729      * @param expected The expected value of the CaptureResult key.
730      */
expectKeyValueNotEquals( CaptureResult result, CaptureResult.Key<T> key, T expected)731     public <T> void expectKeyValueNotEquals(
732             CaptureResult result, CaptureResult.Key<T> key, T expected) {
733         if (result == null || key == null || expected == null) {
734             throw new IllegalArgumentException("result, key and expected shouldn't be null");
735         }
736 
737         T value;
738         if ((value = expectKeyValueNotNull(result, key)) == null) {
739             return;
740         }
741 
742         String reason = "Key " + key.getName() + " shouldn't have value " + value.toString();
743         checkThat(reason, value, CoreMatchers.not(expected));
744     }
745 
746     /**
747      * Check if the value is non-null and the value is equal to target.
748      *
749      * @param result The  {@link CaptureResult} to lookup the value in.
750      * @param key The {@link CaptureResult} key to be checked.
751      * @param expected The expected value of the {@link CaptureResult} key.
752      */
expectKeyValueEquals(CaptureResult result, CaptureResult.Key<T> key, T expected)753     public <T> void expectKeyValueEquals(CaptureResult result, CaptureResult.Key<T> key,
754             T expected) {
755         if (result == null || key == null || expected == null) {
756             throw new IllegalArgumentException("request, key and expected shouldn't be null");
757         }
758 
759         T value;
760         if ((value = expectKeyValueNotNull(result, key)) == null) {
761             return;
762         }
763 
764         String reason = "Key " + key.getName() + " value " + value.toString()
765                 + " doesn't match the expected value " + expected.toString();
766         checkThat(reason, value, CoreMatchers.equalTo(expected));
767     }
768 
769     /**
770      * Check if the key is non-null and the value is equal to target.
771      *
772      * <p>Only check non-null if the target is null.</p>
773      *
774      * @param request The The {@link CaptureRequest#Builder} to get the key from.
775      * @param key The {@link CaptureRequest} key to be checked.
776      * @param expected The expected value of the CaptureRequest key.
777      */
expectKeyValueEquals(Builder request, CaptureRequest.Key<T> key, T expected)778     public <T> void expectKeyValueEquals(Builder request, CaptureRequest.Key<T> key, T expected) {
779         if (request == null || key == null || expected == null) {
780             throw new IllegalArgumentException("request, key and expected shouldn't be null");
781         }
782 
783         T value;
784         if ((value = expectKeyValueNotNull(request, key)) == null) {
785             return;
786         }
787 
788         String reason = "Key " + key.getName() + " value " + value.toString()
789                 + " doesn't match the expected value " + expected.toString();
790         checkThat(reason, value, CoreMatchers.equalTo(expected));
791     }
792 
793     /**
794      * Check if the key is non-null, and the key value is greater than the expected value.
795      *
796      * @param result {@link CaptureResult} to check.
797      * @param key The {@link CaptureResult} key to be checked.
798      * @param expected The expected to be compared to the value for the given key.
799      */
expectKeyValueGreaterOrEqual( CaptureResult result, CaptureResult.Key<T> key, T expected)800     public <T extends Comparable<? super T>> void expectKeyValueGreaterOrEqual(
801             CaptureResult result, CaptureResult.Key<T> key, T expected) {
802         T value;
803         if ((value = expectKeyValueNotNull(result, key)) == null) {
804             return;
805         }
806 
807         expectGreaterOrEqual(key.getName(), expected, value);
808     }
809 
810     /**
811      * Check if the key is non-null, and the key value is greater than the expected value.
812      *
813      * @param characteristics {@link CameraCharacteristics} to check.
814      * @param key The {@link CameraCharacteristics} key to be checked.
815      * @param expected The expected to be compared to the value for the given key.
816      */
expectKeyValueGreaterThan( CameraCharacteristics characteristics, CameraCharacteristics.Key<T> key, T expected)817     public <T extends Comparable<? super T>> void expectKeyValueGreaterThan(
818             CameraCharacteristics characteristics, CameraCharacteristics.Key<T> key, T expected) {
819         T value;
820         if ((value = expectKeyValueNotNull(characteristics, key)) == null) {
821             return;
822         }
823 
824         expectGreater(key.getName(), expected, value);
825     }
826 
827     /**
828      * Check if the key is non-null, and the key value is in the expected range.
829      *
830      * @param characteristics {@link CameraCharacteristics} to check.
831      * @param key The {@link CameraCharacteristics} key to be checked.
832      * @param min The min value of the range
833      * @param max The max value of the range
834      */
expectKeyValueInRange( CameraCharacteristics characteristics, CameraCharacteristics.Key<T> key, T min, T max)835     public <T extends Comparable<? super T>> void expectKeyValueInRange(
836             CameraCharacteristics characteristics, CameraCharacteristics.Key<T> key, T min, T max) {
837         T value;
838         if ((value = expectKeyValueNotNull(characteristics, key)) == null) {
839             return;
840         }
841         expectInRange(key.getName(), value, min, max);
842     }
843 
844   /**
845      * Check if the key is non-null, and the key value is in the expected range.
846      *
847      * @param request {@link CaptureRequest.Builder} to check.
848      * @param key The {@link CaptureRequest} key to be checked.
849      * @param min The min value of the range
850      * @param max The max value of the range
851      */
expectKeyValueInRange( Builder request, CaptureRequest.Key<T> key, T min, T max)852     public <T extends Comparable<? super T>> void expectKeyValueInRange(
853             Builder request, CaptureRequest.Key<T> key, T min, T max) {
854         T value;
855         if ((value = expectKeyValueNotNull(request, key)) == null) {
856             return;
857         }
858         expectInRange(key.getName(), value, min, max);
859     }
860 
861     /**
862      * Check if the key is non-null, and the key value is one of the expected values.
863      *
864      * @param characteristics {@link CameraCharacteristics} to check.
865      * @param key The {@link CameraCharacteristics} key to be checked.
866      * @param expected The expected values for the given key.
867      */
expectKeyValueIsIn(CameraCharacteristics characteristics, CameraCharacteristics.Key<T> key, T... expected)868     public <T> void expectKeyValueIsIn(CameraCharacteristics characteristics,
869                                        CameraCharacteristics.Key<T> key, T... expected) {
870         T value = expectKeyValueNotNull(characteristics, key);
871         if (value == null) {
872             return;
873         }
874         String reason = "Key " + key.getName() + " value " + value
875                 + " isn't one of the expected values " + Arrays.deepToString(expected);
876         expectContains(reason, expected, value);
877     }
878 
879     /**
880      * Check if the key is non-null, and the key value is one of the expected values.
881      *
882      * @param request The The {@link CaptureRequest#Builder} to get the key from.
883      * @param key The {@link CaptureRequest} key to be checked.
884      * @param expected The expected values of the CaptureRequest key.
885      */
expectKeyValueIsIn(Builder request, CaptureRequest.Key<T> key, T... expected)886     public <T> void expectKeyValueIsIn(Builder request, CaptureRequest.Key<T> key, T... expected) {
887         T value = expectKeyValueNotNull(request, key);
888         if (value == null) {
889             return;
890         }
891         String reason = "Key " + key.getName() + " value " + value
892                 + " isn't one of the expected values " + Arrays.deepToString(expected);
893         expectContains(reason, expected, value);
894     }
895 
896     /**
897      * Check if the key is non-null, and the key value is one of the expected values.
898      *
899      * @param result {@link CaptureResult} to get the key from.
900      * @param key The {@link CaptureResult} key to be checked.
901      * @param expected The expected values of the CaptureResult key.
902      */
expectKeyValueIsIn(CaptureResult result, CaptureResult.Key<T> key, T... expected)903     public <T> void expectKeyValueIsIn(CaptureResult result,
904                                        CaptureResult.Key<T> key, T... expected) {
905         T value = expectKeyValueNotNull(result, key);
906         if (value == null) {
907             return;
908         }
909         String reason = "Key " + key.getName() + " value " + value
910                 + " isn't one of the expected values " + Arrays.deepToString(expected);
911         expectContains(reason, expected, value);
912     }
913 
914     /**
915      * Check if the key is non-null, and the key value contains the expected element.
916      *
917      * @param characteristics {@link CameraCharacteristics} to check.
918      * @param key The {@link CameraCharacteristics} key to be checked.
919      * @param expected The expected element to be contained in the value for the given key.
920      */
expectKeyValueContains(CameraCharacteristics characteristics, CameraCharacteristics.Key<T[]> key, T expected)921     public <T> void expectKeyValueContains(CameraCharacteristics characteristics,
922                                            CameraCharacteristics.Key<T[]> key, T expected) {
923         T[] value;
924         if ((value = expectKeyValueNotNull(characteristics, key)) == null) {
925             return;
926         }
927         String reason = "Key " + key.getName() + " value " + Arrays.toString(value)
928                 + " doesn't contain the expected value " + expected;
929         expectContains(reason, value, expected);
930     }
931 
932     /**
933      * Check if the key is non-null, and the key value contains the expected element.
934      *
935      * @param characteristics {@link CameraCharacteristics} to check.
936      * @param key The {@link CameraCharacteristics} key to be checked.
937      * @param expected The expected element to be contained in the value for the given key.
938      */
expectKeyValueContains(CameraCharacteristics characteristics, CameraCharacteristics.Key<int[]> key, int expected)939     public void expectKeyValueContains(CameraCharacteristics characteristics,
940                                            CameraCharacteristics.Key<int[]> key, int expected) {
941         int[] value;
942         if ((value = expectKeyValueNotNull(characteristics, key)) == null) {
943             return;
944         }
945         String reason = "Key " + key.getName() + " value " + Arrays.toString(value)
946                 + " doesn't contain the expected value " + expected;
947         expectContains(reason, value, expected);
948     }
949 
950     /**
951      * Check if the key is non-null, and the key value contains the expected element.
952      *
953      * @param characteristics {@link CameraCharacteristics} to check.
954      * @param key The {@link CameraCharacteristics} key to be checked.
955      * @param expected The expected element to be contained in the value for the given key.
956      */
expectKeyValueContains(CameraCharacteristics characteristics, CameraCharacteristics.Key<boolean[]> key, boolean expected)957     public void expectKeyValueContains(CameraCharacteristics characteristics,
958                                        CameraCharacteristics.Key<boolean[]> key, boolean expected) {
959         boolean[] value;
960         if ((value = expectKeyValueNotNull(characteristics, key)) == null) {
961             return;
962         }
963         String reason = "Key " + key.getName() + " value " + Arrays.toString(value)
964                 + " doesn't contain the expected value " + expected;
965         expectContains(reason, value, expected);
966     }
967 
968     /**
969      * Check if the {@code values} array contains the expected element.
970      *
971      * @param reason reason to print for failure.
972      * @param values array to check for membership in.
973      * @param expected the value to check.
974      */
expectContains(String reason, T[] values, T expected)975     public <T> void expectContains(String reason, T[] values, T expected) {
976         if (values == null) {
977             throw new NullPointerException();
978         }
979         checkThat(reason, expected, InMatcher.in(values));
980     }
981 
expectContains(T[] values, T expected)982     public <T> void expectContains(T[] values, T expected) {
983         String reason = "Expected value " + expected
984                 + " is not contained in the given values " + Arrays.toString(values);
985         expectContains(reason, values, expected);
986     }
987 
988     /**
989      * Specialize {@link InMatcher} class for integer primitive array.
990      */
991     private static class IntInMatcher extends InMatcher<Integer> {
IntInMatcher(int[] values)992         public IntInMatcher(int[] values) {
993             Preconditions.checkNotNull("values", values);
994             mValues = new ArrayList<>(values.length);
995             for (int i : values) {
996                 mValues.add(i);
997             }
998         }
999     }
1000 
1001     /**
1002      * Check if the {@code values} array contains the expected element.
1003      *
1004      * <p>Specialized for primitive int arrays</p>
1005      *
1006      * @param reason reason to print for failure.
1007      * @param values array to check for membership in.
1008      * @param expected the value to check.
1009      */
expectContains(String reason, int[] values, int expected)1010     public void expectContains(String reason, int[] values, int expected) {
1011         if (values == null) {
1012             throw new NullPointerException();
1013         }
1014 
1015         checkThat(reason, expected, new IntInMatcher(values));
1016     }
1017 
expectContains(int[] values, int expected)1018     public void expectContains(int[] values, int expected) {
1019         String reason = "Expected value " + expected
1020                 + " is not contained in the given values " + Arrays.toString(values);
1021         expectContains(reason, values, expected);
1022     }
1023 
1024     /**
1025      * Specialize {@link BooleanInMatcher} class for boolean primitive array.
1026      */
1027     private static class BooleanInMatcher extends InMatcher<Boolean> {
BooleanInMatcher(boolean[] values)1028         public BooleanInMatcher(boolean[] values) {
1029             Preconditions.checkNotNull("values", values);
1030             mValues = new ArrayList<>(values.length);
1031             for (boolean i : values) {
1032                 mValues.add(i);
1033             }
1034         }
1035     }
1036 
1037     /**
1038      * Check if the {@code values} array contains the expected element.
1039      *
1040      * <p>Specialized for primitive boolean arrays</p>
1041      *
1042      * @param reason reason to print for failure.
1043      * @param values array to check for membership in.
1044      * @param expected the value to check.
1045      */
expectContains(String reason, boolean[] values, boolean expected)1046     public void expectContains(String reason, boolean[] values, boolean expected) {
1047         if (values == null) {
1048             throw new NullPointerException();
1049         }
1050 
1051         checkThat(reason, expected, new BooleanInMatcher(values));
1052     }
1053 
1054     /**
1055      * Check if the {@code values} array contains the expected element.
1056      *
1057      * <p>Specialized for primitive boolean arrays</p>
1058      *
1059      * @param values array to check for membership in.
1060      * @param expected the value to check.
1061      */
expectContains(boolean[] values, boolean expected)1062     public void expectContains(boolean[] values, boolean expected) {
1063         String reason = "Expected value " + expected
1064                 + " is not contained in the given values " + Arrays.toString(values);
1065         expectContains(reason, values, expected);
1066     }
1067 
1068     /**
1069      * Check if the element inside of the list are unique.
1070      *
1071      * @param msg The message to be logged
1072      * @param list The list of values to be checked
1073      */
expectValuesUnique(String msg, List<T> list)1074     public <T> void expectValuesUnique(String msg, List<T> list) {
1075         Set<T> sizeSet = new HashSet<T>(list);
1076         expectTrue(msg + " each element must be distinct", sizeSet.size() == list.size());
1077     }
1078 
expectImageProperties(String msg, Image image, int format, Size size, long timestampNs)1079     public void expectImageProperties(String msg, Image image, int format, Size size,
1080             long timestampNs) {
1081         expectEquals(msg + "Image format is wrong.", image.getFormat(), format);
1082         expectEquals(msg + "Image width is wrong.", image.getWidth(), size.getWidth());
1083         expectEquals(msg + "Image height is wrong.", image.getHeight(), size.getHeight());
1084         expectEquals(msg + "Image timestamp is wrong.", image.getTimestamp(), timestampNs);
1085     }
1086 
1087 }
1088