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