diff --git a/spring-core/src/main/java/org/springframework/util/FastByteArrayOutputStream.java b/spring-core/src/main/java/org/springframework/util/FastByteArrayOutputStream.java index 72afa88775a..09cb9e8cc01 100644 --- a/spring-core/src/main/java/org/springframework/util/FastByteArrayOutputStream.java +++ b/spring-core/src/main/java/org/springframework/util/FastByteArrayOutputStream.java @@ -421,7 +421,8 @@ public class FastByteArrayOutputStream extends OutputStream { System.arraycopy(this.currentBuffer, this.nextIndexInCurrentBuffer, b, off, bytesToCopy); this.totalBytesRead += bytesToCopy; this.nextIndexInCurrentBuffer += bytesToCopy; - return (bytesToCopy + read(b, off + bytesToCopy, len - bytesToCopy)); + int remaining = read(b, off + bytesToCopy, len - bytesToCopy); + return bytesToCopy + Math.max(remaining, 0); } else { if (this.buffersIterator.hasNext()) { diff --git a/spring-core/src/test/java/org/springframework/util/FastByteArrayOutputStreamTests.java b/spring-core/src/test/java/org/springframework/util/FastByteArrayOutputStreamTests.java index 030083efb69..15217c87b3e 100644 --- a/spring-core/src/test/java/org/springframework/util/FastByteArrayOutputStreamTests.java +++ b/spring-core/src/test/java/org/springframework/util/FastByteArrayOutputStreamTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,6 @@ package org.springframework.util; -import static org.junit.Assert.*; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -25,6 +23,8 @@ import java.io.InputStream; import org.junit.Before; import org.junit.Test; +import static org.junit.Assert.*; + /** * Test suite for {@link FastByteArrayOutputStream} * @author Craig Andrews @@ -37,21 +37,23 @@ public class FastByteArrayOutputStreamTests { private byte[] helloBytes; + @Before public void setUp() throws Exception { this.os = new FastByteArrayOutputStream(INITIAL_CAPACITY); this.helloBytes = "Hello World".getBytes("UTF-8"); } + @Test public void size() throws Exception { - this.os.write(helloBytes); - assertEquals(this.os.size(), helloBytes.length); + this.os.write(this.helloBytes); + assertEquals(this.os.size(), this.helloBytes.length); } @Test public void resize() throws Exception { - this.os.write(helloBytes); + this.os.write(this.helloBytes); int sizeBefore = this.os.size(); this.os.resize(64); assertByteArrayEqualsString(this.os); @@ -70,104 +72,118 @@ public class FastByteArrayOutputStreamTests { @Test public void write() throws Exception { - this.os.write(helloBytes); + this.os.write(this.helloBytes); assertByteArrayEqualsString(this.os); } @Test public void reset() throws Exception { - this.os.write(helloBytes); + this.os.write(this.helloBytes); assertByteArrayEqualsString(this.os); this.os.reset(); assertEquals(0, this.os.size()); - this.os.write(helloBytes); + this.os.write(this.helloBytes); assertByteArrayEqualsString(this.os); } @Test(expected = IOException.class) public void close() throws Exception { this.os.close(); - this.os.write(helloBytes); + this.os.write(this.helloBytes); } @Test public void toByteArrayUnsafe() throws Exception { - this.os.write(helloBytes); + this.os.write(this.helloBytes); assertByteArrayEqualsString(this.os); assertSame(this.os.toByteArrayUnsafe(), this.os.toByteArrayUnsafe()); - assertArrayEquals(this.os.toByteArray(), helloBytes); + assertArrayEquals(this.os.toByteArray(), this.helloBytes); } @Test public void writeTo() throws Exception { - this.os.write(helloBytes); + this.os.write(this.helloBytes); assertByteArrayEqualsString(this.os); ByteArrayOutputStream baos = new ByteArrayOutputStream(); this.os.writeTo(baos); - assertArrayEquals(baos.toByteArray(), helloBytes); + assertArrayEquals(baos.toByteArray(), this.helloBytes); } @Test(expected = IllegalArgumentException.class) public void failResize() throws Exception { - this.os.write(helloBytes); + this.os.write(this.helloBytes); this.os.resize(5); } @Test public void getInputStream() throws Exception { - this.os.write(helloBytes); + this.os.write(this.helloBytes); assertNotNull(this.os.getInputStream()); } @Test public void getInputStreamAvailable() throws Exception { - this.os.write(helloBytes); - assertEquals(this.os.getInputStream().available(), helloBytes.length); + this.os.write(this.helloBytes); + assertEquals(this.os.getInputStream().available(), this.helloBytes.length); } @Test public void getInputStreamRead() throws Exception { - this.os.write(helloBytes); + this.os.write(this.helloBytes); InputStream inputStream = this.os.getInputStream(); - assertEquals(inputStream.read(), helloBytes[0]); - assertEquals(inputStream.read(), helloBytes[1]); - assertEquals(inputStream.read(), helloBytes[2]); - assertEquals(inputStream.read(), helloBytes[3]); + assertEquals(inputStream.read(), this.helloBytes[0]); + assertEquals(inputStream.read(), this.helloBytes[1]); + assertEquals(inputStream.read(), this.helloBytes[2]); + assertEquals(inputStream.read(), this.helloBytes[3]); } @Test public void getInputStreamReadAll() throws Exception { - this.os.write(helloBytes); + this.os.write(this.helloBytes); InputStream inputStream = this.os.getInputStream(); byte[] actual = new byte[inputStream.available()]; int bytesRead = inputStream.read(actual); - assertEquals(bytesRead, helloBytes.length); - assertArrayEquals(actual, helloBytes); + assertEquals(this.helloBytes.length, bytesRead); + assertArrayEquals(this.helloBytes, actual); + assertEquals(0, inputStream.available()); + } + + @Test + public void getInputStreamReadBeyondEndOfStream() throws Exception { + this.os.write(this.helloBytes); + InputStream inputStream = os.getInputStream(); + byte[] actual = new byte[inputStream.available() + 1]; + int bytesRead = inputStream.read(actual); + assertEquals(this.helloBytes.length, bytesRead); + for (int i = 0; i < bytesRead; i++) { + assertEquals(this.helloBytes[i], actual[i]); + } + assertEquals(0, actual[this.helloBytes.length]); assertEquals(0, inputStream.available()); } @Test public void getInputStreamSkip() throws Exception { - this.os.write(helloBytes); + this.os.write(this.helloBytes); InputStream inputStream = this.os.getInputStream(); - assertEquals(inputStream.read(), helloBytes[0]); + assertEquals(inputStream.read(), this.helloBytes[0]); assertEquals(inputStream.skip(1), 1); - assertEquals(inputStream.read(), helloBytes[2]); - assertEquals(helloBytes.length - 3, inputStream.available()); + assertEquals(inputStream.read(), this.helloBytes[2]); + assertEquals(this.helloBytes.length - 3, inputStream.available()); } @Test public void getInputStreamSkipAll() throws Exception { - this.os.write(helloBytes); + this.os.write(this.helloBytes); InputStream inputStream = this.os.getInputStream(); - assertEquals(inputStream.skip(1000), helloBytes.length); + assertEquals(inputStream.skip(1000), this.helloBytes.length); assertEquals(0, inputStream.available()); } @Test public void updateMessageDigest() throws Exception { StringBuilder builder = new StringBuilder("\"0"); - this.os.write(helloBytes); + this.os.write(this.helloBytes); InputStream inputStream = this.os.getInputStream(); DigestUtils.appendMd5DigestAsHex(inputStream, builder); builder.append("\""); @@ -180,7 +196,7 @@ public class FastByteArrayOutputStreamTests { StringBuilder builder = new StringBuilder("\"0"); // filling at least one 256 buffer for ( int i = 0; i < 30; i++) { - this.os.write(helloBytes); + this.os.write(this.helloBytes); } InputStream inputStream = this.os.getInputStream(); DigestUtils.appendMd5DigestAsHex(inputStream, builder); @@ -189,8 +205,9 @@ public class FastByteArrayOutputStreamTests { assertEquals("\"06225ca1e4533354c516e74512065331d\"", actual); } + private void assertByteArrayEqualsString(FastByteArrayOutputStream actual) { - assertArrayEquals(helloBytes, actual.toByteArray()); + assertArrayEquals(this.helloBytes, actual.toByteArray()); } }