From ebe6b0d4c0339ea8089e9d40414ae14fdce1efa6 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 24 Dec 2018 17:39:40 -0200 Subject: [PATCH] [android] Split up AttachmentController tests into integration and unit --- .../androidTestOfficial/assets/error_zero.jpg | 0 ... AttachmentControllerIntegrationTest.java} | 86 +--------- .../conversation/AttachmentController.java | 41 +++-- .../android/conversation/ImageManager.java | 18 ++ .../AttachmentControllerTest.java | 162 ++++++++++++++++++ .../BitmapDecoderExpectations.java | 48 ++++++ 6 files changed, 256 insertions(+), 99 deletions(-) delete mode 100644 briar-android/src/androidTestOfficial/assets/error_zero.jpg rename briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/conversation/{AttachmentControllerTest.java => AttachmentControllerIntegrationTest.java} (77%) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageManager.java create mode 100644 briar-android/src/test/java/org/briarproject/briar/android/conversation/AttachmentControllerTest.java create mode 100644 briar-android/src/test/java/org/briarproject/briar/android/conversation/BitmapDecoderExpectations.java diff --git a/briar-android/src/androidTestOfficial/assets/error_zero.jpg b/briar-android/src/androidTestOfficial/assets/error_zero.jpg deleted file mode 100644 index e69de29bb..000000000 diff --git a/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/conversation/AttachmentControllerTest.java b/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/conversation/AttachmentControllerIntegrationTest.java similarity index 77% rename from briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/conversation/AttachmentControllerTest.java rename to briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/conversation/AttachmentControllerIntegrationTest.java index 6fbc6baf9..e4804206b 100644 --- a/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/conversation/AttachmentControllerTest.java +++ b/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/conversation/AttachmentControllerIntegrationTest.java @@ -21,7 +21,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @RunWith(AndroidJUnit4.class) -public class AttachmentControllerTest { +public class AttachmentControllerIntegrationTest { private static final String smallKitten = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/06/Kitten_in_Rizal_Park%2C_Manila.jpg/160px-Kitten_in_Rizal_Park%2C_Manila.jpg"; @@ -51,49 +51,6 @@ public class AttachmentControllerTest { private final AttachmentController controller = new AttachmentController(null, dimensions); - @Test - public void testNoSizeWrongMimeTypeProducesError() throws Exception { - AttachmentHeader h = - new AttachmentHeader(msgId, "application/octet-stream"); - InputStream is = getUrlInputStream(smallKitten); - Attachment a = new Attachment(is); - AttachmentItem item = controller.getAttachmentItem(h, a, false); - assertTrue(item.hasError()); - } - - @Test - public void testNoSizeJpeg() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg"); - InputStream is = getUrlInputStream(smallKitten); - Attachment a = new Attachment(is); - AttachmentItem item = controller.getAttachmentItem(h, a, false); - assertEquals("image/jpeg", item.getMimeType()); - assertEquals("jpg", item.getExtension()); - assertFalse(item.hasError()); - } - - @Test - public void testNoSizePng() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/png"); - InputStream is = getUrlInputStream(smallKitten); - Attachment a = new Attachment(is); - AttachmentItem item = controller.getAttachmentItem(h, a, false); - assertEquals("image/png", item.getMimeType()); - assertEquals("png", item.getExtension()); - assertFalse(item.hasError()); - } - - @Test - public void testNoSizeGif() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/gif"); - InputStream is = getUrlInputStream(smallKitten); - Attachment a = new Attachment(is); - AttachmentItem item = controller.getAttachmentItem(h, a, false); - assertEquals("image/gif", item.getMimeType()); - assertEquals("gif", item.getExtension()); - assertFalse(item.hasError()); - } - @Test public void testSmallJpegImage() throws Exception { AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg"); @@ -110,22 +67,6 @@ public class AttachmentControllerTest { assertFalse(item.hasError()); } - @Test - public void testSmallJpegImageHealsWrongMimeType() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/png"); - InputStream is = getUrlInputStream(smallKitten); - Attachment a = new Attachment(is); - AttachmentItem item = controller.getAttachmentItem(h, a, true); - assertEquals(msgId, item.getMessageId()); - assertEquals(160, item.getWidth()); - assertEquals(240, item.getHeight()); - assertEquals(160, item.getThumbnailWidth()); - assertEquals(240, item.getThumbnailHeight()); - assertEquals("image/jpeg", item.getMimeType()); - assertEquals("jpg", item.getExtension()); - assertFalse(item.hasError()); - } - @Test public void testBigJpegImage() throws Exception { AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg"); @@ -158,22 +99,6 @@ public class AttachmentControllerTest { assertFalse(item.hasError()); } - @Test - public void testSmallPngImageHealsWrongMimeType() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); - InputStream is = getUrlInputStream(pngKitten); - Attachment a = new Attachment(is); - AttachmentItem item = controller.getAttachmentItem(h, a, true); - assertEquals(msgId, item.getMessageId()); - assertEquals(737, item.getWidth()); - assertEquals(510, item.getHeight()); - assertEquals(dimensions.maxWidth, item.getThumbnailWidth()); - assertEquals(138, item.getThumbnailHeight()); - assertEquals("image/png", item.getMimeType()); - assertEquals("png", item.getExtension()); - assertFalse(item.hasError()); - } - @Test public void testUberGif() throws Exception { AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); @@ -333,15 +258,6 @@ public class AttachmentControllerTest { assertFalse(item.hasError()); } - @Test - public void testZeroSizeError() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); - InputStream is = getAssetInputStream("error_zero.jpg"); - Attachment a = new Attachment(is); - AttachmentItem item = controller.getAttachmentItem(h, a, true); - assertTrue(item.hasError()); - } - private InputStream getUrlInputStream(String url) throws IOException { return new URL(url).openStream(); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/AttachmentController.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/AttachmentController.java index 11af29438..be9b4fcfc 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/AttachmentController.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/AttachmentController.java @@ -1,6 +1,7 @@ package org.briarproject.briar.android.conversation; import android.graphics.BitmapFactory; +import android.graphics.BitmapFactory.Options; import android.support.annotation.Nullable; import android.support.media.ExifInterface; import android.webkit.MimeTypeMap; @@ -47,6 +48,7 @@ class AttachmentController { private static final int READ_LIMIT = 1024 * 8192; private final MessagingManager messagingManager; + private final ImageManager imageManager; private final int defaultSize; private final int minWidth, maxWidth; private final int minHeight, maxHeight; @@ -55,8 +57,9 @@ class AttachmentController { new ConcurrentHashMap<>(); AttachmentController(MessagingManager messagingManager, - AttachmentDimensions dimensions) { + AttachmentDimensions dimensions, ImageManager imageManager) { this.messagingManager = messagingManager; + this.imageManager = imageManager; defaultSize = dimensions.defaultSize; minWidth = dimensions.minWidth; maxWidth = dimensions.maxWidth; @@ -64,6 +67,23 @@ class AttachmentController { maxHeight = dimensions.maxHeight; } + AttachmentController(MessagingManager messagingManager, + AttachmentDimensions dimensions) { + this(messagingManager, dimensions, new ImageManager() { + @Override + public void decodeStream(InputStream is, Options options) { + BitmapFactory.decodeStream(is, null, options); + } + + @Nullable + @Override + public String getExtensionFromMimeType(String mimeType) { + MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton(); + return mimeTypeMap.getExtensionFromMimeType(mimeType); + } + }); + } + void put(MessageId messageId, List attachments) { attachmentCache.put(messageId, attachments); } @@ -113,7 +133,7 @@ class AttachmentController { MessageId messageId = h.getMessageId(); if (!needsSize) { String mimeType = h.getContentType(); - String extension = getExtensionFromMimeType(mimeType); + String extension = imageManager.getExtensionFromMimeType(mimeType); boolean hasError = false; if (extension == null) { extension = ""; @@ -156,7 +176,7 @@ class AttachmentController { getThumbnailSize(size.width, size.height, size.mimeType); } // get file extension - String extension = getExtensionFromMimeType(size.mimeType); + String extension = imageManager.getExtensionFromMimeType(size.mimeType); boolean hasError = extension == null || size.error; if (extension == null) extension = ""; return new AttachmentItem(messageId, size.width, size.height, @@ -164,17 +184,10 @@ class AttachmentController { thumbnailSize.height, hasError); } - @Nullable - private String getExtensionFromMimeType(String mimeType) { - MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton(); - return mimeTypeMap.getExtensionFromMimeType(mimeType); - } - /** * Gets the size of a JPEG {@link InputStream} if EXIF info is available. */ - private static Size getSizeFromExif(InputStream is) - throws IOException { + private Size getSizeFromExif(InputStream is) throws IOException { ExifInterface exif = new ExifInterface(is); // these can return 0 independent of default value int width = exif.getAttributeInt(TAG_IMAGE_WIDTH, 0); @@ -194,10 +207,10 @@ class AttachmentController { /** * Gets the size of any image {@link InputStream}. */ - private static Size getSizeFromBitmap(InputStream is) { - BitmapFactory.Options options = new BitmapFactory.Options(); + private Size getSizeFromBitmap(InputStream is) { + Options options = new Options(); options.inJustDecodeBounds = true; - BitmapFactory.decodeStream(is, null, options); + imageManager.decodeStream(is, options); if (options.outWidth < 1 || options.outHeight < 1) return new Size(); return new Size(options.outWidth, options.outHeight, diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageManager.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageManager.java new file mode 100644 index 000000000..ca49eee01 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageManager.java @@ -0,0 +1,18 @@ +package org.briarproject.briar.android.conversation; + +import android.graphics.BitmapFactory; +import android.support.annotation.Nullable; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.io.InputStream; + +@NotNullByDefault +interface ImageManager { + + void decodeStream(InputStream is, BitmapFactory.Options options); + + @Nullable + String getExtensionFromMimeType(String mimeType); + +} diff --git a/briar-android/src/test/java/org/briarproject/briar/android/conversation/AttachmentControllerTest.java b/briar-android/src/test/java/org/briarproject/briar/android/conversation/AttachmentControllerTest.java new file mode 100644 index 000000000..bfbdb0bc7 --- /dev/null +++ b/briar-android/src/test/java/org/briarproject/briar/android/conversation/AttachmentControllerTest.java @@ -0,0 +1,162 @@ +package org.briarproject.briar.android.conversation; + +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.test.BrambleMockTestCase; +import org.briarproject.briar.api.messaging.Attachment; +import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.briarproject.briar.api.messaging.MessagingManager; +import org.jmock.Expectations; +import org.junit.Test; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; + +import static org.briarproject.bramble.test.TestUtils.getRandomBytes; +import static org.briarproject.bramble.test.TestUtils.getRandomId; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class AttachmentControllerTest extends BrambleMockTestCase { + + private final AttachmentDimensions dimensions = new AttachmentDimensions( + 100, 50, 200, 75, 300 + ); + private final MessageId msgId = new MessageId(getRandomId()); + private final Attachment attachment = new Attachment( + new BufferedInputStream( + new ByteArrayInputStream(getRandomBytes(42)))); + + private final MessagingManager messagingManager = + context.mock(MessagingManager.class); + private final ImageManager imageManager = context.mock(ImageManager.class); + private final AttachmentController controller = + new AttachmentController( + messagingManager, + dimensions, + imageManager + ); + + @Test + public void testNoSize() { + String mimeType = "image/jpeg"; + AttachmentHeader h = getAttachmentHeader(mimeType); + + context.checking(new Expectations() {{ + oneOf(imageManager).getExtensionFromMimeType(mimeType); + will(returnValue("jpg")); + }}); + + AttachmentItem item = + controller.getAttachmentItem(h, attachment, false); + assertEquals(mimeType, item.getMimeType()); + assertEquals("jpg", item.getExtension()); + assertFalse(item.hasError()); + } + + @Test + public void testNoSizeWrongMimeTypeProducesError() { + String mimeType = "application/octet-stream"; + AttachmentHeader h = getAttachmentHeader(mimeType); + + context.checking(new Expectations() {{ + oneOf(imageManager).getExtensionFromMimeType(mimeType); + will(returnValue(null)); + }}); + + AttachmentItem item = + controller.getAttachmentItem(h, attachment, false); + assertTrue(item.hasError()); + } + + @Test + public void testSmallJpegImage() { + String mimeType = "image/jpeg"; + AttachmentHeader h = getAttachmentHeader(mimeType); + + context.checking(new BitmapDecoderExpectations() {{ + withDecodeStream(imageManager, options -> { + options.outWidth = 160; + options.outHeight = 240; + options.outMimeType = mimeType; + }); + oneOf(imageManager).getExtensionFromMimeType(mimeType); + will(returnValue("jpg")); + }}); + + AttachmentItem item = controller.getAttachmentItem(h, attachment, true); + assertEquals(msgId, item.getMessageId()); + assertEquals(160, item.getWidth()); + assertEquals(240, item.getHeight()); + assertEquals(160, item.getThumbnailWidth()); + assertEquals(240, item.getThumbnailHeight()); + assertEquals(mimeType, item.getMimeType()); + assertEquals("jpg", item.getExtension()); + assertFalse(item.hasError()); + } + + @Test + public void testImageHealsWrongMimeType() { + AttachmentHeader h = getAttachmentHeader("image/png"); + + context.checking(new BitmapDecoderExpectations() {{ + withDecodeStream(imageManager, options -> { + options.outWidth = 160; + options.outHeight = 240; + options.outMimeType = "image/jpeg"; + }); + oneOf(imageManager).getExtensionFromMimeType("image/jpeg"); + will(returnValue("jpg")); + }}); + + AttachmentItem item = controller.getAttachmentItem(h, attachment, true); + assertEquals("image/jpeg", item.getMimeType()); + assertEquals("jpg", item.getExtension()); + assertFalse(item.hasError()); + } + + @Test + public void testBigJpegImage() { + String mimeType = "image/jpeg"; + AttachmentHeader h = getAttachmentHeader(mimeType); + + context.checking(new BitmapDecoderExpectations() {{ + withDecodeStream(imageManager, options -> { + options.outWidth = 1728; + options.outHeight = 2592; + options.outMimeType = mimeType; + }); + oneOf(imageManager).getExtensionFromMimeType(mimeType); + will(returnValue("jpg")); + }}); + + AttachmentItem item = controller.getAttachmentItem(h, attachment, true); + assertEquals(1728, item.getWidth()); + assertEquals(2592, item.getHeight()); + assertEquals(dimensions.maxWidth, item.getThumbnailWidth()); + assertEquals(dimensions.maxHeight, item.getThumbnailHeight()); + assertFalse(item.hasError()); + } + + @Test + public void testMalformedError() { + AttachmentHeader h = getAttachmentHeader("image/jpeg"); + + context.checking(new BitmapDecoderExpectations() {{ + withDecodeStream(imageManager, options -> { + options.outWidth = 0; + options.outHeight = 0; + }); + oneOf(imageManager).getExtensionFromMimeType(""); + will(returnValue(null)); + }}); + + AttachmentItem item = controller.getAttachmentItem(h, attachment, true); + assertTrue(item.hasError()); + } + + private AttachmentHeader getAttachmentHeader(String contentType) { + return new AttachmentHeader(msgId, contentType); + } + +} diff --git a/briar-android/src/test/java/org/briarproject/briar/android/conversation/BitmapDecoderExpectations.java b/briar-android/src/test/java/org/briarproject/briar/android/conversation/BitmapDecoderExpectations.java new file mode 100644 index 000000000..8ff53a0c9 --- /dev/null +++ b/briar-android/src/test/java/org/briarproject/briar/android/conversation/BitmapDecoderExpectations.java @@ -0,0 +1,48 @@ +package org.briarproject.briar.android.conversation; + +import android.graphics.BitmapFactory.Options; +import android.support.annotation.Nullable; + +import org.hamcrest.Description; +import org.jmock.Expectations; +import org.jmock.api.Action; +import org.jmock.api.Invocation; + +import java.io.InputStream; + +class BitmapDecoderExpectations extends Expectations { + + protected void withDecodeStream(ImageManager imageManager, + OptionsModifier optionsModifier) { + oneOf(imageManager).decodeStream(with(any(InputStream.class)), + with(any(Options.class))); + currentBuilder().setAction(new BitmapDecoderAction(optionsModifier)); + } + + private class BitmapDecoderAction implements Action { + + private final OptionsModifier optionsModifier; + + private BitmapDecoderAction(OptionsModifier optionsModifier) { + this.optionsModifier = optionsModifier; + } + + @Nullable + @Override + public Object invoke(Invocation invocation) { + Options options = (Options) invocation.getParameter(1); + optionsModifier.modifyOptions(options); + return null; + } + + @Override + public void describeTo(Description description) { + description.appendText("decodes a Bitmap InputStream"); + } + } + + interface OptionsModifier { + void modifyOptions(Options options); + } + +}