1 /*
2  * Copyright (C) 2011 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.providers.contacts;
18 
19 import android.accounts.Account;
20 import android.content.ContentValues;
21 import android.database.ContentObserver;
22 import android.database.Cursor;
23 import android.database.sqlite.SQLiteDatabase;
24 import android.net.Uri;
25 import android.os.Handler;
26 import android.os.Looper;
27 import android.provider.ContactsContract;
28 import android.provider.ContactsContract.ProviderStatus;
29 import android.provider.ContactsContract.RawContacts;
30 import android.test.MoreAsserts;
31 
32 import androidx.test.filters.LargeTest;
33 import androidx.test.filters.SmallTest;
34 
35 import com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns;
36 import com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns;
37 import com.android.providers.contacts.ContactsDatabaseHelper.Tables;
38 
39 import com.google.android.collect.Sets;
40 
41 import java.util.HashSet;
42 import java.util.Set;
43 import java.util.concurrent.CountDownLatch;
44 import java.util.concurrent.TimeUnit;
45 import java.util.concurrent.atomic.AtomicReference;
46 
47 @SmallTest
48 public class ContactsDatabaseHelperTest extends BaseContactsProvider2Test {
49     private static final String TAG = "ContactsDHT";
50 
51     private ContactsDatabaseHelper mDbHelper;
52     private SQLiteDatabase mDb;
53 
54     @Override
setUp()55     protected void setUp() throws Exception {
56         super.setUp();
57         mDbHelper = getContactsProvider().getDatabaseHelper();
58         mDb = mDbHelper.getWritableDatabase();
59     }
60 
testGetOrCreateAccountId()61     public void testGetOrCreateAccountId() {
62         final AccountWithDataSet a1 = null;
63         final AccountWithDataSet a2 = new AccountWithDataSet("a", null, null);
64         final AccountWithDataSet a3 = new AccountWithDataSet(null, "b", null);
65         final AccountWithDataSet a4 = new AccountWithDataSet(null, null, "c");
66         final AccountWithDataSet a5 = new AccountWithDataSet("a", "b", "c");
67 
68         // First, there's no accounts.  getAccountIdOrNull() always returns null.
69         assertNull(mDbHelper.getAccountIdOrNull(a1));
70         assertNull(mDbHelper.getAccountIdOrNull(a2));
71         assertNull(mDbHelper.getAccountIdOrNull(a3));
72         assertNull(mDbHelper.getAccountIdOrNull(a4));
73         assertNull(mDbHelper.getAccountIdOrNull(a5));
74 
75         // getOrCreateAccountId should create accounts.
76         final long a1id = mDbHelper.getOrCreateAccountIdInTransaction(a1);
77         final long a2id = mDbHelper.getOrCreateAccountIdInTransaction(a2);
78         final long a3id = mDbHelper.getOrCreateAccountIdInTransaction(a3);
79         final long a4id = mDbHelper.getOrCreateAccountIdInTransaction(a4);
80         final long a5id = mDbHelper.getOrCreateAccountIdInTransaction(a5);
81 
82         // The IDs should be all positive and unique.
83         assertTrue(a1id > 0);
84         assertTrue(a2id > 0);
85         assertTrue(a3id > 0);
86         assertTrue(a4id > 0);
87         assertTrue(a5id > 0);
88 
89         final Set<Long> ids = Sets.newHashSet();
90         ids.add(a1id);
91         ids.add(a2id);
92         ids.add(a3id);
93         ids.add(a4id);
94         ids.add(a5id);
95         assertEquals(5, ids.size());
96 
97         // Second call: This time getOrCreateAccountId will return the existing IDs.
98         assertEquals(a1id, mDbHelper.getOrCreateAccountIdInTransaction(a1));
99         assertEquals(a2id, mDbHelper.getOrCreateAccountIdInTransaction(a2));
100         assertEquals(a3id, mDbHelper.getOrCreateAccountIdInTransaction(a3));
101         assertEquals(a4id, mDbHelper.getOrCreateAccountIdInTransaction(a4));
102         assertEquals(a5id, mDbHelper.getOrCreateAccountIdInTransaction(a5));
103 
104         // Now getAccountIdOrNull() returns IDs too.
105         assertEquals((Long) a1id, mDbHelper.getAccountIdOrNull(a1));
106         assertEquals((Long) a2id, mDbHelper.getAccountIdOrNull(a2));
107         assertEquals((Long) a3id, mDbHelper.getAccountIdOrNull(a3));
108         assertEquals((Long) a4id, mDbHelper.getAccountIdOrNull(a4));
109         assertEquals((Long) a5id, mDbHelper.getAccountIdOrNull(a5));
110 
111         // null and AccountWithDataSet.NULL should be treated as the same thing.
112         assertEquals(a1id, mDbHelper.getOrCreateAccountIdInTransaction(AccountWithDataSet.LOCAL));
113         assertEquals((Long) a1id, mDbHelper.getAccountIdOrNull(AccountWithDataSet.LOCAL));
114 
115         // Remove all accounts.
116         mDbHelper.getWritableDatabase().execSQL("delete from " + Tables.ACCOUNTS);
117 
118         assertNull(mDbHelper.getAccountIdOrNull(AccountWithDataSet.LOCAL));
119         assertNull(mDbHelper.getAccountIdOrNull(a1));
120         assertNull(mDbHelper.getAccountIdOrNull(a2));
121         assertNull(mDbHelper.getAccountIdOrNull(a3));
122         assertNull(mDbHelper.getAccountIdOrNull(a4));
123         assertNull(mDbHelper.getAccountIdOrNull(a5));
124 
125         // Logically same as a5, but physically different object.
126         final AccountWithDataSet a5b = new AccountWithDataSet("a", "b", "c");
127         // a5 and a5b should have the same ID.
128         assertEquals(
129                 mDbHelper.getOrCreateAccountIdInTransaction(a5),
130                 mDbHelper.getOrCreateAccountIdInTransaction(a5b));
131     }
132 
133     /**
134      * Test for {@link ContactsDatabaseHelper#queryIdWithOneArg} and
135      * {@link ContactsDatabaseHelper#insertWithOneArgAndReturnId}.
136      */
testQueryIdWithOneArg_insertWithOneArgAndReturnId()137     public void testQueryIdWithOneArg_insertWithOneArgAndReturnId() {
138         final String query =
139                 "SELECT " + MimetypesColumns._ID +
140                         " FROM " + Tables.MIMETYPES +
141                         " WHERE " + MimetypesColumns.MIMETYPE + "=?";
142 
143         final String insert =
144                 "INSERT INTO " + Tables.MIMETYPES + "("
145                         + MimetypesColumns.MIMETYPE +
146                         ") VALUES (?)";
147 
148         // First, the table is empty.
149         assertEquals(-1, ContactsDatabaseHelper.queryIdWithOneArg(mDb, query, "value1"));
150         assertEquals(-1, ContactsDatabaseHelper.queryIdWithOneArg(mDb, query, "value2"));
151 
152         // Insert one value.
153         final long id1 = ContactsDatabaseHelper.insertWithOneArgAndReturnId(mDb, insert, "value1");
154         MoreAsserts.assertNotEqual(-1, id1);
155 
156         assertEquals(id1, ContactsDatabaseHelper.queryIdWithOneArg(mDb, query, "value1"));
157         assertEquals(-1, ContactsDatabaseHelper.queryIdWithOneArg(mDb, query, "value2"));
158 
159 
160         // Insert one value.
161         final long id2 = ContactsDatabaseHelper.insertWithOneArgAndReturnId(mDb, insert, "value2");
162         MoreAsserts.assertNotEqual(-1, id2);
163 
164         assertEquals(id1, ContactsDatabaseHelper.queryIdWithOneArg(mDb, query, "value1"));
165         assertEquals(id2, ContactsDatabaseHelper.queryIdWithOneArg(mDb, query, "value2"));
166 
167         // Insert the same value and cause a conflict.
168         assertEquals(-1, ContactsDatabaseHelper.insertWithOneArgAndReturnId(mDb, insert, "value2"));
169     }
170 
171     /**
172      * Test for {@link ContactsDatabaseHelper#getPackageId(String)}
173      */
testGetPackageId()174     public void testGetPackageId() {
175         // Test for getPackageId.
176         final long packageId1 = mDbHelper.getPackageId("value1");
177         final long packageId2 = mDbHelper.getPackageId("value2");
178         final long packageId3 = mDbHelper.getPackageId("value3");
179 
180         // Make sure they're all different.
181         final HashSet<Long> set = new HashSet<>();
182         set.add(packageId1);
183         set.add(packageId2);
184         set.add(packageId3);
185         assertEquals(3, set.size());
186 
187         // Make sure that repeated calls return the same value
188         assertEquals(packageId1, mDbHelper.getPackageId("value1"));
189     }
190 
191     /**
192      * Test for {@link ContactsDatabaseHelper#getMimeTypeId(String)}
193      */
testGetMimeTypeId()194     public void testGetMimeTypeId() {
195         // Test for getMimeTypeId.
196         final long mimetypeId1 = mDbHelper.getMimeTypeId("value1");
197         final long mimetypeId2 = mDbHelper.getMimeTypeId("value2");
198         final long mimetypeId3 = mDbHelper.getMimeTypeId("value3");
199 
200         // Make sure they're all different.
201         final HashSet<Long> set = new HashSet<>();
202         set.clear();
203         set.add(mimetypeId1);
204         set.add(mimetypeId2);
205         set.add(mimetypeId3);
206         assertEquals(3, set.size());
207 
208         // Make sure repeated calls return the same value
209         assertEquals(mimetypeId1, mDbHelper.getMimeTypeId("value1"));
210     }
211 
212     /**
213      * Test for cache {@link ContactsDatabaseHelper#mCommonMimeTypeIdsCache} which stores ids for
214      * common mime types for faster access.
215      */
testGetCommonMimeTypeIds()216     public void testGetCommonMimeTypeIds() {
217         // getMimeTypeId should return the same value as the value stored in the cache
218         for (String commonMimeType : ContactsDatabaseHelper.COMMON_MIME_TYPES) {
219             assertEquals(mDbHelper.mCommonMimeTypeIdsCache.get(commonMimeType).longValue(),
220                     mDbHelper.getMimeTypeId(commonMimeType));
221         }
222 
223         // The ids should be available even after deleting them from the table
224         mDb.execSQL("DELETE FROM " + Tables.MIMETYPES + ";");
225 
226         for (String commonMimeType : ContactsDatabaseHelper.COMMON_MIME_TYPES) {
227             assertEquals(mDbHelper.mCommonMimeTypeIdsCache.get(commonMimeType).longValue(),
228                     mDbHelper.getMimeTypeId(commonMimeType));
229         }
230     }
231 
232     /**
233      * Try to cause conflicts in getMimeTypeId() by calling it from multiple threads with
234      * the current time as the argument and make sure it won't crash.
235      *
236      * We don't know from the test if there have actually been conflits, but if you look at
237      * logcat you'll see a lot of conflict warnings.
238      */
239     @LargeTest
testGetMimeTypeId_conflict()240     public void testGetMimeTypeId_conflict() {
241 
242         final int NUM_THREADS = 4;
243         final int DURATION_SECONDS = 5;
244 
245         final long finishTime = System.currentTimeMillis() + DURATION_SECONDS * 1000;
246 
247         final Runnable r = new Runnable() {
248             @Override
249             public void run() {
250                 for (;;) {
251                     final long now = System.currentTimeMillis();
252                     if (now >= finishTime) {
253                         return;
254                     }
255                     assertTrue(mDbHelper.getMimeTypeId(String.valueOf(now)) > 0);
256                 }
257             }
258         };
259         final Thread[] threads = new Thread[NUM_THREADS];
260         for (int i = 0; i < threads.length; i++) {
261             threads[i] = new Thread(r);
262             threads[i].setDaemon(true);
263         }
264         for (int i = 0; i < threads.length; i++) {
265             threads[i].start();
266         }
267         for (int i = 0; i < threads.length; i++) {
268             try {
269                 threads[i].join();
270             } catch (InterruptedException ignore) {
271             }
272         }
273     }
274 
testUpgradeHashId()275     public void testUpgradeHashId() {
276         // Create an account.
277         final long accountId = mDbHelper.getOrCreateAccountIdInTransaction(
278                 AccountWithDataSet.LOCAL);
279         // Create a raw contact.
280         ContentValues rawContactValues = new ContentValues();
281         rawContactValues.put(ContactsDatabaseHelper.RawContactsColumns.ACCOUNT_ID, accountId);
282         final long rawContactId = mDb.insert(Tables.RAW_CONTACTS,null, rawContactValues);
283         assertTrue(rawContactId > 0);
284         // Create data for the raw contact Id.
285         final StringBuilder data1 = new StringBuilder();
286         for (int i = 0; i < 2048; i++) {
287             data1.append("L");
288         }
289         final String dataString = data1.toString();
290         final String hashId = mDbHelper.generateHashId(dataString, null);
291         final int mimeType = 1;
292         final ContentValues values = new ContentValues();
293         values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
294         values.put(ContactsDatabaseHelper.DataColumns.MIMETYPE_ID, mimeType);
295         values.put(ContactsContract.Data.DATA1, dataString);
296         for (int i = 0; i < 2048; i++) {
297             assertTrue(mDb.insert(Tables.DATA, null, values) > 0);
298         }
299         mDbHelper.upgradeToVersion1101(mDb);
300         final Cursor c = mDb.query(Tables.DATA, new String[]{ContactsContract.Data.HASH_ID},
301                 null, null, null, null, null);
302         try {
303             assertEquals(2048, c.getCount());
304             while (c.moveToNext()) {
305                 final String expectedHashId = c.getString(0);
306                 assertEquals(expectedHashId, hashId);
307             }
308         } finally {
309             c.close();
310         }
311     }
312 
testUpgradeHashIdForPhoto()313     public void testUpgradeHashIdForPhoto() {
314         // Create an account.
315         final long accountId = mDbHelper.getOrCreateAccountIdInTransaction(
316                 AccountWithDataSet.LOCAL);
317         // Create a raw contact.
318         ContentValues rawContactValues = new ContentValues();
319         rawContactValues.put(ContactsDatabaseHelper.RawContactsColumns.ACCOUNT_ID, accountId);
320         final long rawContactId = mDb.insert(Tables.RAW_CONTACTS,null, rawContactValues);
321         assertTrue(rawContactId > 0);
322 
323         // Create data for the raw contact Id.
324         final long mimeType = mDbHelper.getMimeTypeId(
325                 ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
326         final String photoHashId = mDbHelper.getPhotoHashId();
327         final ContentValues values = new ContentValues();
328         values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
329         values.put(ContactsDatabaseHelper.DataColumns.MIMETYPE_ID, mimeType);
330         for (int i = 0; i < 2048; i++) {
331             assertTrue(mDb.insert(Tables.DATA, null, values) > 0);
332         }
333         mDbHelper.upgradeToVersion1110(mDb);
334         final Cursor c = mDb.query(Tables.DATA, new String[]{ContactsContract.Data.HASH_ID},
335                 null, null, null, null, null);
336         try {
337             assertEquals(2048, c.getCount());
338             while (c.moveToNext()) {
339                 final String actualHashId = c.getString(0);
340                 assertEquals(photoHashId, actualHashId);
341             }
342         } finally {
343             c.close();
344         }
345     }
346 
testUpgradeToVersion111_SetPrimaryPhonebookBucketToNumberBucket()347     public void testUpgradeToVersion111_SetPrimaryPhonebookBucketToNumberBucket() {
348         // Zero primary phone book bucket and null primary sort key
349         final ContentValues contentValues = new ContentValues();
350         contentValues.put(RawContactsColumns.PHONEBOOK_BUCKET_PRIMARY, 0);
351         mDb.insert(Tables.RAW_CONTACTS, null, contentValues);
352 
353         mDbHelper.upgradeToVersion1111(mDb);
354 
355         // Assert that the primary phone book bucket/label has been set to the number bucket/label
356         final ContactLocaleUtils localeUtils = ContactLocaleUtils.getInstance();
357         final int numberBucket = localeUtils.getNumberBucketIndex();
358         final String numberLabel = localeUtils.getBucketLabel(numberBucket);
359         assertUpgradeToVersion1111(numberBucket, numberLabel,
360                 RawContactsColumns.PHONEBOOK_BUCKET_PRIMARY,
361                 RawContactsColumns.PHONEBOOK_LABEL_PRIMARY);
362     }
363 
testUpgradeToVersion111_SetAltPhonebookBucketToNumberBucket()364     public void testUpgradeToVersion111_SetAltPhonebookBucketToNumberBucket() {
365         // Zero alt phone book bucket and null alt sort key
366         final ContentValues contentValues = new ContentValues();
367         contentValues.put(RawContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE, 0);
368         mDb.insert(Tables.RAW_CONTACTS, null, contentValues);
369 
370         mDbHelper.upgradeToVersion1111(mDb);
371 
372         // Assert that the alt phone book bucket/label has been set to the number bucket/label
373         final ContactLocaleUtils localeUtils = ContactLocaleUtils.getInstance();
374         final int numberBucket = localeUtils.getNumberBucketIndex();
375         final String numberLabel = localeUtils.getBucketLabel(numberBucket);
376         assertUpgradeToVersion1111(numberBucket, numberLabel,
377                 RawContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE,
378                 RawContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE);
379     }
380 
testUpgradeToVersion111_NonZeroPrimaryPhonebookBucket()381     public void testUpgradeToVersion111_NonZeroPrimaryPhonebookBucket() {
382         // Non-zero primary phone book bucket
383         final int primaryBucket = 1;
384         final ContentValues contentValues = new ContentValues();
385         contentValues.put(RawContactsColumns.PHONEBOOK_BUCKET_PRIMARY, primaryBucket);
386         mDb.insert(Tables.RAW_CONTACTS, null, contentValues);
387 
388         mDbHelper.upgradeToVersion1111(mDb);
389 
390         // Assert that the primary phone book bucket/label is unchanged
391         assertUpgradeToVersion1111(primaryBucket, null, RawContactsColumns.PHONEBOOK_BUCKET_PRIMARY,
392                 RawContactsColumns.PHONEBOOK_LABEL_PRIMARY);
393     }
394 
testUpgradeToVersion111_NonNullPrimarySortKey()395     public void testUpgradeToVersion111_NonNullPrimarySortKey() {
396         // Non-null primary sort key
397         final ContentValues contentValues = new ContentValues();
398         contentValues.put(RawContacts.SORT_KEY_PRIMARY, "sort_key_primary");
399         mDb.insert(Tables.RAW_CONTACTS, null, contentValues);
400 
401         mDbHelper.upgradeToVersion1111(mDb);
402 
403         // Assert that the primary phone book bucket/label is unchanged
404         assertUpgradeToVersion1111(0, null, RawContactsColumns.PHONEBOOK_BUCKET_PRIMARY,
405                 RawContactsColumns.PHONEBOOK_LABEL_PRIMARY);
406     }
407 
testUpgradeToVersion111_NonZeroAltPhonebookBucket()408     public void testUpgradeToVersion111_NonZeroAltPhonebookBucket() {
409         // Non-zero alt phone book bucket
410         final int altBucket = 1;
411         final ContentValues contentValues = new ContentValues();
412         contentValues.put(RawContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE, altBucket);
413         mDb.insert(Tables.RAW_CONTACTS, null, contentValues);
414 
415         mDbHelper.upgradeToVersion1111(mDb);
416 
417         // Assert that the alt phone book bucket/label is unchanged
418         assertUpgradeToVersion1111(altBucket, null, RawContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE,
419                 RawContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE);
420     }
421 
testUpgradeToVersion111_NonNullAltSortKeyToNumber()422     public void testUpgradeToVersion111_NonNullAltSortKeyToNumber() {
423         // Non-null alt sort key
424         final ContentValues contentValues = new ContentValues();
425         contentValues.put(RawContacts.SORT_KEY_ALTERNATIVE, "sort_key_alt");
426         mDb.insert(Tables.RAW_CONTACTS, null, contentValues);
427 
428         mDbHelper.upgradeToVersion1111(mDb);
429 
430         // Assert that the alt phone book bucket/label is unchanged
431         assertUpgradeToVersion1111(0, null, RawContactsColumns.PHONEBOOK_BUCKET_ALTERNATIVE,
432                 RawContactsColumns.PHONEBOOK_LABEL_ALTERNATIVE);
433     }
434 
assertUpgradeToVersion1111(int expectedBucket, String expectedLabel, String bucketColumn, String labelColumn)435     private void assertUpgradeToVersion1111(int expectedBucket, String expectedLabel,
436             String bucketColumn, String labelColumn) {
437         final Cursor cursor = mDb.query(Tables.RAW_CONTACTS,
438                 new String[]{bucketColumn, labelColumn}, null, null, null, null, null);
439         try {
440             assertEquals(1, cursor.getCount());
441             assertTrue(cursor.moveToNext());
442             assertEquals(expectedBucket, cursor.getInt(0));
443             assertEquals(expectedLabel, cursor.getString(1));
444         } finally {
445             cursor.close();
446         }
447     }
448 
getIntegerFromExpression(String expression)449     private Integer getIntegerFromExpression(String expression) {
450         try (Cursor c = mDb.rawQuery("SELECT " + expression, null)) {
451             assertTrue(c.moveToPosition(0));
452             if (c.isNull(0)) {
453                 return null;
454             }
455             return c.getInt(0);
456         }
457     }
458 
testNotifyProviderStatusChange()459     public void testNotifyProviderStatusChange() throws Exception {
460         final AtomicReference<Uri> calledUri = new AtomicReference<>();
461 
462         final Handler h = new Handler(Looper.getMainLooper());
463 
464         final CountDownLatch latch = new CountDownLatch(1);
465 
466         final ContentObserver observer = new ContentObserver(h) {
467             @Override
468             public void onChange(boolean selfChange, Uri uri) {
469                 calledUri.set(uri);
470                 latch.countDown();
471             }
472         };
473 
474         // Notify on ProviderStatus.CONTENT_URI.
475         getContext().getContentResolver().registerContentObserver(
476                 ProviderStatus.CONTENT_URI,
477                 /* notifyForDescendants= */ false, observer);
478 
479         // This should trigger it.
480         calledUri.set(null);
481         ContactsDatabaseHelper.notifyProviderStatusChange(getContext());
482 
483         assertTrue(latch.await(30, TimeUnit.SECONDS));
484         assertEquals(ProviderStatus.CONTENT_URI, calledUri.get());
485     }
486 
testOpenTimestamp()487     public void testOpenTimestamp() {
488         final long startTime = System.currentTimeMillis();
489 
490         final String dbFilename = "testOpenTimestamp.db";
491 
492         getContext().deleteDatabase(dbFilename);
493 
494         final ContactsDatabaseHelper dbHelper = ContactsDatabaseHelper.getNewInstanceForTest(
495                 mContext, dbFilename);
496 
497         dbHelper.getReadableDatabase(); // Open the DB.
498 
499         final long creationTime = dbHelper.getDatabaseCreationTime();
500 
501         assertTrue("Expected " + creationTime + " >= " + startTime, creationTime >= startTime);
502 
503         dbHelper.close();
504 
505         // Open again.
506         final ContactsDatabaseHelper dbHelper2 = ContactsDatabaseHelper.getNewInstanceForTest(
507                 mContext, dbFilename);
508 
509         dbHelper2.getReadableDatabase(); // Open the DB.
510 
511         assertEquals(creationTime, dbHelper2.getDatabaseCreationTime());
512     }
513 
testGetAndSetDefaultAccount()514     public void testGetAndSetDefaultAccount() {
515         Account account = mDbHelper.getDefaultAccount();
516         assertNull(account);
517 
518         mDbHelper.setDefaultAccount("a", "b");
519         account = mDbHelper.getDefaultAccount();
520         assertEquals("a", account.name);
521         assertEquals("b", account.type);
522 
523         mDbHelper.setDefaultAccount("c", "d");
524         account = mDbHelper.getDefaultAccount();
525         assertEquals("c", account.name);
526         assertEquals("d", account.type);
527 
528         mDbHelper.setDefaultAccount(null, null);
529         account = mDbHelper.getDefaultAccount();
530         assertNull(account);
531 
532         // Invalid account (not-null account name and null account type) throws exception.
533         try {
534             mDbHelper.setDefaultAccount("name", null);
535             fail("Setting default account to an invalid account should fail.");
536         } catch (IllegalArgumentException e) {
537             // expected.
538         }
539         account = mDbHelper.getDefaultAccount();
540         assertNull(account);
541 
542         // Update default account to an existing account
543         mDbHelper.setDefaultAccount("a", "b");
544         account = mDbHelper.getDefaultAccount();
545         assertEquals("a", account.name);
546         assertEquals("b", account.type);
547 
548         try (Cursor cursor = mDbHelper.getReadableDatabase().query(Tables.ACCOUNTS, new String[]{
549                 ContactsDatabaseHelper.AccountsColumns.ACCOUNT_NAME,
550                 ContactsDatabaseHelper.AccountsColumns.ACCOUNT_TYPE
551         }, null, null, null, null, null)) {
552             assertEquals(3, cursor.getCount());
553         }
554     }
555 }
556