package org.robolectric.shadows; import android.accounts.Account; import android.app.Activity; import android.app.Application; import android.content.ContentProvider; import android.content.ContentProviderOperation; import android.content.ContentProviderResult; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.OperationApplicationException; import android.content.PeriodicSync; import android.content.pm.ProviderInfo; import android.content.res.AssetFileDescriptor; import android.database.ContentObserver; import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.robolectric.DefaultTestLifecycle; import org.robolectric.Robolectric; import org.robolectric.RuntimeEnvironment; import org.robolectric.TestRunners; import org.robolectric.fakes.BaseCursor; import org.robolectric.manifest.AndroidManifest; import org.robolectric.manifest.ContentProviderData; import org.robolectric.util.ReflectionHelpers; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import static android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.same; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.robolectric.Shadows.shadowOf; @RunWith(TestRunners.MultiApiSelfTest.class) public class ShadowContentResolverTest { static final String AUTHORITY = "org.robolectric"; private ContentResolver contentResolver; private ShadowContentResolver shadowContentResolver; private Uri uri21; private Uri uri22; private Account a, b; @Before public void setUp() throws Exception { contentResolver = Robolectric.setupActivity(Activity.class).getContentResolver(); shadowContentResolver = shadowOf(contentResolver); uri21 = Uri.parse(EXTERNAL_CONTENT_URI.toString() + "/21"); uri22 = Uri.parse(EXTERNAL_CONTENT_URI.toString() + "/22"); a = new Account("a", "type"); b = new Account("b", "type"); } @Test public void insert_shouldReturnIncreasingUris() throws Exception { shadowContentResolver.setNextDatabaseIdForInserts(20); assertThat(contentResolver.insert(EXTERNAL_CONTENT_URI, new ContentValues())).isEqualTo(uri21); assertThat(contentResolver.insert(EXTERNAL_CONTENT_URI, new ContentValues())).isEqualTo(uri22); } @Test public void getType_shouldDefaultToNull() throws Exception { assertThat(contentResolver.getType(uri21)).isNull(); } @Test public void getType_shouldReturnProviderValue() throws Exception { ShadowContentResolver.registerProviderInternal(AUTHORITY, new ContentProvider() { @Override public boolean onCreate() { return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { return new BaseCursor(); } @Override public Uri insert(Uri uri, ContentValues values) { return null; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { return -1; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return -1; } @Override public String getType(Uri uri) { return "mytype"; } }); final Uri uri = Uri.parse("content://"+AUTHORITY+"/some/path"); assertThat(contentResolver.getType(uri)).isEqualTo("mytype"); } @Test public void insert_shouldTrackInsertStatements() throws Exception { ContentValues contentValues = new ContentValues(); contentValues.put("foo", "bar"); contentResolver.insert(EXTERNAL_CONTENT_URI, contentValues); assertThat(shadowContentResolver.getInsertStatements().size()).isEqualTo(1); assertThat(shadowContentResolver.getInsertStatements().get(0).getUri()).isEqualTo(EXTERNAL_CONTENT_URI); assertThat(shadowContentResolver.getInsertStatements().get(0).getContentValues().getAsString("foo")).isEqualTo("bar"); contentValues = new ContentValues(); contentValues.put("hello", "world"); contentResolver.insert(EXTERNAL_CONTENT_URI, contentValues); assertThat(shadowContentResolver.getInsertStatements().size()).isEqualTo(2); assertThat(shadowContentResolver.getInsertStatements().get(1).getContentValues().getAsString("hello")).isEqualTo("world"); } @Test public void insert_shouldTrackUpdateStatements() throws Exception { ContentValues contentValues = new ContentValues(); contentValues.put("foo", "bar"); contentResolver.update(EXTERNAL_CONTENT_URI, contentValues, "robolectric", new String[] { "awesome" }); assertThat(shadowContentResolver.getUpdateStatements().size()).isEqualTo(1); assertThat(shadowContentResolver.getUpdateStatements().get(0).getUri()).isEqualTo(EXTERNAL_CONTENT_URI); assertThat(shadowContentResolver.getUpdateStatements().get(0).getContentValues().getAsString("foo")).isEqualTo("bar"); assertThat(shadowContentResolver.getUpdateStatements().get(0).getWhere()).isEqualTo("robolectric"); assertThat(shadowContentResolver.getUpdateStatements().get(0).getSelectionArgs()).isEqualTo(new String[]{"awesome"}); contentValues = new ContentValues(); contentValues.put("hello", "world"); contentResolver.update(EXTERNAL_CONTENT_URI, contentValues, null, null); assertThat(shadowContentResolver.getUpdateStatements().size()).isEqualTo(2); assertThat(shadowContentResolver.getUpdateStatements().get(1).getUri()).isEqualTo(EXTERNAL_CONTENT_URI); assertThat(shadowContentResolver.getUpdateStatements().get(1).getContentValues().getAsString("hello")).isEqualTo("world"); assertThat(shadowContentResolver.getUpdateStatements().get(1).getWhere()).isNull(); assertThat(shadowContentResolver.getUpdateStatements().get(1).getSelectionArgs()).isNull(); } @Test public void insert_supportsNullContentValues() throws Exception { contentResolver.insert(EXTERNAL_CONTENT_URI, null); assertThat(shadowContentResolver.getInsertStatements().get(0).getContentValues()).isNull(); } @Test public void update_supportsNullContentValues() throws Exception { contentResolver.update(EXTERNAL_CONTENT_URI, null, null, null); assertThat(shadowContentResolver.getUpdateStatements().get(0).getContentValues()).isNull(); } @Test public void delete_shouldTrackDeletedUris() throws Exception { assertThat(shadowContentResolver.getDeletedUris().size()).isEqualTo(0); assertThat(contentResolver.delete(uri21, null, null)).isEqualTo(1); assertThat(shadowContentResolver.getDeletedUris()).contains(uri21); assertThat(shadowContentResolver.getDeletedUris().size()).isEqualTo(1); assertThat(contentResolver.delete(uri22, null, null)).isEqualTo(1); assertThat(shadowContentResolver.getDeletedUris()).contains(uri22); assertThat(shadowContentResolver.getDeletedUris().size()).isEqualTo(2); } @Test public void delete_shouldTrackDeletedStatements() { assertThat(shadowContentResolver.getDeleteStatements().size()).isEqualTo(0); assertThat(contentResolver.delete(uri21, "id", new String[]{"5"})).isEqualTo(1); assertThat(shadowContentResolver.getDeleteStatements().size()).isEqualTo(1); assertThat(shadowContentResolver.getDeleteStatements().get(0).getUri()).isEqualTo(uri21); assertThat(shadowContentResolver.getDeleteStatements().get(0).getContentProvider()).isNull(); assertThat(shadowContentResolver.getDeleteStatements().get(0).getWhere()).isEqualTo("id"); assertThat(shadowContentResolver.getDeleteStatements().get(0).getSelectionArgs()[0]).isEqualTo("5"); assertThat(contentResolver.delete(uri21, "foo", new String[]{"bar"})).isEqualTo(1); assertThat(shadowContentResolver.getDeleteStatements().size()).isEqualTo(2); assertThat(shadowContentResolver.getDeleteStatements().get(1).getUri()).isEqualTo(uri21); assertThat(shadowContentResolver.getDeleteStatements().get(1).getWhere()).isEqualTo("foo"); assertThat(shadowContentResolver.getDeleteStatements().get(1).getSelectionArgs()[0]).isEqualTo("bar"); } @Test public void whenCursorHasBeenSet_query_shouldReturnTheCursor() throws Exception { assertThat(shadowContentResolver.query(null, null, null, null, null)).isNull(); BaseCursor cursor = new BaseCursor(); shadowContentResolver.setCursor(cursor); assertThat((BaseCursor) shadowContentResolver.query(null, null, null, null, null)).isSameAs(cursor); } @Test public void whenCursorHasBeenSet_queryWithCancellationSignal_shouldReturnTheCursor() throws Exception { assertThat(shadowContentResolver.query(null, null, null, null, null, new CancellationSignal())).isNull(); BaseCursor cursor = new BaseCursor(); shadowContentResolver.setCursor(cursor); assertThat((BaseCursor) shadowContentResolver.query(null, null, null, null, null, new CancellationSignal())).isSameAs(cursor); } @Test public void query_shouldReturnSpecificCursorsForSpecificUris() throws Exception { assertThat(shadowContentResolver.query(uri21, null, null, null, null)).isNull(); assertThat(shadowContentResolver.query(uri22, null, null, null, null)).isNull(); BaseCursor cursor21 = new BaseCursor(); BaseCursor cursor22 = new BaseCursor(); shadowContentResolver.setCursor(uri21, cursor21); shadowContentResolver.setCursor(uri22, cursor22); assertThat((BaseCursor) shadowContentResolver.query(uri21, null, null, null, null)).isSameAs(cursor21); assertThat((BaseCursor) shadowContentResolver.query(uri22, null, null, null, null)).isSameAs(cursor22); } @Test public void query_shouldKnowWhatItsParamsWere() throws Exception { String[] projection = {}; String selection = "select"; String[] selectionArgs = {}; String sortOrder = "order"; QueryParamTrackingCursor testCursor = new QueryParamTrackingCursor(); shadowContentResolver.setCursor(testCursor); Cursor cursor = shadowContentResolver.query(uri21, projection, selection, selectionArgs, sortOrder); assertThat((QueryParamTrackingCursor) cursor).isEqualTo(testCursor); assertThat(testCursor.uri).isEqualTo(uri21); assertThat(testCursor.projection).isEqualTo(projection); assertThat(testCursor.selection).isEqualTo(selection); assertThat(testCursor.selectionArgs).isEqualTo(selectionArgs); assertThat(testCursor.sortOrder).isEqualTo(sortOrder); } @Test public void acquireUnstableProvider_shouldDefaultToNull() throws Exception { assertThat(contentResolver.acquireUnstableProvider(uri21)).isNull(); } @Test public void acquireUnstableProvider_shouldReturnWithUri() throws Exception { ContentProvider cp = mock(ContentProvider.class); ShadowContentResolver.registerProviderInternal(AUTHORITY, cp); final Uri uri = Uri.parse("content://" + AUTHORITY); assertThat(contentResolver.acquireUnstableProvider(uri)).isSameAs(cp.getIContentProvider()); } @Test public void acquireUnstableProvider_shouldReturnWithString() throws Exception { ContentProvider cp = mock(ContentProvider.class); ShadowContentResolver.registerProviderInternal(AUTHORITY, cp); assertThat(contentResolver.acquireUnstableProvider(AUTHORITY)).isSameAs(cp.getIContentProvider()); } @Test public void call_shouldCallProvider() throws Exception { final String METHOD = "method"; final String ARG = "arg"; final Bundle EXTRAS = new Bundle(); final Uri uri = Uri.parse("content://" + AUTHORITY); ContentProvider provider = mock(ContentProvider.class); doReturn(null).when(provider).call(METHOD, ARG, EXTRAS); ShadowContentResolver.registerProviderInternal(AUTHORITY, provider); contentResolver.call(uri, METHOD, ARG, EXTRAS); verify(provider).call(METHOD, ARG, EXTRAS); } @Test public void registerProvider_shouldAttachProviderInfo() throws Exception { ContentProvider mock = mock(ContentProvider.class); ProviderInfo providerInfo0 = new ProviderInfo(); providerInfo0.authority = "the-authority"; // todo: support multiple authorities providerInfo0.grantUriPermissions = true; mock.attachInfo(RuntimeEnvironment.application, providerInfo0); mock.onCreate(); ArgumentCaptor<ProviderInfo> captor = ArgumentCaptor.forClass(ProviderInfo.class); verify(mock).attachInfo(same(RuntimeEnvironment.application), captor.capture()); ProviderInfo providerInfo = captor.getValue(); assertThat(providerInfo.authority).isEqualTo("the-authority"); assertThat(providerInfo.grantUriPermissions).isEqualTo(true); } @Test(expected = UnsupportedOperationException.class) public void openInputStream_shouldReturnAnInputStreamThatExceptionsOnRead() throws Exception { InputStream inputStream = contentResolver.openInputStream(uri21); inputStream.read(); } @Test public void openInputStream_returnsPreRegisteredStream() throws Exception { shadowContentResolver.registerInputStream(uri21, new ByteArrayInputStream("ourStream".getBytes())); InputStream inputStream = contentResolver.openInputStream(uri21); byte[] data = new byte[9]; inputStream.read(data); assertThat(new String(data)).isEqualTo("ourStream"); } @Test public void openOutputStream_shouldReturnAnOutputStream() throws Exception { assertThat(contentResolver.openOutputStream(uri21)).isInstanceOf(OutputStream.class); } @Test public void shouldTrackNotifiedUris() throws Exception { contentResolver.notifyChange(Uri.parse("foo"), null, true); contentResolver.notifyChange(Uri.parse("bar"), null); assertThat(shadowContentResolver.getNotifiedUris().size()).isEqualTo(2); ShadowContentResolver.NotifiedUri uri = shadowContentResolver.getNotifiedUris().get(0); assertThat(uri.uri.toString()).isEqualTo("foo"); assertThat(uri.syncToNetwork).isTrue(); assertThat(uri.observer).isNull(); uri = shadowContentResolver.getNotifiedUris().get(1); assertThat(uri.uri.toString()).isEqualTo("bar"); assertThat(uri.syncToNetwork).isFalse(); assertThat(uri.observer).isNull(); } @SuppressWarnings("serial") @Test public void applyBatchForRegisteredProvider() throws RemoteException, OperationApplicationException { final ArrayList<String> operations = new ArrayList<>(); ShadowContentResolver.registerProviderInternal("registeredProvider", new ContentProvider() { @Override public boolean onCreate() { return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { operations.add("query"); MatrixCursor cursor = new MatrixCursor(new String[] {"a"}); cursor.addRow(new Object[] {"b"}); return cursor; } @Override public String getType(Uri uri) { return null; } @Override public Uri insert(Uri uri, ContentValues values) { operations.add("insert"); return ContentUris.withAppendedId(uri, 1); } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { operations.add("delete"); return 0; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { operations.add("update"); return 0; } }); final Uri uri = Uri.parse("content://registeredProvider/path"); contentResolver.applyBatch("registeredProvider", new ArrayList<ContentProviderOperation>() { { add(ContentProviderOperation.newInsert(uri).withValue("a", "b").build()); add(ContentProviderOperation.newUpdate(uri).withValue("a", "b").build()); add(ContentProviderOperation.newDelete(uri).build()); add(ContentProviderOperation.newAssertQuery(uri).withValue("a", "b").build()); } }); assertThat(operations).containsExactly("insert", "update", "delete", "query"); } @Test public void applyBatchForUnregisteredProvider() throws RemoteException, OperationApplicationException { List<ContentProviderOperation> resultOperations = shadowContentResolver.getContentProviderOperations(AUTHORITY); assertThat(resultOperations).isNotNull(); assertThat(resultOperations.size()).isEqualTo(0); ContentProviderResult[] contentProviderResults = new ContentProviderResult[] { new ContentProviderResult(1), new ContentProviderResult(1), }; shadowContentResolver.setContentProviderResult(contentProviderResults); Uri uri = Uri.parse("content://org.robolectric"); ArrayList<ContentProviderOperation> operations = new ArrayList<>(); operations.add(ContentProviderOperation.newInsert(uri) .withValue("column1", "foo") .withValue("column2", 5) .build()); operations.add(ContentProviderOperation.newUpdate(uri) .withSelection("id_column", new String[] { "99" }) .withValue("column1", "bar") .build()); operations.add(ContentProviderOperation.newDelete(uri) .withSelection("id_column", new String[] { "11" }) .build()); ContentProviderResult[] result = contentResolver.applyBatch(AUTHORITY, operations); resultOperations = shadowContentResolver.getContentProviderOperations(AUTHORITY); assertThat(resultOperations).isEqualTo(operations); assertThat(result).isEqualTo(contentProviderResults); } @Test public void shouldKeepTrackOfSyncRequests() throws Exception { ShadowContentResolver.Status status = ShadowContentResolver.getStatus(a, AUTHORITY, true); assertThat(status).isNotNull(); assertThat(status.syncRequests).isEqualTo(0); ContentResolver.requestSync(a, AUTHORITY, new Bundle()); assertThat(status.syncRequests).isEqualTo(1); assertThat(status.syncExtras).isNotNull(); } @Test public void shouldKnowIfSyncIsActive() throws Exception { assertThat(ContentResolver.isSyncActive(a, AUTHORITY)).isFalse(); ContentResolver.requestSync(a, AUTHORITY, new Bundle()); assertThat(ContentResolver.isSyncActive(a, AUTHORITY)).isTrue(); } @Test public void shouldCancelSync() throws Exception { ContentResolver.requestSync(a, AUTHORITY, new Bundle()); ContentResolver.requestSync(b, AUTHORITY, new Bundle()); assertThat(ContentResolver.isSyncActive(a, AUTHORITY)).isTrue(); assertThat(ContentResolver.isSyncActive(b, AUTHORITY)).isTrue(); ContentResolver.cancelSync(a, AUTHORITY); assertThat(ContentResolver.isSyncActive(a, AUTHORITY)).isFalse(); assertThat(ContentResolver.isSyncActive(b, AUTHORITY)).isTrue(); } @Test public void shouldSetIsSyncable() throws Exception { assertThat(ContentResolver.getIsSyncable(a, AUTHORITY)).isEqualTo(-1); assertThat(ContentResolver.getIsSyncable(b, AUTHORITY)).isEqualTo(-1); ContentResolver.setIsSyncable(a, AUTHORITY, 1); ContentResolver.setIsSyncable(b, AUTHORITY, 2); assertThat(ContentResolver.getIsSyncable(a, AUTHORITY)).isEqualTo(1); assertThat(ContentResolver.getIsSyncable(b, AUTHORITY)).isEqualTo(2); } @Test public void shouldSetSyncAutomatically() throws Exception { assertThat(ContentResolver.getSyncAutomatically(a, AUTHORITY)).isFalse(); ContentResolver.setSyncAutomatically(a, AUTHORITY, true); assertThat(ContentResolver.getSyncAutomatically(a, AUTHORITY)).isTrue(); } @Test public void shouldAddPeriodicSync() throws Exception { Bundle fooBar = new Bundle(); fooBar.putString("foo", "bar"); Bundle fooBaz = new Bundle(); fooBaz.putString("foo", "baz"); ContentResolver.addPeriodicSync(a, AUTHORITY, fooBar, 6000L); ContentResolver.addPeriodicSync(a, AUTHORITY, fooBaz, 6000L); ContentResolver.addPeriodicSync(b, AUTHORITY, fooBar, 6000L); ContentResolver.addPeriodicSync(b, AUTHORITY, fooBaz, 6000L); assertThat(ShadowContentResolver.getPeriodicSyncs(a, AUTHORITY)).containsOnly( new PeriodicSync(a, AUTHORITY, fooBar, 6000L), new PeriodicSync(a, AUTHORITY, fooBaz, 6000L)); assertThat(ShadowContentResolver.getPeriodicSyncs(b, AUTHORITY)).containsOnly( new PeriodicSync(b, AUTHORITY, fooBar, 6000L), new PeriodicSync(b, AUTHORITY, fooBaz, 6000L)); // If same extras, but different time, simply update the time. ContentResolver.addPeriodicSync(a, AUTHORITY, fooBar, 42L); ContentResolver.addPeriodicSync(b, AUTHORITY, fooBaz, 42L); assertThat(ShadowContentResolver.getPeriodicSyncs(a, AUTHORITY)).containsOnly( new PeriodicSync(a, AUTHORITY, fooBar, 42L), new PeriodicSync(a, AUTHORITY, fooBaz, 6000L)); assertThat(ShadowContentResolver.getPeriodicSyncs(b, AUTHORITY)).containsOnly( new PeriodicSync(b, AUTHORITY, fooBar, 6000L), new PeriodicSync(b, AUTHORITY, fooBaz, 42L)); } @Test public void shouldRemovePeriodSync() throws Exception { Bundle fooBar = new Bundle(); fooBar.putString("foo", "bar"); Bundle fooBaz = new Bundle(); fooBaz.putString("foo", "baz"); Bundle foo42 = new Bundle(); foo42.putInt("foo", 42); assertThat(ShadowContentResolver.getPeriodicSyncs(b, AUTHORITY)).isEmpty(); assertThat(ShadowContentResolver.getPeriodicSyncs(a, AUTHORITY)).isEmpty(); ContentResolver.addPeriodicSync(a, AUTHORITY, fooBar, 6000L); ContentResolver.addPeriodicSync(a, AUTHORITY, fooBaz, 6000L); ContentResolver.addPeriodicSync(a, AUTHORITY, foo42, 6000L); ContentResolver.addPeriodicSync(b, AUTHORITY, fooBar, 6000L); ContentResolver.addPeriodicSync(b, AUTHORITY, fooBaz, 6000L); ContentResolver.addPeriodicSync(b, AUTHORITY, foo42, 6000L); assertThat(ShadowContentResolver.getPeriodicSyncs(a, AUTHORITY)).containsOnly( new PeriodicSync(a, AUTHORITY, fooBar, 6000L), new PeriodicSync(a, AUTHORITY, fooBaz, 6000L), new PeriodicSync(a, AUTHORITY, foo42, 6000L)); ContentResolver.removePeriodicSync(a, AUTHORITY, fooBar); assertThat(ShadowContentResolver.getPeriodicSyncs(a, AUTHORITY)).containsOnly( new PeriodicSync(a, AUTHORITY, fooBaz, 6000L), new PeriodicSync(a, AUTHORITY, foo42, 6000L)); ContentResolver.removePeriodicSync(a, AUTHORITY, fooBaz); assertThat(ShadowContentResolver.getPeriodicSyncs(a, AUTHORITY)).containsOnly( new PeriodicSync(a, AUTHORITY, foo42, 6000L)); ContentResolver.removePeriodicSync(a, AUTHORITY, foo42); assertThat(ShadowContentResolver.getPeriodicSyncs(a, AUTHORITY)).isEmpty(); assertThat(ShadowContentResolver.getPeriodicSyncs(b, AUTHORITY)).containsOnly( new PeriodicSync(b, AUTHORITY, fooBar, 6000L), new PeriodicSync(b, AUTHORITY, fooBaz, 6000L), new PeriodicSync(b, AUTHORITY, foo42, 6000L)); } @Test public void shouldGetPeriodSyncs() throws Exception { assertThat(ContentResolver.getPeriodicSyncs(a, AUTHORITY).size()).isEqualTo(0); ContentResolver.addPeriodicSync(a, AUTHORITY, new Bundle(), 6000l); List<PeriodicSync> syncs = ContentResolver.getPeriodicSyncs(a, AUTHORITY); assertThat(syncs.size()).isEqualTo(1); PeriodicSync first = syncs.get(0); assertThat(first.account).isEqualTo(a); assertThat(first.authority).isEqualTo(AUTHORITY); assertThat(first.period).isEqualTo(6000l); assertThat(first.extras).isNotNull(); } @Test public void shouldValidateSyncExtras() throws Exception { Bundle bundle = new Bundle(); bundle.putString("foo", "strings"); bundle.putLong("long", 10l); bundle.putDouble("double", 10.0d); bundle.putFloat("float", 10.0f); bundle.putInt("int", 10); bundle.putParcelable("account", a); ContentResolver.validateSyncExtrasBundle(bundle); } @Test(expected = IllegalArgumentException.class) public void shouldValidateSyncExtrasAndThrow() throws Exception { Bundle bundle = new Bundle(); bundle.putParcelable("intent", new Intent()); ContentResolver.validateSyncExtrasBundle(bundle); } @Test public void shouldSetMasterSyncAutomatically() throws Exception { assertThat(ContentResolver.getMasterSyncAutomatically()).isFalse(); ContentResolver.setMasterSyncAutomatically(true); assertThat(ContentResolver.getMasterSyncAutomatically()).isTrue(); } @Test public void shouldDelegateCallsToRegisteredProvider() throws Exception { ShadowContentResolver.registerProviderInternal(AUTHORITY, new ContentProvider() { @Override public boolean onCreate() { return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { return new BaseCursor(); } @Override public Uri insert(Uri uri, ContentValues values) { return null; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { return -1; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return -1; } @Override public String getType(Uri uri) { return null; } }); final Uri uri = Uri.parse("content://"+AUTHORITY+"/some/path"); final Uri unrelated = Uri.parse("content://unrelated/some/path"); assertThat(contentResolver.query(uri, null, null, null, null)).isNotNull(); assertThat(contentResolver.insert(uri, new ContentValues())).isNull(); assertThat(contentResolver.delete(uri, null, null)).isEqualTo(-1); assertThat(contentResolver.update(uri, new ContentValues(), null, null)).isEqualTo(-1); assertThat(contentResolver.query(unrelated, null, null, null, null)).isNull(); assertThat(contentResolver.insert(unrelated, new ContentValues())).isNotNull(); assertThat(contentResolver.delete(unrelated, null, null)).isEqualTo(1); assertThat(contentResolver.update(unrelated, new ContentValues(), null, null)).isEqualTo(1); } @Test public void shouldRegisterContentObservers() throws Exception { TestContentObserver co = new TestContentObserver(null); ShadowContentResolver scr = shadowOf(contentResolver); assertThat(scr.getContentObservers(EXTERNAL_CONTENT_URI)).isEmpty(); contentResolver.registerContentObserver(EXTERNAL_CONTENT_URI, true, co); assertThat(scr.getContentObservers(EXTERNAL_CONTENT_URI)).containsExactly((ContentObserver) co); assertThat(co.changed).isFalse(); contentResolver.notifyChange(EXTERNAL_CONTENT_URI, null); assertThat(co.changed).isTrue(); scr.clearContentObservers(); assertThat(scr.getContentObservers(EXTERNAL_CONTENT_URI)).isEmpty(); } @Test public void shouldRegisterMultipleContentObservers() throws Exception { TestContentObserver co = new TestContentObserver(null); TestContentObserver co1 = new TestContentObserver(null); TestContentObserver co2 = new TestContentObserver(null); assertThat(shadowContentResolver.getContentObservers(uri21)).isEmpty(); contentResolver.registerContentObserver(uri21, true, co); contentResolver.registerContentObserver(uri21, true, co1); contentResolver.registerContentObserver(uri22, true, co2); assertThat(shadowContentResolver.getContentObservers(uri21)).containsExactly(co, co1); assertThat(shadowContentResolver.getContentObservers(uri22)).containsExactly(co2); assertThat(co.changed).isFalse(); assertThat(co1.changed).isFalse(); assertThat(co2.changed).isFalse(); contentResolver.notifyChange(uri21, null); assertThat(co.changed).isTrue(); assertThat(co1.changed).isTrue(); assertThat(co2.changed).isFalse(); shadowContentResolver.clearContentObservers(); assertThat(shadowContentResolver.getContentObservers(uri21)).isEmpty(); } @Test public void shouldUnregisterContentObservers() throws Exception { TestContentObserver co = new TestContentObserver(null); ShadowContentResolver scr = shadowOf(contentResolver); contentResolver.registerContentObserver(EXTERNAL_CONTENT_URI, true, co); assertThat(scr.getContentObservers(EXTERNAL_CONTENT_URI)).containsExactly((ContentObserver) co); contentResolver.unregisterContentObserver(co); assertThat(scr.getContentObservers(EXTERNAL_CONTENT_URI)).isEmpty(); assertThat(co.changed).isFalse(); contentResolver.notifyChange(EXTERNAL_CONTENT_URI, null); assertThat(co.changed).isFalse(); } @Test public void shouldUnregisterMultipleContentObservers() throws Exception { TestContentObserver co = new TestContentObserver(null); TestContentObserver co1 = new TestContentObserver(null); TestContentObserver co2 = new TestContentObserver(null); contentResolver.registerContentObserver(uri21, true, co); contentResolver.registerContentObserver(uri21, true, co1); contentResolver.registerContentObserver(uri22, true, co); contentResolver.registerContentObserver(uri22, true, co2); assertThat(shadowContentResolver.getContentObservers(uri21)).containsExactly(co, co1); assertThat(shadowContentResolver.getContentObservers(uri22)).containsExactly(co, co2); contentResolver.unregisterContentObserver(co); assertThat(shadowContentResolver.getContentObservers(uri21)).containsExactly(co1); assertThat(shadowContentResolver.getContentObservers(uri22)).containsExactly(co2); contentResolver.unregisterContentObserver(co2); assertThat(shadowContentResolver.getContentObservers(uri21)).containsExactly(co1); assertThat(shadowContentResolver.getContentObservers(uri22)).isEmpty(); assertThat(co.changed).isFalse(); assertThat(co1.changed).isFalse(); assertThat(co2.changed).isFalse(); contentResolver.notifyChange(uri21, null); contentResolver.notifyChange(uri22, null); assertThat(co.changed).isFalse(); assertThat(co1.changed).isTrue(); assertThat(co2.changed).isFalse(); } @Test public void getProvider_shouldCreateProviderFromManifest() { AndroidManifest manifest = ShadowApplication.getInstance().getAppManifest(); ContentProviderData testProviderData = new ContentProviderData("org.robolectric.shadows.ShadowContentResolverTest$TestContentProvider", null, AUTHORITY, null, null, null); try { manifest.getContentProviders().add(testProviderData); assertThat(ShadowContentResolver.getProvider(Uri.parse("content://" + AUTHORITY + "/shadows"))).isNotNull(); } finally { manifest.getContentProviders().remove(testProviderData); } } @Test public void getProvider_shouldNotReturnAnyProviderWhenManifestIsNull() { Application application = new DefaultTestLifecycle().createApplication(null, null, null); ReflectionHelpers.callInstanceMethod(application, "attach", ReflectionHelpers.ClassParameter.from(Context.class, RuntimeEnvironment.application.getBaseContext())); assertThat(ShadowContentResolver.getProvider(Uri.parse("content://"))).isNull(); } @Test public void getProvider_shouldSetAuthority() throws RemoteException { AndroidManifest manifest = ShadowApplication.getInstance().getAppManifest(); ContentProviderData testProviderData = new ContentProviderData("org.robolectric.shadows.ShadowContentResolverTest$TestContentProvider", null, AUTHORITY, null, null, null); try { manifest.getContentProviders().add(testProviderData); Uri uri = Uri.parse("content://" + AUTHORITY + "/shadows"); ContentProvider provider = ShadowContentResolver.getProvider(uri); // unfortunately, there is no direct way of testing if authority is set or not // however, it's checked in ContentProvider.Transport method calls (validateIncomingUri), so it's the closest we can test against provider.getIContentProvider().getType(uri); // should not throw } finally { manifest.getContentProviders().remove(testProviderData); } } static class QueryParamTrackingCursor extends BaseCursor { public Uri uri; public String[] projection; public String selection; public String[] selectionArgs; public String sortOrder; @Override public void setQuery(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { this.uri = uri; this.projection = projection; this.selection = selection; this.selectionArgs = selectionArgs; this.sortOrder = sortOrder; } } @Test public void openTypedAssetFileDescriptor_shouldOpenDescriptor() throws IOException, RemoteException { final File file = new File(RuntimeEnvironment.application.getFilesDir(), "test_file"); file.createNewFile(); ShadowContentResolver.registerProviderInternal(AUTHORITY, new ContentProvider() { @Override public boolean onCreate() { return true; } @Override public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) { return null; } @Override public String getType(Uri uri) { return null; } @Override public Uri insert(Uri uri, ContentValues contentValues) { return null; } @Override public int delete(Uri uri, String s, String[] strings) { return 0; } @Override public int update(Uri uri, ContentValues contentValues, String s, String[] strings) { return 0; } @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); } }); AssetFileDescriptor afd = contentResolver.openTypedAssetFileDescriptor(Uri.parse("content://" + AUTHORITY + "/whatever"), "*/*", null); FileDescriptor descriptor = afd.getFileDescriptor(); assertThat(descriptor).isNotNull(); } private class TestContentObserver extends ContentObserver { public TestContentObserver(Handler handler) { super(handler); } public boolean changed = false; @Override public void onChange(boolean selfChange) { changed = true; } @Override public void onChange(boolean selfChange, Uri uri) { changed = true; } } public static class TestContentProvider extends ContentProvider { @Override public int delete(Uri arg0, String arg1, String[] arg2) { return 0; } @Override public String getType(Uri arg0) { return null; } @Override public Uri insert(Uri arg0, ContentValues arg1) { return null; } @Override public boolean onCreate() { return false; } @Override public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4) { return null; } @Override public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) { return 0; } } }