summaryrefslogtreecommitdiff
path: root/tests/src/com/android/contacts/test/mocks/MockContentProvider.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/com/android/contacts/test/mocks/MockContentProvider.java')
-rw-r--r--tests/src/com/android/contacts/test/mocks/MockContentProvider.java699
1 files changed, 699 insertions, 0 deletions
diff --git a/tests/src/com/android/contacts/test/mocks/MockContentProvider.java b/tests/src/com/android/contacts/test/mocks/MockContentProvider.java
new file mode 100644
index 000000000..77eb1c910
--- /dev/null
+++ b/tests/src/com/android/contacts/test/mocks/MockContentProvider.java
@@ -0,0 +1,699 @@
+/*
+ * Copyright (C) 2010 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 com.android.contacts.test.mocks;
+
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.support.annotation.Nullable;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A programmable mock content provider.
+ */
+public class MockContentProvider extends android.test.mock.MockContentProvider {
+ private static final String TAG = "MockContentProvider";
+
+ public static class Query {
+
+ private final Uri mUri;
+ private UriMatcher mMatcher;
+
+ private String[] mProjection;
+ private String[] mDefaultProjection;
+ private String mSelection;
+ private String[] mSelectionArgs;
+ private String mSortOrder;
+ private List<Object> mRows = new ArrayList<>();
+ private boolean mAnyProjection;
+ private boolean mAnySelection;
+ private boolean mAnySortOrder;
+ private boolean mAnyNumberOfTimes;
+
+ private boolean mExecuted;
+
+ private Query() {
+ mUri = null;
+ }
+
+ private Query(UriMatcher matcher) {
+ mUri = null;
+ mMatcher = matcher;
+ }
+
+ public Query(Uri uri) {
+ mUri = uri;
+ }
+
+ @Override
+ public String toString() {
+ return queryToString(mUri, mProjection, mSelection, mSelectionArgs, mSortOrder);
+ }
+
+ public Query withProjection(String... projection) {
+ mProjection = projection;
+ return this;
+ }
+
+ public Query withDefaultProjection(String... projection) {
+ mDefaultProjection = projection;
+ return this;
+ }
+
+ public Query withAnyProjection() {
+ mAnyProjection = true;
+ return this;
+ }
+
+ public Query withSelection(String selection, String... selectionArgs) {
+ mSelection = selection;
+ mSelectionArgs = selectionArgs;
+ return this;
+ }
+
+ public Query withAnySelection() {
+ mAnySelection = true;
+ return this;
+ }
+
+ public Query withSortOrder(String sortOrder) {
+ mSortOrder = sortOrder;
+ return this;
+ }
+
+ public Query withAnySortOrder() {
+ mAnySortOrder = true;
+ return this;
+ }
+
+ public Query returnRow(ContentValues values) {
+ mRows.add(values);
+ return this;
+ }
+
+ public Query returnRow(Object... row) {
+ mRows.add(row);
+ return this;
+ }
+
+ public Query returnEmptyCursor() {
+ mRows.clear();
+ return this;
+ }
+
+ public Query anyNumberOfTimes() {
+ mAnyNumberOfTimes = true;
+ return this;
+ }
+
+ public boolean equals(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ if (mUri == null) {
+ if (mMatcher != null && mMatcher.match(uri) == UriMatcher.NO_MATCH) {
+ return false;
+ }
+ } else if (!uri.equals(mUri)) {
+ return false;
+ }
+
+ if (!mAnyProjection && !Arrays.equals(projection, mProjection)) {
+ return false;
+ }
+
+ if (!mAnySelection && !Objects.equals(selection, mSelection)) {
+ return false;
+ }
+
+ if (!mAnySelection && !Arrays.equals(selectionArgs, mSelectionArgs)) {
+ return false;
+ }
+
+ if (!mAnySortOrder && !Objects.equals(sortOrder, mSortOrder)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public Cursor getResult(String[] projection) {
+ String[] columnNames;
+ if (mAnyProjection) {
+ columnNames = projection != null ? projection : mDefaultProjection;
+ } else {
+ columnNames = mProjection != null ? mProjection : mDefaultProjection;
+ }
+
+ MatrixCursor cursor = new MatrixCursor(columnNames);
+ for (Object row : mRows) {
+ if (row instanceof Object[]) {
+ cursor.addRow((Object[]) row);
+ } else {
+ ContentValues values = (ContentValues) row;
+ Object[] columns = new Object[columnNames.length];
+ for (int i = 0; i < columnNames.length; i++) {
+ columns[i] = values.get(columnNames[i]);
+ }
+ cursor.addRow(columns);
+ }
+ }
+ return cursor;
+ }
+
+ public static Query forAnyUri() {
+ return new Query();
+ }
+
+ public static Query forUrisMatching(UriMatcher matcher) {
+ return new Query(matcher);
+ }
+
+ public static Query forUrisMatching(String authority, String... paths) {
+ final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
+ for (int i = 0; i < paths.length; i++) {
+ matcher.addURI(authority, paths[i], i);
+ }
+ return new Query(matcher);
+ }
+
+ }
+
+ public static class TypeQuery {
+ private final Uri mUri;
+ private final String mType;
+
+ public TypeQuery(Uri uri, String type) {
+ mUri = uri;
+ mType = type;
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
+
+ public String getType() {
+ return mType;
+ }
+
+ @Override
+ public String toString() {
+ return mUri + " --> " + mType;
+ }
+
+ public boolean equals(Uri uri) {
+ return getUri().equals(uri);
+ }
+ }
+
+ public static class Insert {
+ private final Uri mUri;
+ private final ContentValues mContentValues;
+ private final Uri mResultUri;
+ private boolean mAnyNumberOfTimes;
+ private boolean mIsExecuted;
+
+ /**
+ * Creates a new Insert to expect.
+ *
+ * @param uri the uri of the insertion request.
+ * @param contentValues the ContentValues to insert.
+ * @param resultUri the {@link Uri} for the newly inserted item.
+ * @throws NullPointerException if any parameter is {@code null}.
+ */
+ public Insert(Uri uri, ContentValues contentValues, Uri resultUri) {
+ mUri = Preconditions.checkNotNull(uri);
+ mContentValues = Preconditions.checkNotNull(contentValues);
+ mResultUri = Preconditions.checkNotNull(resultUri);
+ }
+
+ /**
+ * Causes this insert expectation to be useable for mutliple calls to insert, rather than
+ * just one.
+ *
+ * @return this
+ */
+ public Insert anyNumberOfTimes() {
+ mAnyNumberOfTimes = true;
+ return this;
+ }
+
+ private boolean equals(Uri uri, ContentValues contentValues) {
+ return mUri.equals(uri) && mContentValues.equals(contentValues);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Insert insert = (Insert) o;
+ return mAnyNumberOfTimes == insert.mAnyNumberOfTimes &&
+ mIsExecuted == insert.mIsExecuted &&
+ Objects.equals(mUri, insert.mUri) &&
+ Objects.equals(mContentValues, insert.mContentValues) &&
+ Objects.equals(mResultUri, insert.mResultUri);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUri, mContentValues, mResultUri, mAnyNumberOfTimes, mIsExecuted);
+ }
+
+ @Override
+ public String toString() {
+ return "Insert{" +
+ "mUri=" + mUri +
+ ", mContentValues=" + mContentValues +
+ ", mResultUri=" + mResultUri +
+ ", mAnyNumberOfTimes=" + mAnyNumberOfTimes +
+ ", mIsExecuted=" + mIsExecuted +
+ '}';
+ }
+ }
+
+ public static class Delete {
+ private final Uri mUri;
+
+ private boolean mAnyNumberOfTimes;
+ private boolean mAnySelection;
+ @Nullable private String mSelection;
+ @Nullable private String[] mSelectionArgs;
+ private boolean mIsExecuted;
+ private int mRowsAffected;
+
+ /**
+ * Creates a new Delete to expect.
+ * @param uri the uri of the delete request.
+ * @throws NullPointerException if uri is {@code null}.
+ */
+ public Delete(Uri uri) {
+ mUri = Preconditions.checkNotNull(uri);
+ }
+
+ /**
+ * Sets the given information as expected selection arguments.
+ *
+ * @param selection The selection to expect.
+ * @param selectionArgs The selection args to expect.
+ * @return this.
+ */
+ public Delete withSelection(String selection, @Nullable String[] selectionArgs) {
+ mSelection = Preconditions.checkNotNull(selection);
+ mSelectionArgs = selectionArgs;
+ mAnySelection = false;
+ return this;
+ }
+
+ /**
+ * Sets this delete to expect any selection arguments.
+ *
+ * @return this.
+ */
+ public Delete withAnySelection() {
+ mAnySelection = true;
+ return this;
+ }
+
+ /**
+ * Sets this delete to return the given number of rows affected.
+ *
+ * @param rowsAffected The value to return when this expected delete is executed.
+ * @return this.
+ */
+ public Delete returnRowsAffected(int rowsAffected) {
+ mRowsAffected = rowsAffected;
+ return this;
+ }
+
+ /**
+ * Causes this delete expectation to be useable for multiple calls to delete, rather than
+ * just one.
+ *
+ * @return this.
+ */
+ public Delete anyNumberOfTimes() {
+ mAnyNumberOfTimes = true;
+ return this;
+ }
+
+ private boolean equals(Uri uri, String selection, String[] selectionArgs) {
+ return mUri.equals(uri) && Objects.equals(mSelection, selection)
+ && Arrays.equals(mSelectionArgs, selectionArgs);
+ }
+ }
+
+ public static class Update {
+ private final Uri mUri;
+ private final ContentValues mContentValues;
+ @Nullable private String mSelection;
+ @Nullable private String[] mSelectionArgs;
+ private boolean mAnyNumberOfTimes;
+ private boolean mIsExecuted;
+ private int mRowsAffected;
+
+ /**
+ * Creates a new Update to expect.
+ *
+ * @param uri the uri of the update request.
+ * @param contentValues the ContentValues to update.
+ *
+ * @throws NullPointerException if any parameter is {@code null}.
+ */
+ public Update(Uri uri,
+ ContentValues contentValues,
+ @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ mUri = Preconditions.checkNotNull(uri);
+ mContentValues = Preconditions.checkNotNull(contentValues);
+ mSelection = selection;
+ mSelectionArgs = selectionArgs;
+ }
+
+ /**
+ * Causes this update expectation to be useable for mutliple calls to update, rather than
+ * just one.
+ *
+ * @return this
+ */
+ public Update anyNumberOfTimes() {
+ mAnyNumberOfTimes = true;
+ return this;
+ }
+
+ /**
+ * Sets this update to return the given number of rows affected.
+ *
+ * @param rowsAffected The value to return when this expected update is executed.
+ * @return this.
+ */
+ public Update returnRowsAffected(int rowsAffected) {
+ mRowsAffected = rowsAffected;
+ return this;
+ }
+
+ private boolean equals(Uri uri,
+ ContentValues contentValues,
+ @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ return mUri.equals(uri) && mContentValues.equals(contentValues) &&
+ Objects.equals(mSelection, selection) &&
+ Objects.equals(mSelectionArgs, selectionArgs);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Update update = (Update) o;
+ return mAnyNumberOfTimes == update.mAnyNumberOfTimes &&
+ mIsExecuted == update.mIsExecuted &&
+ Objects.equals(mUri, update.mUri) &&
+ Objects.equals(mContentValues, update.mContentValues) &&
+ Objects.equals(mSelection, update.mSelection) &&
+ Objects.equals(mSelectionArgs, update.mSelectionArgs);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUri, mContentValues, mAnyNumberOfTimes, mIsExecuted, mSelection,
+ mSelectionArgs);
+ }
+
+ @Override
+ public String toString() {
+ return "Update{" +
+ "mUri=" + mUri +
+ ", mContentValues=" + mContentValues +
+ ", mAnyNumberOfTimes=" + mAnyNumberOfTimes +
+ ", mIsExecuted=" + mIsExecuted +
+ ", mSelection=" + mSelection +
+ ", mSelectionArgs=" + mSelectionArgs +
+ '}';
+ }
+ }
+
+ private List<Query> mExpectedQueries = new ArrayList<>();
+ private Map<Uri, String> mExpectedTypeQueries = Maps.newHashMap();
+ private List<Insert> mExpectedInserts = new ArrayList<>();
+ private List<Delete> mExpectedDeletes = new ArrayList<>();
+ private List<Update> mExpectedUpdates = new ArrayList<>();
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ public Query expect(Query query) {
+ mExpectedQueries.add(query);
+ return query;
+ }
+
+ public Query expectQuery(Uri contentUri) {
+ return expect(new Query(contentUri));
+ }
+
+ public Query expectQuery(String contentUri) {
+ return expectQuery(Uri.parse(contentUri));
+ }
+
+ public void expectTypeQuery(Uri uri, String type) {
+ mExpectedTypeQueries.put(uri, type);
+ }
+
+ public void expectInsert(Uri contentUri, ContentValues contentValues, Uri resultUri) {
+ mExpectedInserts.add(new Insert(contentUri, contentValues, resultUri));
+ }
+
+ public Update expectUpdate(Uri contentUri,
+ ContentValues contentValues,
+ @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ Update update = new Update(contentUri, contentValues, selection, selectionArgs);
+ mExpectedUpdates.add(update);
+ return update;
+ }
+
+ public Delete expectDelete(Uri contentUri) {
+ Delete delete = new Delete(contentUri);
+ mExpectedDeletes.add(delete);
+ return delete;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ if (mExpectedQueries.isEmpty()) {
+ Assert.fail("Unexpected query: Actual:"
+ + queryToString(uri, projection, selection, selectionArgs, sortOrder));
+ }
+
+ for (Iterator<Query> iterator = mExpectedQueries.iterator(); iterator.hasNext();) {
+ Query query = iterator.next();
+ if (query.equals(uri, projection, selection, selectionArgs, sortOrder)) {
+ query.mExecuted = true;
+ if (!query.mAnyNumberOfTimes) {
+ iterator.remove();
+ }
+ return query.getResult(projection);
+ }
+ }
+
+ Assert.fail("Incorrect query. Expected one of: " + mExpectedQueries + ". Actual: " +
+ queryToString(uri, projection, selection, selectionArgs, sortOrder));
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ if (mExpectedTypeQueries.isEmpty()) {
+ Assert.fail("Unexpected getType query: " + uri);
+ }
+
+ String mimeType = mExpectedTypeQueries.get(uri);
+ if (mimeType != null) {
+ return mimeType;
+ }
+
+ Assert.fail("Unknown mime type for: " + uri);
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ if (mExpectedInserts.isEmpty()) {
+ Assert.fail("Unexpected insert. Actual: " + insertToString(uri, values));
+ }
+ for (Iterator<Insert> iterator = mExpectedInserts.iterator(); iterator.hasNext(); ) {
+ Insert insert = iterator.next();
+ if (insert.equals(uri, values)) {
+ insert.mIsExecuted = true;
+ if (!insert.mAnyNumberOfTimes) {
+ iterator.remove();
+ }
+ return insert.mResultUri;
+ }
+ }
+
+ Assert.fail("Incorrect insert. Expected one of: " + mExpectedInserts + ". Actual: "
+ + insertToString(uri, values));
+ return null;
+ }
+
+ private String insertToString(Uri uri, ContentValues contentValues) {
+ return "Insert { uri=" + uri + ", contentValues=" + contentValues + '}';
+ }
+
+ @Override
+ public int update(Uri uri,
+ ContentValues values,
+ @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ if (mExpectedUpdates.isEmpty()) {
+ Assert.fail("Unexpected update. Actual: "
+ + updateToString(uri, values, selection, selectionArgs));
+ }
+ for (Iterator<Update> iterator = mExpectedUpdates.iterator(); iterator.hasNext(); ) {
+ Update update = iterator.next();
+ if (update.equals(uri, values, selection, selectionArgs)) {
+ update.mIsExecuted = true;
+ if (!update.mAnyNumberOfTimes) {
+ iterator.remove();
+ }
+ return update.mRowsAffected;
+ }
+ }
+
+ Assert.fail("Incorrect update. Expected one of: " + mExpectedUpdates + ". Actual: "
+ + updateToString(uri, values, selection, selectionArgs));
+ return - 1;
+ }
+
+ private String updateToString(Uri uri,
+ ContentValues contentValues,
+ @Nullable String selection,
+ @Nullable String[] selectionArgs) {
+ return "Update { uri=" + uri + ", contentValues=" + contentValues + ", selection=" +
+ selection + ", selectionArgs" + Arrays.toString(selectionArgs) + '}';
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ if (mExpectedDeletes.isEmpty()) {
+ Assert.fail("Unexpected delete. Actual: " + deleteToString(uri, selection,
+ selectionArgs));
+ }
+ for (Iterator<Delete> iterator = mExpectedDeletes.iterator(); iterator.hasNext(); ) {
+ Delete delete = iterator.next();
+ if (delete.equals(uri, selection, selectionArgs)) {
+ delete.mIsExecuted = true;
+ if (!delete.mAnyNumberOfTimes) {
+ iterator.remove();
+ }
+ return delete.mRowsAffected;
+ }
+ }
+ Assert.fail("Incorrect delete. Expected one of: " + mExpectedDeletes + ". Actual: "
+ + deleteToString(uri, selection, selectionArgs));
+ return -1;
+ }
+
+ private String deleteToString(Uri uri, String selection, String[] selectionArgs) {
+ return "Delete { uri=" + uri + ", selection=" + selection + ", selectionArgs"
+ + Arrays.toString(selectionArgs) + '}';
+ }
+
+ private static String queryToString(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(uri == null ? "<Any Uri>" : uri).append(" ");
+ if (projection != null) {
+ sb.append(Arrays.toString(projection));
+ } else {
+ sb.append("[]");
+ }
+ if (selection != null) {
+ sb.append(" selection: '").append(selection).append("'");
+ if (selectionArgs != null) {
+ sb.append(Arrays.toString(selectionArgs));
+ } else {
+ sb.append("[]");
+ }
+ }
+ if (sortOrder != null) {
+ sb.append(" sort: '").append(sortOrder).append("'");
+ }
+ return sb.toString();
+ }
+
+ public void verify() {
+ verifyQueries();
+ verifyInserts();
+ verifyDeletes();
+ }
+
+ private void verifyQueries() {
+ List<Query> missedQueries = new ArrayList<>();
+ for (Query query : mExpectedQueries) {
+ if (!query.mExecuted) {
+ missedQueries.add(query);
+ }
+ }
+ Assert.assertTrue("Not all expected queries have been called: " + missedQueries,
+ missedQueries.isEmpty());
+ }
+
+ private void verifyInserts() {
+ List<Insert> missedInserts = new ArrayList<>();
+ for (Insert insert : mExpectedInserts) {
+ if (!insert.mIsExecuted) {
+ missedInserts.add(insert);
+ }
+ }
+ Assert.assertTrue("Not all expected inserts have been called: " + missedInserts,
+ missedInserts.isEmpty());
+ }
+
+ private void verifyDeletes() {
+ List<Delete> missedDeletes = new ArrayList<>();
+ for (Delete delete : mExpectedDeletes) {
+ if (!delete.mIsExecuted) {
+ missedDeletes.add(delete);
+ }
+ }
+ Assert.assertTrue("Not all expected deletes have been called: " + missedDeletes,
+ missedDeletes.isEmpty());
+ }
+}