package org.exist.util.io; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.util.Random; import org.apache.commons.io.output.ByteArrayOutputStream; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.Test; /** * @author Adam Retter <adam.retter@googlemail.com> */ public class ByteBufferInputStreamTest { @Test public void available() throws IOException { final byte testData[] = "test data".getBytes(); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); assertEquals(testData.length, is.available()); } @Test public void availableIsZeroAfterClose() throws IOException { final byte testData[] = "test data".getBytes(); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); is.close(); assertEquals(0, is.available()); } @Test public void availableAfterRead() throws IOException { final byte testData[] = "test data".getBytes(); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); //read first 2 bytes is.read(); is.read(); assertEquals(testData.length -2 , is.available()); } @Test public void readByteByByteCorrectAndThenReturnMinus1AtEndOfStream() throws IOException { final byte testData[] = "test data".getBytes(); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); for(int i = 0; i < testData.length; i++) { assertEquals(testData[i], is.read()); } //ensure reading past the end of the stream returns -1 assertEquals(-1, is.read()); } @Test public void readMultipleBytesCorrectAndThenReturnMinus1AtEndOfStream() throws IOException { final byte testData[] = "test data".getBytes(); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); byte readData[] = new byte[testData.length]; int read = is.read(readData); assertEquals(testData.length, read); assertArrayEquals(testData, readData); //ensure reading past the end of the stream returns -1 assertEquals(-1, is.read(readData)); } @Test public void readMultipleBytesPastAvailable() throws IOException { final byte testData[] = "test data".getBytes(); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); byte readData[] = new byte[testData.length + 2]; int read = is.read(readData); assertEquals(testData.length, read); assertArrayEquals(testData, subArray(readData, testData.length)); //bytes past the available should still be 0 assertArrayEquals(new byte[]{0,0}, subArray(readData, testData.length, 2)); } @Test public void readMultipleBytesSpecificCorrectAndThenReturnMinus1AtEndOfStream() throws IOException { final byte testData[] = "test data".getBytes(); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); byte readData[] = new byte[testData.length]; is.read(readData, 0, testData.length); assertArrayEquals(testData, readData); //ensure reading past the end of the stream returns -1 assertEquals(-1, is.read(readData, 0, testData.length)); } @Test public void readMultipleBytesSpecificPastAvailable() throws IOException { final byte testData[] = "test data".getBytes(); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); byte readData[] = new byte[testData.length + 2]; int read = is.read(readData, 0, readData.length); assertEquals(testData.length, read); assertArrayEquals(testData, subArray(readData, testData.length)); //bytes past the available should still be 0 assertArrayEquals(new byte[]{0,0}, subArray(readData, testData.length, 2)); } @Test(expected=IOException.class) public void readSingleByteAfterCloseThrowsException() throws IOException { final byte testData[] = "test data".getBytes(); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); try { is.close(); } catch(IOException ioe) { fail(ioe.getMessage()); } //should throw IOException is.read(); } @Test(expected=IOException.class) public void readMultipleBytesAfterCloseThrowsException() throws IOException { final byte testData[] = "test data".getBytes(); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); try { is.close(); } catch(IOException ioe) { fail(ioe.getMessage()); } byte readBuf[] = new byte[2]; //should throw IOException is.read(readBuf); } @Test(expected=IOException.class) public void readMultipleBytesSpecificAfterCloseThrowsException() throws IOException { final byte testData[] = "test data".getBytes(); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); try { is.close(); } catch(IOException ioe) { fail(ioe.getMessage()); } byte readBuf[] = new byte[2]; //should throw IOException is.read(readBuf, 0, 2); } @Test public void readMultipleBytesInLoop() throws IOException { //generate 1KB of test data Random random = new Random(); byte testData[] = new byte[1024]; random.nextBytes(testData); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte readBuf[] = new byte[56]; int read = -1; while((read = is.read(readBuf)) > -1) { assertLessThanOrEqual(readBuf.length, read); baos.write(readBuf, 0, read); } assertArrayEquals(testData, baos.toByteArray()); } @Test public void readMultipleBytesSpecificInLoop() throws IOException { //generate 1KB of test data Random random = new Random(); byte testData[] = new byte[1024]; random.nextBytes(testData); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte readBuf[] = new byte[56]; int read = -1; while((read = is.read(readBuf, 0, readBuf.length)) > -1) { assertLessThanOrEqual(readBuf.length, read); baos.write(readBuf, 0, read); } assertArrayEquals(testData, baos.toByteArray()); } @Test public void markReturnsTrue() { final byte testData[] = "test data".getBytes(); final ByteBuffer buf = ByteBuffer.wrap(testData); InputStream is = new ByteBufferInputStream(new TestableByteBufferAccessor(buf)); assertTrue(is.markSupported()); } public class TestableByteBufferAccessor implements ByteBufferAccessor { private final ByteBuffer buf; public TestableByteBufferAccessor(ByteBuffer buf) { this.buf = buf; } @Override public ByteBuffer getBuffer() { return buf; } } private byte[] subArray(byte data[], int len) { byte newData[] = new byte[len]; System.arraycopy(data, 0, newData, 0, len); return newData; } private byte[] subArray(byte data[], int offset, int len) { byte newData[] = new byte[len]; System.arraycopy(data, offset, newData, 0, len); return newData; } private static void assertLessThanOrEqual(int expectedMax, int actual) { if(actual > expectedMax) { fail("Expected actual value" + actual + " to be less than or equal to " + expectedMax); } } }