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