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