diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java index 7c980e610b27a7..1cae0f27284c1f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/camera/ImageStoreManager.java @@ -78,20 +78,12 @@ protected void doInBackgroundGuarded(Void... params) { ContentResolver contentResolver = getReactApplicationContext().getContentResolver(); Uri uri = Uri.parse(mUri); InputStream is = contentResolver.openInputStream(uri); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - Base64OutputStream b64os = new Base64OutputStream(baos, Base64.DEFAULT); - byte[] buffer = new byte[BUFFER_SIZE]; - int bytesRead; try { - while ((bytesRead = is.read(buffer)) > -1) { - b64os.write(buffer, 0, bytesRead); - } - mSuccess.invoke(baos.toString()); + mSuccess.invoke(convertInputStreamToBase64OutputStream(is)); } catch (IOException e) { mError.invoke(e.getMessage()); } finally { closeQuietly(is); - closeQuietly(b64os); // this also closes baos } } catch (FileNotFoundException e) { mError.invoke(e.getMessage()); @@ -99,6 +91,21 @@ protected void doInBackgroundGuarded(Void... params) { } } + String convertInputStreamToBase64OutputStream(InputStream is) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Base64OutputStream b64os = new Base64OutputStream(baos, Base64.NO_WRAP); + byte[] buffer = new byte[BUFFER_SIZE]; + int bytesRead; + try { + while ((bytesRead = is.read(buffer)) > -1) { + b64os.write(buffer, 0, bytesRead); + } + } finally { + closeQuietly(b64os); // this also closes baos and flushes the final content to it + } + return baos.toString(); + } + private static void closeQuietly(Closeable closeable) { try { closeable.close(); diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK b/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK index 1cb5292c353c0d..dcccaf7a563d5f 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK @@ -26,6 +26,7 @@ rn_robolectric_test( react_native_target("java/com/facebook/react/common/network:network"), react_native_target("java/com/facebook/react/devsupport:interfaces"), react_native_target("java/com/facebook/react/jstasks:jstasks"), + react_native_target("java/com/facebook/react/modules/camera:camera"), react_native_target("java/com/facebook/react/modules/clipboard:clipboard"), react_native_target("java/com/facebook/react/modules/common:common"), react_native_target("java/com/facebook/react/modules/core:core"), diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/camera/ImageStoreManagerTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/camera/ImageStoreManagerTest.java new file mode 100644 index 00000000000000..5c618858d0bc7e --- /dev/null +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/camera/ImageStoreManagerTest.java @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +package com.facebook.react.modules.camera; + +import android.util.Base64; +import android.util.Base64InputStream; + +import com.facebook.react.bridge.ReactApplicationContext; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.robolectric.RobolectricTestRunner; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Random; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.Mockito.mock; + +@RunWith(RobolectricTestRunner.class) +@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"}) +public class ImageStoreManagerTest { + + @Test + public void itDoesNotAddLineBreaks_whenBasicStringProvided() throws IOException { + byte[] exampleString = "test".getBytes(); + assertEquals("dGVzdA==", invokeConversion(new ByteArrayInputStream(exampleString))); + } + + @Test + public void itDoesNotAddLineBreaks_whenEmptyStringProvided() throws IOException { + byte[] exampleString = "".getBytes(); + assertEquals("", invokeConversion(new ByteArrayInputStream(exampleString))); + } + + @Test + public void itDoesNotAddLineBreaks_whenStringWithSpecialCharsProvided() throws IOException { + byte[] exampleString = "sdfsdf\nasdfsdfsdfsd\r\nasdas".getBytes(); + ByteArrayInputStream inputStream = new ByteArrayInputStream(exampleString); + assertFalse(invokeConversion(inputStream).contains("\n")); + } + + /** + * This test tries to test the conversion when going beyond the current buffer size (8192 bytes) + */ + @Test + public void itDoesNotAddLineBreaks_whenStringBiggerThanBuffer() throws IOException { + ByteArrayInputStream inputStream = new ByteArrayInputStream(generateRandomByteString(10000)); + assertFalse(invokeConversion(inputStream).contains("\n")); + } + + /** + * Just to test if using the ByteArrayInputStream isn't missing something + */ + @Test + public void itDoesNotAddLineBreaks_whenBase64InputStream() throws IOException { + byte[] exampleString = "dGVzdA==".getBytes(); + Base64InputStream inputStream = + new Base64InputStream(new ByteArrayInputStream(exampleString), Base64.NO_WRAP); + assertEquals("dGVzdA==", invokeConversion(inputStream)); + } + + private String invokeConversion(InputStream inputStream) throws IOException { + return new ImageStoreManager(mock(ReactApplicationContext.class)) + .convertInputStreamToBase64OutputStream(inputStream); + } + + private byte[] generateRandomByteString(final int length) { + Random r = new Random(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + char c = (char) (r.nextInt((int) (Character.MAX_VALUE))); + sb.append(c); + } + return sb.toString().getBytes(); + } +}