From 7a5ec2af125faff75911d3127c32c9425211e30a Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 20 Dec 2018 16:52:22 -0200 Subject: [PATCH 1/5] [android] Add test for MarkEnforcingInputStream --- .../MarkEnforcingInputStreamTest.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 briar-android/src/test/java/org/briarproject/briar/android/conversation/MarkEnforcingInputStreamTest.java diff --git a/briar-android/src/test/java/org/briarproject/briar/android/conversation/MarkEnforcingInputStreamTest.java b/briar-android/src/test/java/org/briarproject/briar/android/conversation/MarkEnforcingInputStreamTest.java new file mode 100644 index 000000000..45a30a499 --- /dev/null +++ b/briar-android/src/test/java/org/briarproject/briar/android/conversation/MarkEnforcingInputStreamTest.java @@ -0,0 +1,77 @@ +package org.briarproject.briar.android.conversation; + +import com.bumptech.glide.util.MarkEnforcingInputStream; + +import org.briarproject.bramble.test.BrambleTestCase; +import org.junit.Test; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +public class MarkEnforcingInputStreamTest extends BrambleTestCase { + + private final int readLimit = 4; + private final byte[] bytes = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6}; + + @Test + public void testPlainStreamReadsAllBytes() throws Exception { + InputStream is = getStream(); + is.mark(readLimit); + for (byte ignored : bytes) { + assertNotEquals(-1, is.read()); + } + assertEquals(0, is.available()); + is.close(); + } + + @Test + public void testMarkEnforcingStreamReadsUntilMarkLimit() throws Exception { + InputStream is = new MarkEnforcingInputStream(getStream()); + is.mark(readLimit); + assertEquals(readLimit, is.available()); + for (int i = 0; i < bytes.length; i++) { + if (i < readLimit) { + assertEquals(readLimit - i, is.available()); + assertNotEquals(-1, is.read()); + } else { + assertEquals(0, is.available()); + assertEquals(-1, is.read()); + } + } + assertEquals(0, is.available()); + is.close(); + } + + @Test + public void testMarkEnforcingStreamCanBeReset() throws Exception { + InputStream is = new MarkEnforcingInputStream(getStream()); + is.mark(readLimit); + assertEquals(readLimit, is.available()); + for (int i = 0; i < readLimit; i++) { + assertNotEquals(-1, is.read()); + } + assertEquals(0, is.available()); + is.reset(); + is.mark(readLimit); + assertEquals(readLimit, is.available()); + for (int i = 0; i < bytes.length; i++) { + if (i < readLimit) { + assertEquals(readLimit - i, is.available()); + assertNotEquals(-1, is.read()); + } else { + assertEquals(0, is.available()); + assertEquals(-1, is.read()); + } + } + is.close(); + } + + private InputStream getStream() { + return new BufferedInputStream(new ByteArrayInputStream(bytes)); + } + +} From 6e83fb7aefd910dfff6307ccdf9c60d8c245a375 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 20 Dec 2018 19:07:08 -0200 Subject: [PATCH 2/5] [android] add tests for getting attachment items from AttachmentController --- .../androidTestOfficial/assets/animated.gif | Bin 0 -> 43 bytes .../androidTestOfficial/assets/animated2.gif | Bin 0 -> 317 bytes .../androidTestOfficial/assets/error_high.jpg | Bin 0 -> 3096 bytes .../assets/error_large.gif | Bin 0 -> 43 bytes .../androidTestOfficial/assets/error_wide.jpg | Bin 0 -> 1076 bytes .../androidTestOfficial/assets/error_zero.jpg | 0 .../AttachmentControllerTest.java | 364 ++++++++++++++++++ .../conversation/AttachmentController.java | 20 +- .../conversation/AttachmentDimensions.java | 39 ++ .../conversation/ConversationViewModel.java | 3 +- 10 files changed, 412 insertions(+), 14 deletions(-) create mode 100644 briar-android/src/androidTestOfficial/assets/animated.gif create mode 100644 briar-android/src/androidTestOfficial/assets/animated2.gif create mode 100644 briar-android/src/androidTestOfficial/assets/error_high.jpg create mode 100644 briar-android/src/androidTestOfficial/assets/error_large.gif create mode 100644 briar-android/src/androidTestOfficial/assets/error_wide.jpg create mode 100644 briar-android/src/androidTestOfficial/assets/error_zero.jpg create mode 100644 briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/conversation/AttachmentControllerTest.java create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/conversation/AttachmentDimensions.java diff --git a/briar-android/src/androidTestOfficial/assets/animated.gif b/briar-android/src/androidTestOfficial/assets/animated.gif new file mode 100644 index 0000000000000000000000000000000000000000..1962fbfb57973030dd4ec166fee375bdae46c93c GIT binary patch literal 43 rcmZ?wbhEHb{0{^l7#M&g0|SHNPZpLGAgu$$42(d?z{KRj$Y2csY+?(_ literal 0 HcmV?d00001 diff --git a/briar-android/src/androidTestOfficial/assets/animated2.gif b/briar-android/src/androidTestOfficial/assets/animated2.gif new file mode 100644 index 0000000000000000000000000000000000000000..46cfc5df72cc4ad9f2d7ac3c13e4dfd6727ed203 GIT binary patch literal 317 zcmZ?wbhEHb6i^pX|G>cTp8*6Ef3mQofaw3+ey$4XU<-)c(`Pbk7?EB9z mp<&?>kx|hxW5tdWH(vbU$c#WZ4eSm^pi3Gcjvg4-SOWkRG@ZTx literal 0 HcmV?d00001 diff --git a/briar-android/src/androidTestOfficial/assets/error_high.jpg b/briar-android/src/androidTestOfficial/assets/error_high.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e2511cb26fca3274a9d8617f7c2aab5eccc3adec GIT binary patch literal 3096 zcmex=nP38T>!MAjqLEz`)4NsKme|$jB_n z`2PswA_fLVRz@&jfC5G)p!?X^IXJnv1sIqZnVFebm_e=us;mXdF|Y`-3Mm>ovIz$! zvMUve7&T5@$f4}C@t|nX#SbdRNkvVZTw>x9l2WQ_>Kd9_CZ=ZQ7M51dF0O9w9-dyo zA)#U65s^{JDXD4c8JStdC8cHM6_r)ZEv;?s9i3g1CQq3GGAU*RJ2VdF$b$$4{OPfBE|D`;VW$ z7#Wx$-T{&j4Gc)#w^HS&+zk7m&W?T o{9k=E7IiU<;?Xb|O#`E8U^ESkrh(BkFq#HN)4nP38T>!MAjrYM$lk!rsKme|$jB_n z`2PswA_fLVRz@&jfC5G)p!?X^IXJnv1sIqZnVFebm_e=us;mXdF|Y`-3Mm>ovIz$! zvMUve7&T5@$f4}C@t|nX#SbdRNkvVZTw>x9l2WQ_>Kd9_CZ=ZQ7M51dF0O9w9-dyo zA)#U65s^{JDXD4c8JStdC8cHM6_r)ZEv;?s9i3g1CQq3GGAU*RJ2VdF$b$$4{OPfBE|D`;VW$ z7#Wx$-T{&j4Gc)#w^HS&+zk7m&W?T T{9k=E7IiU<;^7$v|8D{SFo9Ub literal 0 HcmV?d00001 diff --git a/briar-android/src/androidTestOfficial/assets/error_zero.jpg b/briar-android/src/androidTestOfficial/assets/error_zero.jpg new file mode 100644 index 000000000..e69de29bb 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/AttachmentControllerTest.java new file mode 100644 index 000000000..6fbc6baf9 --- /dev/null +++ b/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/conversation/AttachmentControllerTest.java @@ -0,0 +1,364 @@ +package org.briarproject.briar.android.conversation; + +import android.content.res.AssetManager; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.briarproject.bramble.api.UniqueId; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.briar.api.messaging.Attachment; +import org.briarproject.briar.api.messaging.AttachmentHeader; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Random; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@RunWith(AndroidJUnit4.class) +public class AttachmentControllerTest { + + 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"; + private static final String originalKitten = + "https://upload.wikimedia.org/wikipedia/commons/0/06/Kitten_in_Rizal_Park%2C_Manila.jpg"; + private static final String pngKitten = + "https://upload.wikimedia.org/wikipedia/commons/c/c8/Young_cat.png"; + private static final String uberGif = + "https://raw.githubusercontent.com/fuzzdb-project/fuzzdb/master/attack/file-upload/malicious-images/uber.gif"; + private static final String lottaPixel = + "https://raw.githubusercontent.com/fuzzdb-project/fuzzdb/master/attack/file-upload/malicious-images/lottapixel.jpg"; + private static final String imageIoCrash = + "https://www.landaire.net/img/crasher.png"; + private static final String gimpCrash = + "https://gitlab.gnome.org/GNOME/gimp/uploads/75f5b7ed3b09b3f1c13f1f65bffe784f/31153c919d3aa634e8e6cff82219fe7352dd8a37.png"; + private static final String optiPngAfl = + "https://sourceforge.net/p/optipng/bugs/64/attachment/test.gif"; + private static final String librawError = + "https://www.libraw.org/sites/libraw.org/files/P1010671.JPG"; + + private final AttachmentDimensions dimensions = new AttachmentDimensions( + 100, 50, 200, 75, 300 + ); + private final MessageId msgId = new MessageId(getRandomId()); + + @SuppressWarnings("ConstantConditions") // not needed for now + 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"); + 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 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"); + InputStream is = getUrlInputStream(originalKitten); + Attachment a = new Attachment(is); + AttachmentItem item = controller.getAttachmentItem(h, a, true); + assertEquals(msgId, item.getMessageId()); + assertEquals(1728, item.getWidth()); + assertEquals(2592, item.getHeight()); + assertEquals(dimensions.maxWidth, item.getThumbnailWidth()); + assertEquals(dimensions.maxHeight, item.getThumbnailHeight()); + assertEquals("image/jpeg", item.getMimeType()); + assertEquals("jpg", item.getExtension()); + assertFalse(item.hasError()); + } + + @Test + public void testSmallPngImage() throws Exception { + AttachmentHeader h = new AttachmentHeader(msgId, "image/png"); + 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 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"); + InputStream is = getUrlInputStream(uberGif); + Attachment a = new Attachment(is); + AttachmentItem item = controller.getAttachmentItem(h, a, true); + assertEquals(1, item.getWidth()); + assertEquals(1, item.getHeight()); + assertEquals(dimensions.minHeight, item.getThumbnailWidth()); + assertEquals(dimensions.minHeight, item.getThumbnailHeight()); + assertEquals("image/gif", item.getMimeType()); + assertEquals("gif", item.getExtension()); + assertFalse(item.hasError()); + } + + @Test + public void testLottaPixels() throws Exception { + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + InputStream is = getUrlInputStream(lottaPixel); + Attachment a = new Attachment(is); + AttachmentItem item = controller.getAttachmentItem(h, a, true); + assertEquals(64250, item.getWidth()); + assertEquals(64250, item.getHeight()); + assertEquals(dimensions.maxWidth, item.getThumbnailWidth()); + assertEquals(dimensions.maxWidth, item.getThumbnailHeight()); + assertEquals("image/jpeg", item.getMimeType()); + assertEquals("jpg", item.getExtension()); + assertFalse(item.hasError()); + } + + @Test + public void testImageIoCrash() throws Exception { + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + InputStream is = getUrlInputStream(imageIoCrash); + Attachment a = new Attachment(is); + AttachmentItem item = controller.getAttachmentItem(h, a, true); + assertEquals(1184, item.getWidth()); + assertEquals(448, item.getHeight()); + assertEquals(dimensions.maxWidth, item.getThumbnailWidth()); + assertEquals(dimensions.minHeight, item.getThumbnailHeight()); + assertEquals("image/png", item.getMimeType()); + assertEquals("png", item.getExtension()); + assertFalse(item.hasError()); + } + + @Test + public void testGimpCrash() throws Exception { + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + InputStream is = getUrlInputStream(gimpCrash); + Attachment a = new Attachment(is); + AttachmentItem item = controller.getAttachmentItem(h, a, true); + assertEquals(1, item.getWidth()); + assertEquals(1, item.getHeight()); + assertEquals(dimensions.minHeight, item.getThumbnailWidth()); + assertEquals(dimensions.minHeight, item.getThumbnailHeight()); + assertEquals("image/gif", item.getMimeType()); + assertEquals("gif", item.getExtension()); + assertFalse(item.hasError()); + } + + @Test + public void testOptiPngAfl() throws Exception { + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + InputStream is = getUrlInputStream(optiPngAfl); + Attachment a = new Attachment(is); + AttachmentItem item = controller.getAttachmentItem(h, a, true); + assertEquals(32, item.getWidth()); + assertEquals(32, item.getHeight()); + assertEquals(dimensions.minHeight, item.getThumbnailWidth()); + assertEquals(dimensions.minHeight, item.getThumbnailHeight()); + assertEquals("image/gif", item.getMimeType()); + assertEquals("gif", item.getExtension()); + assertFalse(item.hasError()); + } + + @Test + public void testLibrawError() throws Exception { + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + InputStream is = getUrlInputStream(librawError); + Attachment a = new Attachment(is); + AttachmentItem item = controller.getAttachmentItem(h, a, true); + assertTrue(item.hasError()); + } + + @Test + public void testSmallAnimatedGifMaxDimensions() throws Exception { + AttachmentHeader h = new AttachmentHeader(msgId, "image/gif"); + InputStream is = getAssetInputStream("animated.gif"); + Attachment a = new Attachment(is); + AttachmentItem item = controller.getAttachmentItem(h, a, true); + assertEquals(65535, item.getWidth()); + assertEquals(65535, item.getHeight()); + assertEquals(dimensions.maxWidth, item.getThumbnailWidth()); + assertEquals(dimensions.maxWidth, item.getThumbnailHeight()); + assertEquals("image/gif", item.getMimeType()); + assertEquals("gif", item.getExtension()); + assertFalse(item.hasError()); + } + + @Test + public void testSmallAnimatedGifHugeDimensions() throws Exception { + AttachmentHeader h = new AttachmentHeader(msgId, "image/gif"); + InputStream is = getAssetInputStream("animated2.gif"); + Attachment a = new Attachment(is); + AttachmentItem item = controller.getAttachmentItem(h, a, true); + assertEquals(10000, item.getWidth()); + assertEquals(10000, item.getHeight()); + assertEquals(dimensions.maxWidth, item.getThumbnailWidth()); + assertEquals(dimensions.maxWidth, item.getThumbnailHeight()); + assertEquals("image/gif", item.getMimeType()); + assertEquals("gif", item.getExtension()); + assertFalse(item.hasError()); + } + + @Test + public void testSmallGifLargeDimensions() throws Exception { + AttachmentHeader h = new AttachmentHeader(msgId, "image/gif"); + InputStream is = getAssetInputStream("error_large.gif"); + Attachment a = new Attachment(is); + AttachmentItem item = controller.getAttachmentItem(h, a, true); + assertEquals(16384, item.getWidth()); + assertEquals(16384, item.getHeight()); + assertEquals(dimensions.maxWidth, item.getThumbnailWidth()); + assertEquals(dimensions.maxWidth, item.getThumbnailHeight()); + assertEquals("image/gif", item.getMimeType()); + assertEquals("gif", item.getExtension()); + assertFalse(item.hasError()); + } + + @Test + public void testHighError() throws Exception { + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + InputStream is = getAssetInputStream("error_high.jpg"); + Attachment a = new Attachment(is); + AttachmentItem item = controller.getAttachmentItem(h, a, true); + assertEquals(1, item.getWidth()); + assertEquals(10000, item.getHeight()); + assertEquals(dimensions.minWidth, item.getThumbnailWidth()); + assertEquals(dimensions.maxHeight, item.getThumbnailHeight()); + assertEquals("image/jpeg", item.getMimeType()); + assertEquals("jpg", item.getExtension()); + assertFalse(item.hasError()); + } + + @Test + public void testWideError() throws Exception { + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + InputStream is = getAssetInputStream("error_wide.jpg"); + Attachment a = new Attachment(is); + AttachmentItem item = controller.getAttachmentItem(h, a, true); + assertEquals(1920, item.getWidth()); + assertEquals(1, item.getHeight()); + assertEquals(dimensions.maxWidth, item.getThumbnailWidth()); + assertEquals(dimensions.minHeight, item.getThumbnailHeight()); + assertEquals("image/jpeg", item.getMimeType()); + assertEquals("jpg", item.getExtension()); + 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(); + } + + private InputStream getAssetInputStream(String name) throws IOException { + AssetManager assets = InstrumentationRegistry.getContext().getAssets(); + return assets.open(name); + } + + public static byte[] getRandomBytes(int length) { + byte[] b = new byte[length]; + new Random().nextBytes(b); + return b; + } + + public static byte[] getRandomId() { + return getRandomBytes(UniqueId.LENGTH); + } + +} 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 3f1c55d6d..11af29438 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,5 @@ package org.briarproject.briar.android.conversation; -import android.content.res.Resources; import android.graphics.BitmapFactory; import android.support.annotation.Nullable; import android.support.media.ExifInterface; @@ -13,7 +12,6 @@ import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; -import org.briarproject.briar.R; import org.briarproject.briar.api.messaging.Attachment; import org.briarproject.briar.api.messaging.AttachmentHeader; import org.briarproject.briar.api.messaging.MessagingManager; @@ -56,18 +54,14 @@ class AttachmentController { private final Map> attachmentCache = new ConcurrentHashMap<>(); - AttachmentController(MessagingManager messagingManager, Resources res) { + AttachmentController(MessagingManager messagingManager, + AttachmentDimensions dimensions) { this.messagingManager = messagingManager; - defaultSize = - res.getDimensionPixelSize(R.dimen.message_bubble_image_default); - minWidth = res.getDimensionPixelSize( - R.dimen.message_bubble_image_min_width); - maxWidth = res.getDimensionPixelSize( - R.dimen.message_bubble_image_max_width); - minHeight = res.getDimensionPixelSize( - R.dimen.message_bubble_image_min_height); - maxHeight = res.getDimensionPixelSize( - R.dimen.message_bubble_image_max_height); + defaultSize = dimensions.defaultSize; + minWidth = dimensions.minWidth; + maxWidth = dimensions.maxWidth; + minHeight = dimensions.minHeight; + maxHeight = dimensions.maxHeight; } void put(MessageId messageId, List attachments) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/AttachmentDimensions.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/AttachmentDimensions.java new file mode 100644 index 000000000..081a6480b --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/AttachmentDimensions.java @@ -0,0 +1,39 @@ +package org.briarproject.briar.android.conversation; + +import android.content.res.Resources; +import android.support.annotation.VisibleForTesting; + +import org.briarproject.briar.R; + +class AttachmentDimensions { + + final int defaultSize; + final int minWidth, maxWidth; + final int minHeight, maxHeight; + + @VisibleForTesting + AttachmentDimensions(int defaultSize, int minWidth, int maxWidth, + int minHeight, int maxHeight) { + this.defaultSize = defaultSize; + this.minWidth = minWidth; + this.maxWidth = maxWidth; + this.minHeight = minHeight; + this.maxHeight = maxHeight; + } + + static AttachmentDimensions getAttachmentDimensions(Resources res) { + int defaultSize = + res.getDimensionPixelSize(R.dimen.message_bubble_image_default); + int minWidth = res.getDimensionPixelSize( + R.dimen.message_bubble_image_min_width); + int maxWidth = res.getDimensionPixelSize( + R.dimen.message_bubble_image_max_width); + int minHeight = res.getDimensionPixelSize( + R.dimen.message_bubble_image_min_height); + int maxHeight = res.getDimensionPixelSize( + R.dimen.message_bubble_image_max_height); + return new AttachmentDimensions(defaultSize, minWidth, maxWidth, + minHeight, minHeight); + } + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java index 9c998e9eb..5f93fcd14 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ConversationViewModel.java @@ -51,6 +51,7 @@ import static org.briarproject.bramble.util.IoUtils.tryToClose; import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.now; +import static org.briarproject.briar.android.conversation.AttachmentDimensions.getAttachmentDimensions; import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE; import static org.briarproject.briar.android.util.UiUtils.observeForeverOnce; @@ -114,7 +115,7 @@ public class ConversationViewModel extends AndroidViewModel { this.settingsManager = settingsManager; this.privateMessageFactory = privateMessageFactory; this.attachmentController = new AttachmentController(messagingManager, - application.getResources()); + getAttachmentDimensions(application.getResources())); contactDeleted.setValue(false); } From ebe6b0d4c0339ea8089e9d40414ae14fdce1efa6 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 24 Dec 2018 17:39:40 -0200 Subject: [PATCH 3/5] [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); + } + +} From 9557afabc6f98fda9ed8caefdee4617eaee1fe26 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 15 Jan 2019 16:49:18 +0000 Subject: [PATCH 4/5] Change MIME types to "image/jpeg", unsuppress warning. --- .../AttachmentControllerIntegrationTest.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/conversation/AttachmentControllerIntegrationTest.java b/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/conversation/AttachmentControllerIntegrationTest.java index e4804206b..d639230b8 100644 --- a/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/conversation/AttachmentControllerIntegrationTest.java +++ b/briar-android/src/androidTestOfficial/java/org/briarproject/briar/android/conversation/AttachmentControllerIntegrationTest.java @@ -47,7 +47,6 @@ public class AttachmentControllerIntegrationTest { ); private final MessageId msgId = new MessageId(getRandomId()); - @SuppressWarnings("ConstantConditions") // not needed for now private final AttachmentController controller = new AttachmentController(null, dimensions); @@ -101,7 +100,7 @@ public class AttachmentControllerIntegrationTest { @Test public void testUberGif() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg"); InputStream is = getUrlInputStream(uberGif); Attachment a = new Attachment(is); AttachmentItem item = controller.getAttachmentItem(h, a, true); @@ -116,7 +115,7 @@ public class AttachmentControllerIntegrationTest { @Test public void testLottaPixels() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg"); InputStream is = getUrlInputStream(lottaPixel); Attachment a = new Attachment(is); AttachmentItem item = controller.getAttachmentItem(h, a, true); @@ -131,7 +130,7 @@ public class AttachmentControllerIntegrationTest { @Test public void testImageIoCrash() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg"); InputStream is = getUrlInputStream(imageIoCrash); Attachment a = new Attachment(is); AttachmentItem item = controller.getAttachmentItem(h, a, true); @@ -146,7 +145,7 @@ public class AttachmentControllerIntegrationTest { @Test public void testGimpCrash() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg"); InputStream is = getUrlInputStream(gimpCrash); Attachment a = new Attachment(is); AttachmentItem item = controller.getAttachmentItem(h, a, true); @@ -161,7 +160,7 @@ public class AttachmentControllerIntegrationTest { @Test public void testOptiPngAfl() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg"); InputStream is = getUrlInputStream(optiPngAfl); Attachment a = new Attachment(is); AttachmentItem item = controller.getAttachmentItem(h, a, true); @@ -176,7 +175,7 @@ public class AttachmentControllerIntegrationTest { @Test public void testLibrawError() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg"); InputStream is = getUrlInputStream(librawError); Attachment a = new Attachment(is); AttachmentItem item = controller.getAttachmentItem(h, a, true); @@ -230,7 +229,7 @@ public class AttachmentControllerIntegrationTest { @Test public void testHighError() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg"); InputStream is = getAssetInputStream("error_high.jpg"); Attachment a = new Attachment(is); AttachmentItem item = controller.getAttachmentItem(h, a, true); @@ -245,7 +244,7 @@ public class AttachmentControllerIntegrationTest { @Test public void testWideError() throws Exception { - AttachmentHeader h = new AttachmentHeader(msgId, "image/jpg"); + AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg"); InputStream is = getAssetInputStream("error_wide.jpg"); Attachment a = new Attachment(is); AttachmentItem item = controller.getAttachmentItem(h, a, true); From 986d884b400ce1b1589656d01b23ffcc8ee9c48e Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 15 Jan 2019 17:14:57 +0000 Subject: [PATCH 5/5] Refactor ImageManager to ImageHelper. --- .../conversation/AttachmentController.java | 31 ++++++----- .../android/conversation/ImageHelper.java | 29 ++++++++++ .../android/conversation/ImageManager.java | 18 ------- .../AttachmentControllerTest.java | 53 ++++++++----------- .../BitmapDecoderExpectations.java | 48 ----------------- 5 files changed, 68 insertions(+), 111 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageHelper.java delete mode 100644 briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageManager.java delete mode 100644 briar-android/src/test/java/org/briarproject/briar/android/conversation/BitmapDecoderExpectations.java 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 be9b4fcfc..11833f2ed 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 @@ -13,6 +13,7 @@ import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.briar.android.conversation.ImageHelper.DecodeResult; import org.briarproject.briar.api.messaging.Attachment; import org.briarproject.briar.api.messaging.AttachmentHeader; import org.briarproject.briar.api.messaging.MessagingManager; @@ -48,7 +49,7 @@ class AttachmentController { private static final int READ_LIMIT = 1024 * 8192; private final MessagingManager messagingManager; - private final ImageManager imageManager; + private final ImageHelper imageHelper; private final int defaultSize; private final int minWidth, maxWidth; private final int minHeight, maxHeight; @@ -57,9 +58,9 @@ class AttachmentController { new ConcurrentHashMap<>(); AttachmentController(MessagingManager messagingManager, - AttachmentDimensions dimensions, ImageManager imageManager) { + AttachmentDimensions dimensions, ImageHelper imageHelper) { this.messagingManager = messagingManager; - this.imageManager = imageManager; + this.imageHelper = imageHelper; defaultSize = dimensions.defaultSize; minWidth = dimensions.minWidth; maxWidth = dimensions.maxWidth; @@ -69,10 +70,16 @@ class AttachmentController { AttachmentController(MessagingManager messagingManager, AttachmentDimensions dimensions) { - this(messagingManager, dimensions, new ImageManager() { + this(messagingManager, dimensions, new ImageHelper() { @Override - public void decodeStream(InputStream is, Options options) { + public DecodeResult decodeStream(InputStream is) { + Options options = new Options(); + options.inJustDecodeBounds = true; BitmapFactory.decodeStream(is, null, options); + String mimeType = options.outMimeType; + if (mimeType == null) mimeType = ""; + return new DecodeResult(options.outWidth, options.outHeight, + mimeType); } @Nullable @@ -133,7 +140,7 @@ class AttachmentController { MessageId messageId = h.getMessageId(); if (!needsSize) { String mimeType = h.getContentType(); - String extension = imageManager.getExtensionFromMimeType(mimeType); + String extension = imageHelper.getExtensionFromMimeType(mimeType); boolean hasError = false; if (extension == null) { extension = ""; @@ -176,7 +183,7 @@ class AttachmentController { getThumbnailSize(size.width, size.height, size.mimeType); } // get file extension - String extension = imageManager.getExtensionFromMimeType(size.mimeType); + String extension = imageHelper.getExtensionFromMimeType(size.mimeType); boolean hasError = extension == null || size.error; if (extension == null) extension = ""; return new AttachmentItem(messageId, size.width, size.height, @@ -208,13 +215,9 @@ class AttachmentController { * Gets the size of any image {@link InputStream}. */ private Size getSizeFromBitmap(InputStream is) { - Options options = new Options(); - options.inJustDecodeBounds = true; - imageManager.decodeStream(is, options); - if (options.outWidth < 1 || options.outHeight < 1) - return new Size(); - return new Size(options.outWidth, options.outHeight, - options.outMimeType); + DecodeResult result = imageHelper.decodeStream(is); + if (result.width < 1 || result.height < 1) return new Size(); + return new Size(result.width, result.height, result.mimeType); } private Size getThumbnailSize(int width, int height, String mimeType) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageHelper.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageHelper.java new file mode 100644 index 000000000..203a45222 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageHelper.java @@ -0,0 +1,29 @@ +package org.briarproject.briar.android.conversation; + +import android.support.annotation.Nullable; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.io.InputStream; + +@NotNullByDefault +interface ImageHelper { + + DecodeResult decodeStream(InputStream is); + + @Nullable + String getExtensionFromMimeType(String mimeType); + + class DecodeResult { + + final int width; + final int height; + final String mimeType; + + DecodeResult(int width, int height, String mimeType) { + this.width = width; + this.height = height; + this.mimeType = mimeType; + } + } +} 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 deleted file mode 100644 index ca49eee01..000000000 --- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageManager.java +++ /dev/null @@ -1,18 +0,0 @@ -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 index bfbdb0bc7..d66b69697 100644 --- 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 @@ -2,6 +2,7 @@ package org.briarproject.briar.android.conversation; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.test.BrambleMockTestCase; +import org.briarproject.briar.android.conversation.ImageHelper.DecodeResult; import org.briarproject.briar.api.messaging.Attachment; import org.briarproject.briar.api.messaging.AttachmentHeader; import org.briarproject.briar.api.messaging.MessagingManager; @@ -10,6 +11,7 @@ import org.junit.Test; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; +import java.io.InputStream; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; @@ -29,12 +31,12 @@ public class AttachmentControllerTest extends BrambleMockTestCase { private final MessagingManager messagingManager = context.mock(MessagingManager.class); - private final ImageManager imageManager = context.mock(ImageManager.class); + private final ImageHelper imageHelper = context.mock(ImageHelper.class); private final AttachmentController controller = new AttachmentController( messagingManager, dimensions, - imageManager + imageHelper ); @Test @@ -43,7 +45,7 @@ public class AttachmentControllerTest extends BrambleMockTestCase { AttachmentHeader h = getAttachmentHeader(mimeType); context.checking(new Expectations() {{ - oneOf(imageManager).getExtensionFromMimeType(mimeType); + oneOf(imageHelper).getExtensionFromMimeType(mimeType); will(returnValue("jpg")); }}); @@ -60,7 +62,7 @@ public class AttachmentControllerTest extends BrambleMockTestCase { AttachmentHeader h = getAttachmentHeader(mimeType); context.checking(new Expectations() {{ - oneOf(imageManager).getExtensionFromMimeType(mimeType); + oneOf(imageHelper).getExtensionFromMimeType(mimeType); will(returnValue(null)); }}); @@ -74,13 +76,10 @@ public class AttachmentControllerTest extends BrambleMockTestCase { 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); + context.checking(new Expectations() {{ + oneOf(imageHelper).decodeStream(with(any(InputStream.class))); + will(returnValue(new DecodeResult(160, 240, mimeType))); + oneOf(imageHelper).getExtensionFromMimeType(mimeType); will(returnValue("jpg")); }}); @@ -99,13 +98,10 @@ public class AttachmentControllerTest extends BrambleMockTestCase { 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"); + context.checking(new Expectations() {{ + oneOf(imageHelper).decodeStream(with(any(InputStream.class))); + will(returnValue(new DecodeResult(160, 240, "image/jpeg"))); + oneOf(imageHelper).getExtensionFromMimeType("image/jpeg"); will(returnValue("jpg")); }}); @@ -120,13 +116,10 @@ public class AttachmentControllerTest extends BrambleMockTestCase { 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); + context.checking(new Expectations() {{ + oneOf(imageHelper).decodeStream(with(any(InputStream.class))); + will(returnValue(new DecodeResult(1728, 2592, mimeType))); + oneOf(imageHelper).getExtensionFromMimeType(mimeType); will(returnValue("jpg")); }}); @@ -142,12 +135,10 @@ public class AttachmentControllerTest extends BrambleMockTestCase { public void testMalformedError() { AttachmentHeader h = getAttachmentHeader("image/jpeg"); - context.checking(new BitmapDecoderExpectations() {{ - withDecodeStream(imageManager, options -> { - options.outWidth = 0; - options.outHeight = 0; - }); - oneOf(imageManager).getExtensionFromMimeType(""); + context.checking(new Expectations() {{ + oneOf(imageHelper).decodeStream(with(any(InputStream.class))); + will(returnValue(new DecodeResult(0, 0, ""))); + oneOf(imageHelper).getExtensionFromMimeType(""); will(returnValue(null)); }}); 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 deleted file mode 100644 index 8ff53a0c9..000000000 --- a/briar-android/src/test/java/org/briarproject/briar/android/conversation/BitmapDecoderExpectations.java +++ /dev/null @@ -1,48 +0,0 @@ -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); - } - -}