summaryrefslogtreecommitdiffstats
path: root/tests/src
diff options
context:
space:
mode:
authorGeorge Mount <mount@google.com>2013-02-20 17:01:54 -0800
committerGeorge Mount <mount@google.com>2013-02-26 12:49:13 -0800
commit178b04f4cea6dcbe0f84f0f189e9280d4c0d1442 (patch)
treedcf7aafa07634ee30491f50de3ce3d811723ec7e /tests/src
parentaae069d8a006e4664414df56750b86844825b39c (diff)
downloadandroid_packages_apps_Snap-178b04f4cea6dcbe0f84f0f189e9280d4c0d1442.tar.gz
android_packages_apps_Snap-178b04f4cea6dcbe0f84f0f189e9280d4c0d1442.tar.bz2
android_packages_apps_Snap-178b04f4cea6dcbe0f84f0f189e9280d4c0d1442.zip
Add initial implementation of PhotosProvider.
Change-Id: I98694cf54bd0fb549703a7184e1816e9590a05ff
Diffstat (limited to 'tests/src')
-rw-r--r--tests/src/com/android/photos/data/DataTestRunner.java36
-rw-r--r--tests/src/com/android/photos/data/PhotoDatabaseTest.java187
-rw-r--r--tests/src/com/android/photos/data/PhotoDatabaseUtils.java117
-rw-r--r--tests/src/com/android/photos/data/PhotoProviderTest.java463
4 files changed, 803 insertions, 0 deletions
diff --git a/tests/src/com/android/photos/data/DataTestRunner.java b/tests/src/com/android/photos/data/DataTestRunner.java
new file mode 100644
index 000000000..432258561
--- /dev/null
+++ b/tests/src/com/android/photos/data/DataTestRunner.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.photos.data;
+
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+
+import junit.framework.TestSuite;
+
+public class DataTestRunner extends InstrumentationTestRunner {
+ @Override
+ public TestSuite getAllTests() {
+ TestSuite suite = new InstrumentationTestSuite(this);
+ suite.addTestSuite(PhotoDatabaseTest.class);
+ suite.addTestSuite(PhotoProviderTest.class);
+ return suite;
+ }
+
+ @Override
+ public ClassLoader getLoader() {
+ return DataTestRunner.class.getClassLoader();
+ }
+}
diff --git a/tests/src/com/android/photos/data/PhotoDatabaseTest.java b/tests/src/com/android/photos/data/PhotoDatabaseTest.java
new file mode 100644
index 000000000..48e79d4e1
--- /dev/null
+++ b/tests/src/com/android/photos/data/PhotoDatabaseTest.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.photos.data;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.test.InstrumentationTestCase;
+
+import com.android.photos.data.PhotoProvider.Albums;
+import com.android.photos.data.PhotoProvider.Metadata;
+import com.android.photos.data.PhotoProvider.Photos;
+
+import java.io.File;
+import java.io.IOException;
+
+public class PhotoDatabaseTest extends InstrumentationTestCase {
+
+ private PhotoDatabase mDBHelper;
+
+ @Override
+ protected void setUp() {
+ Context context = getInstrumentation().getTargetContext();
+ mDBHelper = new PhotoDatabase(context);
+ }
+
+ @Override
+ protected void tearDown() {
+ mDBHelper.close();
+ }
+
+ public void testCreateDatabase() throws IOException {
+ Context context = getInstrumentation().getTargetContext();
+ File dbFile = context.getDatabasePath(PhotoDatabase.DB_NAME);
+ if (dbFile.exists()) {
+ dbFile.delete();
+ }
+ SQLiteDatabase db = getReadableDB();
+ db.beginTransaction();
+ db.endTransaction();
+ assertTrue(dbFile.exists());
+ dbFile.delete();
+ }
+
+ public void testTables() {
+ validateTable(Metadata.TABLE, PhotoDatabaseUtils.PROJECTION_METADATA);
+ validateTable(Albums.TABLE, PhotoDatabaseUtils.PROJECTION_ALBUMS);
+ validateTable(Photos.TABLE, PhotoDatabaseUtils.PROJECTION_PHOTOS);
+ }
+
+ public void testAlbumsConstraints() {
+ SQLiteDatabase db = getWriteableDB();
+ db.beginTransaction();
+ try {
+ // Test NOT NULL constraint on name
+ assertFalse(PhotoDatabaseUtils
+ .insertAlbum(db, null, null, Albums.VISIBILITY_PRIVATE, null));
+
+ // test NOT NULL constraint on privacy
+ assertFalse(PhotoDatabaseUtils.insertAlbum(db, null, "hello", null, null));
+
+ // Normal insert
+ assertTrue(PhotoDatabaseUtils.insertAlbum(db, null, "hello", Albums.VISIBILITY_PRIVATE,
+ 100L));
+
+ // Test server id uniqueness
+ assertFalse(PhotoDatabaseUtils.insertAlbum(db, null, "world", Albums.VISIBILITY_PRIVATE,
+ 100L));
+
+ // Different server id allowed
+ assertTrue(PhotoDatabaseUtils.insertAlbum(db, null, "world", Albums.VISIBILITY_PRIVATE,
+ 101L));
+
+ // Allow null server id
+ assertTrue(PhotoDatabaseUtils.insertAlbum(db, null, "hello world",
+ Albums.VISIBILITY_PRIVATE, null));
+
+ long albumId = PhotoDatabaseUtils.queryAlbumIdFromServerId(db, 100);
+
+ // Assign a valid child
+ assertTrue(PhotoDatabaseUtils.insertAlbum(db, albumId, "hello", Albums.VISIBILITY_PRIVATE,
+ null));
+
+ long otherAlbumId = PhotoDatabaseUtils.queryAlbumIdFromServerId(db, 101);
+ assertNotSame(albumId, otherAlbumId);
+
+ // This is a valid child of another album.
+ assertTrue(PhotoDatabaseUtils.insertAlbum(db, otherAlbumId, "hello",
+ Albums.VISIBILITY_PRIVATE, null));
+
+ // This isn't allowed due to uniqueness constraint (parent_id/name)
+ assertFalse(PhotoDatabaseUtils.insertAlbum(db, otherAlbumId, "hello",
+ Albums.VISIBILITY_PRIVATE, null));
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ public void testPhotosConstraints() {
+ SQLiteDatabase db = getWriteableDB();
+ db.beginTransaction();
+ try {
+ int width = 100;
+ int height = 100;
+ long dateTaken = System.currentTimeMillis();
+ String mimeType = "test/test";
+
+ // Test NOT NULL mime-type
+ assertFalse(PhotoDatabaseUtils.insertPhoto(db, null, width, height, dateTaken, null,
+ null));
+
+ // Test NOT NULL width
+ assertFalse(PhotoDatabaseUtils.insertPhoto(db, null, null, height, dateTaken, null,
+ mimeType));
+
+ // Test NOT NULL height
+ assertFalse(PhotoDatabaseUtils.insertPhoto(db, null, width, null, dateTaken, null,
+ mimeType));
+
+ // Test NOT NULL dateTaken
+ assertFalse(PhotoDatabaseUtils.insertPhoto(db, null, width, height, null, null,
+ mimeType));
+
+ // Test normal insert
+ assertTrue(PhotoDatabaseUtils.insertPhoto(db, null, width, height, dateTaken, null,
+ mimeType));
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ public void testMetadataConstraints() {
+ SQLiteDatabase db = getWriteableDB();
+ db.beginTransaction();
+ try {
+ final String mimeType = "test/test";
+ long photoServerId = 100;
+ PhotoDatabaseUtils.insertPhoto(db, photoServerId, 100, 100, 100L, null, mimeType);
+ long photoId = PhotoDatabaseUtils.queryPhotoIdFromServerId(db, photoServerId);
+
+ // Test NOT NULL PHOTO_ID constraint.
+ assertFalse(PhotoDatabaseUtils.insertMetadata(db, null, "foo", "bar"));
+
+ // Normal insert.
+ assertTrue(PhotoDatabaseUtils.insertMetadata(db, photoId, "foo", "bar"));
+
+ // Test uniqueness constraint.
+ assertFalse(PhotoDatabaseUtils.insertMetadata(db, photoId, "foo", "baz"));
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ private SQLiteDatabase getReadableDB() {
+ return mDBHelper.getReadableDatabase();
+ }
+
+ private SQLiteDatabase getWriteableDB() {
+ return mDBHelper.getWritableDatabase();
+ }
+
+ private void validateTable(String table, String[] projection) {
+ SQLiteDatabase db = getReadableDB();
+ Cursor cursor = db.query(table, projection, null, null, null, null, null);
+ assertNotNull(cursor);
+ assertEquals(cursor.getCount(), 0);
+ assertEquals(cursor.getColumnCount(), projection.length);
+ for (int i = 0; i < projection.length; i++) {
+ assertEquals(cursor.getColumnName(i), projection[i]);
+ }
+ }
+
+
+}
diff --git a/tests/src/com/android/photos/data/PhotoDatabaseUtils.java b/tests/src/com/android/photos/data/PhotoDatabaseUtils.java
new file mode 100644
index 000000000..6fd73e1b3
--- /dev/null
+++ b/tests/src/com/android/photos/data/PhotoDatabaseUtils.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.photos.data;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+
+import com.android.photos.data.PhotoProvider.Albums;
+import com.android.photos.data.PhotoProvider.Metadata;
+import com.android.photos.data.PhotoProvider.Photos;
+
+import junit.framework.AssertionFailedError;
+
+public class PhotoDatabaseUtils {
+ public static String[] PROJECTION_ALBUMS = {
+ Albums._ID,
+ Albums.PARENT_ID,
+ Albums.VISIBILITY,
+ Albums.NAME,
+ Albums.SERVER_ID,
+ };
+
+ public static String[] PROJECTION_METADATA = {
+ Metadata.PHOTO_ID,
+ Metadata.KEY,
+ Metadata.VALUE,
+ };
+
+ public static String[] PROJECTION_PHOTOS = {
+ Photos._ID,
+ Photos.SERVER_ID,
+ Photos.WIDTH,
+ Photos.HEIGHT,
+ Photos.DATE_TAKEN,
+ Photos.ALBUM_ID,
+ Photos.MIME_TYPE,
+ };
+
+ private static String SELECTION_ALBUM_SERVER_ID = Albums.SERVER_ID + " = ?";
+ private static String SELECTION_PHOTO_SERVER_ID = Photos.SERVER_ID + " = ?";
+
+ public static long queryAlbumIdFromServerId(SQLiteDatabase db, long serverId) {
+ return queryId(db, Albums.TABLE, PROJECTION_ALBUMS, SELECTION_ALBUM_SERVER_ID, serverId);
+ }
+
+ public static long queryPhotoIdFromServerId(SQLiteDatabase db, long serverId) {
+ return queryId(db, Photos.TABLE, PROJECTION_PHOTOS, SELECTION_PHOTO_SERVER_ID, serverId);
+ }
+
+ public static long queryId(SQLiteDatabase db, String table, String[] projection,
+ String selection, Object parameter) {
+ String paramString = parameter == null ? null : parameter.toString();
+ String[] selectionArgs = {
+ paramString,
+ };
+ Cursor cursor = db.query(table, projection, selection, selectionArgs, null, null, null);
+ try {
+ if (cursor.getCount() != 1 || !cursor.moveToNext()) {
+ throw new AssertionFailedError("Couldn't find item in table");
+ }
+ long id = cursor.getLong(0);
+ return id;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ public static boolean insertPhoto(SQLiteDatabase db, Long serverId, Integer width,
+ Integer height, Long dateTaken, Long albumId, String mimeType) {
+ ContentValues values = new ContentValues();
+ values.put(Photos.SERVER_ID, serverId);
+ values.put(Photos.WIDTH, width);
+ values.put(Photos.HEIGHT, height);
+ values.put(Photos.DATE_TAKEN, dateTaken);
+ values.put(Photos.ALBUM_ID, albumId);
+ values.put(Photos.MIME_TYPE, mimeType);
+ return db.insert(Photos.TABLE, null, values) != -1;
+ }
+
+ public static boolean insertAlbum(SQLiteDatabase db, Long parentId, String name,
+ Integer privacy, Long serverId) {
+ ContentValues values = new ContentValues();
+ values.put(Albums.PARENT_ID, parentId);
+ values.put(Albums.NAME, name);
+ values.put(Albums.VISIBILITY, privacy);
+ values.put(Albums.SERVER_ID, serverId);
+ return db.insert(Albums.TABLE, null, values) != -1;
+ }
+
+ public static boolean insertMetadata(SQLiteDatabase db, Long photosId, String key, String value) {
+ ContentValues values = new ContentValues();
+ values.put(Metadata.PHOTO_ID, photosId);
+ values.put(Metadata.KEY, key);
+ values.put(Metadata.VALUE, value);
+ return db.insert(Metadata.TABLE, null, values) != -1;
+ }
+
+ public static void deleteAllContent(SQLiteDatabase db) {
+ db.delete(Metadata.TABLE, null, null);
+ db.delete(Photos.TABLE, null, null);
+ db.delete(Albums.TABLE, null, null);
+ }
+}
diff --git a/tests/src/com/android/photos/data/PhotoProviderTest.java b/tests/src/com/android/photos/data/PhotoProviderTest.java
new file mode 100644
index 000000000..ad913b0bd
--- /dev/null
+++ b/tests/src/com/android/photos/data/PhotoProviderTest.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.photos.data;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.BaseColumns;
+import android.test.InstrumentationTestCase;
+
+import com.android.photos.data.PhotoProvider.Albums;
+import com.android.photos.data.PhotoProvider.Metadata;
+import com.android.photos.data.PhotoProvider.Photos;
+
+public class PhotoProviderTest extends InstrumentationTestCase {
+ @SuppressWarnings("unused")
+ private static final String TAG = PhotoProviderTest.class.getSimpleName();
+
+ private static final String MIME_TYPE = "test/test";
+ private static final String ALBUM_NAME = "My Album";
+ private static final long ALBUM_SERVER_ID = 100;
+ private static final long PHOTO_SERVER_ID = 50;
+ private static final String META_KEY = "mykey";
+ private static final String META_VALUE = "myvalue";
+
+ private static final Uri NO_TABLE_URI = PhotoProvider.BASE_CONTENT_URI;
+ private static final Uri BAD_TABLE_URI = Uri.withAppendedPath(PhotoProvider.BASE_CONTENT_URI,
+ "bad_table");
+
+ private static final String WHERE_METADATA_PHOTOS_ID = Metadata.PHOTO_ID + " = ?";
+ private static final String WHERE_METADATA = Metadata.PHOTO_ID + " = ? AND " + Metadata.KEY
+ + " = ?";
+
+ private static final long WAIT_FOR_CHANGE_MILLIS = 200;
+
+ private long mAlbumId;
+ private long mPhotoId;
+ private long mMetadataId;
+
+ private PhotoDatabase mDBHelper;
+ private ContentResolver mResolver;
+
+ private static class WatchContentObserverThread extends Thread {
+ private WatchContentObserver mObserver;
+ private Looper mLooper;
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ mLooper = Looper.myLooper();
+ WatchContentObserver observer = new WatchContentObserver();
+ synchronized (this) {
+ mObserver = observer;
+ this.notifyAll();
+ }
+ Looper.loop();
+ }
+
+ public void waitForObserver() throws InterruptedException {
+ synchronized (this) {
+ while (mObserver == null) {
+ this.wait();
+ }
+ }
+ }
+
+ public WatchContentObserver getObserver() {
+ return mObserver;
+ }
+
+ public void stopLooper() {
+ mLooper.quit();
+ }
+ };
+
+ private static class WatchContentObserver extends ContentObserver {
+ private boolean mOnChangeReceived = false;
+ private Uri mUri = null;
+
+ public WatchContentObserver() {
+ super(new Handler());
+ }
+
+ @Override
+ public synchronized void onChange(boolean selfChange, Uri uri) {
+ mOnChangeReceived = true;
+ mUri = uri;
+ notifyAll();
+ }
+
+ @Override
+ public synchronized void onChange(boolean selfChange) {
+ mOnChangeReceived = true;
+ notifyAll();
+ }
+
+ public boolean waitForNotification() {
+ synchronized (this) {
+ if (!mOnChangeReceived) {
+ try {
+ wait(WAIT_FOR_CHANGE_MILLIS);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ return mOnChangeReceived;
+ }
+ };
+
+ @Override
+ protected void setUp() {
+ Context context = getInstrumentation().getTargetContext();
+ mDBHelper = new PhotoDatabase(context);
+ mResolver = context.getContentResolver();
+ SQLiteDatabase db = mDBHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ PhotoDatabaseUtils.insertAlbum(db, null, ALBUM_NAME, Albums.VISIBILITY_PRIVATE,
+ ALBUM_SERVER_ID);
+ mAlbumId = PhotoDatabaseUtils.queryAlbumIdFromServerId(db, ALBUM_SERVER_ID);
+ PhotoDatabaseUtils.insertPhoto(db, PHOTO_SERVER_ID, 100, 100,
+ System.currentTimeMillis(), mAlbumId, MIME_TYPE);
+ mPhotoId = PhotoDatabaseUtils.queryPhotoIdFromServerId(db, PHOTO_SERVER_ID);
+ PhotoDatabaseUtils.insertMetadata(db, mPhotoId, META_KEY, META_VALUE);
+ String[] projection = {
+ BaseColumns._ID,
+ };
+ Cursor cursor = db.query(Metadata.TABLE, projection, null, null, null, null, null);
+ cursor.moveToNext();
+ mMetadataId = cursor.getLong(0);
+ cursor.close();
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ @Override
+ protected void tearDown() {
+ SQLiteDatabase db = mDBHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ PhotoDatabaseUtils.deleteAllContent(db);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ mDBHelper.close();
+ mDBHelper = null;
+ }
+
+ public void testDelete() {
+ try {
+ mResolver.delete(NO_TABLE_URI, null, null);
+ fail("Exeption should be thrown when no table given");
+ } catch (Exception e) {
+ // expected exception
+ }
+ try {
+ mResolver.delete(BAD_TABLE_URI, null, null);
+ fail("Exeption should be thrown when deleting from a table that doesn't exist");
+ } catch (Exception e) {
+ // expected exception
+ }
+
+ String[] selectionArgs = {
+ String.valueOf(mPhotoId)
+ };
+ // Delete some metadata
+ assertEquals(1,
+ mResolver.delete(Metadata.CONTENT_URI, WHERE_METADATA_PHOTOS_ID, selectionArgs));
+ Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
+ assertEquals(1, mResolver.delete(photoUri, null, null));
+ Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId);
+ assertEquals(1, mResolver.delete(albumUri, null, null));
+ // now delete something that isn't there
+ assertEquals(0, mResolver.delete(photoUri, null, null));
+ }
+
+ public void testDeleteMetadataId() {
+ Uri metadataUri = ContentUris.withAppendedId(Metadata.CONTENT_URI, mMetadataId);
+ assertEquals(1, mResolver.delete(metadataUri, null, null));
+ Cursor cursor = mResolver.query(Metadata.CONTENT_URI, null, null, null, null);
+ assertEquals(0, cursor.getCount());
+ cursor.close();
+ }
+ // Delete the album and ensure that the photos referring to the album are
+ // deleted.
+ public void testDeleteAlbumCascade() {
+ WatchContentObserverThread observerThread = createObserverThread();
+ WatchContentObserver observer = observerThread.getObserver();
+ mResolver.registerContentObserver(Photos.CONTENT_URI, true, observer);
+ try {
+ Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId);
+ mResolver.delete(albumUri, null, null);
+ assertTrue(observer.waitForNotification());
+ assertEquals(observer.mUri, Photos.CONTENT_URI);
+ Cursor cursor = mResolver.query(Photos.CONTENT_URI,
+ PhotoDatabaseUtils.PROJECTION_PHOTOS, null, null, null);
+ assertEquals(0, cursor.getCount());
+ cursor.close();
+ } finally {
+ mResolver.unregisterContentObserver(observer);
+ observerThread.stopLooper();
+ }
+ }
+
+ // Delete the album and ensure that the metadata referring to photos in that
+ // album are deleted.
+ public void testDeleteAlbumCascade2() {
+ WatchContentObserverThread observerThread = createObserverThread();
+ WatchContentObserver observer = observerThread.getObserver();
+ mResolver.registerContentObserver(Metadata.CONTENT_URI, true, observer);
+ try {
+ Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId);
+ mResolver.delete(albumUri, null, null);
+ assertTrue(observer.waitForNotification());
+ assertEquals(observer.mUri, Metadata.CONTENT_URI);
+ Cursor cursor = mResolver.query(Metadata.CONTENT_URI,
+ PhotoDatabaseUtils.PROJECTION_METADATA, null, null, null);
+ assertEquals(0, cursor.getCount());
+ cursor.close();
+ } finally {
+ mResolver.unregisterContentObserver(observer);
+ observerThread.stopLooper();
+ }
+ }
+
+ // Delete all albums and ensure that photos in any album are deleted.
+ public void testDeleteAlbumCascade3() {
+ WatchContentObserverThread observerThread = createObserverThread();
+ WatchContentObserver observer = observerThread.getObserver();
+ mResolver.registerContentObserver(Photos.CONTENT_URI, true, observer);
+ try {
+ mResolver.delete(Albums.CONTENT_URI, null, null);
+ assertTrue(observer.waitForNotification());
+ assertEquals(observer.mUri, Photos.CONTENT_URI);
+ Cursor cursor = mResolver.query(Photos.CONTENT_URI,
+ PhotoDatabaseUtils.PROJECTION_PHOTOS, null, null, null);
+ assertEquals(0, cursor.getCount());
+ cursor.close();
+ } finally {
+ mResolver.unregisterContentObserver(observer);
+ observerThread.stopLooper();
+ }
+ }
+
+ // Delete a photo and ensure that the metadata for that photo are deleted.
+ public void testDeletePhotoCascade() {
+ WatchContentObserverThread observerThread = createObserverThread();
+ WatchContentObserver observer = observerThread.getObserver();
+ mResolver.registerContentObserver(Metadata.CONTENT_URI, true, observer);
+ try {
+ Uri albumUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
+ mResolver.delete(albumUri, null, null);
+ assertTrue(observer.waitForNotification());
+ assertEquals(observer.mUri, Metadata.CONTENT_URI);
+ Cursor cursor = mResolver.query(Metadata.CONTENT_URI,
+ PhotoDatabaseUtils.PROJECTION_METADATA, null, null, null);
+ assertEquals(0, cursor.getCount());
+ cursor.close();
+ } finally {
+ mResolver.unregisterContentObserver(observer);
+ observerThread.stopLooper();
+ }
+ }
+
+ public void testGetType() {
+ // We don't return types for albums
+ assertNull(mResolver.getType(Albums.CONTENT_URI));
+
+ Uri noImage = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId + 1);
+ assertNull(mResolver.getType(noImage));
+
+ Uri image = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
+ assertEquals(MIME_TYPE, mResolver.getType(image));
+ }
+
+ public void testInsert() {
+ ContentValues values = new ContentValues();
+ values.put(Albums.NAME, "don't add me");
+ values.put(Albums.VISIBILITY, Albums.VISIBILITY_PRIVATE);
+ assertNull(mResolver.insert(Albums.CONTENT_URI, values));
+ }
+
+ public void testUpdate() {
+ ContentValues values = new ContentValues();
+ // Normal update -- use an album.
+ values.put(Albums.NAME, "foo");
+ Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId);
+ assertEquals(1, mResolver.update(albumUri, values, null, null));
+ String[] projection = {
+ Albums.NAME,
+ };
+ Cursor cursor = mResolver.query(albumUri, projection, null, null, null);
+ assertEquals(1, cursor.getCount());
+ assertTrue(cursor.moveToNext());
+ assertEquals("foo", cursor.getString(0));
+ cursor.close();
+
+ // Update a row that doesn't exist.
+ Uri noAlbumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId + 1);
+ values.put(Albums.NAME, "bar");
+ assertEquals(0, mResolver.update(noAlbumUri, values, null, null));
+
+ // Update a metadata value that exists.
+ ContentValues metadata = new ContentValues();
+ metadata.put(Metadata.PHOTO_ID, mPhotoId);
+ metadata.put(Metadata.KEY, META_KEY);
+ metadata.put(Metadata.VALUE, "new value");
+ assertEquals(1, mResolver.update(Metadata.CONTENT_URI, metadata, null, null));
+
+ projection = new String[] {
+ Metadata.VALUE,
+ };
+
+ String[] selectionArgs = {
+ String.valueOf(mPhotoId), META_KEY,
+ };
+
+ cursor = mResolver.query(Metadata.CONTENT_URI, projection, WHERE_METADATA, selectionArgs,
+ null);
+ assertEquals(1, cursor.getCount());
+ assertTrue(cursor.moveToNext());
+ assertEquals("new value", cursor.getString(0));
+ cursor.close();
+
+ // Update a metadata value that doesn't exist.
+ metadata.put(Metadata.KEY, "other stuff");
+ assertEquals(1, mResolver.update(Metadata.CONTENT_URI, metadata, null, null));
+
+ selectionArgs[1] = "other stuff";
+ cursor = mResolver.query(Metadata.CONTENT_URI, projection, WHERE_METADATA, selectionArgs,
+ null);
+ assertEquals(1, cursor.getCount());
+ assertTrue(cursor.moveToNext());
+ assertEquals("new value", cursor.getString(0));
+ cursor.close();
+
+ // Remove a metadata value using update.
+ metadata.putNull(Metadata.VALUE);
+ assertEquals(1, mResolver.update(Metadata.CONTENT_URI, metadata, null, null));
+ cursor = mResolver.query(Metadata.CONTENT_URI, projection, WHERE_METADATA, selectionArgs,
+ null);
+ assertEquals(0, cursor.getCount());
+ cursor.close();
+ }
+
+ public void testQuery() {
+ // Query a photo that exists.
+ Cursor cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS,
+ null, null, null);
+ assertNotNull(cursor);
+ assertEquals(1, cursor.getCount());
+ assertTrue(cursor.moveToNext());
+ assertEquals(mPhotoId, cursor.getLong(0));
+ cursor.close();
+
+ // Query a photo that doesn't exist.
+ Uri noPhotoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId + 1);
+ cursor = mResolver.query(noPhotoUri, PhotoDatabaseUtils.PROJECTION_PHOTOS, null, null,
+ null);
+ assertNotNull(cursor);
+ assertEquals(0, cursor.getCount());
+ cursor.close();
+
+ // Query a photo that exists using selection arguments.
+ String[] selectionArgs = {
+ String.valueOf(mPhotoId),
+ };
+
+ cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS,
+ Photos._ID + " = ?", selectionArgs, null);
+ assertNotNull(cursor);
+ assertEquals(1, cursor.getCount());
+ assertTrue(cursor.moveToNext());
+ assertEquals(mPhotoId, cursor.getLong(0));
+ cursor.close();
+ }
+
+ public void testUpdatePhotoNotification() {
+ WatchContentObserverThread observerThread = createObserverThread();
+ WatchContentObserver observer = observerThread.getObserver();
+ mResolver.registerContentObserver(Photos.CONTENT_URI, true, observer);
+ try {
+ Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
+ ContentValues values = new ContentValues();
+ values.put(Photos.MIME_TYPE, "not-a/mime-type");
+ mResolver.update(photoUri, values, null, null);
+ assertTrue(observer.waitForNotification());
+ assertEquals(observer.mUri, photoUri);
+ } finally {
+ mResolver.unregisterContentObserver(observer);
+ observerThread.stopLooper();
+ }
+ }
+
+ public void testUpdateMetadataNotification() {
+ WatchContentObserverThread observerThread = createObserverThread();
+ WatchContentObserver observer = observerThread.getObserver();
+ mResolver.registerContentObserver(Metadata.CONTENT_URI, true, observer);
+ try {
+ ContentValues values = new ContentValues();
+ values.put(Metadata.PHOTO_ID, mPhotoId);
+ values.put(Metadata.KEY, META_KEY);
+ values.put(Metadata.VALUE, "hello world");
+ mResolver.update(Metadata.CONTENT_URI, values, null, null);
+ assertTrue(observer.waitForNotification());
+ assertEquals(observer.mUri, Metadata.CONTENT_URI);
+ } finally {
+ mResolver.unregisterContentObserver(observer);
+ observerThread.stopLooper();
+ }
+ }
+
+ public void testDeletePhotoNotification() {
+ WatchContentObserverThread observerThread = createObserverThread();
+ WatchContentObserver observer = observerThread.getObserver();
+ mResolver.registerContentObserver(Photos.CONTENT_URI, true, observer);
+ try {
+ Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
+ mResolver.delete(photoUri, null, null);
+ assertTrue(observer.waitForNotification());
+ assertEquals(observer.mUri, photoUri);
+ } finally {
+ mResolver.unregisterContentObserver(observer);
+ observerThread.stopLooper();
+ }
+ }
+
+ private WatchContentObserverThread createObserverThread() {
+ WatchContentObserverThread thread = new WatchContentObserverThread();
+ thread.start();
+ try {
+ thread.waitForObserver();
+ return thread;
+ } catch (InterruptedException e) {
+ thread.stopLooper();
+ fail("Interruption while waiting for observer being created.");
+ return null;
+ }
+ }
+}