content: /*
   * Copyright (C) 2014 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package androidx.test.espresso.matcher;
  
  import static androidx.test.internal.util.Checks.checkArgument;
  import static androidx.test.internal.util.Checks.checkNotNull;
  import static org.hamcrest.Matchers.is;
  
  import android.database.Cursor;
  import android.database.CursorIndexOutOfBoundsException;
  import android.widget.AdapterView;
  import org.hamcrest.Description;
  import org.hamcrest.Matcher;
  import org.hamcrest.SelfDescribing;
  import org.hamcrest.StringDescription;
  
  /**
   * A collection of Hamcrest matchers that matches a data row in a {@link Cursor}. <br>
   *
   * <p>{@link AdapterView}s that are backed by a {@link Cursor} are very common. This class contains
   * <a href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
   * </code></a>s that can be used together with {@link
   * androidx.test.espresso.Espresso#onData(Matcher)} to match a data row in a {@link Cursor}.
   * The <a href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>
   * Matcher</code></a>s can only operate on a single data row of the cursor and Espresso internally
   * moves the {@link Cursor} to the correct adapter position.
   */
  public final class CursorMatchers {
  
    private static final int COLUMN_NOT_FOUND = -1;
    private static final int MULTIPLE_COLUMNS_FOUND = -2;
    private static final int USE_COLUMN_PICKER = -3;
  
    private CursorMatchers() {
      // no instance
    }
  
    /** A {@link Matcher} that matches {@link Cursor}s based on values in their columns. */
    @SuppressWarnings("Extended from BoundedMatcher to be binary compatible")
    public static class CursorMatcher extends BoundedMatcher<Object, Cursor> {
  
      private final int columnIndex;
      private final Matcher<String> columnNameMatcher;
      private final Matcher<?> valueMatcher;
      private final CursorDataRetriever<?> cursorDataRetriever;
      private boolean checkColumns = false;
  
      private CursorMatcher(
          int columnIndex, Matcher<?> valueMatcher, CursorDataRetriever<?> cursorDataRetriever) {
        super(Cursor.class);
        checkArgument(columnIndex >= 0);
        this.columnIndex = columnIndex;
        this.valueMatcher = checkNotNull(valueMatcher);
        this.cursorDataRetriever = checkNotNull(cursorDataRetriever);
        this.columnNameMatcher = null;
      }
  
      private CursorMatcher(
          Matcher<String> columnPicker,
          Matcher<?> valueMatcher,
          CursorDataRetriever<?> cursorDataRetriever) {
        super(Cursor.class);
        this.columnNameMatcher = checkNotNull(columnPicker);
        this.valueMatcher = checkNotNull(valueMatcher);
        this.cursorDataRetriever = checkNotNull(cursorDataRetriever);
        this.columnIndex = USE_COLUMN_PICKER;
      }
  
      @Override
      public boolean matchesSafely(Cursor cursor) {
        int chosenColumn = columnIndex;
        StringDescription mismatchDescription = new StringDescription();
        if (chosenColumn < 0) {
          chosenColumn = findColumnIndex(columnNameMatcher, cursor);
          if (chosenColumn < 0) {
            if (chosenColumn == MULTIPLE_COLUMNS_FOUND) {
              mismatchDescription
                  .appendText("Multiple columns in ")
                  .appendValue(cursor.getColumnNames())
                  .appendText(" match ")
                  .appendDescriptionOf(columnNameMatcher);
            } else {
              mismatchDescription
                  .appendText("Couldn't find column in ")
                  .appendValue(cursor.getColumnNames())
                  .appendText(" matching ")
                  .appendDescriptionOf(columnNameMatcher);
            }
            if (checkColumns) {
              throw new IllegalArgumentException(mismatchDescription.toString());
            }
            return false;
          }
        }
        try {
          Object data = cursorDataRetriever.getData(cursor, chosenColumn);
          boolean result = valueMatcher.matches(data);
          if (!result) {
            mismatchDescription
                .appendText("value at column ")
                .appendValue(chosenColumn)
                .appendText(" ");
            valueMatcher.describeMismatch(data, mismatchDescription);
          }
          return result;
        } catch (CursorIndexOutOfBoundsException e) {
          mismatchDescription
              .appendText("Column index ")
              .appendValue(chosenColumn)
              .appendText(" is invalid");
          if (checkColumns) {
            throw new IllegalArgumentException(mismatchDescription.toString(), e);
          }
          // this cursor position doesn't have a column with this index, but other ones might
          // (e.g. in case of MergeCursor), so if columnChecks are off continue the search.
          return false;
        }
      }
  
      @Override
      public void describeTo(Description description) {
        description.appendText("an instance of android.database.Cursor and Rows with column: ");
        if (columnIndex < 0) {
          columnNameMatcher.describeTo(description);
        } else {
          description.appendText("index = " + columnIndex);
        }
        description
            .appendText(" ")
            .appendDescriptionOf(cursorDataRetriever)
            .appendText(" matching ")
            .appendDescriptionOf(valueMatcher);
      }
  
      /**
       * Allows test authors to override whether the the matcher should throw an {@link
       * IllegalArgumentException} if the column name/count is not valid. This is useful in the case
       * where a cursor may iterates over a data set with variable columns. By default, the checks are
       * off.
       */
      public CursorMatcher withStrictColumnChecks(boolean checkColumns) {
        this.checkColumns = checkColumns;
        return this;
      }
    }
  
    private static int findColumnIndex(Matcher<String> nameMatcher, Cursor cursor) {
      int result = COLUMN_NOT_FOUND;
      String[] columnNames = cursor.getColumnNames();
      for (int i = 0; i < columnNames.length; i++) {
        String column = columnNames[i];
        if (nameMatcher.matches(column)) {
          if (result == COLUMN_NOT_FOUND) {
            result = i;
          } else {
            result = MULTIPLE_COLUMNS_FOUND;
            break;
          }
        }
      }
      return result;
    }
  
    private interface CursorDataRetriever<T> extends SelfDescribing {
      T getData(Cursor cursor, int chosenColumn);
    }
  
    private static final CursorDataRetriever<byte[]> BLOB_MATCHER_APPLIER =
        new CursorDataRetriever<byte[]>() {
          @Override
          public void describeTo(Description description) {
            description.appendText("with Blob");
          }
  
          @Override
          public byte[] getData(Cursor cursor, int chosenColumn) {
            return cursor.getBlob(chosenColumn);
          }
        };
  
    private static final CursorDataRetriever<Long> LONG_MATCHER_APPLIER =
        new CursorDataRetriever<Long>() {
          @Override
          public void describeTo(Description description) {
            description.appendText("with Long");
          }
  
          @Override
          public Long getData(Cursor cursor, int chosenColumn) {
            return cursor.getLong(chosenColumn);
          }
        };
  
    private static final CursorDataRetriever<Short> SHORT_MATCHER_APPLIER =
        new CursorDataRetriever<Short>() {
          @Override
          public void describeTo(Description description) {
            description.appendText("with Short");
          }
  
          @Override
          public Short getData(Cursor cursor, int chosenColumn) {
            return cursor.getShort(chosenColumn);
          }
        };
  
    private static final CursorDataRetriever<Integer> INT_MATCHER_APPLIER =
        new CursorDataRetriever<Integer>() {
          @Override
          public void describeTo(Description description) {
            description.appendText("with Int");
          }
  
          @Override
          public Integer getData(Cursor cursor, int chosenColumn) {
            return cursor.getInt(chosenColumn);
          }
        };
  
    private static final CursorDataRetriever<Float> FLOAT_MATCHER_APPLIER =
        new CursorDataRetriever<Float>() {
          @Override
          public void describeTo(Description description) {
            description.appendText("with Float");
          }
  
          @Override
          public Float getData(Cursor cursor, int chosenColumn) {
            return cursor.getFloat(chosenColumn);
          }
        };
  
    private static final CursorDataRetriever<Double> DOUBLE_MATCHER_APPLIER =
        new CursorDataRetriever<Double>() {
          @Override
          public void describeTo(Description description) {
            description.appendText("with Double");
          }
  
          @Override
          public Double getData(Cursor cursor, int chosenColumn) {
            return cursor.getDouble(chosenColumn);
          }
        };
  
    private static final CursorDataRetriever<String> STRING_MATCHER_APPLIER =
        new CursorDataRetriever<String>() {
          @Override
          public void describeTo(Description description) {
            description.appendText("with String");
          }
  
          @Override
          public String getData(Cursor cursor, int chosenColumn) {
            return cursor.getString(chosenColumn);
          }
        };
  
    /**
     * Returns a matcher that matches a {@link Short} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnIndex int column index
     * @param value a short value to match
     */
    public static CursorMatcher withRowShort(int columnIndex, short value) {
      return withRowShort(columnIndex, is(value));
    }
  
    /**
     * Returns a matcher that matches a {@link Short} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnIndex int column index
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Short} value
     */
    public static CursorMatcher withRowShort(int columnIndex, Matcher<Short> valueMatcher) {
      return new CursorMatcher(columnIndex, valueMatcher, SHORT_MATCHER_APPLIER);
    }
  
    /**
     * Returns a matcher that matches a {@link Short} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnName as a {@link String}
     * @param value a short value to match
     */
    public static CursorMatcher withRowShort(String columnName, short value) {
      return withRowShort(columnName, is(value));
    }
  
    /**
     * Returns a matcher that matches a {@link Short} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnName as a {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Short} value
     */
    public static CursorMatcher withRowShort(String columnName, Matcher<Short> valueMatcher) {
      return withRowShort(is(columnName), valueMatcher);
    }
  
    /**
     * Returns a matcher that matches a {@link Short} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnNameMatcher as a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> of {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Short} value
     */
    public static CursorMatcher withRowShort(
        Matcher<String> columnNameMatcher, Matcher<Short> valueMatcher) {
      return new CursorMatcher(columnNameMatcher, valueMatcher, SHORT_MATCHER_APPLIER);
    }
  
    /**
     * Returns a matcher that matches a {@link Integer} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnIndex int column index
     * @param value a int value to match
     */
    public static CursorMatcher withRowInt(int columnIndex, int value) {
      return withRowInt(columnIndex, is(value));
    }
  
    /**
     * Returns a matcher that matches a {@link Integer} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnIndex int column index
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Integer} value
     */
    public static CursorMatcher withRowInt(int columnIndex, Matcher<Integer> valueMatcher) {
      return new CursorMatcher(columnIndex, valueMatcher, INT_MATCHER_APPLIER);
    }
  
    /**
     * Returns a matcher that matches a {@link Integer} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnName as a {@link String}
     * @param value a int value to match
     */
    public static CursorMatcher withRowInt(String columnName, int value) {
      return withRowInt(columnName, is(value));
    }
  
    /**
     * Returns a matcher that matches a {@link Integer} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnName as a {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Integer} value
     */
    public static CursorMatcher withRowInt(String columnName, Matcher<Integer> valueMatcher) {
      return withRowInt(is(columnName), valueMatcher);
    }
  
    /**
     * Returns a matcher that matches a {@link Integer} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnNameMatcher as a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> of {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Integer} value
     */
    public static CursorMatcher withRowInt(
        Matcher<String> columnNameMatcher, final Matcher<Integer> valueMatcher) {
      return new CursorMatcher(columnNameMatcher, valueMatcher, INT_MATCHER_APPLIER);
    }
  
    /**
     * Returns a matcher that matches a {@link Long} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnIndex int column index
     * @param value a long value to match
     */
    public static CursorMatcher withRowLong(int columnIndex, long value) {
      return withRowLong(columnIndex, is(value));
    }
  
    /**
     * Returns a matcher that matches a {@link Long} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnIndex int column index
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Long} value
     */
    public static CursorMatcher withRowLong(int columnIndex, Matcher<Long> valueMatcher) {
      return new CursorMatcher(columnIndex, valueMatcher, LONG_MATCHER_APPLIER);
    }
  
    /**
     * Returns a matcher that matches a {@link Long} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnName as a {@link String}
     * @param value a long value to match
     */
    public static CursorMatcher withRowLong(String columnName, long value) {
      return withRowLong(columnName, is(value));
    }
  
    /**
     * Returns a matcher that matches a {@link Long} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnName as a {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Long} value
     */
    public static CursorMatcher withRowLong(String columnName, Matcher<Long> valueMatcher) {
      return withRowLong(is(columnName), valueMatcher);
    }
  
    /**
     * Returns a matcher that matches a {@link Long} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnNameMatcher as a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> of {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Long} value
     */
    public static CursorMatcher withRowLong(
        Matcher<String> columnNameMatcher, Matcher<Long> valueMatcher) {
      return new CursorMatcher(columnNameMatcher, valueMatcher, LONG_MATCHER_APPLIER);
    }
  
    /**
     * Returns a matcher that matches a {@link Float} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnIndex int column index
     * @param value a float value to match
     */
    public static CursorMatcher withRowFloat(int columnIndex, float value) {
      return withRowFloat(columnIndex, is(value));
    }
  
    /**
     * Returns a matcher that matches a {@link Float} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnIndex int column index
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Float} value
     */
    public static CursorMatcher withRowFloat(int columnIndex, Matcher<Float> valueMatcher) {
      return new CursorMatcher(columnIndex, valueMatcher, FLOAT_MATCHER_APPLIER);
    }
  
    /**
     * Returns a matcher that matches a {@link Float} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnName as a {@link String}
     * @param value a float value to match
     */
    public static CursorMatcher withRowFloat(String columnName, float value) {
      return withRowFloat(columnName, is(value));
    }
  
    /**
     * Returns a matcher that matches a {@link Float} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnName as a {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Float} value
     */
    public static CursorMatcher withRowFloat(String columnName, Matcher<Float> valueMatcher) {
      return withRowFloat(is(columnName), valueMatcher);
    }
  
    /**
     * Returns a matcher that matches a {@link Float} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnNameMatcher as a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> of {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Float} value
     */
    public static CursorMatcher withRowFloat(
        Matcher<String> columnNameMatcher, Matcher<Float> valueMatcher) {
      return new CursorMatcher(columnNameMatcher, valueMatcher, FLOAT_MATCHER_APPLIER);
    }
  
    /**
     * Returns a matcher that matches a {@link Double} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnIndex int column index
     * @param value a double value to match
     */
    public static CursorMatcher withRowDouble(int columnIndex, double value) {
      return withRowDouble(columnIndex, is(value));
    }
  
    /**
     * Returns a matcher that matches a {@link Double} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnIndex int column index
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Double} value
     */
    public static CursorMatcher withRowDouble(int columnIndex, Matcher<Double> valueMatcher) {
      return new CursorMatcher(columnIndex, valueMatcher, DOUBLE_MATCHER_APPLIER);
    }
  
    /**
     * Returns a matcher that matches a {@link Double} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnName as a {@link String}
     * @param value a double value to match
     */
    public static CursorMatcher withRowDouble(String columnName, double value) {
      return withRowDouble(columnName, is(value));
    }
  
    /**
     * Returns a matcher that matches a {@link Double} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnName as a {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Double} value
     */
    public static CursorMatcher withRowDouble(String columnName, Matcher<Double> valueMatcher) {
      return withRowDouble(is(columnName), valueMatcher);
    }
  
    /**
     * Returns a matcher that matches a {@link Double} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnNameMatcher as a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> of {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link Double} value
     */
    public static CursorMatcher withRowDouble(
        Matcher<String> columnNameMatcher, Matcher<Double> valueMatcher) {
      return new CursorMatcher(columnNameMatcher, valueMatcher, DOUBLE_MATCHER_APPLIER);
    }
  
    /**
     * Returns a matcher that matches a {@link String} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnIndex int column index
     * @param value a {@link String} value to match
     */
    public static CursorMatcher withRowString(int columnIndex, String value) {
      return withRowString(columnIndex, is(value));
    }
  
    /**
     * Returns a matcher that matches a {@link String} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnIndex int column index
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link String} value
     */
    public static CursorMatcher withRowString(int columnIndex, Matcher<String> valueMatcher) {
      return new CursorMatcher(columnIndex, valueMatcher, STRING_MATCHER_APPLIER);
    }
  
    /**
     * Returns a matcher that matches a {@link String} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnName as a {@link String}
     * @param value a {@link String} value to match
     */
    public static CursorMatcher withRowString(String columnName, String value) {
      return withRowString(is(columnName), is(value));
    }
  
    /**
     * Returns a matcher that matches a {@link String} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnName as a {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link String} value
     */
    public static CursorMatcher withRowString(String columnName, Matcher<String> valueMatcher) {
      return withRowString(is(columnName), valueMatcher);
    }
  
    /**
     * Returns a matcher that matches a {@link String} value at a given column index in a {@link
     * Cursor}s data row. <br>
     *
     * @param columnPicker as a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> of {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a {@link String} value
     */
    public static CursorMatcher withRowString(
        final Matcher<String> columnPicker, final Matcher<String> valueMatcher) {
      return new CursorMatcher(columnPicker, valueMatcher, STRING_MATCHER_APPLIER);
    }
  
    /**
     * Returns a matcher that matches a byte[] at a given column index in a {@link Cursor}s data row.
     * <br>
     *
     * @param columnIndex int column index
     * @param value byte[] to match
     */
    public static CursorMatcher withRowBlob(int columnIndex, byte[] value) {
      return withRowBlob(columnIndex, is(value));
    }
  
    /**
     * Returns a matcher that matches a byte[] at a given column index in a {@link Cursor}s data row.
     * <br>
     *
     * @param columnIndex int column index
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a byte[]
     */
    public static CursorMatcher withRowBlob(int columnIndex, Matcher<byte[]> valueMatcher) {
      return new CursorMatcher(columnIndex, valueMatcher, BLOB_MATCHER_APPLIER);
    }
  
    /**
     * Returns a matcher that matches a byte[] at a given column index in a {@link Cursor}s data row.
     * <br>
     *
     * @param columnName as a {@link String}
     * @param value byte[] to match
     */
    public static CursorMatcher withRowBlob(String columnName, byte[] value) {
      return withRowBlob(is(columnName), is(value));
    }
  
    /**
     * Returns a matcher that matches a byte[] at a given column index in a {@link Cursor}s data row.
     * <br>
     *
     * @param columnName as a {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a byte[]
     */
    public static CursorMatcher withRowBlob(String columnName, Matcher<byte[]> valueMatcher) {
      return withRowBlob(is(columnName), valueMatcher);
    }
  
    /**
     * Returns a matcher that matches a byte[] at a given column index in a {@link Cursor}s data row.
     * <br>
     *
     * @param columnPicker as a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> of {@link String}
     * @param valueMatcher a <a
     *     href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matcher.html"><code>Matcher
     *     </code></a> that matches a byte[]
     */
    public static CursorMatcher withRowBlob(
        Matcher<String> columnPicker, Matcher<byte[]> valueMatcher) {
      return new CursorMatcher(columnPicker, valueMatcher, BLOB_MATCHER_APPLIER);
    }
  }
  