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