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