diff --git a/k9mail/src/main/java/com/fsck/k9/mailstore/DeferredFileBody.java b/k9mail/src/main/java/com/fsck/k9/mailstore/DeferredFileBody.java index e21882f5c..db6cabff4 100644 --- a/k9mail/src/main/java/com/fsck/k9/mailstore/DeferredFileBody.java +++ b/k9mail/src/main/java/com/fsck/k9/mailstore/DeferredFileBody.java @@ -11,6 +11,7 @@ import java.io.InputStream; import java.io.OutputStream; import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; import android.util.Log; import com.fsck.k9.K9; @@ -26,11 +27,12 @@ import org.apache.commons.io.IOUtils; * @see FileFactory */ public class DeferredFileBody implements RawDataBody, SizeAware { - public static final int MEMORY_BACKED_THRESHOLD = 1024 * 8; + public static final int DEFAULT_MEMORY_BACKED_THRESHOLD = 1024 * 8; private final FileFactory fileFactory; private final String encoding; + private final int memoryBackedThreshold; @Nullable private byte[] data; @@ -38,12 +40,19 @@ public class DeferredFileBody implements RawDataBody, SizeAware { public DeferredFileBody(FileFactory fileFactory, String transferEncoding) { + this(DEFAULT_MEMORY_BACKED_THRESHOLD, fileFactory, transferEncoding); + } + + @VisibleForTesting + DeferredFileBody(int memoryBackedThreshold, FileFactory fileFactory, + String transferEncoding) { this.fileFactory = fileFactory; + this.memoryBackedThreshold = memoryBackedThreshold; this.encoding = transferEncoding; } public OutputStream getOutputStream() throws IOException { - return new DeferredFileOutputStream(MEMORY_BACKED_THRESHOLD, fileFactory) { + return new DeferredFileOutputStream(memoryBackedThreshold, fileFactory) { @Override public void close() throws IOException { super.close(); @@ -104,6 +113,7 @@ public class DeferredFileBody implements RawDataBody, SizeAware { Log.d(K9.LOG_TAG, "Writing body to file for attachment access"); + file = fileFactory.createFile(); FileOutputStream fos = new FileOutputStream(file); fos.write(data); fos.close(); diff --git a/k9mail/src/test/java/com/fsck/k9/mailstore/DeferredFileBodyTest.java b/k9mail/src/test/java/com/fsck/k9/mailstore/DeferredFileBodyTest.java new file mode 100644 index 000000000..4cf448e7e --- /dev/null +++ b/k9mail/src/test/java/com/fsck/k9/mailstore/DeferredFileBodyTest.java @@ -0,0 +1,147 @@ +package com.fsck.k9.mailstore; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import com.fsck.k9.mailstore.util.FileFactory; +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; + + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE, sdk = 21) +public class DeferredFileBodyTest { + public static final String TEST_ENCODING = "test-encoding"; + public static final byte[] TEST_DATA_SHORT = "test data".getBytes(); + public static final byte[] TEST_DATA_LONG = "test data long enough to be file backed".getBytes(); + public static final int TEST_THRESHOLD = 15; + + + private File createdFile; + private DeferredFileBody deferredFileBody; + + + @Before + public void setUp() throws Exception { + FileFactory fileFactory = new FileFactory() { + @Override + public File createFile() throws IOException { + assertNull("only a single file should be created", createdFile); + createdFile = File.createTempFile("test", "tmp"); + createdFile.deleteOnExit(); + return createdFile; + } + }; + + deferredFileBody = new DeferredFileBody(TEST_THRESHOLD, fileFactory, TEST_ENCODING); + } + + @Test + public void withShortData__getLength__shouldReturnWrittenLength() throws Exception { + writeShortTestData(); + + assertNull(createdFile); + assertEquals(TEST_DATA_SHORT.length, deferredFileBody.getSize()); + } + + @Test + public void withLongData__getLength__shouldReturnWrittenLength() throws Exception { + writeLongTestData(); + + assertNotNull(createdFile); + assertEquals(TEST_DATA_LONG.length, deferredFileBody.getSize()); + } + + @Test + public void withShortData__shouldReturnData() throws Exception { + writeShortTestData(); + + InputStream inputStream = deferredFileBody.getInputStream(); + byte[] data = IOUtils.toByteArray(inputStream); + + assertNull(createdFile); + assertArrayEquals(TEST_DATA_SHORT, data); + } + + @Test + public void withLongData__shouldReturnData() throws Exception { + writeLongTestData(); + + InputStream inputStream = deferredFileBody.getInputStream(); + byte[] data = IOUtils.toByteArray(inputStream); + InputStream fileInputStream = new FileInputStream(createdFile); + byte[] dataFromFile = IOUtils.toByteArray(fileInputStream); + + assertArrayEquals(TEST_DATA_LONG, data); + assertArrayEquals(TEST_DATA_LONG, dataFromFile); + } + + @Test + public void withShortData__getFile__shouldWriteDataToFile() throws Exception { + writeShortTestData(); + + File returnedFile = deferredFileBody.getFile(); + InputStream fileInputStream = new FileInputStream(returnedFile); + byte[] dataFromFile = IOUtils.toByteArray(fileInputStream); + + assertSame(createdFile, returnedFile); + assertArrayEquals(TEST_DATA_SHORT, dataFromFile); + } + + @Test + public void withLongData__getFile__shouldReturnCreatedFile() throws Exception { + writeLongTestData(); + + File returnedFile = deferredFileBody.getFile(); + + assertSame(createdFile, returnedFile); + } + + @Test + public void withShortData__writeTo__shouldWriteData() throws Exception { + writeShortTestData(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + deferredFileBody.writeTo(baos); + + assertArrayEquals(TEST_DATA_SHORT, baos.toByteArray()); + } + + @Test(expected = UnsupportedOperationException.class) + public void setEncoding__shouldThrow() throws Exception { + deferredFileBody.setEncoding("anything"); + } + + @Test + public void getEncoding__shouldReturnEncoding() throws Exception { + assertEquals(TEST_ENCODING, deferredFileBody.getEncoding()); + } + + private void writeShortTestData() throws IOException { + OutputStream outputStream = deferredFileBody.getOutputStream(); + outputStream.write(TEST_DATA_SHORT); + outputStream.close(); + } + + private void writeLongTestData() throws IOException { + OutputStream outputStream = deferredFileBody.getOutputStream(); + outputStream.write(TEST_DATA_LONG); + outputStream.close(); + } +} \ No newline at end of file