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