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