aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc R. Hoffmann <hoffmann@mountainminds.com>2013-05-20 12:56:11 +0200
committerMarc R. Hoffmann <hoffmann@mountainminds.com>2013-05-27 06:55:19 +0200
commitac07e252571819685d3f74cb69c90c23abd340a0 (patch)
tree1bf566cccd3830251dc96bd08c5d2f019a80aa32
parent65d0700ffc0988767ca4c003b22063e56d2e837f (diff)
downloadjacoco-ac07e252571819685d3f74cb69c90c23abd340a0.tar.gz
Context information for error messages.
Analyzer and Instrumenter now expect a resource name parameter to provide better messages in case of internal errors.
-rw-r--r--jacoco-maven-plugin/src/org/jacoco/maven/InstrumentMojo.java20
-rw-r--r--org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java2
-rw-r--r--org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java6
-rw-r--r--org.jacoco.ant/src/org/jacoco/ant/InstrumentTask.java3
-rw-r--r--org.jacoco.ant/src/org/jacoco/ant/ReportTask.java2
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/analysis/AnalyzerTest.java56
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/instr/InstrumenterTest.java76
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/test/perf/AnalysisTimeScenario.java11
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/test/perf/ExecuteInstrumentedCodeScenario.java13
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/test/perf/InstrumentationTimeScenario.java11
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/test/perf/TimedScenario.java18
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target01.java7
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target02.java7
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target03.java6
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java20
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/test/validation/FramesTest.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java86
-rw-r--r--org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java99
-rw-r--r--org.jacoco.doc/docroot/doc/changes.html9
-rw-r--r--org.jacoco.examples/src/org/jacoco/examples/CoreTutorial.java6
20 files changed, 312 insertions, 148 deletions
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/InstrumentMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/InstrumentMojo.java
index 0888b796..d5af656a 100644
--- a/jacoco-maven-plugin/src/org/jacoco/maven/InstrumentMojo.java
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/InstrumentMojo.java
@@ -11,13 +11,6 @@
*******************************************************************************/
package org.jacoco.maven;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.codehaus.plexus.util.FileUtils;
-import org.codehaus.plexus.util.IOUtil;
-import org.jacoco.core.instr.Instrumenter;
-import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator;
-
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -26,6 +19,13 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+import org.jacoco.core.instr.Instrumenter;
+import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator;
+
/**
* Performs offline instrumentation. Note that after execution of test you must
* restore original classes with help of "restore-instrumented-classes" goal.
@@ -59,8 +59,8 @@ public class InstrumentMojo extends AbstractJacocoMojo {
final List<String> fileNames;
try {
- fileNames = new FileFilter(this.getIncludes(),
- this.getExcludes()).getFileNames(classesDir);
+ fileNames = new FileFilter(this.getIncludes(), this.getExcludes())
+ .getFileNames(classesDir);
} catch (final IOException e1) {
throw new MojoExecutionException(
"Unable to get list of files to instrument.", e1);
@@ -78,7 +78,7 @@ public class InstrumentMojo extends AbstractJacocoMojo {
FileUtils.copyFile(source, backup);
input = new FileInputStream(backup);
output = new FileOutputStream(source);
- instrumenter.instrument(input, output);
+ instrumenter.instrument(input, output, source.getPath());
} catch (final IOException e2) {
throw new MojoExecutionException(
"Unable to instrument file.", e2);
diff --git a/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java b/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java
index 563f531f..98cca18c 100644
--- a/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java
+++ b/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java
@@ -139,7 +139,7 @@ public class CoverageTransformerTest {
}
recorder.assertException(IllegalClassFormatException.class,
"Error while instrumenting class org.jacoco.Sample.",
- NullPointerException.class);
+ IOException.class);
recorder.clear();
}
diff --git a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java
index c53e7d42..a2b35f24 100644
--- a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java
+++ b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java
@@ -11,8 +11,6 @@
*******************************************************************************/
package org.jacoco.agent.rt.internal;
-import static java.lang.String.format;
-
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
@@ -86,10 +84,10 @@ public class CoverageTransformer implements ClassFileTransformer {
// reference as probes might have changed.
runtime.disconnect(classBeingRedefined);
}
- return instrumenter.instrument(classfileBuffer);
+ return instrumenter.instrument(classfileBuffer, classname);
} catch (final Exception ex) {
final IllegalClassFormatException wrapper = new IllegalClassFormatException(
- format("Error while instrumenting class %s.", classname));
+ ex.getMessage());
wrapper.initCause(ex);
// Report this, as the exception is ignored by the JVM:
logger.logExeption(wrapper);
diff --git a/org.jacoco.ant/src/org/jacoco/ant/InstrumentTask.java b/org.jacoco.ant/src/org/jacoco/ant/InstrumentTask.java
index 09b8aec2..345197a8 100644
--- a/org.jacoco.ant/src/org/jacoco/ant/InstrumentTask.java
+++ b/org.jacoco.ant/src/org/jacoco/ant/InstrumentTask.java
@@ -88,7 +88,8 @@ public class InstrumentTask extends Task {
try {
input = resource.getInputStream();
output = new FileOutputStream(file);
- return instrumenter.instrumentAll(input, output);
+ return instrumenter.instrumentAll(input, output,
+ resource.getName());
} finally {
FileUtils.close(input);
FileUtils.close(output);
diff --git a/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java b/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java
index 329914ff..21dc34c2 100644
--- a/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java
+++ b/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java
@@ -568,7 +568,7 @@ public class ReportTask extends Task {
analyzer.analyzeAll(((FileResource) resource).getFile());
} else {
final InputStream in = resource.getInputStream();
- analyzer.analyzeAll(in);
+ analyzer.analyzeAll(in, resource.getName());
in.close();
}
}
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 741f63e1..69a601c4 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
@@ -13,6 +13,7 @@ package org.jacoco.core.analysis;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -65,7 +66,8 @@ public class AnalyzerTest {
@Test
public void testAnalyzeClass1() throws IOException {
- analyzer.analyzeClass(TargetLoader.getClassData(AnalyzerTest.class));
+ analyzer.analyzeClass(TargetLoader.getClassData(AnalyzerTest.class),
+ "Test");
assertEquals(
Collections.singleton("org/jacoco/core/analysis/AnalyzerTest"),
classes);
@@ -73,17 +75,30 @@ public class AnalyzerTest {
@Test
public void testAnalyzeClass2() throws IOException {
- analyzer.analyzeClass(TargetLoader
- .getClassDataAsBytes(AnalyzerTest.class));
+ analyzer.analyzeClass(
+ TargetLoader.getClassDataAsBytes(AnalyzerTest.class), "Test");
assertEquals(
Collections.singleton("org/jacoco/core/analysis/AnalyzerTest"),
classes);
}
@Test
+ public void testAnalyzeClass_Broken() throws IOException {
+ final byte[] brokenclass = TargetLoader
+ .getClassDataAsBytes(AnalyzerTest.class);
+ brokenclass[10] = 0x23;
+ try {
+ analyzer.analyzeClass(brokenclass, "Broken");
+ fail();
+ } catch (IOException e) {
+ assertEquals("Error while analyzing class Broken.", e.getMessage());
+ }
+ }
+
+ @Test
public void testAnalyzeAll_Class() throws IOException {
- final int count = analyzer.analyzeAll(TargetLoader
- .getClassData(AnalyzerTest.class));
+ final int count = analyzer.analyzeAll(
+ TargetLoader.getClassData(AnalyzerTest.class), "Test");
assertEquals(1, count);
assertEquals(
Collections.singleton("org/jacoco/core/analysis/AnalyzerTest"),
@@ -98,8 +113,8 @@ public class AnalyzerTest {
"org/jacoco/core/analysis/AnalyzerTest.class"));
zip.write(TargetLoader.getClassDataAsBytes(AnalyzerTest.class));
zip.finish();
- final int count = analyzer.analyzeAll(new ByteArrayInputStream(buffer
- .toByteArray()));
+ final int count = analyzer.analyzeAll(
+ new ByteArrayInputStream(buffer.toByteArray()), "Test");
assertEquals(1, count);
assertEquals(
Collections.singleton("org/jacoco/core/analysis/AnalyzerTest"),
@@ -123,7 +138,7 @@ public class AnalyzerTest {
gzipOutput.finish();
final int count = analyzer.analyzeAll(new ByteArrayInputStream(
- pack200buffer.toByteArray()));
+ pack200buffer.toByteArray()), "Test");
assertEquals(1, count);
assertEquals(
Collections.singleton("org/jacoco/core/analysis/AnalyzerTest"),
@@ -133,7 +148,7 @@ public class AnalyzerTest {
@Test
public void testAnalyzeAll_Empty() throws IOException {
final int count = analyzer.analyzeAll(new ByteArrayInputStream(
- new byte[0]));
+ new byte[0]), "Test");
assertEquals(0, count);
assertEquals(Collections.emptySet(), classes);
}
@@ -172,6 +187,29 @@ public class AnalyzerTest {
analyzer.analyzeAll(file);
}
+ @Test
+ public void testAnalyzeAll_BrokenClassFileInZip() throws IOException {
+ final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ final ZipOutputStream zip = new ZipOutputStream(buffer);
+ zip.putNextEntry(new ZipEntry(
+ "org/jacoco/core/analysis/AnalyzerTest.class"));
+ final byte[] brokenclass = TargetLoader
+ .getClassDataAsBytes(AnalyzerTest.class);
+ brokenclass[10] = 0x23;
+ zip.write(brokenclass);
+ zip.finish();
+
+ try {
+ analyzer.analyzeAll(new ByteArrayInputStream(buffer.toByteArray()),
+ "test.zip");
+ fail();
+ } catch (IOException e) {
+ assertEquals(
+ "Error while analyzing class test.zip@org/jacoco/core/analysis/AnalyzerTest.class.",
+ e.getMessage());
+ }
+ }
+
private void createClassfile(final String dir, final Class<?> source)
throws IOException {
File file = new File(folder.getRoot(), dir);
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 26b8a8f2..50bc200c 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
@@ -13,6 +13,7 @@ package org.jacoco.core.instr;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -31,6 +32,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
+import org.jacoco.core.analysis.AnalyzerTest;
import org.jacoco.core.runtime.RuntimeData;
import org.jacoco.core.runtime.SystemPropertiesRuntime;
import org.jacoco.core.test.TargetLoader;
@@ -80,10 +82,49 @@ public class InstrumenterTest {
}
@Test
+ public void testInstrumentClass() throws Exception {
+ byte[] bytes = instrumenter.instrument(
+ TargetLoader.getClassDataAsBytes(InstrumenterTest.class),
+ "Test");
+ TargetLoader loader = new TargetLoader(InstrumenterTest.class, bytes);
+ Class<?> clazz = loader.getTargetClass();
+ assertEquals("org.jacoco.core.instr.InstrumenterTest", clazz.getName());
+ }
+
+ @Test
+ public void testInstrumentBrokenClass1() throws IOException {
+ final byte[] brokenclass = TargetLoader
+ .getClassDataAsBytes(AnalyzerTest.class);
+ brokenclass[10] = 0x23;
+ try {
+ instrumenter.instrument(brokenclass, "Broken");
+ fail();
+ } catch (IOException e) {
+ assertEquals("Error while instrumenting class Broken.",
+ e.getMessage());
+ }
+ }
+
+ @Test
+ public void testInstrumentBrokenClass2() throws IOException {
+ final byte[] brokenclass = TargetLoader
+ .getClassDataAsBytes(AnalyzerTest.class);
+ brokenclass[10] = 0x23;
+ try {
+ instrumenter.instrument(new ByteArrayInputStream(brokenclass),
+ "Broken");
+ fail();
+ } catch (IOException e) {
+ assertEquals("Error while instrumenting class Broken.",
+ e.getMessage());
+ }
+ }
+
+ @Test
public void testSerialization() throws Exception {
// Create instrumented instance:
- byte[] bytes = instrumenter.instrument(TargetLoader
- .getClassData(SerializationTarget.class));
+ byte[] bytes = instrumenter.instrument(
+ TargetLoader.getClassData(SerializationTarget.class), "Test");
TargetLoader loader = new TargetLoader(SerializationTarget.class, bytes);
Object obj1 = loader.getTargetClass()
.getConstructor(String.class, Integer.TYPE)
@@ -104,7 +145,7 @@ public class InstrumenterTest {
InputStream in = TargetLoader.getClassData(getClass());
OutputStream out = new ByteArrayOutputStream();
- int count = instrumenter.instrumentAll(in, out);
+ int count = instrumenter.instrumentAll(in, out, "Test");
assertEquals(1, count);
}
@@ -119,7 +160,7 @@ public class InstrumenterTest {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int count = instrumenter.instrumentAll(
- new ByteArrayInputStream(buffer.toByteArray()), out);
+ new ByteArrayInputStream(buffer.toByteArray()), out, "Test");
assertEquals(1, count);
ZipInputStream zipin = new ZipInputStream(new ByteArrayInputStream(
@@ -129,6 +170,29 @@ public class InstrumenterTest {
}
@Test
+ public void testInstrumentAll_BrokenClassFileInZip() throws IOException {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ ZipOutputStream zipout = new ZipOutputStream(buffer);
+ zipout.putNextEntry(new ZipEntry("Test.class"));
+ final byte[] brokenclass = TargetLoader.getClassDataAsBytes(getClass());
+ brokenclass[10] = 0x23;
+ zipout.write(brokenclass);
+ zipout.finish();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ try {
+ instrumenter.instrumentAll(
+ new ByteArrayInputStream(buffer.toByteArray()), out,
+ "test.zip");
+ fail();
+ } catch (IOException e) {
+ assertEquals(
+ "Error while instrumenting class test.zip@Test.class.",
+ e.getMessage());
+ }
+ }
+
+ @Test
public void testInstrumentAll_Pack200() throws IOException {
ByteArrayOutputStream jarbuffer = new ByteArrayOutputStream();
ZipOutputStream zipout = new ZipOutputStream(jarbuffer);
@@ -145,7 +209,7 @@ public class InstrumenterTest {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int count = instrumenter.instrumentAll(new ByteArrayInputStream(
- pack200buffer.toByteArray()), out);
+ pack200buffer.toByteArray()), out, "Test");
jarbuffer.reset();
Pack200.newUnpacker()
@@ -164,7 +228,7 @@ public class InstrumenterTest {
InputStream in = new ByteArrayInputStream("text".getBytes());
ByteArrayOutputStream out = new ByteArrayOutputStream();
- int count = instrumenter.instrumentAll(in, out);
+ int count = instrumenter.instrumentAll(in, out, "Test");
assertEquals(0, count);
assertEquals("text", new String(out.toByteArray()));
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/perf/AnalysisTimeScenario.java b/org.jacoco.core.test/src/org/jacoco/core/test/perf/AnalysisTimeScenario.java
index bcc57e72..846eb821 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/perf/AnalysisTimeScenario.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/perf/AnalysisTimeScenario.java
@@ -11,6 +11,8 @@
*******************************************************************************/
package org.jacoco.core.test.perf;
+import java.util.concurrent.Callable;
+
import org.jacoco.core.analysis.Analyzer;
import org.jacoco.core.analysis.IClassCoverage;
import org.jacoco.core.analysis.ICoverageVisitor;
@@ -33,7 +35,7 @@ public class AnalysisTimeScenario extends TimedScenario {
}
@Override
- protected Runnable getInstrumentedRunnable() throws Exception {
+ protected Callable<Void> getInstrumentedCallable() throws Exception {
final byte[] bytes = TargetLoader.getClassDataAsBytes(target);
final ExecutionDataStore executionData = new ExecutionDataStore();
ICoverageVisitor visitor = new ICoverageVisitor() {
@@ -41,11 +43,12 @@ public class AnalysisTimeScenario extends TimedScenario {
}
};
final Analyzer analyzer = new Analyzer(executionData, visitor);
- return new Runnable() {
- public void run() {
+ return new Callable<Void>() {
+ public Void call() throws Exception {
for (int i = 0; i < count; i++) {
- analyzer.analyzeClass(bytes);
+ analyzer.analyzeClass(bytes, target.getName());
}
+ return null;
}
};
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/perf/ExecuteInstrumentedCodeScenario.java b/org.jacoco.core.test/src/org/jacoco/core/test/perf/ExecuteInstrumentedCodeScenario.java
index 98afdde6..d78156e1 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/perf/ExecuteInstrumentedCodeScenario.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/perf/ExecuteInstrumentedCodeScenario.java
@@ -11,6 +11,8 @@
*******************************************************************************/
package org.jacoco.core.test.perf;
+import java.util.concurrent.Callable;
+
import org.jacoco.core.instr.Instrumenter;
import org.jacoco.core.runtime.IRuntime;
import org.jacoco.core.runtime.LoggerRuntime;
@@ -24,16 +26,17 @@ import org.objectweb.asm.ClassReader;
*/
public class ExecuteInstrumentedCodeScenario extends TimedScenario {
- private final Class<? extends Runnable> target;
+ private final Class<? extends Callable<Void>> target;
protected ExecuteInstrumentedCodeScenario(String description,
- Class<? extends Runnable> target) {
+ Class<? extends Callable<Void>> target) {
super(description);
this.target = target;
}
@Override
- protected Runnable getInstrumentedRunnable() throws Exception {
+ @SuppressWarnings("unchecked")
+ protected Callable<Void> getInstrumentedCallable() throws Exception {
ClassReader reader = new ClassReader(TargetLoader.getClassData(target));
IRuntime runtime = new LoggerRuntime();
runtime.startup(new RuntimeData());
@@ -41,11 +44,11 @@ public class ExecuteInstrumentedCodeScenario extends TimedScenario {
final byte[] instrumentedBuffer = instr.instrument(reader);
final TargetLoader loader = new TargetLoader(target, instrumentedBuffer);
- return (Runnable) loader.newTargetInstance();
+ return (Callable<Void>) loader.newTargetInstance();
}
@Override
- protected Runnable getReferenceRunnable() throws Exception {
+ protected Callable<Void> getReferenceCallable() throws Exception {
return target.newInstance();
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/perf/InstrumentationTimeScenario.java b/org.jacoco.core.test/src/org/jacoco/core/test/perf/InstrumentationTimeScenario.java
index a5138504..2c171421 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/perf/InstrumentationTimeScenario.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/perf/InstrumentationTimeScenario.java
@@ -11,6 +11,8 @@
*******************************************************************************/
package org.jacoco.core.test.perf;
+import java.util.concurrent.Callable;
+
import org.jacoco.core.instr.Instrumenter;
import org.jacoco.core.runtime.LoggerRuntime;
import org.jacoco.core.test.TargetLoader;
@@ -31,14 +33,15 @@ public class InstrumentationTimeScenario extends TimedScenario {
}
@Override
- protected Runnable getInstrumentedRunnable() throws Exception {
+ protected Callable<Void> getInstrumentedCallable() throws Exception {
final byte[] bytes = TargetLoader.getClassDataAsBytes(target);
final Instrumenter instr = new Instrumenter(new LoggerRuntime());
- return new Runnable() {
- public void run() {
+ return new Callable<Void>() {
+ public Void call() throws Exception {
for (int i = 0; i < count; i++) {
- instr.instrument(bytes);
+ instr.instrument(bytes, "TestTarget");
}
+ return null;
}
};
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/perf/TimedScenario.java b/org.jacoco.core.test/src/org/jacoco/core/test/perf/TimedScenario.java
index 20f5f179..56693ac9 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/perf/TimedScenario.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/perf/TimedScenario.java
@@ -11,6 +11,8 @@
*******************************************************************************/
package org.jacoco.core.test.perf;
+import java.util.concurrent.Callable;
+
/**
* Base class for execution time test scenarios.
*/
@@ -25,8 +27,8 @@ public abstract class TimedScenario implements IPerfScenario {
}
public void run(final IPerfOutput output) throws Exception {
- final long time = getMinimumTime(getInstrumentedRunnable());
- final Runnable refRunnable = getReferenceRunnable();
+ final long time = getMinimumTime(getInstrumentedCallable());
+ final Callable<Void> refRunnable = getReferenceCallable();
final long reftime;
if (refRunnable == null) {
reftime = IPerfOutput.NO_REFERENCE;
@@ -42,8 +44,9 @@ public abstract class TimedScenario implements IPerfScenario {
*
* @param subject
* @return minimum execution time in nano seconds
+ * @throws Exception
*/
- private long getMinimumTime(final Runnable subject) {
+ private long getMinimumTime(final Callable<Void> subject) throws Exception {
long min = Long.MAX_VALUE;
for (int i = 0; i < RUNS; i++) {
final long t = getTime(subject);
@@ -52,15 +55,16 @@ public abstract class TimedScenario implements IPerfScenario {
return min;
}
- private long getTime(final Runnable subject) {
+ private long getTime(final Callable<Void> subject) throws Exception {
long start = System.nanoTime();
- subject.run();
+ subject.call();
return System.nanoTime() - start;
}
- protected abstract Runnable getInstrumentedRunnable() throws Exception;
+ protected abstract Callable<Void> getInstrumentedCallable()
+ throws Exception;
- protected Runnable getReferenceRunnable() throws Exception {
+ protected Callable<Void> getReferenceCallable() throws Exception {
return null;
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target01.java b/org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target01.java
index 521ca831..06de916e 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target01.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target01.java
@@ -11,21 +11,24 @@
*******************************************************************************/
package org.jacoco.core.test.perf.targets;
+import java.util.concurrent.Callable;
+
/**
* Plain method calls.
*/
-public class Target01 implements Runnable {
+public class Target01 implements Callable<Void> {
@SuppressWarnings("unused")
private int c;
// 4 ^ 0 = 1 times
- public void run() {
+ public Void call() throws Exception {
m1();
m1();
m1();
m1();
c++; // some side effect, otherwise the JIT will remove the method
+ return null;
}
// 4 ^ 1 = 4 times
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target02.java b/org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target02.java
index c36946a1..b32d8191 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target02.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target02.java
@@ -11,17 +11,20 @@
*******************************************************************************/
package org.jacoco.core.test.perf.targets;
+import java.util.concurrent.Callable;
+
/**
* Simple Loop.
*/
-public class Target02 implements Runnable {
+public class Target02 implements Callable<Void> {
- public void run() {
+ public Void call() throws Exception {
@SuppressWarnings("unused")
int count = 0;
for (int i = 0; i < 10000000; i++) {
count++;
}
+ return null;
}
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target03.java b/org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target03.java
index 25eac46d..c104e7da 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target03.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/perf/targets/Target03.java
@@ -12,6 +12,7 @@
package org.jacoco.core.test.perf.targets;
import java.util.Random;
+import java.util.concurrent.Callable;
/**
* "Game of Life" implementation as a more reference scenario. Obviously the
@@ -19,7 +20,7 @@ import java.util.Random;
* runner targets one class only. Also one could think about more efficient
* implementations which again is not the focus here.
*/
-public class Target03 implements Runnable {
+public class Target03 implements Callable<Void> {
private final int width;
@@ -130,12 +131,13 @@ public class Target03 implements Runnable {
return sb.toString();
}
- public void run() {
+ public Void call() throws Exception {
clear();
randomFill(123, width * height / 2);
for (int i = 0; i < 20; i++) {
tick();
}
+ return null;
}
// Demo
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java
index 6b6e5c10..6b5d2bfc 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java
@@ -25,6 +25,8 @@ import static org.objectweb.asm.Opcodes.V1_5;
import static org.objectweb.asm.Opcodes.V1_6;
import static org.objectweb.asm.Opcodes.V1_7;
+import java.io.IOException;
+
import org.jacoco.core.instr.Instrumenter;
import org.jacoco.core.runtime.IRuntime;
import org.jacoco.core.runtime.SystemPropertiesRuntime;
@@ -41,46 +43,46 @@ import org.objectweb.asm.Opcodes;
public class ClassFileVersionsTest {
@Test
- public void test_1_1() {
+ public void test_1_1() throws IOException {
testVersion(V1_1, false);
}
@Test
- public void test_1_2() {
+ public void test_1_2() throws IOException {
testVersion(V1_2, false);
}
@Test
- public void test_1_3() {
+ public void test_1_3() throws IOException {
testVersion(V1_3, false);
}
@Test
- public void test_1_4() {
+ public void test_1_4() throws IOException {
testVersion(V1_4, false);
}
@Test
- public void test_1_5() {
+ public void test_1_5() throws IOException {
testVersion(V1_5, false);
}
@Test
- public void test_1_6() {
+ public void test_1_6() throws IOException {
testVersion(V1_6, true);
}
@Test
- public void test_1_7() {
+ public void test_1_7() throws IOException {
testVersion(V1_7, true);
}
- private void testVersion(int version, boolean frames) {
+ private void testVersion(int version, boolean frames) throws IOException {
final byte[] original = createClass(version);
IRuntime runtime = new SystemPropertiesRuntime();
Instrumenter instrumenter = new Instrumenter(runtime);
- byte[] instrumented = instrumenter.instrument(original);
+ byte[] instrumented = instrumenter.instrument(original, "TestTarget");
assertFrames(instrumented, frames);
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/FramesTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/FramesTest.java
index 162ccc52..f5ac4f5e 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/FramesTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/FramesTest.java
@@ -76,7 +76,7 @@ public class FramesTest {
IRuntime runtime = new SystemPropertiesRuntime();
Instrumenter instrumenter = new Instrumenter(runtime);
source = calculateFrames(source);
- byte[] actual = instrumenter.instrument(source);
+ byte[] actual = instrumenter.instrument(source, "TestTarget");
byte[] expected = calculateFrames(actual);
assertEquals(dump(expected), dump(actual));
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java
index f25da1e1..0a55213d 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java
@@ -17,6 +17,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.StringTokenizer;
import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.jacoco.core.data.ExecutionData;
@@ -100,9 +101,18 @@ public class Analyzer {
*
* @param buffer
* class definitions
+ * @param name
+ * a name used for exception messages
+ * @throws IOException
+ * if the class can't be analyzed
*/
- public void analyzeClass(final byte[] buffer) {
- analyzeClass(new ClassReader(buffer));
+ public void analyzeClass(final byte[] buffer, final String name)
+ throws IOException {
+ try {
+ analyzeClass(new ClassReader(buffer));
+ } catch (final RuntimeException cause) {
+ throw analyzerError(name, cause);
+ }
}
/**
@@ -110,27 +120,26 @@ public class Analyzer {
*
* @param input
* stream to read class definition from
+ * @param name
+ * a name used for exception messages
* @throws IOException
- * if the stream can't be read
+ * if the stream can't be read or the class can't be analyzed
*/
- public void analyzeClass(final InputStream input) throws IOException {
- analyzeClass(new ClassReader(input));
+ public void analyzeClass(final InputStream input, final String name)
+ throws IOException {
+ try {
+ analyzeClass(new ClassReader(input));
+ } catch (final RuntimeException e) {
+ throw analyzerError(name, e);
+ }
}
- /**
- * Analyzes all classes contained in the ZIP archive (jar, war, ear, etc.)
- * given as an input stream. Contained archives are read recursively.
- *
- * @param input
- * ZIP archive data
- * @return number of class files found
- * @throws IOException
- * if the stream can't be read
- * @deprecated Use {@link #analyzeAll(InputStream)} instead
- */
- @Deprecated
- public int analyzeArchive(final InputStream input) throws IOException {
- return analyzeZip(input);
+ private IOException analyzerError(final String name,
+ final RuntimeException cause) {
+ final IOException ex = new IOException(String.format(
+ "Error while analyzing class %s.", name));
+ ex.initCause(cause);
+ return ex;
}
/**
@@ -141,22 +150,25 @@ public class Analyzer {
*
* @param input
* input data
+ * @param name
+ * a name used for exception messages
* @return number of class files found
* @throws IOException
- * if the stream can't be read
+ * if the stream can't be read or a class can't be analyzed
*/
- public int analyzeAll(final InputStream input) throws IOException {
+ public int analyzeAll(final InputStream input, final String name)
+ throws IOException {
final ContentTypeDetector detector = new ContentTypeDetector(input);
switch (detector.getType()) {
case ContentTypeDetector.CLASSFILE:
- analyzeClass(detector.getInputStream());
+ analyzeClass(detector.getInputStream(), name);
return 1;
case ContentTypeDetector.ZIPFILE:
- return analyzeZip(detector.getInputStream());
+ return analyzeZip(detector.getInputStream(), name);
case ContentTypeDetector.GZFILE:
- return analyzeGzip(detector.getInputStream());
+ return analyzeGzip(detector.getInputStream(), name);
case ContentTypeDetector.PACK200FILE:
- return analyzePack200(detector.getInputStream());
+ return analyzePack200(detector.getInputStream(), name);
default:
return 0;
}
@@ -171,7 +183,7 @@ public class Analyzer {
* file or folder to look for class files
* @return number of class files found
* @throws IOException
- * if the file can't be read
+ * if the file can't be read or a class can't be analyzed
*/
public int analyzeAll(final File file) throws IOException {
int count = 0;
@@ -182,7 +194,7 @@ public class Analyzer {
} else {
final InputStream in = new FileInputStream(file);
try {
- count += analyzeAll(in);
+ count += analyzeAll(in, file.getPath());
} finally {
in.close();
}
@@ -202,7 +214,7 @@ public class Analyzer {
* entries
* @return number of class files found
* @throws IOException
- * if a file can't be read
+ * if a file can't be read or a class can't be analyzed
*/
public int analyzeAll(final String path, final File basedir)
throws IOException {
@@ -214,21 +226,25 @@ public class Analyzer {
return count;
}
- private int analyzeZip(final InputStream input) throws IOException {
+ private int analyzeZip(final InputStream input, final String name)
+ throws IOException {
final ZipInputStream zip = new ZipInputStream(input);
+ ZipEntry entry;
int count = 0;
- while (zip.getNextEntry() != null) {
- count += analyzeAll(zip);
+ while ((entry = zip.getNextEntry()) != null) {
+ count += analyzeAll(zip, name + "@" + entry.getName());
}
return count;
}
- private int analyzeGzip(final InputStream input) throws IOException {
- return analyzeAll(new GZIPInputStream(input));
+ private int analyzeGzip(final InputStream input, final String name)
+ throws IOException {
+ return analyzeAll(new GZIPInputStream(input), name);
}
- private int analyzePack200(final InputStream input) throws IOException {
- return analyzeAll(Pack200Streams.unpack(input));
+ private int analyzePack200(final InputStream input, final String name)
+ throws IOException {
+ return analyzeAll(Pack200Streams.unpack(input), name);
}
}
diff --git a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java
index 9f7c5158..c4d52669 100644
--- a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java
+++ b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java
@@ -84,11 +84,19 @@ public class Instrumenter {
*
* @param buffer
* definition of the class
+ * @param name
+ * a name used for exception messages
* @return instrumented definition
- *
+ * @throws IOException
+ * if the class can't be analyzed
*/
- public byte[] instrument(final byte[] buffer) {
- return instrument(new ClassReader(buffer));
+ public byte[] instrument(final byte[] buffer, final String name)
+ throws IOException {
+ try {
+ return instrument(new ClassReader(buffer));
+ } catch (final RuntimeException e) {
+ throw instrumentError(name, e);
+ }
}
/**
@@ -96,12 +104,20 @@ public class Instrumenter {
*
* @param input
* stream to read class definition from
+ * @param name
+ * a name used for exception messages
* @return instrumented definition
* @throws IOException
- * if reading data from the stream fails
+ * if reading data from the stream fails or the class can't be
+ * instrumented
*/
- public byte[] instrument(final InputStream input) throws IOException {
- return instrument(new ClassReader(input));
+ public byte[] instrument(final InputStream input, final String name)
+ throws IOException {
+ try {
+ return instrument(new ClassReader(input));
+ } catch (final RuntimeException e) {
+ throw instrumentError(name, e);
+ }
}
/**
@@ -111,32 +127,27 @@ public class Instrumenter {
* stream to read class definition from
* @param output
* stream to write the instrumented version of the class to
+ * @param name
+ * a name used for exception messages
* @throws IOException
- * if reading data from the stream fails
+ * if reading data from the stream fails or the class can't be
+ * instrumented
*/
- public void instrument(final InputStream input, final OutputStream output)
- throws IOException {
- output.write(instrument(new ClassReader(input)));
+ public void instrument(final InputStream input, final OutputStream output,
+ final String name) throws IOException {
+ try {
+ output.write(instrument(new ClassReader(input)));
+ } catch (final RuntimeException e) {
+ throw instrumentError(name, e);
+ }
}
- /**
- * Creates a instrumented version of the given archive, i.e. with all class
- * files contained in this archive instrumented. Contained resources which
- * are no class files or archive files are copied as is.
- *
- * @param input
- * stream to read archive from
- * @param output
- * stream to write the instrumented version of the class to
- * @return number of instrumented classes
- * @throws IOException
- * if reading data from the stream fails
- * @deprecated Use {@link #instrumentAll(InputStream, OutputStream)} instead
- */
- @Deprecated
- public int instrumentArchive(final InputStream input,
- final OutputStream output) throws IOException {
- return instrumentZip(input, output);
+ private IOException instrumentError(final String name,
+ final RuntimeException cause) {
+ final IOException ex = new IOException(String.format(
+ "Error while instrumenting class %s.", name));
+ ex.initCause(cause);
+ return ex;
}
/**
@@ -148,38 +159,41 @@ public class Instrumenter {
* stream to contents from
* @param output
* stream to write the instrumented version of the contents
+ * @param name
+ * a name used for exception messages
* @return number of instrumented classes
* @throws IOException
- * if reading data from the stream fails
+ * if reading data from the stream fails or a class can't be
+ * instrumented
*/
- public int instrumentAll(final InputStream input, final OutputStream output)
- throws IOException {
+ public int instrumentAll(final InputStream input,
+ final OutputStream output, final String name) throws IOException {
final ContentTypeDetector detector = new ContentTypeDetector(input);
switch (detector.getType()) {
case ContentTypeDetector.CLASSFILE:
- instrument(detector.getInputStream(), output);
+ instrument(detector.getInputStream(), output, name);
return 1;
case ContentTypeDetector.ZIPFILE:
- return instrumentZip(detector.getInputStream(), output);
+ return instrumentZip(detector.getInputStream(), output, name);
case ContentTypeDetector.GZFILE:
- return instrumentGzip(detector.getInputStream(), output);
+ return instrumentGzip(detector.getInputStream(), output, name);
case ContentTypeDetector.PACK200FILE:
- return instrumentPack200(detector.getInputStream(), output);
+ return instrumentPack200(detector.getInputStream(), output, name);
default:
copy(detector.getInputStream(), output);
return 0;
}
}
- private int instrumentZip(final InputStream input, final OutputStream output)
- throws IOException {
+ private int instrumentZip(final InputStream input,
+ final OutputStream output, final String name) throws IOException {
final ZipInputStream zipin = new ZipInputStream(input);
final ZipOutputStream zipout = new ZipOutputStream(output);
ZipEntry entry;
int count = 0;
while ((entry = zipin.getNextEntry()) != null) {
zipout.putNextEntry(new ZipEntry(entry.getName()));
- count += instrumentAll(zipin, zipout);
+ count += instrumentAll(zipin, zipout, name + "@" + entry.getName());
zipout.closeEntry();
}
zipout.finish();
@@ -187,17 +201,18 @@ public class Instrumenter {
}
private int instrumentGzip(final InputStream input,
- final OutputStream output) throws IOException {
+ final OutputStream output, final String name) throws IOException {
final GZIPOutputStream gzout = new GZIPOutputStream(output);
- final int count = instrumentAll(new GZIPInputStream(input), gzout);
+ final int count = instrumentAll(new GZIPInputStream(input), gzout, name);
gzout.finish();
return count;
}
private int instrumentPack200(final InputStream input,
- final OutputStream output) throws IOException {
+ final OutputStream output, final String name) throws IOException {
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- final int count = instrumentAll(Pack200Streams.unpack(input), buffer);
+ final int count = instrumentAll(Pack200Streams.unpack(input), buffer,
+ name);
Pack200Streams.pack(buffer.toByteArray(), output);
return count;
}
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index 661f6fc9..9415660c 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -34,10 +34,19 @@
by certain tools like ProGuard (GitHub #85).</li>
</ul>
+<h3>Non-functional Changes</h3>
+<ul>
+ <li>More context information when exceptions occur during analysis or
+ instrumentation (GitHub #104).</li>
+</ul>
+
+
<h3>API Changes</h3>
<ul>
<li>The configuration of the Maven check goal has been reworked to support
checks on any element type (GitHub #106).</li>
+ <li><code>Analyzer</code> and <code>Instrumenter</code> expect resource name
+ as additional parameter for better error messages (GitHub #104).</li>
</ul>
diff --git a/org.jacoco.examples/src/org/jacoco/examples/CoreTutorial.java b/org.jacoco.examples/src/org/jacoco/examples/CoreTutorial.java
index c02f76d1..55fd6cf2 100644
--- a/org.jacoco.examples/src/org/jacoco/examples/CoreTutorial.java
+++ b/org.jacoco.examples/src/org/jacoco/examples/CoreTutorial.java
@@ -119,8 +119,8 @@ public final class CoreTutorial {
// The Instrumenter creates a modified version of our test target class
// that contains additional probes for execution data recording:
final Instrumenter instr = new Instrumenter(runtime);
- final byte[] instrumented = instr
- .instrument(getTargetClass(targetName));
+ final byte[] instrumented = instr.instrument(
+ getTargetClass(targetName), targetName);
// Now we're ready to run our instrumented class and need to startup the
// runtime first:
@@ -148,7 +148,7 @@ public final class CoreTutorial {
// information:
final CoverageBuilder coverageBuilder = new CoverageBuilder();
final Analyzer analyzer = new Analyzer(executionData, coverageBuilder);
- analyzer.analyzeClass(getTargetClass(targetName));
+ analyzer.analyzeClass(getTargetClass(targetName), targetName);
// Let's dump some metrics and line coverage information:
for (final IClassCoverage cc : coverageBuilder.getClasses()) {