aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jacoco-maven-plugin/src/org/jacoco/maven/AbstractAgentMojo.java12
-rw-r--r--org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java12
-rw-r--r--org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java17
-rw-r--r--org.jacoco.ant.test/src/org/jacoco/ant/CoverageTaskTest.xml21
-rw-r--r--org.jacoco.ant.test/src/org/jacoco/ant/DumpExecClassNames.java34
-rw-r--r--org.jacoco.ant.test/src/org/jacoco/ant/InstrumentTaskTest.xml8
-rw-r--r--org.jacoco.ant.test/src/org/jacoco/ant/TestTarget.java4
-rw-r--r--org.jacoco.ant/src/org/jacoco/ant/AbstractCoverageTask.java11
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/runtime/AgentOptionsTest.java31
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java37
-rw-r--r--org.jacoco.doc/docroot/doc/agent.html8
-rw-r--r--org.jacoco.doc/docroot/doc/ant.html8
-rw-r--r--org.jacoco.doc/docroot/doc/changes.html8
13 files changed, 194 insertions, 17 deletions
diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/AbstractAgentMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/AbstractAgentMojo.java
index 4ed00c54..ee38381f 100644
--- a/jacoco-maven-plugin/src/org/jacoco/maven/AbstractAgentMojo.java
+++ b/jacoco-maven-plugin/src/org/jacoco/maven/AbstractAgentMojo.java
@@ -73,6 +73,14 @@ public abstract class AbstractAgentMojo extends AbstractJacocoMojo {
*/
String exclClassLoaders;
/**
+ * Specifies whether also classes from the bootstrap classloader should be
+ * instrumented. Use this feature with caution, it needs heavy
+ * includes/excludes tuning.
+ *
+ * @parameter property="jacoco.includebootstrapclasses"
+ */
+ Boolean includebootstrapclasses;
+ /**
* A session identifier that is written with the execution data. Without
* this parameter a random identifier is created by the agent.
*
@@ -178,6 +186,10 @@ public abstract class AbstractAgentMojo extends AbstractJacocoMojo {
if (exclClassLoaders != null) {
agentOptions.setExclClassloader(exclClassLoaders);
}
+ if (includebootstrapclasses != null) {
+ agentOptions.setIncludeBootstrapClasses(includebootstrapclasses
+ .booleanValue());
+ }
if (sessionId != null) {
agentOptions.setSessionId(sessionId);
}
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 15e3d1a5..09b97aa3 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
@@ -64,9 +64,17 @@ public class CoverageTransformerTest {
}
@Test
- public void testFilterSystemClass() {
+ public void testFilterIncludesBootstrapClassesPositive() {
+ options.setIncludeBootstrapClasses(true);
CoverageTransformer t = createTransformer();
- assertFalse(t.filter(null, "org/example/Foo"));
+ assertTrue(t.filter(null, "java/util/TreeSet"));
+ }
+
+ @Test
+ public void testFilterIncludesBootstrapClassesNegative() {
+ options.setIncludeBootstrapClasses(false);
+ CoverageTransformer t = createTransformer();
+ assertFalse(t.filter(null, "java/util/TreeSet"));
}
@Test
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 78d7b5e5..8b14a237 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
@@ -44,6 +44,8 @@ public class CoverageTransformer implements ClassFileTransformer {
private final ClassFileDumper classFileDumper;
+ private final boolean includeBootstrapClasses;
+
/**
* New transformer with the given delegates.
*
@@ -63,6 +65,7 @@ public class CoverageTransformer implements ClassFileTransformer {
excludes = new WildcardMatcher(toVMName(options.getExcludes()));
exclClassloader = new WildcardMatcher(options.getExclClassloader());
classFileDumper = new ClassFileDumper(options.getClassDumpDir());
+ includeBootstrapClasses = options.getIncludeBootstrapClasses();
}
public byte[] transform(final ClassLoader loader, final String classname,
@@ -102,12 +105,16 @@ public class CoverageTransformer implements ClassFileTransformer {
* @return <code>true</code> if the class should be instrumented
*/
protected boolean filter(final ClassLoader loader, final String classname) {
- // Don't instrument classes of the bootstrap loader:
- return loader != null &&
-
- !classname.startsWith(AGENT_PREFIX) &&
+ if (!includeBootstrapClasses) {
+ if (loader == null) {
+ return false;
+ }
+ if (exclClassloader.matches(loader.getClass().getName())) {
+ return false;
+ }
+ }
- !exclClassloader.matches(loader.getClass().getName()) &&
+ return !classname.startsWith(AGENT_PREFIX) &&
includes.matches(classname) &&
diff --git a/org.jacoco.ant.test/src/org/jacoco/ant/CoverageTaskTest.xml b/org.jacoco.ant.test/src/org/jacoco/ant/CoverageTaskTest.xml
index c6684f13..0afab42a 100644
--- a/org.jacoco.ant.test/src/org/jacoco/ant/CoverageTaskTest.xml
+++ b/org.jacoco.ant.test/src/org/jacoco/ant/CoverageTaskTest.xml
@@ -18,7 +18,7 @@
<target name="setUp">
<tempfile property="temp.dir" prefix="jacocoTest" destdir="${java.io.tmpdir}" />
<mkdir dir="${temp.dir}"/>
- <property name="exec.file" location="${temp.dir}/exec.file" />
+ <property name="exec.file" location="${temp.dir}/jacoco.exec" />
</target>
<target name="tearDown">
@@ -141,5 +141,22 @@
<au:assertLogDoesntContain text="Target executed"/>
</target>
-
+
+ <target name="testIncludeBootstrapClasses">
+ <jacoco:coverage destfile="${exec.file}" includebootstrapclasses="true" includes="java/sql/*">
+ <java classname="org.jacoco.ant.TestTarget" fork="true" failonerror="true">
+ <classpath path="${org.jacoco.ant.coverageTaskTest.classes.dir}"/>
+ </java>
+ </jacoco:coverage>
+
+ <au:assertLogContains text="Enhancing java with coverage"/>
+ <au:assertFileExists file="${exec.file}"/>
+ <au:assertLogContains text="Target executed"/>
+
+ <java classname="org.jacoco.ant.DumpExecClassNames" classpath="${java.class.path}" failonerror="true">
+ <arg value="${exec.file}" />
+ </java>
+ <au:assertLogContains text="java/sql/Timestamp"/>
+ </target>
+
</project> \ No newline at end of file
diff --git a/org.jacoco.ant.test/src/org/jacoco/ant/DumpExecClassNames.java b/org.jacoco.ant.test/src/org/jacoco/ant/DumpExecClassNames.java
new file mode 100644
index 00000000..60133b09
--- /dev/null
+++ b/org.jacoco.ant.test/src/org/jacoco/ant/DumpExecClassNames.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2014 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc R. Hoffmann - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.ant;
+
+import java.io.File;
+
+import org.jacoco.core.data.ExecutionData;
+import org.jacoco.core.tools.ExecFileLoader;
+
+/**
+ * Test utility to dump class names from exec file.
+ */
+public class DumpExecClassNames {
+
+ public static void main(String[] args) throws Exception {
+ final ExecFileLoader loader = new ExecFileLoader();
+ for (String f : args) {
+ loader.load(new File(f));
+ }
+ for (ExecutionData d : loader.getExecutionDataStore().getContents()) {
+ System.out.println(d.getName());
+ }
+ }
+
+}
diff --git a/org.jacoco.ant.test/src/org/jacoco/ant/InstrumentTaskTest.xml b/org.jacoco.ant.test/src/org/jacoco/ant/InstrumentTaskTest.xml
index dbf616d1..345c9db7 100644
--- a/org.jacoco.ant.test/src/org/jacoco/ant/InstrumentTaskTest.xml
+++ b/org.jacoco.ant.test/src/org/jacoco/ant/InstrumentTaskTest.xml
@@ -64,7 +64,7 @@
<jacoco:instrument destdir="${instr.dir}">
<fileset dir="${lib.dir}" includes="*.jar"/>
</jacoco:instrument>
- <au:assertLogContains text="Instrumented 12 classes to ${temp.dir}"/>
+ <au:assertLogContains text="Instrumented 13 classes to ${temp.dir}"/>
<unzip src="${instr.dir}/test.jar" dest="${instr.dir}"/>
<au:assertFileDoesntExist file="${instr.dir}/META-INF/TEST.RSA" />
@@ -85,7 +85,7 @@
<jacoco:instrument destdir="${instr.dir}" removesignatures="false">
<fileset dir="${lib.dir}" includes="*.jar"/>
</jacoco:instrument>
- <au:assertLogContains text="Instrumented 12 classes to ${temp.dir}"/>
+ <au:assertLogContains text="Instrumented 13 classes to ${temp.dir}"/>
<unzip src="${instr.dir}/test.jar" dest="${instr.dir}"/>
<au:assertFileExists file="${instr.dir}/META-INF/TEST.RSA" />
@@ -96,7 +96,7 @@
<jacoco:instrument destdir="${temp.dir}">
<fileset dir="${org.jacoco.ant.instrumentTaskTest.classes.dir}" includes="**/*.class"/>
</jacoco:instrument>
- <au:assertLogContains text="Instrumented 12 classes to ${temp.dir}"/>
+ <au:assertLogContains text="Instrumented 13 classes to ${temp.dir}"/>
<au:assertFileExists file="${temp.dir}/org/jacoco/ant/InstrumentTaskTest.class" />
<echo file="${temp.dir}/jacoco-agent.properties">destfile=test.exec</echo>
@@ -113,7 +113,7 @@
<jacoco:instrument destdir="${temp.dir}">
<fileset dir="${org.jacoco.ant.instrumentTaskTest.classes.dir}" includes="**/*.class"/>
</jacoco:instrument>
- <au:assertLogContains text="Instrumented 12 classes to ${temp.dir}"/>
+ <au:assertLogContains text="Instrumented 13 classes to ${temp.dir}"/>
<au:assertFileExists file="${temp.dir}/org/jacoco/ant/InstrumentTaskTest.class" />
<java classname="org.jacoco.ant.TestTarget" failonerror="true" fork="true">
diff --git a/org.jacoco.ant.test/src/org/jacoco/ant/TestTarget.java b/org.jacoco.ant.test/src/org/jacoco/ant/TestTarget.java
index 5b5023eb..9bc91b67 100644
--- a/org.jacoco.ant.test/src/org/jacoco/ant/TestTarget.java
+++ b/org.jacoco.ant.test/src/org/jacoco/ant/TestTarget.java
@@ -31,6 +31,10 @@ public class TestTarget {
}
public static void main(String[] args) throws Exception {
+
+ // Load some class from the bootstrap classloader:
+ new java.sql.Timestamp(0);
+
System.out.println("Target executed");
// Wait for termination file to turn up
diff --git a/org.jacoco.ant/src/org/jacoco/ant/AbstractCoverageTask.java b/org.jacoco.ant/src/org/jacoco/ant/AbstractCoverageTask.java
index 18ef70c1..8a9cbb70 100644
--- a/org.jacoco.ant/src/org/jacoco/ant/AbstractCoverageTask.java
+++ b/org.jacoco.ant/src/org/jacoco/ant/AbstractCoverageTask.java
@@ -120,6 +120,17 @@ public class AbstractCoverageTask extends Task {
}
/**
+ * Sets whether classes from the bootstrap classloader should be
+ * instrumented.
+ *
+ * @param enabled
+ * <code>true</code> if bootstrap classes should be instrumented
+ */
+ public void setIncludeBootstrapClasses(final boolean enabled) {
+ agentOptions.setIncludeBootstrapClasses(enabled);
+ }
+
+ /**
* Sets the session identifier. Default is a auto-generated id
*
* @param id
diff --git a/org.jacoco.core.test/src/org/jacoco/core/runtime/AgentOptionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/runtime/AgentOptionsTest.java
index e64beaa0..75e7641f 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/runtime/AgentOptionsTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/runtime/AgentOptionsTest.java
@@ -43,6 +43,7 @@ public class AgentOptionsTest {
assertEquals("", options.getExcludes());
assertEquals("sun.reflect.DelegatingClassLoader",
options.getExclClassloader());
+ assertFalse(options.getIncludeBootstrapClasses());
assertNull(options.getSessionId());
assertTrue(options.getDumpOnExit());
assertEquals(AgentOptions.OutputMode.file, options.getOutput());
@@ -74,6 +75,7 @@ public class AgentOptionsTest {
properties.put("includes", "org.*:com.*");
properties.put("excludes", "*Test");
properties.put("exclclassloader", "org.jacoco.test.TestLoader");
+ properties.put("includebootstrapclasses", "true");
properties.put("sessionid", "testsession");
properties.put("dumponexit", "false");
properties.put("output", "tcpserver");
@@ -89,6 +91,7 @@ public class AgentOptionsTest {
assertEquals("org.*:com.*", options.getIncludes());
assertEquals("*Test", options.getExcludes());
assertEquals("org.jacoco.test.TestLoader", options.getExclClassloader());
+ assertTrue(options.getIncludeBootstrapClasses());
assertEquals("testsession", options.getSessionId());
assertFalse(options.getDumpOnExit());
assertEquals(AgentOptions.OutputMode.tcpserver, options.getOutput());
@@ -185,6 +188,34 @@ public class AgentOptionsTest {
}
@Test
+ public void testGetIncludeBootstrapClassesTrue() {
+ AgentOptions options = new AgentOptions("includebootstrapclasses=true");
+ assertTrue(options.getIncludeBootstrapClasses());
+ }
+
+ @Test
+ public void testGetIncludeBootstrapClassesFalse() {
+ AgentOptions options = new AgentOptions("includebootstrapclasses=false");
+ assertFalse(options.getIncludeBootstrapClasses());
+ }
+
+ @Test
+ public void testSetIncludeBootstrapClassesTrue() {
+ AgentOptions options = new AgentOptions();
+ options.setIncludeBootstrapClasses(true);
+ assertTrue(options.getIncludeBootstrapClasses());
+ assertEquals("includebootstrapclasses=true", options.toString());
+ }
+
+ @Test
+ public void testSetIncludeBootstrapClassesFalse() {
+ AgentOptions options = new AgentOptions();
+ options.setIncludeBootstrapClasses(false);
+ assertFalse(options.getIncludeBootstrapClasses());
+ assertEquals("includebootstrapclasses=false", options.toString());
+ }
+
+ @Test
public void testGetSessionId() {
AgentOptions options = new AgentOptions("sessionid=testsession");
assertEquals("testsession", options.getSessionId());
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java b/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java
index f45a35a5..a36fe4fc 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java
@@ -72,6 +72,13 @@ public final class AgentOptions {
public static final String EXCLCLASSLOADER = "exclclassloader";
/**
+ * Specifies whether also classes from the bootstrap classloader should be
+ * instrumented. Use this feature with caution, it needs heavy
+ * includes/excludes tuning. Default is <code>false</code>.
+ */
+ public static final String INCLUDEBOOTSTRAPCLASSES = "includebootstrapclasses";
+
+ /**
* Specifies a session identifier that is written with the execution data.
* Without this parameter a random identifier is created by the agent.
*/
@@ -165,8 +172,9 @@ public final class AgentOptions {
public static final String JMX = "jmx";
private static final Collection<String> VALID_OPTIONS = Arrays.asList(
- DESTFILE, APPEND, INCLUDES, EXCLUDES, EXCLCLASSLOADER, SESSIONID,
- DUMPONEXIT, OUTPUT, ADDRESS, PORT, CLASSDUMPDIR, JMX);
+ DESTFILE, APPEND, INCLUDES, EXCLUDES, EXCLCLASSLOADER,
+ INCLUDEBOOTSTRAPCLASSES, SESSIONID, DUMPONEXIT, OUTPUT, ADDRESS,
+ PORT, CLASSDUMPDIR, JMX);
private final Map<String, String> options;
@@ -335,6 +343,27 @@ public final class AgentOptions {
}
/**
+ * Returns whether classes from the bootstrap classloader should be
+ * instrumented.
+ *
+ * @return <code>true</code> if coverage data will be written on VM exit
+ */
+ public boolean getIncludeBootstrapClasses() {
+ return getOption(INCLUDEBOOTSTRAPCLASSES, false);
+ }
+
+ /**
+ * Sets whether classes from the bootstrap classloader should be
+ * instrumented.
+ *
+ * @param enabled
+ * <code>true</code> if bootstrap classes should be instrumented
+ */
+ public void setIncludeBootstrapClasses(final boolean enabled) {
+ setOption(INCLUDEBOOTSTRAPCLASSES, enabled);
+ }
+
+ /**
* Returns the session identifier.
*
* @return session identifier
@@ -354,7 +383,7 @@ public final class AgentOptions {
}
/**
- * Returns whether coverage data should be dumped on exit
+ * Returns whether coverage data should be dumped on exit.
*
* @return <code>true</code> if coverage data will be written on VM exit
*/
@@ -363,7 +392,7 @@ public final class AgentOptions {
}
/**
- * Sets whether coverage data should be dumped on exit
+ * Sets whether coverage data should be dumped on exit.
*
* @param dumpOnExit
* <code>true</code> if coverage data should be written on VM
diff --git a/org.jacoco.doc/docroot/doc/agent.html b/org.jacoco.doc/docroot/doc/agent.html
index c3dec5f9..5a1628d8 100644
--- a/org.jacoco.doc/docroot/doc/agent.html
+++ b/org.jacoco.doc/docroot/doc/agent.html
@@ -117,6 +117,14 @@
<td><code>sun.reflect.DelegatingClassLoader</code></td>
</tr>
<tr>
+ <td><code>includebootstrapclasses</code></td>
+ <td>Specifies whether also classes from the bootstrap classloader should
+ be instrumented. Use this feature with caution, it needs heavy
+ includes/excludes tuning.
+ </td>
+ <td><code>false</code></td>
+ </tr>
+ <tr>
<td><code>sessionid</code></td>
<td>A session identifier that is written with the execution data. Without
this parameter a random identifier is created by the agent.
diff --git a/org.jacoco.doc/docroot/doc/ant.html b/org.jacoco.doc/docroot/doc/ant.html
index 7400b7d5..aac3473f 100644
--- a/org.jacoco.doc/docroot/doc/ant.html
+++ b/org.jacoco.doc/docroot/doc/ant.html
@@ -205,6 +205,14 @@
<td><code>sun.reflect.DelegatingClassLoader</code></td>
</tr>
<tr>
+ <td><code>includebootstrapclasses</code></td>
+ <td>Specifies whether also classes from the bootstrap classloader should
+ be instrumented. Use this feature with caution, it needs heavy
+ includes/excludes tuning.
+ </td>
+ <td><code>false</code></td>
+ </tr>
+ <tr>
<td><code>sessionid</code></td>
<td>A session identifier that is written with the execution data. Without
this parameter a random identifier is created by the agent.
diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
index 51679b67..9d5209ac 100644
--- a/org.jacoco.doc/docroot/doc/changes.html
+++ b/org.jacoco.doc/docroot/doc/changes.html
@@ -20,6 +20,14 @@
<h2>Snapshot Build @qualified.bundle.version@ (@build.date@)</h2>
+<h3>New Features</h3>
+<ul>
+ <li>New configuration option for the JaCoCo agent
+ <code>includebootstrapclasses</code> to also instrument classes from the
+ bootstrap class loader.
+ (GitHub <a href="https://github.com/jacoco/jacoco/issues/49">#49</a>).</li>
+</ul>
+
<h2>Release 0.7.1 (2014/05/08)</h2>
<h3>Fixed Bugs</h3>