Fix the last failing photo test
Also add some nice features to the asserts for complex data.
- assertImageRawData() now writes the expected and actual images to the
cache dir when failing.
- assertStoredValues() and its siblings now dump the cursor to logcat
when failing.
Bug 6280711
Change-Id: I77aff61b0494580d0b2ba24b35eb045a18cd48c8
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index c1449fc..19e81a9 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -1493,7 +1493,8 @@
new DataRowHandlerForGroupMembership(context, dbHelper, contactAggregator,
mGroupIdCache));
handlerMap.put(Photo.CONTENT_ITEM_TYPE,
- new DataRowHandlerForPhoto(context, dbHelper, contactAggregator, photoStore));
+ new DataRowHandlerForPhoto(context, dbHelper, contactAggregator, photoStore,
+ getMaxDisplayPhotoDim(), getMaxThumbnailDim()));
handlerMap.put(Note.CONTENT_ITEM_TYPE,
new DataRowHandlerForNote(context, dbHelper, contactAggregator));
}
diff --git a/src/com/android/providers/contacts/DataRowHandlerForPhoto.java b/src/com/android/providers/contacts/DataRowHandlerForPhoto.java
index 79f9267..7560ed4 100644
--- a/src/com/android/providers/contacts/DataRowHandlerForPhoto.java
+++ b/src/com/android/providers/contacts/DataRowHandlerForPhoto.java
@@ -34,6 +34,8 @@
private static final String TAG = "DataRowHandlerForPhoto";
private final PhotoStore mPhotoStore;
+ private final int mMaxDisplayPhotoDim;
+ private final int mMaxThumbnailPhotoDim;
/**
* If this is set in the ContentValues passed in, it indicates that the caller has
@@ -45,9 +47,11 @@
public DataRowHandlerForPhoto(
Context context, ContactsDatabaseHelper dbHelper, ContactAggregator aggregator,
- PhotoStore photoStore) {
+ PhotoStore photoStore, int maxDisplayPhotoDim, int maxThumbnailPhotoDim) {
super(context, dbHelper, aggregator, Photo.CONTENT_ITEM_TYPE);
mPhotoStore = photoStore;
+ mMaxDisplayPhotoDim = maxDisplayPhotoDim;
+ mMaxThumbnailPhotoDim = maxThumbnailPhotoDim;
}
@Override
@@ -141,11 +145,9 @@
private boolean processPhoto(ContentValues values) {
byte[] originalPhoto = values.getAsByteArray(Photo.PHOTO);
if (originalPhoto != null) {
- int maxDisplayPhotoDim = PhotoProcessor.getMaxDisplayPhotoSize();
- int maxThumbnailPhotoDim = PhotoProcessor.getMaxThumbnailSize();
try {
PhotoProcessor processor = new PhotoProcessor(
- originalPhoto, maxDisplayPhotoDim, maxThumbnailPhotoDim);
+ originalPhoto, mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim);
long photoFileId = mPhotoStore.insert(processor);
if (photoFileId != 0) {
values.put(Photo.PHOTO_FILE_ID, photoFileId);
diff --git a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
index 5827ff1..863ad4a 100644
--- a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
@@ -930,7 +930,7 @@
assertStoredValues(rowUri, null, null, expectedValues);
}
- protected void assertStoredValues(Uri rowUri, ContentValues[] expectedValues) {
+ protected void assertStoredValues(Uri rowUri, ContentValues... expectedValues) {
assertStoredValues(rowUri, null, null, expectedValues);
}
@@ -941,6 +941,9 @@
assertEquals("Record count", 1, c.getCount());
c.moveToFirst();
assertCursorValues(c, expectedValues);
+ } catch (Error e) {
+ TestUtils.dumpCursor(c);
+ throw e;
} finally {
c.close();
}
@@ -957,6 +960,9 @@
assertEquals("Record count", expectedValues.length, c.getCount());
c.moveToFirst();
assertCursorValues(c, expectedValues);
+ } catch (Error e) {
+ TestUtils.dumpCursor(c);
+ throw e;
} finally {
c.close();
}
@@ -972,6 +978,9 @@
try {
assertEquals("Record count", expectedValues.length, c.getCount());
assertCursorValues(c, expectedValues);
+ } catch (Error e) {
+ TestUtils.dumpCursor(c);
+ throw e;
} finally {
c.close();
}
@@ -997,6 +1006,9 @@
try {
assertEquals("Record count", expectedValues.length, c.getCount());
assertCursorValuesOrderly(c, expectedValues);
+ } catch (Error e) {
+ TestUtils.dumpCursor(c);
+ throw e;
} finally {
c.close();
}
@@ -1045,6 +1057,9 @@
assertEquals("Record count", 1, c.getCount());
c.moveToFirst();
assertCursorValues(c, values);
+ } catch (Error e) {
+ TestUtils.dumpCursor(c);
+ throw e;
} finally {
c.close();
}
@@ -1062,7 +1077,7 @@
assertTrue(message.toString(), result);
}
- protected void assertCursorValues(Cursor cursor, ContentValues[] expectedValues) {
+ protected void assertCursorValues(Cursor cursor, ContentValues... expectedValues) {
StringBuilder message = new StringBuilder();
// In case if expectedValues contains multiple identical values, remember which cursor
@@ -1085,7 +1100,7 @@
}
}
- protected void assertCursorValuesOrderly(Cursor cursor, ContentValues[] expectedValues) {
+ private void assertCursorValuesOrderly(Cursor cursor, ContentValues... expectedValues) {
StringBuilder message = new StringBuilder();
cursor.moveToPosition(-1);
for (ContentValues v : expectedValues) {
@@ -1220,10 +1235,15 @@
protected void assertRowCount(int expectedCount, Uri uri, String selection, String[] args) {
Cursor cursor = mResolver.query(uri, null, selection, args, null);
- int count = cursor.getCount();
- cursor.close();
- assertEquals(expectedCount, count);
+ try {
+ assertEquals(expectedCount, cursor.getCount());
+ } catch (Error e) {
+ TestUtils.dumpCursor(cursor);
+ throw e;
+ } finally {
+ cursor.close();
+ }
}
/**
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index ec909b3..f6770de 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -2255,7 +2255,7 @@
public void testLoadProfilePhoto() throws IOException {
long rawContactId = createBasicProfileContact(new ContentValues());
insertPhoto(rawContactId, R.drawable.earth_normal);
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.THUMBNAIL),
Contacts.openContactPhotoInputStream(mResolver, Profile.CONTENT_URI, false));
}
@@ -2263,7 +2263,7 @@
public void testLoadProfileDisplayPhoto() throws IOException {
long rawContactId = createBasicProfileContact(new ContentValues());
insertPhoto(rawContactId, R.drawable.earth_normal);
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO),
Contacts.openContactPhotoInputStream(mResolver, Profile.CONTENT_URI, true));
}
@@ -3842,7 +3842,7 @@
R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO);
while (c.moveToNext()) {
String photoUri = c.getString(1);
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
expectedPhotoBytes, mResolver.openInputStream(Uri.parse(photoUri)));
}
} finally {
@@ -3903,7 +3903,7 @@
// Check that the photo stored is the expected one.
String displayPhotoUri = getStoredValue(photoUri, StreamItemPhotos.PHOTO_URI);
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.nebula, PhotoSize.DISPLAY_PHOTO),
mResolver.openInputStream(Uri.parse(displayPhotoUri)));
}
@@ -3930,7 +3930,7 @@
// Check that the photo stored is the expected one.
String displayPhotoUri = getStoredValue(photoUri, StreamItemPhotos.PHOTO_URI);
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.nebula, PhotoSize.DISPLAY_PHOTO),
mResolver.openInputStream(Uri.parse(displayPhotoUri)));
}
@@ -5080,9 +5080,9 @@
assertStoredValues(photoLookupUriWithoutId, values);
// Try opening as an input stream.
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
thumbnail, mResolver.openInputStream(photoLookupUriWithId));
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
thumbnail, mResolver.openInputStream(photoLookupUriWithoutId));
}
@@ -5094,10 +5094,19 @@
Uri photoUri = Uri.parse(getStoredValue(contactUri, Contacts.PHOTO_URI));
Uri photoThumbnailUri = Uri.parse(getStoredValue(contactUri, Contacts.PHOTO_THUMBNAIL_URI));
- EvenMoreAsserts.assertImageRawData(loadTestPhoto(PhotoSize.DISPLAY_PHOTO),
- mResolver.openInputStream(photoUri));
- EvenMoreAsserts.assertImageRawData(loadTestPhoto(PhotoSize.THUMBNAIL),
+ // Check the thumbnail.
+ EvenMoreAsserts.assertImageRawData(getContext(), loadTestPhoto(PhotoSize.THUMBNAIL),
mResolver.openInputStream(photoThumbnailUri));
+
+ // Then check the display photo. Note because we only inserted a small photo, but not a
+ // display photo, this returns the thumbnail image itself, which was compressed at
+ // the thumnail compression rate, which is why we compare to
+ // loadTestPhoto(PhotoSize.THUMBNAIL) rather than loadTestPhoto(PhotoSize.DISPLAY_PHOTO)
+ // here.
+ // (In other words, loadTestPhoto(PhotoSize.DISPLAY_PHOTO) returns the same photo as
+ // loadTestPhoto(PhotoSize.THUMBNAIL), except it's compressed at a lower compression rate.)
+ EvenMoreAsserts.assertImageRawData(getContext(), loadTestPhoto(PhotoSize.THUMBNAIL),
+ mResolver.openInputStream(photoUri));
}
public void testSuperPrimaryPhoto() {
@@ -5208,7 +5217,7 @@
Uri photoUri = Contacts.CONTENT_URI.buildUpon()
.appendPath(String.valueOf(contactId))
.appendPath(Contacts.Photo.DISPLAY_PHOTO).build();
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO),
mResolver.openInputStream(photoUri));
}
@@ -5221,7 +5230,7 @@
Uri photoUri = Contacts.CONTENT_LOOKUP_URI.buildUpon()
.appendPath(lookupKey)
.appendPath(Contacts.Photo.DISPLAY_PHOTO).build();
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO),
mResolver.openInputStream(photoUri));
}
@@ -5235,7 +5244,7 @@
.appendPath(lookupKey)
.appendPath(String.valueOf(contactId))
.appendPath(Contacts.Photo.DISPLAY_PHOTO).build();
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO),
mResolver.openInputStream(photoUri));
}
@@ -5246,7 +5255,7 @@
Uri photoUri = RawContacts.CONTENT_URI.buildUpon()
.appendPath(String.valueOf(rawContactId))
.appendPath(RawContacts.DisplayPhoto.CONTENT_DIRECTORY).build();
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO),
mResolver.openInputStream(photoUri));
}
@@ -5260,7 +5269,7 @@
String photoUri = getStoredValue(
ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
Contacts.PHOTO_URI);
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.DISPLAY_PHOTO),
mResolver.openInputStream(Uri.parse(photoUri)));
}
@@ -5312,7 +5321,7 @@
photoUri);
// Loading the photo URI content should get the thumbnail.
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.earth_small, PhotoSize.THUMBNAIL),
mResolver.openInputStream(Uri.parse(photoUri)));
}
@@ -5349,10 +5358,10 @@
assertNotSame(photoUri, thumbnailUri);
// Check the content of the display photo and thumbnail.
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.DISPLAY_PHOTO),
mResolver.openInputStream(Uri.parse(photoUri)));
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.THUMBNAIL),
mResolver.openInputStream(Uri.parse(thumbnailUri)));
}
@@ -5387,10 +5396,10 @@
String hugeEarthThumbnailUri = getStoredValue(
ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
Contacts.PHOTO_THUMBNAIL_URI);
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.DISPLAY_PHOTO),
mResolver.openInputStream(Uri.parse(hugeEarthPhotoUri)));
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.earth_huge, PhotoSize.THUMBNAIL),
mResolver.openInputStream(Uri.parse(hugeEarthThumbnailUri)));
@@ -5592,7 +5601,7 @@
assertEquals(photoUri, thumbnailUri);
// Retrieving the photo URI should get the thumbnail content.
- EvenMoreAsserts.assertImageRawData(
+ EvenMoreAsserts.assertImageRawData(getContext(),
loadPhotoFromResource(R.drawable.earth_small, PhotoSize.THUMBNAIL),
mResolver.openInputStream(Uri.parse(photoUri)));
}
diff --git a/tests/src/com/android/providers/contacts/EvenMoreAsserts.java b/tests/src/com/android/providers/contacts/EvenMoreAsserts.java
index 8d81d67..509a7fe 100644
--- a/tests/src/com/android/providers/contacts/EvenMoreAsserts.java
+++ b/tests/src/com/android/providers/contacts/EvenMoreAsserts.java
@@ -16,6 +16,7 @@
package com.android.providers.contacts;
+import android.content.Context;
import android.graphics.BitmapFactory;
import java.io.ByteArrayOutputStream;
@@ -59,7 +60,8 @@
return userMsg == null ? errorMsg : errorMsg + userMsg;
}
- public static void assertImageRawData(byte[] expected, InputStream actualStream)
+ public static void assertImageRawData(Context context, byte[] expected,
+ InputStream actualStream)
throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -68,11 +70,12 @@
while ((count = actualStream.read(buffer)) != -1) {
baos.write(buffer, 0, count);
}
+ actualStream.close();
- assertImageRawData(expected, baos.toByteArray());
+ assertImageRawData(context, expected, baos.toByteArray());
}
- public static void assertImageRawData(byte[] expected, byte[] actual) {
+ public static void assertImageRawData(Context context, byte[] expected, byte[] actual) {
String failReason = null;
if (expected.length != actual.length) {
failReason = "Different data lengths:" +
@@ -83,9 +86,13 @@
if (failReason == null) {
return;
}
+ String expectedFile = TestUtils.dumpToCacheDir(context, "expected", ".jpg", expected);
+ String actualFile = TestUtils.dumpToCacheDir(context, "actual", ".jpg", actual);
+
// Length or hashCode is different. We'll fail, but put the dimensions in the message.
Assert.fail(failReason + ", expected dimentions=" + getImageDimensions(expected) +
- " actual dimentions=" + getImageDimensions(actual));
+ " actual dimentions=" + getImageDimensions(actual) +
+ " Data written to " + expectedFile + " and " + actualFile);
}
private static final String getImageDimensions(byte[] imageData) {
diff --git a/tests/src/com/android/providers/contacts/PhotoStoreTest.java b/tests/src/com/android/providers/contacts/PhotoStoreTest.java
index 8b8abe8..1550d0b 100644
--- a/tests/src/com/android/providers/contacts/PhotoStoreTest.java
+++ b/tests/src/com/android/providers/contacts/PhotoStoreTest.java
@@ -138,7 +138,8 @@
byte[] expectedStoredVersion = loadPhotoFromResource(resourceId, PhotoSize.DISPLAY_PHOTO);
- EvenMoreAsserts.assertImageRawData(expectedStoredVersion, actualStoredVersion);
+ EvenMoreAsserts.assertImageRawData(getContext(),
+ expectedStoredVersion, actualStoredVersion);
Cursor c = mDb.query(Tables.PHOTO_FILES,
new String[]{PhotoFiles.WIDTH, PhotoFiles.HEIGHT, PhotoFiles.FILESIZE},
diff --git a/tests/src/com/android/providers/contacts/TestUtils.java b/tests/src/com/android/providers/contacts/TestUtils.java
index c7fb6ae..2d0930a 100644
--- a/tests/src/com/android/providers/contacts/TestUtils.java
+++ b/tests/src/com/android/providers/contacts/TestUtils.java
@@ -17,6 +17,13 @@
package com.android.providers.contacts;
import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
import junit.framework.Assert;
@@ -46,4 +53,46 @@
}
return ret;
}
+
+ /**
+ * Writes the content of a cursor to the log.
+ */
+ public static final void dumpCursor(Cursor c) {
+ final String TAG = "contacts";
+
+ final StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < c.getColumnCount(); i++) {
+ if (sb.length() > 0) sb.append("|");
+ sb.append(c.getColumnName(i));
+ }
+ Log.i(TAG, sb.toString());
+
+ c.moveToPosition(-1);
+ while (c.moveToNext()) {
+ sb.setLength(0);
+ for (int i = 0; i < c.getColumnCount(); i++) {
+ if (sb.length() > 0) sb.append("|");
+
+ // TODO Handle binary data somehow.
+ sb.append(c.getString(i));
+ }
+ Log.i(TAG, sb.toString());
+ }
+ }
+
+ /**
+ * Writes an arbitrary byte array to the test apk's cache directory.
+ */
+ public static final String dumpToCacheDir(Context context, String prefix, String suffix,
+ byte[] data) {
+ try {
+ File file = File.createTempFile(prefix, suffix, context.getCacheDir());
+ FileOutputStream fos = new FileOutputStream(file);
+ fos.write(data);
+ fos.close();
+ return file.getAbsolutePath();
+ } catch (IOException e) {
+ return "[Failed to write to file: " + e.getMessage() + "]";
+ }
+ }
}