diff --git a/src/main/java/org/takes/rs/RsPrint.java b/src/main/java/org/takes/rs/RsPrint.java index 5336d2fe8..554655fa9 100644 --- a/src/main/java/org/takes/rs/RsPrint.java +++ b/src/main/java/org/takes/rs/RsPrint.java @@ -169,10 +169,9 @@ public void printHead(final Writer writer) throws IOException { * @throws IOException If fails */ public void printBody(final OutputStream output) throws IOException { - final InputStream body = this.body(); //@checkstyle MagicNumberCheck (1 line) final byte[] buf = new byte[4096]; - try { + try (final InputStream body = this.body()) { while (true) { final int bytes = body.read(buf); if (bytes < 0) { diff --git a/src/test/java/org/takes/rs/RsPrintTest.java b/src/test/java/org/takes/rs/RsPrintTest.java index 4ed7c0912..51cd5bc95 100644 --- a/src/test/java/org/takes/rs/RsPrintTest.java +++ b/src/test/java/org/takes/rs/RsPrintTest.java @@ -24,11 +24,14 @@ package org.takes.rs; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.io.Writer; import java.nio.charset.StandardCharsets; +import org.cactoos.io.InputStreamOf; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; +import org.hamcrest.core.IsEqual; import org.junit.Test; /** @@ -36,7 +39,9 @@ * @author Yegor Bugayenko (yegor256@gmail.com) * @version $Id$ * @since 0.8 + * @checkstyle ClassDataAbstractionCouplingCheck (500 lines) */ +@SuppressWarnings("PMD.TooManyMethods") public final class RsPrintTest { /** @@ -70,6 +75,30 @@ public void flushBodyEvenWhenExceptionHappens() throws IOException { ); } + /** + * RsPrint can close body contents even when exception happens. + * @throws IOException If some problem inside + */ + @Test + public void closeBodyEvenWhenExceptionHappens() throws IOException { + final IOException exception = new IOException("Smth went wrong"); + final FailOutputStream output = new FailOutputStream(exception); + final FakeInput input = new FakeInput(new InputStreamOf("abc")); + try { + new RsPrint(new RsText(input)) + .printBody(output); + } catch (final IOException ex) { + if (!ex.equals(exception)) { + throw ex; + } + } + MatcherAssert.assertThat( + "Input body was not closed", + input.isClosed(), + new IsEqual<>(true) + ); + } + /** * RsPrint can flush head contents even when exception happens. * @throws IOException If some problem inside @@ -190,4 +219,52 @@ public boolean haveFlushed() { return this.flushed; } } + + /** + * Fake wrapper for InputStream to make sure body is closed. + * + * @author Alena Gerasimova (olena.gerasimova@gmail.com) + * @version $Id$ + * @since 2.0 + */ + private static final class FakeInput extends InputStream { + + /** + * Have input been closed? + */ + private boolean closed; + + /** + * Origin. + */ + private final InputStream origin; + + /** + * Ctor. + * @param origin Origin input + */ + FakeInput(final InputStream origin) { + super(); + this.origin = origin; + } + + @Override + public int read() throws IOException { + return this.origin.read(); + } + + @Override + public void close() throws IOException { + this.origin.close(); + this.closed = true; + } + + /** + * Have input been closed? + * @return True, if input wes closed, false - otherwise + */ + public boolean isClosed() { + return this.closed; + } + } }