1 /* 2 * Copyright (C) 2010 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 com.android.contacts.tests.mocks; 18 19 import com.google.android.collect.Lists; 20 import com.google.android.collect.Maps; 21 22 import android.content.ContentProvider; 23 import android.content.ContentValues; 24 import android.database.Cursor; 25 import android.database.MatrixCursor; 26 import android.net.Uri; 27 import android.text.TextUtils; 28 29 import java.util.ArrayList; 30 import java.util.Arrays; 31 import java.util.HashMap; 32 import java.util.Iterator; 33 34 import junit.framework.Assert; 35 36 /** 37 * A programmable mock content provider. 38 */ 39 public class MockContentProvider extends ContentProvider { 40 private static final String TAG = "MockContentProvider"; 41 42 public static class Query { 43 44 private final Uri mUri; 45 private String[] mProjection; 46 private String[] mDefaultProjection; 47 private String mSelection; 48 private String[] mSelectionArgs; 49 private String mSortOrder; 50 private ArrayList<Object> mRows = new ArrayList<Object>(); 51 private boolean mAnyProjection; 52 private boolean mAnySelection; 53 private boolean mAnySortOrder; 54 private boolean mAnyNumberOfTimes; 55 56 private boolean mExecuted; 57 58 public Query(Uri uri) { 59 mUri = uri; 60 } 61 62 @Override 63 public String toString() { 64 return queryToString(mUri, mProjection, mSelection, mSelectionArgs, mSortOrder); 65 } 66 67 public Query withProjection(String... projection) { 68 mProjection = projection; 69 return this; 70 } 71 72 public Query withDefaultProjection(String... projection) { 73 mDefaultProjection = projection; 74 return this; 75 } 76 77 public Query withAnyProjection() { 78 mAnyProjection = true; 79 return this; 80 } 81 82 public Query withSelection(String selection, String... selectionArgs) { 83 mSelection = selection; 84 mSelectionArgs = selectionArgs; 85 return this; 86 } 87 88 public Query withAnySelection() { 89 mAnySelection = true; 90 return this; 91 } 92 93 public Query withSortOrder(String sortOrder) { 94 mSortOrder = sortOrder; 95 return this; 96 } 97 98 public Query withAnySortOrder() { 99 mAnySortOrder = true; 100 return this; 101 } 102 103 public Query returnRow(ContentValues values) { 104 mRows.add(values); 105 return this; 106 } 107 108 public Query returnRow(Object... row) { 109 mRows.add(row); 110 return this; 111 } 112 113 public Query returnEmptyCursor() { 114 mRows.clear(); 115 return this; 116 } 117 118 public Query anyNumberOfTimes() { 119 mAnyNumberOfTimes = true; 120 return this; 121 } 122 123 public boolean equals(Uri uri, String[] projection, String selection, 124 String[] selectionArgs, String sortOrder) { 125 if (!uri.equals(mUri)) { 126 return false; 127 } 128 129 if (!mAnyProjection && !equals(projection, mProjection)) { 130 return false; 131 } 132 133 if (!mAnySelection && !equals(selection, mSelection)) { 134 return false; 135 } 136 137 if (!mAnySelection && !equals(selectionArgs, mSelectionArgs)) { 138 return false; 139 } 140 141 if (!mAnySortOrder && !equals(sortOrder, mSortOrder)) { 142 return false; 143 } 144 145 return true; 146 } 147 148 private boolean equals(String string1, String string2) { 149 if (TextUtils.isEmpty(string1)) { 150 string1 = null; 151 } 152 if (TextUtils.isEmpty(string2)) { 153 string2 = null; 154 } 155 return TextUtils.equals(string1, string2); 156 } 157 158 private static boolean equals(String[] array1, String[] array2) { 159 boolean empty1 = array1 == null || array1.length == 0; 160 boolean empty2 = array2 == null || array2.length == 0; 161 if (empty1 && empty2) { 162 return true; 163 } 164 if (empty1 != empty2 && (empty1 || empty2)) { 165 return false; 166 } 167 168 if (array1.length != array2.length) return false; 169 170 for (int i = 0; i < array1.length; i++) { 171 if (!array1[i].equals(array2[i])) { 172 return false; 173 } 174 } 175 return true; 176 } 177 178 public Cursor getResult(String[] projection) { 179 String[] columnNames; 180 if (mAnyProjection) { 181 columnNames = projection; 182 } else { 183 columnNames = mProjection != null ? mProjection : mDefaultProjection; 184 } 185 186 MatrixCursor cursor = new MatrixCursor(columnNames); 187 for (Object row : mRows) { 188 if (row instanceof Object[]) { 189 cursor.addRow((Object[]) row); 190 } else { 191 ContentValues values = (ContentValues) row; 192 Object[] columns = new Object[projection.length]; 193 for (int i = 0; i < projection.length; i++) { 194 columns[i] = values.get(projection[i]); 195 } 196 cursor.addRow(columns); 197 } 198 } 199 return cursor; 200 } 201 } 202 203 public static class TypeQuery { 204 private final Uri mUri; 205 private final String mType; 206 207 public TypeQuery(Uri uri, String type) { 208 mUri = uri; 209 mType = type; 210 } 211 212 public Uri getUri() { 213 return mUri; 214 } 215 216 public String getType() { 217 return mType; 218 } 219 220 @Override 221 public String toString() { 222 return mUri + " --> " + mType; 223 } 224 225 public boolean equals(Uri uri) { 226 return getUri().equals(uri); 227 } 228 } 229 230 private ArrayList<Query> mExpectedQueries = new ArrayList<Query>(); 231 private HashMap<Uri, String> mExpectedTypeQueries = Maps.newHashMap(); 232 233 @Override 234 public boolean onCreate() { 235 return true; 236 } 237 238 public Query expectQuery(Uri contentUri) { 239 Query query = new Query(contentUri); 240 mExpectedQueries.add(query); 241 return query; 242 } 243 244 public void expectTypeQuery(Uri uri, String type) { 245 mExpectedTypeQueries.put(uri, type); 246 } 247 248 @Override 249 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 250 String sortOrder) { 251 252 for (Iterator<Query> iterator = mExpectedQueries.iterator(); iterator.hasNext();) { 253 Query query = iterator.next(); 254 if (query.equals(uri, projection, selection, selectionArgs, sortOrder)) { 255 query.mExecuted = true; 256 if (!query.mAnyNumberOfTimes) { 257 iterator.remove(); 258 } 259 return query.getResult(projection); 260 } 261 } 262 263 if (mExpectedQueries.isEmpty()) { 264 Assert.fail("Unexpected query: " 265 + queryToString(uri, projection, selection, selectionArgs, sortOrder)); 266 } else { 267 StringBuilder sb = new StringBuilder(); 268 sb.append(mExpectedQueries.get(0)); 269 for (int i = 1; i < mExpectedQueries.size(); i++) { 270 sb.append("\n ").append(mExpectedQueries.get(i)); 271 } 272 Assert.fail("Incorrect query.\n Expected: " + sb + "\n Actual: " + 273 queryToString(uri, projection, selection, selectionArgs, sortOrder)); 274 } 275 return null; 276 } 277 278 @Override 279 public int delete(Uri uri, String selection, String[] selectionArgs) { 280 throw new UnsupportedOperationException(); 281 } 282 283 @Override 284 public String getType(Uri uri) { 285 if (mExpectedTypeQueries.isEmpty()) { 286 Assert.fail("Unexpected getType query: " + uri); 287 } 288 289 String mimeType = mExpectedTypeQueries.get(uri); 290 if (mimeType != null) { 291 return mimeType; 292 } 293 294 Assert.fail("Unknown mime type for: " + uri); 295 return null; 296 } 297 298 @Override 299 public Uri insert(Uri uri, ContentValues values) { 300 throw new UnsupportedOperationException(); 301 } 302 303 @Override 304 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 305 throw new UnsupportedOperationException(); 306 } 307 308 private static String queryToString(Uri uri, String[] projection, String selection, 309 String[] selectionArgs, String sortOrder) { 310 StringBuilder sb = new StringBuilder(); 311 sb.append(uri).append(" "); 312 if (projection != null) { 313 sb.append(Arrays.toString(projection)); 314 } else { 315 sb.append("[]"); 316 } 317 if (selection != null) { 318 sb.append(" selection: '").append(selection).append("'"); 319 if (selectionArgs != null) { 320 sb.append(Arrays.toString(selectionArgs)); 321 } else { 322 sb.append("[]"); 323 } 324 } 325 if (sortOrder != null) { 326 sb.append(" sort: '").append(sortOrder).append("'"); 327 } 328 return sb.toString(); 329 } 330 331 public void verify() { 332 ArrayList<Query> mMissedQueries = Lists.newArrayList(); 333 for (Query query : mExpectedQueries) { 334 if (!query.mExecuted) { 335 mMissedQueries.add(query); 336 } 337 } 338 Assert.assertTrue("Not all expected queries have been called: " + 339 mMissedQueries, mMissedQueries.isEmpty()); 340 } 341 } 342