diff options
Diffstat (limited to 'tests/src/com/android/photos')
-rw-r--r-- | tests/src/com/android/photos/data/DataTestRunner.java | 46 | ||||
-rw-r--r-- | tests/src/com/android/photos/data/MediaCacheTest.java | 388 | ||||
-rw-r--r-- | tests/src/com/android/photos/data/PhotoDatabaseTest.java | 229 | ||||
-rw-r--r-- | tests/src/com/android/photos/data/PhotoDatabaseUtils.java | 135 | ||||
-rw-r--r-- | tests/src/com/android/photos/data/PhotoProviderTest.java | 391 | ||||
-rw-r--r-- | tests/src/com/android/photos/data/TestHelper.java | 53 |
6 files changed, 1242 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..10618d67d --- /dev/null +++ b/tests/src/com/android/photos/data/DataTestRunner.java @@ -0,0 +1,46 @@ +/* + * 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 com.android.photos.data.TestHelper.TestInitialization; + +import junit.framework.TestCase; +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); + TestHelper.addTests(MediaCacheTest.class, suite, new TestInitialization() { + @Override + public void initialize(TestCase testCase) { + MediaCacheTest test = (MediaCacheTest) testCase; + test.setLocalContext(getContext()); + } + }); + return suite; + } + + @Override + public ClassLoader getLoader() { + return DataTestRunner.class.getClassLoader(); + } +} diff --git a/tests/src/com/android/photos/data/MediaCacheTest.java b/tests/src/com/android/photos/data/MediaCacheTest.java new file mode 100644 index 000000000..9e7112807 --- /dev/null +++ b/tests/src/com/android/photos/data/MediaCacheTest.java @@ -0,0 +1,388 @@ +/* + * 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.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Environment; +import android.os.SystemClock; +import android.test.ProviderTestCase2; + +import com.android.gallery3d.tests.R; +import com.android.photos.data.MediaCache.ImageReady; +import com.android.photos.data.MediaCache.OriginalReady; +import com.android.photos.data.MediaRetriever.MediaSize; +import com.android.photos.data.PhotoProvider.Photos; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +public class MediaCacheTest extends ProviderTestCase2<PhotoProvider> { + @SuppressWarnings("unused") + private static final String TAG = MediaCacheTest.class.getSimpleName(); + + private File mDir; + private File mImage; + private File mCacheDir; + private Resources mResources; + private MediaCache mMediaCache; + private ReadyCollector mReady; + + public static final long MAX_WAIT = 2000; + + private static class ReadyCollector implements ImageReady, OriginalReady { + public File mOriginalFile; + public InputStream mInputStream; + + @Override + public synchronized void originalReady(File originalFile) { + mOriginalFile = originalFile; + notifyAll(); + } + + @Override + public synchronized void imageReady(InputStream bitmapInputStream) { + mInputStream = bitmapInputStream; + notifyAll(); + } + + public synchronized boolean waitForNotification() { + long endWait = SystemClock.uptimeMillis() + MAX_WAIT; + + try { + while (mInputStream == null && mOriginalFile == null + && SystemClock.uptimeMillis() < endWait) { + wait(endWait - SystemClock.uptimeMillis()); + } + } catch (InterruptedException e) { + } + return mInputStream != null || mOriginalFile != null; + } + } + + private static class DummyMediaRetriever implements MediaRetriever { + private boolean mNullUri = false; + @Override + public File getLocalFile(Uri contentUri) { + return null; + } + + @Override + public MediaSize getFastImageSize(Uri contentUri, MediaSize size) { + return null; + } + + @Override + public byte[] getTemporaryImage(Uri contentUri, MediaSize temporarySize) { + return null; + } + + @Override + public boolean getMedia(Uri contentUri, MediaSize imageSize, File tempFile) { + return false; + } + + @Override + public Uri normalizeUri(Uri contentUri, MediaSize size) { + if (mNullUri) { + return null; + } else { + return contentUri; + } + } + + @Override + public MediaSize normalizeMediaSize(Uri contentUri, MediaSize size) { + return size; + } + + public void setNullUri() { + mNullUri = true; + } + }; + + public MediaCacheTest() { + super(PhotoProvider.class, PhotoProvider.AUTHORITY); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + + mReady = new ReadyCollector(); + File externalDir = Environment.getExternalStorageDirectory(); + mDir = new File(externalDir, "test"); + mDir.mkdirs(); + mCacheDir = new File(externalDir, "test_cache"); + mImage = new File(mDir, "original.jpg"); + MediaCache.initialize(getMockContext()); + MediaCache.getInstance().setCacheDir(mCacheDir); + mMediaCache = MediaCache.getInstance(); + mMediaCache.addRetriever("file", "", new FileRetriever()); + } + + @Override + public void tearDown() throws Exception { + super.tearDown(); + mMediaCache.clearCacheDir(); + MediaCache.shutdown(); + mMediaCache = null; + mImage.delete(); + mDir.delete(); + mCacheDir.delete(); + } + + public void setLocalContext(Context context) { + mResources = context.getResources(); + } + + public void testRetrieveOriginal() throws IOException { + copyResourceToFile(R.raw.galaxy_nexus, mImage.getPath()); + Uri uri = Uri.fromFile(mImage); + mMediaCache.retrieveOriginal(uri, mReady, null); + assertTrue(mReady.waitForNotification()); + assertNull(mReady.mInputStream); + assertEquals(mImage, mReady.mOriginalFile); + } + + public void testRetrievePreview() throws IOException { + copyResourceToFile(R.raw.galaxy_nexus, mImage.getPath()); + Uri uri = Uri.fromFile(mImage); + mMediaCache.retrievePreview(uri, mReady, null); + assertTrue(mReady.waitForNotification()); + assertNotNull(mReady.mInputStream); + assertNull(mReady.mOriginalFile); + Bitmap bitmap = BitmapFactory.decodeStream(mReady.mInputStream); + mReady.mInputStream.close(); + assertNotNull(bitmap); + Bitmap original = BitmapFactory.decodeFile(mImage.getPath()); + assertTrue(bitmap.getWidth() < original.getWidth()); + assertTrue(bitmap.getHeight() < original.getHeight()); + int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight()); + int targetSize = MediaCacheUtils.getTargetSize(MediaSize.Preview); + assertTrue(maxDimension >= targetSize); + assertTrue(maxDimension < (targetSize * 2)); + } + + public void testRetrieveExifThumb() throws IOException { + copyResourceToFile(R.raw.galaxy_nexus, mImage.getPath()); + Uri uri = Uri.fromFile(mImage); + ReadyCollector done = new ReadyCollector(); + mMediaCache.retrieveThumbnail(uri, done, mReady); + assertTrue(mReady.waitForNotification()); + assertNotNull(mReady.mInputStream); + assertNull(mReady.mOriginalFile); + Bitmap bitmap = BitmapFactory.decodeStream(mReady.mInputStream); + mReady.mInputStream.close(); + assertTrue(done.waitForNotification()); + assertNotNull(done.mInputStream); + done.mInputStream.close(); + assertNotNull(bitmap); + assertEquals(320, bitmap.getWidth()); + assertEquals(240, bitmap.getHeight()); + } + + public void testRetrieveThumb() throws IOException { + copyResourceToFile(R.raw.galaxy_nexus, mImage.getPath()); + Uri uri = Uri.fromFile(mImage); + long downsampleStart = SystemClock.uptimeMillis(); + mMediaCache.retrieveThumbnail(uri, mReady, null); + assertTrue(mReady.waitForNotification()); + long downsampleEnd = SystemClock.uptimeMillis(); + assertNotNull(mReady.mInputStream); + assertNull(mReady.mOriginalFile); + Bitmap bitmap = BitmapFactory.decodeStream(mReady.mInputStream); + mReady.mInputStream.close(); + assertNotNull(bitmap); + Bitmap original = BitmapFactory.decodeFile(mImage.getPath()); + assertTrue(bitmap.getWidth() < original.getWidth()); + assertTrue(bitmap.getHeight() < original.getHeight()); + int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight()); + int targetSize = MediaCacheUtils.getTargetSize(MediaSize.Thumbnail); + assertTrue(maxDimension >= targetSize); + assertTrue(maxDimension < (targetSize * 2)); + + // Retrieve cached thumb. + mReady = new ReadyCollector(); + long start = SystemClock.uptimeMillis(); + mMediaCache.retrieveThumbnail(uri, mReady, null); + assertTrue(mReady.waitForNotification()); + mReady.mInputStream.close(); + long end = SystemClock.uptimeMillis(); + // Already cached. Wait shorter time. + assertTrue((end - start) < (downsampleEnd - downsampleStart) / 2); + } + + public void testGetVideo() throws IOException { + mImage = new File(mDir, "original.mp4"); + copyResourceToFile(R.raw.android_lawn, mImage.getPath()); + Uri uri = Uri.fromFile(mImage); + + mMediaCache.retrieveOriginal(uri, mReady, null); + assertTrue(mReady.waitForNotification()); + assertNull(mReady.mInputStream); + assertNotNull(mReady.mOriginalFile); + + mReady = new ReadyCollector(); + mMediaCache.retrievePreview(uri, mReady, null); + assertTrue(mReady.waitForNotification()); + assertNotNull(mReady.mInputStream); + assertNull(mReady.mOriginalFile); + Bitmap bitmap = BitmapFactory.decodeStream(mReady.mInputStream); + mReady.mInputStream.close(); + int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight()); + int targetSize = MediaCacheUtils.getTargetSize(MediaSize.Preview); + assertTrue(maxDimension >= targetSize); + assertTrue(maxDimension < (targetSize * 2)); + + mReady = new ReadyCollector(); + mMediaCache.retrieveThumbnail(uri, mReady, null); + assertTrue(mReady.waitForNotification()); + assertNotNull(mReady.mInputStream); + assertNull(mReady.mOriginalFile); + bitmap = BitmapFactory.decodeStream(mReady.mInputStream); + mReady.mInputStream.close(); + maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight()); + targetSize = MediaCacheUtils.getTargetSize(MediaSize.Thumbnail); + assertTrue(maxDimension >= targetSize); + assertTrue(maxDimension < (targetSize * 2)); + } + + public void testFastImage() throws IOException { + copyResourceToFile(R.raw.galaxy_nexus, mImage.getPath()); + Uri uri = Uri.fromFile(mImage); + mMediaCache.retrieveThumbnail(uri, mReady, null); + mReady.waitForNotification(); + mReady.mInputStream.close(); + + mMediaCache.retrieveOriginal(uri, mReady, null); + assertTrue(mReady.waitForNotification()); + assertNotNull(mReady.mInputStream); + mReady.mInputStream.close(); + } + + public void testBadRetriever() { + Uri uri = Photos.CONTENT_URI; + try { + mMediaCache.retrieveOriginal(uri, mReady, null); + fail("Expected exception"); + } catch (IllegalArgumentException e) { + // expected + } + } + + public void testInsertIntoCache() throws IOException { + // FileRetriever inserts into the cache opportunistically with Videos + mImage = new File(mDir, "original.mp4"); + copyResourceToFile(R.raw.android_lawn, mImage.getPath()); + Uri uri = Uri.fromFile(mImage); + + mMediaCache.retrieveThumbnail(uri, mReady, null); + assertTrue(mReady.waitForNotification()); + mReady.mInputStream.close(); + assertNotNull(mMediaCache.getCachedFile(uri, MediaSize.Preview)); + } + + public void testBadNormalizedUri() { + DummyMediaRetriever retriever = new DummyMediaRetriever(); + Uri uri = Uri.fromParts("http", "world", "morestuff"); + mMediaCache.addRetriever(uri.getScheme(), uri.getAuthority(), retriever); + retriever.setNullUri(); + try { + mMediaCache.retrieveOriginal(uri, mReady, null); + fail("Expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + } + + public void testClearOldCache() throws IOException { + copyResourceToFile(R.raw.galaxy_nexus, mImage.getPath()); + Uri uri = Uri.fromFile(mImage); + mMediaCache.retrievePreview(uri, mReady, null); + assertTrue(mReady.waitForNotification()); + mReady.mInputStream.close(); + mMediaCache.setMaxCacheSize(mMediaCache.getCachedFile(uri, MediaSize.Preview).length()); + assertNotNull(mMediaCache.getCachedFile(uri, MediaSize.Preview)); + + mReady = new ReadyCollector(); + // This should kick the preview image out of the cache. + mMediaCache.retrieveThumbnail(uri, mReady, null); + assertTrue(mReady.waitForNotification()); + mReady.mInputStream.close(); + assertNull(mMediaCache.getCachedFile(uri, MediaSize.Preview)); + assertNotNull(mMediaCache.getCachedFile(uri, MediaSize.Thumbnail)); + } + + public void testClearLargeInCache() throws IOException { + copyResourceToFile(R.raw.galaxy_nexus, mImage.getPath()); + Uri imageUri = Uri.fromFile(mImage); + mMediaCache.retrieveThumbnail(imageUri, mReady, null); + assertTrue(mReady.waitForNotification()); + mReady.mInputStream.close(); + assertNotNull(mMediaCache.getCachedFile(imageUri, MediaSize.Thumbnail)); + long thumbSize = mMediaCache.getCachedFile(imageUri, MediaSize.Thumbnail).length(); + mMediaCache.setMaxCacheSize(thumbSize * 10); + + for (int i = 0; i < 9; i++) { + File tempImage = new File(mDir, "image" + i + ".jpg"); + mImage.renameTo(tempImage); + Uri tempImageUri = Uri.fromFile(tempImage); + mReady = new ReadyCollector(); + mMediaCache.retrieveThumbnail(tempImageUri, mReady, null); + assertTrue(mReady.waitForNotification()); + mReady.mInputStream.close(); + tempImage.renameTo(mImage); + } + assertNotNull(mMediaCache.getCachedFile(imageUri, MediaSize.Thumbnail)); + + for (int i = 0; i < 9; i++) { + File tempImage = new File(mDir, "image" + i + ".jpg"); + mImage.renameTo(tempImage); + Uri tempImageUri = Uri.fromFile(tempImage); + mReady = new ReadyCollector(); + mMediaCache.retrievePreview(tempImageUri, mReady, null); + assertTrue(mReady.waitForNotification()); + mReady.mInputStream.close(); + tempImage.renameTo(mImage); + } + assertNotNull(mMediaCache.getCachedFile(imageUri, MediaSize.Thumbnail)); + Uri oldestUri = Uri.fromFile(new File(mDir, "image0.jpg")); + assertNull(mMediaCache.getCachedFile(oldestUri, MediaSize.Thumbnail)); + } + + private void copyResourceToFile(int resourceId, String path) throws IOException { + File outputDir = new File(path).getParentFile(); + outputDir.mkdirs(); + + InputStream in = mResources.openRawResource(resourceId); + FileOutputStream out = new FileOutputStream(path); + byte[] buffer = new byte[1000]; + int bytesRead; + + while ((bytesRead = in.read(buffer)) >= 0) { + out.write(buffer, 0, bytesRead); + } + + in.close(); + out.close(); + } +} 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..e7c168947 --- /dev/null +++ b/tests/src/com/android/photos/data/PhotoDatabaseTest.java @@ -0,0 +1,229 @@ +/* + * 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.DatabaseUtils; +import android.database.sqlite.SQLiteDatabase; +import android.test.InstrumentationTestCase; + +import com.android.photos.data.PhotoProvider.Accounts; +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; + private static final String DB_NAME = "dummy.db"; + private static final long PARENT_ID1 = 100; + private static final long PARENT_ID2 = 101; + + @Override + protected void setUp() throws Exception { + super.setUp(); + Context context = getInstrumentation().getTargetContext(); + context.deleteDatabase(DB_NAME); + mDBHelper = new PhotoDatabase(context, DB_NAME); + } + + @Override + protected void tearDown() throws Exception { + mDBHelper.close(); + mDBHelper = null; + Context context = getInstrumentation().getTargetContext(); + context.deleteDatabase(DB_NAME); + super.tearDown(); + } + + public void testCreateDatabase() throws IOException { + Context context = getInstrumentation().getTargetContext(); + File dbFile = context.getDatabasePath(DB_NAME); + SQLiteDatabase db = getReadableDB(); + db.beginTransaction(); + db.endTransaction(); + assertTrue(dbFile.exists()); + } + + 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 = getWritableDB(); + db.beginTransaction(); + try { + long accountId = 100; + // Test NOT NULL constraint on name + assertFalse(PhotoDatabaseUtils.insertAlbum(db, null, null, Albums.VISIBILITY_PRIVATE, + accountId)); + + // test NOT NULL constraint on privacy + assertFalse(PhotoDatabaseUtils.insertAlbum(db, null, "hello", null, accountId)); + + // test NOT NULL constraint on account_id + assertFalse(PhotoDatabaseUtils.insertAlbum(db, null, "hello", + Albums.VISIBILITY_PRIVATE, null)); + + // Normal insert + assertTrue(PhotoDatabaseUtils.insertAlbum(db, PARENT_ID1, "hello", + Albums.VISIBILITY_PRIVATE, accountId)); + + long albumId = PhotoDatabaseUtils.queryAlbumIdFromParentId(db, PARENT_ID1); + + // Assign a valid child + assertTrue(PhotoDatabaseUtils.insertAlbum(db, PARENT_ID2, "hello", + Albums.VISIBILITY_PRIVATE, accountId)); + + long otherAlbumId = PhotoDatabaseUtils.queryAlbumIdFromParentId(db, PARENT_ID2); + assertNotSame(albumId, otherAlbumId); + + // This is a valid child of another album. + assertTrue(PhotoDatabaseUtils.insertAlbum(db, otherAlbumId, "hello", + Albums.VISIBILITY_PRIVATE, accountId)); + + // This isn't allowed due to uniqueness constraint (parent_id/name) + assertFalse(PhotoDatabaseUtils.insertAlbum(db, otherAlbumId, "hello", + Albums.VISIBILITY_PRIVATE, accountId)); + } finally { + db.endTransaction(); + } + } + + public void testPhotosConstraints() { + SQLiteDatabase db = getWritableDB(); + db.beginTransaction(); + try { + int width = 100; + int height = 100; + long dateTaken = System.currentTimeMillis(); + String mimeType = "test/test"; + long accountId = 100; + + // Test NOT NULL mime-type + assertFalse(PhotoDatabaseUtils.insertPhoto(db, width, height, dateTaken, null, null, + accountId)); + + // Test NOT NULL width + assertFalse(PhotoDatabaseUtils.insertPhoto(db, null, height, dateTaken, null, mimeType, + accountId)); + + // Test NOT NULL height + assertFalse(PhotoDatabaseUtils.insertPhoto(db, width, null, dateTaken, null, mimeType, + accountId)); + + // Test NOT NULL dateTaken + assertFalse(PhotoDatabaseUtils.insertPhoto(db, width, height, null, null, mimeType, + accountId)); + + // Test NOT NULL accountId + assertFalse(PhotoDatabaseUtils.insertPhoto(db, width, height, dateTaken, null, + mimeType, null)); + + // Test normal insert + assertTrue(PhotoDatabaseUtils.insertPhoto(db, width, height, dateTaken, null, mimeType, + accountId)); + } finally { + db.endTransaction(); + } + } + + public void testMetadataConstraints() { + SQLiteDatabase db = getWritableDB(); + db.beginTransaction(); + try { + final String mimeType = "test/test"; + PhotoDatabaseUtils.insertPhoto(db, 100, 100, 100L, PARENT_ID1, mimeType, 100L); + long photoId = PhotoDatabaseUtils.queryPhotoIdFromAlbumId(db, PARENT_ID1); + + // 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(); + } + } + + public void testAccountsConstraints() { + SQLiteDatabase db = getWritableDB(); + db.beginTransaction(); + try { + assertFalse(PhotoDatabaseUtils.insertAccount(db, null)); + assertTrue(PhotoDatabaseUtils.insertAccount(db, "hello")); + assertTrue(PhotoDatabaseUtils.insertAccount(db, "hello")); + } finally { + db.endTransaction(); + } + } + + public void testUpgrade() { + SQLiteDatabase db = getWritableDB(); + db.beginTransaction(); + try { + assertTrue(PhotoDatabaseUtils.insertAccount(db, "Hello")); + assertTrue(PhotoDatabaseUtils.insertAlbum(db, PARENT_ID1, "hello", + Albums.VISIBILITY_PRIVATE, 100L)); + final String mimeType = "test/test"; + assertTrue(PhotoDatabaseUtils.insertPhoto(db, 100, 100, 100L, PARENT_ID1, mimeType, + 100L)); + // Normal insert. + assertTrue(PhotoDatabaseUtils.insertMetadata(db, 100L, "foo", "bar")); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + mDBHelper.close(); + Context context = getInstrumentation().getTargetContext(); + mDBHelper = new PhotoDatabase(context, DB_NAME, PhotoDatabase.DB_VERSION + 1); + db = getReadableDB(); + assertEquals(0, DatabaseUtils.queryNumEntries(db, Accounts.TABLE)); + assertEquals(0, DatabaseUtils.queryNumEntries(db, Photos.TABLE)); + assertEquals(0, DatabaseUtils.queryNumEntries(db, Albums.TABLE)); + assertEquals(0, DatabaseUtils.queryNumEntries(db, Metadata.TABLE)); + } + + private SQLiteDatabase getReadableDB() { + return mDBHelper.getReadableDatabase(); + } + + private SQLiteDatabase getWritableDB() { + 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..f7a46d419 --- /dev/null +++ b/tests/src/com/android/photos/data/PhotoDatabaseUtils.java @@ -0,0 +1,135 @@ +/* + * 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.Accounts; +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.ACCOUNT_ID, + Albums.PARENT_ID, + Albums.VISIBILITY, + Albums.LOCATION_STRING, + Albums.TITLE, + Albums.SUMMARY, + Albums.DATE_PUBLISHED, + Albums.DATE_MODIFIED, + }; + + public static String[] PROJECTION_METADATA = { + Metadata.PHOTO_ID, + Metadata.KEY, + Metadata.VALUE, + }; + + public static String[] PROJECTION_PHOTOS = { + Photos._ID, + Photos.ACCOUNT_ID, + Photos.WIDTH, + Photos.HEIGHT, + Photos.DATE_TAKEN, + Photos.ALBUM_ID, + Photos.MIME_TYPE, + Photos.TITLE, + Photos.DATE_MODIFIED, + Photos.ROTATION, + }; + + public static String[] PROJECTION_ACCOUNTS = { + Accounts._ID, + Accounts.ACCOUNT_NAME, + }; + + private static String SELECTION_ALBUM_PARENT_ID = Albums.PARENT_ID + " = ?"; + private static String SELECTION_PHOTO_ALBUM_ID = Photos.ALBUM_ID + " = ?"; + private static String SELECTION_ACCOUNT_ID = Accounts.ACCOUNT_NAME + " = ?"; + + public static long queryAlbumIdFromParentId(SQLiteDatabase db, long parentId) { + return queryId(db, Albums.TABLE, PROJECTION_ALBUMS, SELECTION_ALBUM_PARENT_ID, parentId); + } + + public static long queryPhotoIdFromAlbumId(SQLiteDatabase db, long albumId) { + return queryId(db, Photos.TABLE, PROJECTION_PHOTOS, SELECTION_PHOTO_ALBUM_ID, albumId); + } + + public static long queryAccountIdFromName(SQLiteDatabase db, String accountName) { + return queryId(db, Accounts.TABLE, PROJECTION_ACCOUNTS, SELECTION_ACCOUNT_ID, accountName); + } + + 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, Integer width, Integer height, + Long dateTaken, Long albumId, String mimeType, Long accountId) { + ContentValues values = new ContentValues(); + 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); + values.put(Photos.ACCOUNT_ID, accountId); + return db.insert(Photos.TABLE, null, values) != -1; + } + + public static boolean insertAlbum(SQLiteDatabase db, Long parentId, String title, + Integer privacy, Long accountId) { + ContentValues values = new ContentValues(); + values.put(Albums.PARENT_ID, parentId); + values.put(Albums.TITLE, title); + values.put(Albums.VISIBILITY, privacy); + values.put(Albums.ACCOUNT_ID, accountId); + 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 boolean insertAccount(SQLiteDatabase db, String name) { + ContentValues values = new ContentValues(); + values.put(Accounts.ACCOUNT_NAME, name); + return db.insert(Accounts.TABLE, null, values) != -1; + } +} 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..685946ef0 --- /dev/null +++ b/tests/src/com/android/photos/data/PhotoProviderTest.java @@ -0,0 +1,391 @@ +/* + * 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.ContentProviderOperation; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.OperationApplicationException; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.net.Uri; +import android.os.RemoteException; +import android.provider.BaseColumns; +import android.test.ProviderTestCase2; + +import com.android.photos.data.PhotoProvider.Accounts; +import com.android.photos.data.PhotoProvider.Albums; +import com.android.photos.data.PhotoProvider.Metadata; +import com.android.photos.data.PhotoProvider.Photos; + +import java.util.ArrayList; + +public class PhotoProviderTest extends ProviderTestCase2<PhotoProvider> { + @SuppressWarnings("unused") + private static final String TAG = PhotoProviderTest.class.getSimpleName(); + + private static final String MIME_TYPE = "test/test"; + private static final String ALBUM_TITLE = "My Album"; + private static final long ALBUM_PARENT_ID = 100; + private static final String META_KEY = "mykey"; + private static final String META_VALUE = "myvalue"; + private static final String ACCOUNT_NAME = "foo@bar.com"; + + 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 long mAlbumId; + private long mPhotoId; + private long mMetadataId; + private long mAccountId; + + private SQLiteOpenHelper mDBHelper; + private ContentResolver mResolver; + private NotificationWatcher mNotifications = new NotificationWatcher(); + + public PhotoProviderTest() { + super(PhotoProvider.class, PhotoProvider.AUTHORITY); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mResolver = getMockContentResolver(); + PhotoProvider provider = (PhotoProvider) getProvider(); + provider.setMockNotification(mNotifications); + mDBHelper = provider.getDatabaseHelper(); + SQLiteDatabase db = mDBHelper.getWritableDatabase(); + db.beginTransaction(); + try { + PhotoDatabaseUtils.insertAccount(db, ACCOUNT_NAME); + mAccountId = PhotoDatabaseUtils.queryAccountIdFromName(db, ACCOUNT_NAME); + PhotoDatabaseUtils.insertAlbum(db, ALBUM_PARENT_ID, ALBUM_TITLE, + Albums.VISIBILITY_PRIVATE, mAccountId); + mAlbumId = PhotoDatabaseUtils.queryAlbumIdFromParentId(db, ALBUM_PARENT_ID); + PhotoDatabaseUtils.insertPhoto(db, 100, 100, System.currentTimeMillis(), mAlbumId, + MIME_TYPE, mAccountId); + mPhotoId = PhotoDatabaseUtils.queryPhotoIdFromAlbumId(db, mAlbumId); + 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(); + mNotifications.reset(); + } finally { + db.endTransaction(); + } + } + + @Override + protected void tearDown() throws Exception { + mDBHelper.close(); + mDBHelper = null; + super.tearDown(); + getMockContext().deleteDatabase(PhotoProvider.DB_NAME); + } + + 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() { + Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId); + mResolver.delete(albumUri, null, null); + assertTrue(mNotifications.isNotified(Photos.CONTENT_URI)); + assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI)); + assertTrue(mNotifications.isNotified(albumUri)); + assertEquals(3, mNotifications.notificationCount()); + Cursor cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS, + null, null, null); + assertEquals(0, cursor.getCount()); + cursor.close(); + } + + // Delete all albums and ensure that photos in any album are deleted. + public void testDeleteAlbumCascade2() { + mResolver.delete(Albums.CONTENT_URI, null, null); + assertTrue(mNotifications.isNotified(Photos.CONTENT_URI)); + assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI)); + assertTrue(mNotifications.isNotified(Albums.CONTENT_URI)); + assertEquals(3, mNotifications.notificationCount()); + Cursor cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS, + null, null, null); + assertEquals(0, cursor.getCount()); + cursor.close(); + } + + // Delete a photo and ensure that the metadata for that photo are deleted. + public void testDeletePhotoCascade() { + Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId); + mResolver.delete(photoUri, null, null); + assertTrue(mNotifications.isNotified(photoUri)); + assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI)); + assertEquals(2, mNotifications.notificationCount()); + Cursor cursor = mResolver.query(Metadata.CONTENT_URI, + PhotoDatabaseUtils.PROJECTION_METADATA, null, null, null); + assertEquals(0, cursor.getCount()); + cursor.close(); + } + + public void testDeleteAccountCascade() { + Uri accountUri = ContentUris.withAppendedId(Accounts.CONTENT_URI, mAccountId); + SQLiteDatabase db = mDBHelper.getWritableDatabase(); + db.beginTransaction(); + PhotoDatabaseUtils.insertPhoto(db, 100, 100, System.currentTimeMillis(), null, + "image/jpeg", mAccountId); + PhotoDatabaseUtils.insertPhoto(db, 100, 100, System.currentTimeMillis(), null, + "image/jpeg", 0L); + PhotoDatabaseUtils.insertAlbum(db, null, "title", Albums.VISIBILITY_PRIVATE, 10630L); + db.setTransactionSuccessful(); + db.endTransaction(); + // ensure all pictures are there: + Cursor cursor = mResolver.query(Photos.CONTENT_URI, null, null, null, null); + assertEquals(3, cursor.getCount()); + cursor.close(); + // delete the account + assertEquals(1, mResolver.delete(accountUri, null, null)); + // now ensure that all associated photos were deleted + cursor = mResolver.query(Photos.CONTENT_URI, null, null, null, null); + assertEquals(1, cursor.getCount()); + cursor.close(); + // now ensure all associated albums were deleted. + cursor = mResolver.query(Albums.CONTENT_URI, null, null, null, null); + assertEquals(1, cursor.getCount()); + cursor.close(); + } + + 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.TITLE, "add me"); + values.put(Albums.VISIBILITY, Albums.VISIBILITY_PRIVATE); + values.put(Albums.ACCOUNT_ID, 100L); + values.put(Albums.DATE_MODIFIED, 100L); + values.put(Albums.DATE_PUBLISHED, 100L); + values.put(Albums.LOCATION_STRING, "Home"); + values.put(Albums.TITLE, "hello world"); + values.putNull(Albums.PARENT_ID); + values.put(Albums.SUMMARY, "Nothing much to say about this"); + Uri insertedUri = mResolver.insert(Albums.CONTENT_URI, values); + assertNotNull(insertedUri); + Cursor cursor = mResolver.query(insertedUri, PhotoDatabaseUtils.PROJECTION_ALBUMS, null, + null, null); + assertNotNull(cursor); + assertEquals(1, cursor.getCount()); + cursor.close(); + } + + public void testUpdate() { + ContentValues values = new ContentValues(); + // Normal update -- use an album. + values.put(Albums.TITLE, "foo"); + Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId); + assertEquals(1, mResolver.update(albumUri, values, null, null)); + String[] projection = { + Albums.TITLE, + }; + 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.TITLE, "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() { + 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(mNotifications.isNotified(photoUri)); + } + + public void testUpdateMetadataNotification() { + 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(mNotifications.isNotified(Metadata.CONTENT_URI)); + } + + public void testBatchTransaction() throws RemoteException, OperationApplicationException { + ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(); + ContentProviderOperation.Builder insert = ContentProviderOperation + .newInsert(Photos.CONTENT_URI); + insert.withValue(Photos.WIDTH, 200L); + insert.withValue(Photos.HEIGHT, 100L); + insert.withValue(Photos.DATE_TAKEN, System.currentTimeMillis()); + insert.withValue(Photos.ALBUM_ID, 1000L); + insert.withValue(Photos.MIME_TYPE, "image/jpg"); + insert.withValue(Photos.ACCOUNT_ID, 1L); + operations.add(insert.build()); + ContentProviderOperation.Builder update = ContentProviderOperation.newUpdate(Photos.CONTENT_URI); + update.withValue(Photos.DATE_MODIFIED, System.currentTimeMillis()); + String[] whereArgs = { + "100", + }; + String where = Photos.WIDTH + " = ?"; + update.withSelection(where, whereArgs); + operations.add(update.build()); + ContentProviderOperation.Builder delete = ContentProviderOperation + .newDelete(Photos.CONTENT_URI); + delete.withSelection(where, whereArgs); + operations.add(delete.build()); + mResolver.applyBatch(PhotoProvider.AUTHORITY, operations); + assertEquals(3, mNotifications.notificationCount()); + SQLiteDatabase db = mDBHelper.getReadableDatabase(); + long id = PhotoDatabaseUtils.queryPhotoIdFromAlbumId(db, 1000L); + Uri uri = ContentUris.withAppendedId(Photos.CONTENT_URI, id); + assertTrue(mNotifications.isNotified(uri)); + assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI)); + assertTrue(mNotifications.isNotified(Photos.CONTENT_URI)); + } + +} diff --git a/tests/src/com/android/photos/data/TestHelper.java b/tests/src/com/android/photos/data/TestHelper.java new file mode 100644 index 000000000..338e160cf --- /dev/null +++ b/tests/src/com/android/photos/data/TestHelper.java @@ -0,0 +1,53 @@ +/* + * 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.util.Log; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import java.lang.reflect.Method; + +public class TestHelper { + private static String TAG = TestHelper.class.getSimpleName(); + + public interface TestInitialization { + void initialize(TestCase testCase); + } + + public static void addTests(Class<? extends TestCase> testClass, TestSuite suite, + TestInitialization initialization) { + for (Method method : testClass.getDeclaredMethods()) { + if (method.getName().startsWith("test") && method.getParameterTypes().length == 0) { + TestCase test; + try { + test = testClass.newInstance(); + test.setName(method.getName()); + initialization.initialize(test); + suite.addTest(test); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Failed to create test case", e); + } catch (InstantiationException e) { + Log.e(TAG, "Failed to create test case", e); + } catch (IllegalAccessException e) { + Log.e(TAG, "Failed to create test case", e); + } + } + } + } + +} |