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