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 android.provider.cts.contacts; 18 19 import com.google.android.collect.Lists; 20 import com.google.android.collect.Sets; 21 22 import android.content.ContentProviderClient; 23 import android.content.ContentUris; 24 import android.content.ContentValues; 25 import android.database.Cursor; 26 import android.net.Uri; 27 import android.provider.BaseColumns; 28 import android.provider.ContactsContract; 29 import android.provider.ContactsContract.Contacts; 30 import android.provider.ContactsContract.Data; 31 import android.provider.ContactsContract.Groups; 32 import android.provider.ContactsContract.RawContacts; 33 import android.text.TextUtils; 34 35 import java.util.ArrayList; 36 import java.util.Arrays; 37 import java.util.HashSet; 38 import java.util.Map; 39 import java.util.Set; 40 41 import junit.framework.Assert; 42 import junit.framework.ComparisonFailure; 43 44 /** 45 * A test data builder for ContactsContract tests. 46 */ 47 public class ContactsContract_TestDataBuilder { 48 private ContentProviderClient mProvider; 49 private ArrayList<Builder<?>> mCreatedRows = Lists.newArrayList(); 50 private HashSet<Builder<?>> mLoadedRows = Sets.newHashSet(); 51 52 private interface IdQuery { 53 String[] COLUMNS = new String[] { 54 BaseColumns._ID, 55 }; 56 57 int _ID = 0; 58 } 59 60 public abstract class Builder<T extends Builder<?>> extends Assert { 61 protected ContentValues mValues = new ContentValues(); 62 private Uri mUri; 63 private long mId = -1; 64 private Cursor mCursor; 65 private boolean mAlreadyDeleted; 66 67 protected abstract Uri getContentUri(); 68 69 public long getId() throws Exception { 70 if (mId != -1) { 71 return mId; 72 } 73 74 assertNotNull("Row has not be inserted or loaded yet", mUri); 75 76 Cursor cursor = mProvider.query(mUri, IdQuery.COLUMNS, null, null, null, null); 77 if (cursor != null) { 78 try { 79 cursor.moveToFirst(); 80 mId = cursor.getInt(IdQuery._ID); 81 } finally { 82 cursor.close(); 83 } 84 85 } 86 assertTrue("Could not obtain _ID for URI: " + mUri, mId != -1); 87 return mId; 88 } 89 90 @SuppressWarnings("unchecked") 91 public T setUri(Uri uri) { 92 mUri = uri; 93 return (T)this; 94 } 95 96 public Uri getUri() { 97 if (mUri == null) { 98 assertTrue("Neither URI nor ID has been specified", mId != -1); 99 mUri = ContentUris.withAppendedId(getContentUri(), mId); 100 } 101 return mUri; 102 } 103 104 @SuppressWarnings("unchecked") 105 public T with(String key, String value) { 106 mValues.put(key, value); 107 return (T)this; 108 } 109 110 @SuppressWarnings("unchecked") 111 public T with(String key, long value) { 112 mValues.put(key, value); 113 return (T)this; 114 } 115 116 @SuppressWarnings("unchecked") 117 public T with(String key, byte[] value) { 118 mValues.put(key, value); 119 return (T)this; 120 } 121 122 @SuppressWarnings("unchecked") 123 public T insert() throws Exception { 124 insertDependent(); 125 mCreatedRows.add(this); 126 return (T)this; 127 } 128 129 @SuppressWarnings("unchecked") 130 public T insertDependent() throws Exception { 131 mUri = mProvider.insert(getContentUri(), mValues); 132 assertNotNull("Could not insert a row in " + getContentUri(), mUri); 133 mId = ContentUris.parseId(mUri); 134 return (T)this; 135 } 136 137 public void delete() throws Exception { 138 int count = mProvider.delete(getUri(), null, null); 139 assertEquals("Wrong number of rows deleted for " + getUri(), 1, count); 140 } 141 142 public void deletePermanently() throws Exception { 143 if (mAlreadyDeleted) { 144 return; 145 } 146 Uri uri = getUri().buildUpon() 147 .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true") 148 .build(); 149 int count = mProvider.delete(uri, null, null); 150 assertEquals("Wrong number of rows deleted for " + uri, 1, count); 151 mCreatedRows.remove(this); 152 } 153 154 @SuppressWarnings("unchecked") 155 public T load() throws Exception { 156 close(); 157 mLoadedRows.add(this); 158 159 mCursor = mProvider.query(getUri(), null, null, null, null, null); 160 if (mCursor == null || !mCursor.moveToFirst()) { 161 return null; 162 } else { 163 return (T) this; 164 } 165 } 166 167 @SuppressWarnings("unchecked") 168 public T loadUsingValues() throws Exception { 169 close(); 170 mLoadedRows.add(this); 171 172 StringBuilder selection = new StringBuilder(); 173 ArrayList<String> selectionArgs = Lists.newArrayList(); 174 Set<Map.Entry<String, Object>> entries = mValues.valueSet(); 175 for (Map.Entry<String, Object> entry : entries) { 176 String column = entry.getKey(); 177 Object value = entry.getValue(); 178 179 if (selection.length() != 0) { 180 selection.append(" AND "); 181 } 182 183 selection.append(column); 184 if (value == null) { 185 selection.append(" NOT NULL"); 186 } else { 187 selection.append("=?"); 188 selectionArgs.add(value.toString()); 189 } 190 } 191 mCursor = mProvider.query(getContentUri(), null, 192 selection.toString(), 193 selectionArgs.toArray(new String[0]), null, null); 194 if (mCursor == null || !mCursor.moveToFirst()) { 195 fail("No data rows for " + getContentUri() + "[" + mValues.toString() + "]"); 196 } 197 mId = mCursor.getLong(getColumnIndex(BaseColumns._ID)); 198 return (T)this; 199 } 200 201 public boolean isNull(String columnName) { 202 return mCursor.isNull(mCursor.getColumnIndex(columnName)); 203 } 204 205 public long getLong(String columnName) { 206 return mCursor.getLong(mCursor.getColumnIndex(columnName)); 207 } 208 209 public String getString(String columnName) { 210 return mCursor.getString(mCursor.getColumnIndex(columnName)); 211 } 212 213 public void assertColumn(String columnName, long value) { 214 assertEquals(value, mCursor.getLong(getColumnIndex(columnName))); 215 } 216 217 public void assertColumn(String columnName, String value) { 218 assertEquals(value, mCursor.getString(getColumnIndex(columnName))); 219 } 220 221 public void assertColumn(String columnName, byte[] value) { 222 assertEquals(value, mCursor.getBlob(getColumnIndex(columnName))); 223 } 224 225 public void assertBlobColumnNotNull(String columnName) { 226 assertNotNull(mCursor.getBlob(getColumnIndex(columnName))); 227 } 228 229 public void assertBlobColumnNull(String columnName) { 230 assertNull(mCursor.getBlob(getColumnIndex(columnName))); 231 } 232 233 public void assertEquals(byte[] expected, byte[] actual) { 234 assertEquals(null, expected, actual); 235 } 236 237 public void assertEquals(String message, byte[] expected, byte[] actual) { 238 if (expected == null && actual == null) 239 return; 240 if (expected != null && Arrays.equals(actual, expected)) 241 return; 242 throw new ComparisonFailure(message, Arrays.toString(expected), Arrays.toString(actual)); 243 } 244 245 private int getColumnIndex(String columnName) { 246 int index = mCursor.getColumnIndex(columnName); 247 assertTrue("No such column: " + columnName + 248 ". Available columns: " + TextUtils.join(", ", mCursor.getColumnNames()), 249 index != -1); 250 return index; 251 } 252 253 public void close() { 254 if (mCursor != null) { 255 mCursor.close(); 256 mCursor = null; 257 } 258 mLoadedRows.remove(this); 259 } 260 261 public void setAlreadyDeleted() { 262 mAlreadyDeleted = true; 263 } 264 } 265 266 public class TestRawContact extends Builder<TestRawContact> { 267 268 private TestContact mContact; 269 270 @Override 271 protected Uri getContentUri() { 272 return RawContacts.CONTENT_URI; 273 } 274 275 public TestData newDataRow(String mimeType) { 276 return new TestData(this, mimeType); 277 } 278 279 public long getContactId() { 280 return getLong(RawContacts.CONTACT_ID); 281 } 282 283 public TestContact getContact() throws Exception { 284 if (mContact == null) { 285 mContact = new NestedTestContact(this); 286 } 287 return mContact; 288 } 289 } 290 291 public class TestContact extends Builder<TestContact> { 292 293 @Override 294 protected Uri getContentUri() { 295 return Contacts.CONTENT_URI; 296 } 297 } 298 299 private class NestedTestContact extends TestContact { 300 private final TestRawContact mRawContact; 301 302 public NestedTestContact(TestRawContact rawContact) { 303 mRawContact = rawContact; 304 } 305 306 @Override 307 public long getId() throws Exception { 308 return mRawContact.getContactId(); 309 } 310 311 @Override 312 public TestContact load() throws Exception { 313 return with(Contacts._ID, mRawContact.getContactId()).loadUsingValues(); 314 } 315 } 316 317 public class TestGroup extends Builder<TestGroup> { 318 319 @Override 320 protected Uri getContentUri() { 321 return Groups.CONTENT_URI; 322 } 323 } 324 325 public class TestData extends Builder<TestData> { 326 private final TestRawContact mRawContact; 327 328 public TestData(TestRawContact rawContact, String mimeType) { 329 this.mRawContact = rawContact; 330 mValues.put(Data.MIMETYPE, mimeType); 331 } 332 333 @Override 334 protected Uri getContentUri() { 335 return Data.CONTENT_URI; 336 } 337 338 @Override 339 public TestData insert() throws Exception { 340 mValues.put(Data.RAW_CONTACT_ID, mRawContact.getId()); 341 return super.insertDependent(); 342 } 343 344 public long getRawContactId() { 345 return getLong(Data.RAW_CONTACT_ID); 346 } 347 348 public long getId() { 349 return getLong(Data._ID); 350 } 351 352 public TestRawContact getRawContact() throws Exception { 353 return mRawContact; 354 } 355 } 356 357 public ContactsContract_TestDataBuilder(ContentProviderClient provider) { 358 this.mProvider = provider; 359 } 360 361 public TestRawContact newRawContact() { 362 return new TestRawContact(); 363 } 364 365 public TestContact newContact() { 366 return new TestContact(); 367 } 368 369 public TestGroup newGroup() { 370 return new TestGroup(); 371 } 372 373 public void cleanup() throws Exception { 374 for (Builder<?> builder : new ArrayList<Builder<?>>(mCreatedRows)) { 375 builder.deletePermanently(); 376 } 377 378 for (Builder<?> builder : new HashSet<Builder<?>>(mLoadedRows)) { 379 builder.close(); 380 } 381 } 382 383 } 384