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