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