diff --git a/org.jacoco.core.test/src/org/jacoco/core/analysis/AnalyzerTest.java b/org.jacoco.core.test/src/org/jacoco/core/analysis/AnalyzerTest.java index eed79a442c..ea1d71438c 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/analysis/AnalyzerTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/analysis/AnalyzerTest.java @@ -31,18 +31,18 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import java.util.jar.JarInputStream; -import java.util.jar.Pack200; import java.util.zip.GZIPOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.internal.Pack200Streams; import org.jacoco.core.internal.data.CRC64; import org.jacoco.core.test.TargetLoader; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.internal.AssumptionViolatedException; import org.junit.rules.TemporaryFolder; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; @@ -294,6 +294,13 @@ public void testAnalyzeAll_BrokenGZ() { @Test public void testAnalyzeAll_Pack200() throws IOException { + try { + Class.forName("java.util.jar.Pack200"); + } catch (ClassNotFoundException e) { + throw new AssumptionViolatedException( + "this test requires JDK with Pack200"); + } + final ByteArrayOutputStream zipbuffer = new ByteArrayOutputStream(); final ZipOutputStream zip = new ZipOutputStream(zipbuffer); zip.putNextEntry( @@ -303,10 +310,7 @@ public void testAnalyzeAll_Pack200() throws IOException { final ByteArrayOutputStream pack200buffer = new ByteArrayOutputStream(); GZIPOutputStream gzipOutput = new GZIPOutputStream(pack200buffer); - Pack200.newPacker() - .pack(new JarInputStream( - new ByteArrayInputStream(zipbuffer.toByteArray())), - gzipOutput); + Pack200Streams.pack(zipbuffer.toByteArray(), gzipOutput); gzipOutput.finish(); final int count = analyzer.analyzeAll( diff --git a/org.jacoco.core.test/src/org/jacoco/core/instr/InstrumenterTest.java b/org.jacoco.core.test/src/org/jacoco/core/instr/InstrumenterTest.java index e67138a723..1288a8ea73 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/instr/InstrumenterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/instr/InstrumenterTest.java @@ -26,9 +26,6 @@ import java.io.OutputStream; import java.io.Serializable; import java.util.Arrays; -import java.util.jar.JarInputStream; -import java.util.jar.JarOutputStream; -import java.util.jar.Pack200; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import java.util.zip.ZipEntry; @@ -36,12 +33,14 @@ import java.util.zip.ZipOutputStream; import org.jacoco.core.analysis.AnalyzerTest; +import org.jacoco.core.internal.Pack200Streams; import org.jacoco.core.internal.data.CRC64; import org.jacoco.core.internal.instr.InstrSupport; import org.jacoco.core.runtime.IExecutionDataAccessorGenerator; import org.jacoco.core.test.TargetLoader; import org.junit.Before; import org.junit.Test; +import org.junit.internal.AssumptionViolatedException; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -398,6 +397,13 @@ public void testInstrumentAll_BrokenGZ() { @Test public void testInstrumentAll_Pack200() throws IOException { + try { + Class.forName("java.util.jar.Pack200"); + } catch (ClassNotFoundException e) { + throw new AssumptionViolatedException( + "this test requires JDK with Pack200"); + } + ByteArrayOutputStream jarbuffer = new ByteArrayOutputStream(); ZipOutputStream zipout = new ZipOutputStream(jarbuffer); zipout.putNextEntry(new ZipEntry("Test.class")); @@ -406,10 +412,7 @@ public void testInstrumentAll_Pack200() throws IOException { ByteArrayOutputStream pack200buffer = new ByteArrayOutputStream(); GZIPOutputStream gzipOutput = new GZIPOutputStream(pack200buffer); - Pack200.newPacker() - .pack(new JarInputStream( - new ByteArrayInputStream(jarbuffer.toByteArray())), - gzipOutput); + Pack200Streams.pack(jarbuffer.toByteArray(), gzipOutput); gzipOutput.finish(); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -417,15 +420,10 @@ public void testInstrumentAll_Pack200() throws IOException { new ByteArrayInputStream(pack200buffer.toByteArray()), out, "Test"); - jarbuffer.reset(); - Pack200.newUnpacker() - .unpack(new GZIPInputStream( - new ByteArrayInputStream(out.toByteArray())), - new JarOutputStream(jarbuffer)); - assertEquals(1, count); ZipInputStream zipin = new ZipInputStream( - new ByteArrayInputStream(jarbuffer.toByteArray())); + Pack200Streams.unpack(new GZIPInputStream( + new ByteArrayInputStream(out.toByteArray())))); assertEquals("Test.class", zipin.getNextEntry().getName()); assertNull(zipin.getNextEntry()); } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/ContentTypeDetectorTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/ContentTypeDetectorTest.java index 094c18a17e..6759412c51 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/ContentTypeDetectorTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/ContentTypeDetectorTest.java @@ -19,14 +19,13 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.jar.JarInputStream; -import java.util.jar.Pack200; import java.util.zip.GZIPOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.jacoco.core.test.TargetLoader; import org.junit.Test; +import org.junit.internal.AssumptionViolatedException; /** * Unit tests for {@link ContentTypeDetector}. @@ -218,6 +217,13 @@ public void testZipFile() throws IOException { @Test public void testPack200File() throws IOException { + try { + Class.forName("java.util.jar.Pack200"); + } catch (ClassNotFoundException e) { + throw new AssumptionViolatedException( + "this test requires JDK with Pack200"); + } + final ByteArrayOutputStream zipbuffer = new ByteArrayOutputStream(); final ZipOutputStream zip = new ZipOutputStream(zipbuffer); zip.putNextEntry(new ZipEntry("hello.txt")); @@ -225,10 +231,7 @@ public void testPack200File() throws IOException { zip.close(); final ByteArrayOutputStream pack200buffer = new ByteArrayOutputStream(); - Pack200.newPacker() - .pack(new JarInputStream( - new ByteArrayInputStream(zipbuffer.toByteArray())), - pack200buffer); + Pack200Streams.pack(zipbuffer.toByteArray(), pack200buffer); initData(pack200buffer.toByteArray()); assertEquals(ContentTypeDetector.PACK200FILE, detector.getType()); assertContent(); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/Pack200StreamsTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/Pack200StreamsTest.java index 2b1d9f10aa..9a8e0e63e8 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/Pack200StreamsTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/Pack200StreamsTest.java @@ -14,6 +14,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; @@ -25,13 +26,13 @@ import java.io.OutputStream; import java.util.jar.JarInputStream; import java.util.jar.JarOutputStream; -import java.util.jar.Pack200; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import org.jacoco.core.test.TargetLoader; import org.junit.Test; +import org.junit.internal.AssumptionViolatedException; /** * Unit tests for {@link Pack200Streams}. @@ -39,7 +40,14 @@ public class Pack200StreamsTest { @Test - public void testPack() throws IOException { + public void pack_should_pack() throws Exception { + try { + Class.forName("java.util.jar.Pack200"); + } catch (ClassNotFoundException e) { + throw new AssumptionViolatedException( + "this test requires JDK with Pack200"); + } + ByteArrayOutputStream jarbuffer = new ByteArrayOutputStream(); ZipOutputStream zipout = new ZipOutputStream(jarbuffer); zipout.putNextEntry(new ZipEntry("Test.class")); @@ -51,9 +59,13 @@ public void testPack() throws IOException { new NoCloseOutputStream(pack200buffer)); jarbuffer.reset(); - Pack200.newUnpacker().unpack( - new ByteArrayInputStream(pack200buffer.toByteArray()), - new JarOutputStream(jarbuffer)); + final Object unpacker = Class.forName("java.util.jar.Pack200") + .getMethod("newUnpacker").invoke(null); + Class.forName("java.util.jar.Pack200$Unpacker") + .getMethod("unpack", InputStream.class, JarOutputStream.class) + .invoke(unpacker, + new ByteArrayInputStream(pack200buffer.toByteArray()), + new JarOutputStream(jarbuffer)); ZipInputStream zipin = new ZipInputStream( new ByteArrayInputStream(jarbuffer.toByteArray())); @@ -62,7 +74,52 @@ public void testPack() throws IOException { } @Test - public void testUnpack() throws IOException { + public void pack_should_throw_IOException_when_can_not_write_to_OutputStream() { + try { + Class.forName("java.util.jar.Pack200"); + } catch (ClassNotFoundException e) { + throw new AssumptionViolatedException( + "this test requires JDK with Pack200"); + } + + final OutputStream outputStream = new BrokenOutputStream(); + try { + Pack200Streams.pack(new byte[0], outputStream); + fail("expected exception"); + } catch (IOException e) { + assertTrue(e.getCause() instanceof IOException); + assertEquals("fake broken output stream", + e.getCause().getMessage()); + } + } + + @Test + public void pack_should_throw_IOException_when_Pack200_not_available_in_JDK() { + try { + Class.forName("java.util.jar.Pack200"); + throw new AssumptionViolatedException( + "this test requires JDK without Pack200"); + } catch (ClassNotFoundException ignore) { + } + + try { + Pack200Streams.pack(new byte[0], new ByteArrayOutputStream()); + fail("expected exception"); + } catch (IOException e) { + assertNull(e.getMessage()); + assertTrue(e.getCause() instanceof ClassNotFoundException); + } + } + + @Test + public void unpack_should_unpack() throws Exception { + try { + Class.forName("java.util.jar.Pack200"); + } catch (ClassNotFoundException e) { + throw new AssumptionViolatedException( + "this test requires JDK with Pack200"); + } + ByteArrayOutputStream jarbuffer = new ByteArrayOutputStream(); ZipOutputStream zipout = new ZipOutputStream(jarbuffer); zipout.putNextEntry(new ZipEntry("Test.class")); @@ -70,8 +127,11 @@ public void testUnpack() throws IOException { zipout.finish(); ByteArrayOutputStream pack200buffer = new ByteArrayOutputStream(); - Pack200.newPacker() - .pack(new JarInputStream( + final Object packer = Class.forName("java.util.jar.Pack200") + .getMethod("newPacker").invoke(null); + Class.forName("java.util.jar.Pack200$Packer") + .getMethod("pack", JarInputStream.class, OutputStream.class) + .invoke(packer, new JarInputStream( new ByteArrayInputStream(jarbuffer.toByteArray())), pack200buffer); @@ -83,6 +143,43 @@ public void testUnpack() throws IOException { assertNull(zipin.getNextEntry()); } + @Test + public void unpack_should_throw_IOException_when_can_not_read_from_InputStream() { + try { + Class.forName("java.util.jar.Pack200"); + } catch (ClassNotFoundException e) { + throw new AssumptionViolatedException( + "this test requires JDK with Pack200"); + } + + final InputStream inputStream = new BrokenInputStream(); + try { + Pack200Streams.unpack(inputStream); + fail("expected exception"); + } catch (IOException e) { + assertTrue(e.getCause() instanceof IOException); + assertEquals("fake broken input stream", e.getCause().getMessage()); + } + } + + @Test + public void unpack_should_throw_IOException_when_Pack200_not_available_in_JDK() { + try { + Class.forName("java.util.jar.Pack200"); + throw new AssumptionViolatedException( + "this test requires JDK without Pack200"); + } catch (ClassNotFoundException ignore) { + } + + try { + Pack200Streams.unpack(new ByteArrayInputStream(new byte[0])); + fail("expected exception"); + } catch (IOException e) { + assertNull(e.getMessage()); + assertTrue(e.getCause() instanceof ClassNotFoundException); + } + } + static class NoCloseInputStream extends FilterInputStream { public NoCloseInputStream(InputStream in) { super(in); @@ -105,4 +202,18 @@ public void close() throws IOException { } } + private static class BrokenInputStream extends InputStream { + @Override + public int read() throws IOException { + throw new IOException("fake broken input stream"); + } + } + + private static class BrokenOutputStream extends OutputStream { + @Override + public void write(int b) throws IOException { + throw new IOException("fake broken output stream"); + } + } + } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/Pack200Streams.java b/org.jacoco.core/src/org/jacoco/core/internal/Pack200Streams.java index 96b0596006..5750570646 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/Pack200Streams.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/Pack200Streams.java @@ -18,9 +18,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; import java.util.jar.JarInputStream; import java.util.jar.JarOutputStream; -import java.util.jar.Pack200; /** * Internal wrapper for the weird Pack200 Java API to allow usage with streams. @@ -36,11 +36,27 @@ public final class Pack200Streams { * @throws IOException * in case of errors with the streams */ + @SuppressWarnings("resource") public static InputStream unpack(final InputStream input) throws IOException { final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); final JarOutputStream jar = new JarOutputStream(buffer); - Pack200.newUnpacker().unpack(new NoCloseInput(input), jar); + try { + final Object unpacker = Class.forName("java.util.jar.Pack200") + .getMethod("newUnpacker").invoke(null); + Class.forName("java.util.jar.Pack200$Unpacker") + .getMethod("unpack", InputStream.class, + JarOutputStream.class) + .invoke(unpacker, new NoCloseInput(input), jar); + } catch (ClassNotFoundException e) { + throw newIOException(e); + } catch (NoSuchMethodException e) { + throw newIOException(e); + } catch (IllegalAccessException e) { + throw newIOException(e); + } catch (InvocationTargetException e) { + throw newIOException(e.getCause()); + } jar.finish(); return new ByteArrayInputStream(buffer.toByteArray()); } @@ -55,11 +71,32 @@ public static InputStream unpack(final InputStream input) * @throws IOException * in case of errors with the streams */ + @SuppressWarnings("resource") public static void pack(final byte[] source, final OutputStream output) throws IOException { final JarInputStream jar = new JarInputStream( new ByteArrayInputStream(source)); - Pack200.newPacker().pack(jar, output); + try { + final Object packer = Class.forName("java.util.jar.Pack200") + .getMethod("newPacker").invoke(null); + Class.forName("java.util.jar.Pack200$Packer") + .getMethod("pack", JarInputStream.class, OutputStream.class) + .invoke(packer, jar, output); + } catch (ClassNotFoundException e) { + throw newIOException(e); + } catch (NoSuchMethodException e) { + throw newIOException(e); + } catch (IllegalAccessException e) { + throw newIOException(e); + } catch (InvocationTargetException e) { + throw newIOException(e.getCause()); + } + } + + private static IOException newIOException(final Throwable cause) { + final IOException exception = new IOException(); + exception.initCause(cause); + return exception; } private static class NoCloseInput extends FilterInputStream { diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 37ac81c5e9..be195d9cad 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -20,6 +20,13 @@

Change History

Snapshot Build @qualified.bundle.version@ (@build.date@)

+

Non-functional Changes

+ +

Release 0.8.5 (2019/10/11)

New Features