From 8685ca83dd562f3df9d2c8221ed5b928b36ebf62 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 3 Jan 2018 23:52:02 +0100 Subject: Prepare for next development iteration --- jacoco-maven-plugin.test/pom.xml | 2 +- jacoco-maven-plugin/pom.xml | 2 +- jacoco/pom.xml | 2 +- org.jacoco.agent.rt.test/pom.xml | 2 +- org.jacoco.agent.rt/pom.xml | 2 +- org.jacoco.agent.test/pom.xml | 2 +- org.jacoco.agent/pom.xml | 2 +- org.jacoco.ant.test/pom.xml | 2 +- org.jacoco.ant/pom.xml | 2 +- org.jacoco.build/pom.xml | 2 +- org.jacoco.cli.test/pom.xml | 2 +- org.jacoco.cli/pom.xml | 2 +- org.jacoco.core.test/pom.xml | 2 +- org.jacoco.core/pom.xml | 2 +- org.jacoco.doc/docroot/doc/changes.html | 2 ++ org.jacoco.doc/pom.xml | 2 +- org.jacoco.examples.test/pom.xml | 2 +- org.jacoco.examples/pom.xml | 2 +- org.jacoco.report.test/pom.xml | 2 +- org.jacoco.report/pom.xml | 2 +- org.jacoco.tests/pom.xml | 2 +- pom.xml | 2 +- 22 files changed, 23 insertions(+), 21 deletions(-) diff --git a/jacoco-maven-plugin.test/pom.xml b/jacoco-maven-plugin.test/pom.xml index e114caaa..8b7d72ad 100644 --- a/jacoco-maven-plugin.test/pom.xml +++ b/jacoco-maven-plugin.test/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.tests - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.tests diff --git a/jacoco-maven-plugin/pom.xml b/jacoco-maven-plugin/pom.xml index 52aedbd7..0695eb2a 100644 --- a/jacoco-maven-plugin/pom.xml +++ b/jacoco-maven-plugin/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.build - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.build diff --git a/jacoco/pom.xml b/jacoco/pom.xml index e01371c6..14d65663 100644 --- a/jacoco/pom.xml +++ b/jacoco/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.agent.rt.test/pom.xml b/org.jacoco.agent.rt.test/pom.xml index a14609d1..7d81fd67 100644 --- a/org.jacoco.agent.rt.test/pom.xml +++ b/org.jacoco.agent.rt.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.agent.rt/pom.xml b/org.jacoco.agent.rt/pom.xml index 7ef658d9..600a3e93 100644 --- a/org.jacoco.agent.rt/pom.xml +++ b/org.jacoco.agent.rt/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.agent.test/pom.xml b/org.jacoco.agent.test/pom.xml index ab6291e5..4a09e496 100644 --- a/org.jacoco.agent.test/pom.xml +++ b/org.jacoco.agent.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.agent/pom.xml b/org.jacoco.agent/pom.xml index 07c70d89..22235114 100644 --- a/org.jacoco.agent/pom.xml +++ b/org.jacoco.agent/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.ant.test/pom.xml b/org.jacoco.ant.test/pom.xml index 2284a2f8..d1063789 100644 --- a/org.jacoco.ant.test/pom.xml +++ b/org.jacoco.ant.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.ant/pom.xml b/org.jacoco.ant/pom.xml index efec69bc..88c2e5a0 100644 --- a/org.jacoco.ant/pom.xml +++ b/org.jacoco.ant/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index b4d3e00a..d5f911e4 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -14,7 +14,7 @@ org.jacoco org.jacoco.build - 0.8.0 + 0.8.1-SNAPSHOT pom JaCoCo diff --git a/org.jacoco.cli.test/pom.xml b/org.jacoco.cli.test/pom.xml index 7372fe12..7c0512db 100644 --- a/org.jacoco.cli.test/pom.xml +++ b/org.jacoco.cli.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.cli/pom.xml b/org.jacoco.cli/pom.xml index 203eb476..ae2e0385 100644 --- a/org.jacoco.cli/pom.xml +++ b/org.jacoco.cli/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.core.test/pom.xml b/org.jacoco.core.test/pom.xml index 4a6f5add..3e99fc69 100644 --- a/org.jacoco.core.test/pom.xml +++ b/org.jacoco.core.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.core/pom.xml b/org.jacoco.core/pom.xml index d147c113..0471ca43 100644 --- a/org.jacoco.core/pom.xml +++ b/org.jacoco.core/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 37c93725..352e2d7f 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -18,6 +18,8 @@

Change History

+

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

+

Release 0.8.0 (2018/01/02)

New Features

diff --git a/org.jacoco.doc/pom.xml b/org.jacoco.doc/pom.xml index b866ad11..b9b0e76a 100644 --- a/org.jacoco.doc/pom.xml +++ b/org.jacoco.doc/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.examples.test/pom.xml b/org.jacoco.examples.test/pom.xml index 7605ff3f..f274f575 100644 --- a/org.jacoco.examples.test/pom.xml +++ b/org.jacoco.examples.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.examples/pom.xml b/org.jacoco.examples/pom.xml index 64fd7aa1..4adb9ed5 100644 --- a/org.jacoco.examples/pom.xml +++ b/org.jacoco.examples/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.report.test/pom.xml b/org.jacoco.report.test/pom.xml index 753267d6..7754b5b3 100644 --- a/org.jacoco.report.test/pom.xml +++ b/org.jacoco.report.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.report/pom.xml b/org.jacoco.report/pom.xml index 30f5ba5e..e182c439 100644 --- a/org.jacoco.report/pom.xml +++ b/org.jacoco.report/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.tests/pom.xml b/org.jacoco.tests/pom.xml index ae07b4b9..6e899092 100644 --- a/org.jacoco.tests/pom.xml +++ b/org.jacoco.tests/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.build - 0.8.0 + 0.8.1-SNAPSHOT ../org.jacoco.build diff --git a/pom.xml b/pom.xml index 129c95a8..5e92d25a 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.jacoco root - 0.8.0 + 0.8.1-SNAPSHOT pom -- cgit v1.2.3 From 2760d8db8006fe7731ca72ca21f0da5a671553b2 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sat, 3 Feb 2018 09:09:35 +0100 Subject: Simplify conditions that use "java.version" property in tests (#644) * Simplify conditions that use "java.version" property in tests * Add method `isBefore` --- .../core/test/filter/TryWithResourcesTest.java | 16 ++---- .../test/validation/BadCycleInterfaceTest.java | 7 +-- .../org/jacoco/core/test/filter/FinallyTest.java | 16 ++---- .../jacoco/core/test/validation/JavaVersion.java | 66 ++++++++++++++++++++++ .../core/test/validation/JavaVersionTest.java | 61 ++++++++++++++++++++ .../core/test/validation/ValidationTestBase.java | 3 + 6 files changed, 141 insertions(+), 28 deletions(-) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/JavaVersion.java create mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/JavaVersionTest.java diff --git a/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/TryWithResourcesTest.java b/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/TryWithResourcesTest.java index 3e4dbd8a..ddafd69b 100644 --- a/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/TryWithResourcesTest.java +++ b/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/TryWithResourcesTest.java @@ -16,9 +16,6 @@ import org.jacoco.core.test.filter.targets.TryWithResources; import org.jacoco.core.test.validation.ValidationTestBase; import org.junit.Test; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** * Test of filtering of a bytecode that is generated for a try-with-resources * statement. @@ -79,11 +76,7 @@ public class TryWithResourcesTest extends ValidationTestBase { if (isJDKCompiler) { // https://bugs.openjdk.java.net/browse/JDK-8134759 // javac 7 and 8 up to 8u92 are affected - final String jdkVersion = System.getProperty("java.version"); - final Matcher m = Pattern.compile("1\\.8\\.0_(\\d++)(-ea)?") - .matcher(jdkVersion); - if (jdkVersion.startsWith("1.7.0_") - || (m.matches() && Integer.parseInt(m.group(1)) < 92)) { + if (JAVA_VERSION.isBefore("1.8.0_92")) { assertLine("returnInBody.close", ICounter.FULLY_COVERED, 0, 0); } else { assertLine("returnInBody.close", ICounter.EMPTY); @@ -163,12 +156,11 @@ public class TryWithResourcesTest extends ValidationTestBase { assertLine("empty.open", ICounter.FULLY_COVERED); // empty when EJC: if (isJDKCompiler) { - final String jdkVersion = System.getProperty("java.version"); - if (jdkVersion.startsWith("9") || jdkVersion.startsWith("10")) { - assertLine("empty.close", ICounter.FULLY_COVERED, 0, 0); - } else { + if (JAVA_VERSION.isBefore("9")) { // branches with javac 7 and 8 assertLine("empty.close", ICounter.PARTLY_COVERED); + } else { + assertLine("empty.close", ICounter.FULLY_COVERED, 0, 0); } } } diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BadCycleInterfaceTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BadCycleInterfaceTest.java index ae38ce5e..fdd7e001 100644 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BadCycleInterfaceTest.java +++ b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BadCycleInterfaceTest.java @@ -15,9 +15,6 @@ import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.targets.BadCycleInterface; import org.junit.Test; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** * Test of "bad cycles" with interfaces. */ @@ -29,9 +26,7 @@ public class BadCycleInterfaceTest extends ValidationTestBase { @Test public void test() throws Exception { - final Matcher m = Pattern.compile("1\\.8\\.0_(\\d++)(-ea)?") - .matcher(System.getProperty("java.version")); - if (m.matches() && Integer.parseInt(m.group(1)) < 152) { + if (JAVA_VERSION.isBefore("1.8.0_152")) { // Incorrect interpetation of JVMS 5.5 in JDK 8 causes a default // method to be called before the static initializer of an interface // (see JDK-8098557 and JDK-8164302): diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java index 758bec3c..a72e7f4d 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java @@ -16,7 +16,6 @@ import static org.junit.Assert.assertEquals; import java.io.IOException; import java.util.HashSet; import java.util.Set; -import java.util.regex.Pattern; import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.TargetLoader; @@ -36,9 +35,6 @@ import org.objectweb.asm.tree.MethodNode; */ public class FinallyTest extends ValidationTestBase { - private static boolean isJDK8 = !Pattern.compile("1\\.[567]\\.0_(\\d++)") - .matcher(System.getProperty("java.version")).matches(); - public FinallyTest() { super(Finally.class); } @@ -109,7 +105,7 @@ public class FinallyTest extends ValidationTestBase { @Test public void twoRegions() { assertLine("twoRegions.0", ICounter.EMPTY); - if (isJDKCompiler && !isJDK8) { + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { // https://bugs.openjdk.java.net/browse/JDK-7008643 assertLine("twoRegions.1", ICounter.PARTLY_COVERED); assertLine("twoRegions.return.1", ICounter.EMPTY); @@ -152,13 +148,13 @@ public class FinallyTest extends ValidationTestBase { @Test public void emptyTry() { assertLine("emptyTry.0", ICounter.EMPTY); - if (!isJDKCompiler || isJDK8) { - assertLine("emptyTry.1", ICounter.FULLY_COVERED); - assertLine("emptyTry.2", ICounter.EMPTY); - } else { + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { // compiler bug fixed in javac >= 1.8: assertLine("emptyTry.1", ICounter.PARTLY_COVERED); assertLine("emptyTry.2", ICounter.FULLY_COVERED); + } else { + assertLine("emptyTry.1", ICounter.FULLY_COVERED); + assertLine("emptyTry.2", ICounter.EMPTY); } } @@ -252,7 +248,7 @@ public class FinallyTest extends ValidationTestBase { expected.add("nested.3"); } - if (isJDKCompiler && !isJDK8) { + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { expected.add("emptyTry.2"); } diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/JavaVersion.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/JavaVersion.java new file mode 100644 index 00000000..8c6d261d --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/JavaVersion.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +/** + * Parsed value of "java.version" system property. + */ +public final class JavaVersion { + + private final int feature; + + private final int update; + + /** + * @param javaVersionPropertyValue + * value of "java.version" property + * @see System#getProperties() description of properties + */ + JavaVersion(final String javaVersionPropertyValue) { + final String[] s = javaVersionPropertyValue.split("[._-]"); + if ("1".equals(s[0])) { + this.feature = Integer.parseInt(s[1]); + this.update = s.length > 3 ? Integer.parseInt(s[3]) : 0; + } else { + this.feature = Integer.parseInt(s[0]); + this.update = s.length > 2 ? Integer.parseInt(s[2]) : 0; + } + } + + /** + * @return value of feature-release counter, for example: 8 for version + * "1.8.0_152" and 9 for version "9.0.1" + */ + int feature() { + return feature; + } + + /** + * @return value of update-release counter, for example: 152 for version + * "1.8.0_152" and 1 for version "9.0.1" + */ + int update() { + return update; + } + + /** + * @param version + * version to compare with + * @return true if this version is less than given + */ + public boolean isBefore(final String version) { + final JavaVersion other = new JavaVersion(version); + return this.feature < other.feature || (this.feature == other.feature + && this.update < other.update); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/JavaVersionTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/JavaVersionTest.java new file mode 100644 index 00000000..f5ef5c73 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/JavaVersionTest.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class JavaVersionTest { + + @Test + public void should_parse_values_of_java_version_property() { + JavaVersion v; + + v = new JavaVersion("1.8.0_162"); + assertEquals(8, v.feature()); + assertEquals(162, v.update()); + + v = new JavaVersion("1.8.0_172-ea"); + assertEquals(8, v.feature()); + assertEquals(172, v.update()); + + v = new JavaVersion("9"); + assertEquals(9, v.feature()); + assertEquals(0, v.update()); + + v = new JavaVersion("9.0.1"); + assertEquals(9, v.feature()); + assertEquals(1, v.update()); + + v = new JavaVersion("10-ea"); + assertEquals(10, v.feature()); + assertEquals(0, v.update()); + } + + @Test + public void should_compare_with_given_version() { + assertTrue(new JavaVersion("1.7.0_80").isBefore("1.8.0_92")); + + assertTrue(new JavaVersion("1.8.0_31").isBefore("1.8.0_92")); + + assertFalse(new JavaVersion("1.8.0_92").isBefore("1.8.0_92")); + + assertFalse(new JavaVersion("1.8.0_162").isBefore("1.8.0_92")); + assertFalse(new JavaVersion("1.8.0_162").isBefore("1.8")); + + assertFalse(new JavaVersion("9.0.1").isBefore("1.8.0_92")); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java index d7a2fd0b..6ab58594 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java @@ -39,6 +39,9 @@ public abstract class ValidationTestBase { protected static final boolean isJDKCompiler = Compiler.DETECT.isJDK(); + protected static final JavaVersion JAVA_VERSION = new JavaVersion( + System.getProperty("java.version")); + private static final String[] STATUS_NAME = new String[4]; { -- cgit v1.2.3 From 45a2508db39326a51460032c4bce79877cbf3dbc Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 5 Feb 2018 21:50:29 +0100 Subject: Adjust test to reflect fix of JDK-8180141 in JDK 10 (#646) --- .../src/org/jacoco/core/test/filter/FinallyTest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java index a72e7f4d..0f44588e 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java @@ -220,7 +220,12 @@ public class FinallyTest extends ValidationTestBase { expected.add("breakStatement.for"); if (isJDKCompiler) { - expected.add("breakStatement.1"); + if (JAVA_VERSION.isBefore("10")) { + // https://bugs.openjdk.java.net/browse/JDK-8180141 + expected.add("breakStatement.1"); + } else { + expected.add("breakStatement"); + } expected.add("breakStatement.2"); } else { expected.add("breakStatement"); -- cgit v1.2.3 From 65595d05530621a240fc7511a041e2f3909057ed Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sun, 11 Feb 2018 03:56:18 +0100 Subject: Fix comment maven-shade-plugin and maven-plugin-plugin were updated to versions that can process Java 9 bytecode in commits caa820ed62133f47bacba06ea931bf5d7c43dcd6 and 05a2aa7d21928aad802fe9586e0dbee4026eac2f respectively. However currently used version of maven-bundle-plugin cannot process Java 9 bytecode. --- org.jacoco.build/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index d5f911e4..46536814 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -735,7 +735,7 @@ 1.8 -- cgit v1.2.3 From 06e8f36dee7bd3f19efa91b486af78eb4d375b46 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 12 Feb 2018 13:45:50 +0100 Subject: Add filter for empty constructor without parameters in enum (#649) --- .../filter/EnumEmptyConstructorFilterTest.java | 151 +++++++++++++++++++++ .../core/test/filter/EnumConstructorTest.java | 62 +++++++++ .../core/test/filter/targets/EnumConstructor.java | 49 +++++++ .../internal/analysis/filter/AbstractMatcher.java | 32 ++++- .../filter/EnumEmptyConstructorFilter.java | 59 ++++++++ .../core/internal/analysis/filter/Filters.java | 2 +- .../filter/PrivateEmptyNoArgConstructorFilter.java | 27 ++-- org.jacoco.doc/docroot/doc/changes.html | 7 + 8 files changed, 369 insertions(+), 20 deletions(-) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java create mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumConstructorTest.java create mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumConstructor.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java new file mode 100644 index 00000000..a2216546 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +public class EnumEmptyConstructorFilterTest implements IFilterOutput { + + private final EnumEmptyConstructorFilter filter = new EnumEmptyConstructorFilter(); + + private AbstractInsnNode fromInclusive; + private AbstractInsnNode toInclusive; + + @Test + public void should_filter() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, + Opcodes.ACC_PRIVATE, "", "(Ljava/lang/String;I)V", null, + null); + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitVarInsn(Opcodes.ILOAD, 2); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Enum", "", + "(Ljava/lang/String;I)V", false); + m.visitInsn(Opcodes.RETURN); + + filter.filter("Foo", "java/lang/Enum", m, this); + + assertEquals(m.instructions.getFirst(), fromInclusive); + assertEquals(m.instructions.getLast(), toInclusive); + } + + /** + *
+	 * enum E {
+	 *   ;
+	 *   private E() {
+	 *     ...
+	 *   }
+	 * }
+	 * 
+ */ + @Test + public void should_not_filter_non_empty_constructor() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, + Opcodes.ACC_PRIVATE, "", "(Ljava/lang/String;I)V", null, + null); + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitVarInsn(Opcodes.ILOAD, 2); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Enum", "", + "(Ljava/lang/String;I)V", false); + m.visitInsn(Opcodes.NOP); + m.visitInsn(Opcodes.RETURN); + + filter.filter("Foo", "java/lang/Enum", m, this); + + assertNull(fromInclusive); + assertNull(toInclusive); + } + + /** + *
+	 * enum E {
+	 *   ;
+	 *   private E(long p) {
+	 *   }
+	 * }
+	 * 
+ */ + @Test + public void should_not_filter_constructor_with_additional_parameters() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, + Opcodes.ACC_PRIVATE, "", "(Ljava/lang/String;IJ)V", null, + null); + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitVarInsn(Opcodes.ILOAD, 2); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Enum", "", + "(Ljava/lang/String;I)V", false); + m.visitInsn(Opcodes.RETURN); + + filter.filter("Foo", "java/lang/Enum", m, this); + + assertNull(fromInclusive); + assertNull(toInclusive); + } + + /** + *
+	 * enum E {
+	 *   ;
+	 *   private void method(String p1, int p2) {
+	 *   }
+	 * }
+	 * 
+ */ + @Test + public void should_not_filter_non_constructor() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, + Opcodes.ACC_PRIVATE, "method", "(Ljava/lang/String;I)V", null, + null); + m.visitInsn(Opcodes.NOP); + + filter.filter("Foo", "java/lang/Enum", m, this); + + assertNull(fromInclusive); + assertNull(toInclusive); + } + + @Test + public void should_not_filter_non_Enum() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, + Opcodes.ACC_PRIVATE, "", "(Ljava/lang/String;I)V", null, + null); + m.visitInsn(Opcodes.NOP); + + filter.filter("Foo", "java/lang/Object", m, this); + + assertNull(fromInclusive); + assertNull(toInclusive); + } + + public void ignore(AbstractInsnNode fromInclusive, + AbstractInsnNode toInclusive) { + assertNull(this.fromInclusive); + this.fromInclusive = fromInclusive; + this.toInclusive = toInclusive; + } + + public void merge(AbstractInsnNode i1, AbstractInsnNode i2) { + fail(); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumConstructorTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumConstructorTest.java new file mode 100644 index 00000000..fd88787b --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumConstructorTest.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.filter.targets.EnumConstructor; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.junit.Test; + +/** + * Test of filtering of enum constructors. + */ +public class EnumConstructorTest extends ValidationTestBase { + + public EnumConstructorTest() { + super(EnumConstructor.class); + } + + /** + * {@link EnumConstructor.ImplicitConstructor} + */ + @Test + public void implicit_constructor_should_be_filtered() { + // without filter next line is partly covered: + assertLine("implicitConstructor", ICounter.FULLY_COVERED); + } + + /** + * {@link EnumConstructor.ExplicitNonEmptyConstructor#ExplicitNonEmptyConstructor()} + */ + @Test + public void explicit_non_empty_constructor_should_not_be_filtered() { + assertLine("explicitNonEmptyConstructor", ICounter.NOT_COVERED); + } + + /** + * {@link EnumConstructor.ExplicitEmptyConstructor#ExplicitEmptyConstructor()} + */ + @Test + public void explicit_empty_constructor_should_be_filtered() { + // without filter next line is not covered: + assertLine("explicitEmptyConstructor", ICounter.EMPTY); + } + + /** + * {@link EnumConstructor.ExplicitEmptyConstructor#ExplicitEmptyConstructor(Object)} + */ + @Test + public void explicit_empty_constructor_with_parameters_should_not_be_filtered() { + assertLine("explicitEmptyConstructorWithParameter", ICounter.NOT_COVERED); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumConstructor.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumConstructor.java new file mode 100644 index 00000000..c6eb1c53 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumConstructor.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target is an enum constructor. + */ +public class EnumConstructor { + + private enum ImplicitConstructor { // $line-implicitConstructor$ + } + + private enum ExplicitNonEmptyConstructor { + ; + + ExplicitNonEmptyConstructor() { + nop(); // $line-explicitNonEmptyConstructor$ + } + } + + @SuppressWarnings("unused") + private enum ExplicitEmptyConstructor { + ; + + ExplicitEmptyConstructor() { + } // $line-explicitEmptyConstructor$ + + ExplicitEmptyConstructor(Object p) { + } // $line-explicitEmptyConstructorWithParameter$ + } + + public static void main(String[] args) { + ImplicitConstructor.values(); + ExplicitEmptyConstructor.values(); + ExplicitNonEmptyConstructor.values(); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java index b5aea723..fcd1c888 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java @@ -17,6 +17,7 @@ import java.util.Map; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; abstract class AbstractMatcher { @@ -25,6 +26,35 @@ abstract class AbstractMatcher { AbstractInsnNode cursor; + /** + * Sets {@link #cursor} to first instruction of method if it is + * ALOAD 0, otherwise sets it to null. + */ + final void firstIsALoad0(final MethodNode methodNode) { + cursor = methodNode.instructions.getFirst(); + skipNonOpcodes(); + if (cursor.getOpcode() == Opcodes.ALOAD + && ((VarInsnNode) cursor).var == 0) { + return; + } + cursor = null; + } + + /** + * Moves {@link #cursor} to next instruction if it is + * INVOKESPECIAL <init> with given owner and descriptor, + * otherwise sets it to null. + */ + final void nextIsInvokeSuper(final String owner, final String desc) { + nextIs(Opcodes.INVOKESPECIAL); + MethodInsnNode m = (MethodInsnNode) cursor; + if (m != null && owner.equals(m.owner) && "".equals(m.name) + && desc.equals(m.desc)) { + return; + } + cursor = null; + } + final void nextIsInvokeVirtual(final String owner, final String name) { nextIs(Opcodes.INVOKEVIRTUAL); if (cursor == null) { @@ -76,7 +106,7 @@ abstract class AbstractMatcher { skipNonOpcodes(); } - final void skipNonOpcodes() { + private void skipNonOpcodes() { while (cursor != null && (cursor.getType() == AbstractInsnNode.FRAME || cursor.getType() == AbstractInsnNode.LABEL || cursor.getType() == AbstractInsnNode.LINE)) { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java new file mode 100644 index 00000000..9bdc5077 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.MethodNode; + +/** + * Filters empty enum constructors. + * + * Constructor of enum is invoked from static initialization block to create + * instance of each enum constant. So it won't be executed if number of enum + * constants is zero. Such enums are sometimes used as alternative to classes + * with static utilities and private empty constructor. Implicit constructor of + * enum created by compiler doesn't have a synthetic flag and refers to a line + * of enum definition. Therefore in order to not have partial coverage of enum + * definition line in enums without enum constants and similarly to + * {@link PrivateEmptyNoArgConstructorFilter filter of private empty + * constructors} - empty constructor in enums without additional parameters + * should be filtered out even if it is not implicit. + */ +public final class EnumEmptyConstructorFilter implements IFilter { + + private static final String CONSTRUCTOR_NAME = ""; + private static final String CONSTRUCTOR_DESC = "(Ljava/lang/String;I)V"; + + public void filter(String className, String superClassName, + MethodNode methodNode, IFilterOutput output) { + if ("java/lang/Enum".equals(superClassName) + && CONSTRUCTOR_NAME.equals(methodNode.name) + && CONSTRUCTOR_DESC.equals(methodNode.desc) + && new Matcher().match(methodNode, superClassName)) { + output.ignore(methodNode.instructions.getFirst(), + methodNode.instructions.getLast()); + } + } + + private static class Matcher extends AbstractMatcher { + private boolean match(final MethodNode methodNode, + final String superClassName) { + firstIsALoad0(methodNode); + nextIs(Opcodes.ALOAD); + nextIs(Opcodes.ILOAD); + nextIsInvokeSuper(superClassName, CONSTRUCTOR_DESC); + nextIs(Opcodes.RETURN); + return cursor != null; + } + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index 0f344180..40c0dfc3 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -31,7 +31,7 @@ public final class Filters implements IFilter { new TryWithResourcesJavacFilter(), new TryWithResourcesEcjFilter(), new FinallyFilter(), new PrivateEmptyNoArgConstructorFilter(), new StringSwitchJavacFilter(), new LombokGeneratedFilter(), - new GroovyGeneratedFilter()); + new GroovyGeneratedFilter(), new EnumEmptyConstructorFilter()); private final IFilter[] filters; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java index 08c654e3..29214c5b 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java @@ -12,20 +12,21 @@ package org.jacoco.core.internal.analysis.filter; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.objectweb.asm.tree.VarInsnNode; /** * Filters private empty constructors that do not have arguments. */ public final class PrivateEmptyNoArgConstructorFilter implements IFilter { + private static final String CONSTRUCTOR_NAME = ""; + private static final String CONSTRUCTOR_DESC = "()V"; + public void filter(final String className, final String superClassName, final MethodNode methodNode, final IFilterOutput output) { if ((methodNode.access & Opcodes.ACC_PRIVATE) != 0 - && "".equals(methodNode.name) - && "()V".equals(methodNode.desc) + && CONSTRUCTOR_NAME.equals(methodNode.name) + && CONSTRUCTOR_DESC.equals(methodNode.desc) && new Matcher().match(methodNode, superClassName)) { output.ignore(methodNode.instructions.getFirst(), methodNode.instructions.getLast()); @@ -35,20 +36,10 @@ public final class PrivateEmptyNoArgConstructorFilter implements IFilter { private static class Matcher extends AbstractMatcher { private boolean match(final MethodNode methodNode, final String superClassName) { - cursor = methodNode.instructions.getFirst(); - skipNonOpcodes(); - if (cursor.getOpcode() != Opcodes.ALOAD - || ((VarInsnNode) cursor).var != 0) { - return false; - } - nextIs(Opcodes.INVOKESPECIAL); - MethodInsnNode m = (MethodInsnNode) cursor; - if (m != null && superClassName.equals(m.owner) - && "".equals(m.name) && ("()V").equals(m.desc)) { - nextIs(Opcodes.RETURN); - return cursor != null; - } - return false; + firstIsALoad0(methodNode); + nextIsInvokeSuper(superClassName, CONSTRUCTOR_DESC); + nextIs(Opcodes.RETURN); + return cursor != null; } } diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 352e2d7f..eebd90f7 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -20,6 +20,13 @@

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

+

New Features

+
    +
  • Empty constructor without parameters in enum is filtered out during + generation of report + (GitHub #649).
  • +
+

Release 0.8.0 (2018/01/02)

New Features

-- cgit v1.2.3 From 3de67428286f4d984aa10246b28cf54594a0f713 Mon Sep 17 00:00:00 2001 From: "Marc R. Hoffmann" Date: Thu, 15 Feb 2018 01:11:57 +0100 Subject: Add FAQ entry about release dates (#602) --- org.jacoco.doc/docroot/doc/faq.html | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/org.jacoco.doc/docroot/doc/faq.html b/org.jacoco.doc/docroot/doc/faq.html index 8eb14e46..adfa66dc 100644 --- a/org.jacoco.doc/docroot/doc/faq.html +++ b/org.jacoco.doc/docroot/doc/faq.html @@ -23,6 +23,20 @@ before.

+

When will feature X be released?

+

+ JaCoCo is maintained by volunteers in their free time. Since we cannot + guarantee free capacity, we do not commit to particular release dates. + Typically, you can expect a couple of releases every year. +

+

+ In the change log, you can see all features + that have been been implemented in master branch and will be available + with the next release. And in the meantime you can test latest build of + of master branch (Maven SNAPSHOT) and provide + feedback to us. +

+

Does JaCoCo have a plug-in for [Eclipse|Netbeans|Whatever...]?

See this list for current integrations with -- cgit v1.2.3 From 04e13929cff687d829c7704e345ccabb85ee6723 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Tue, 20 Mar 2018 14:31:33 +0100 Subject: Add test of ASM bug 317815 (#662) Because of this bug we can't use ASM 6.1 --- .../validation/AnnotationOnLocalVariableTest.java | 35 +++++++++++++++++++ .../targets/AnnotationOnLocalVariableTarget.java | 40 ++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java create mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java new file mode 100644 index 00000000..64720491 --- /dev/null +++ b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.AnnotationOnLocalVariableTarget; +import org.junit.Test; + +/** + * Test of ASM bug + * #317815 + */ +public class AnnotationOnLocalVariableTest extends ValidationTestBase { + + public AnnotationOnLocalVariableTest() { + super("src-java8", AnnotationOnLocalVariableTarget.class); + } + + @Test + public void testCoverageResult() { + + assertLine("var", ICounter.FULLY_COVERED); + + } + +} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java new file mode 100644 index 00000000..3417c098 --- /dev/null +++ b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.targets; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This test target contains annotation on local variable. + */ +public class AnnotationOnLocalVariableTarget { + + @Documented + @Retention(RetentionPolicy.CLASS) + @Target(ElementType.TYPE_USE) + @interface NonNull { + } + + private static Object legacy() { + return new Object(); + } + + public static void main(String[] args) { + @NonNull + Object o = legacy(); // $line-var$ + } + +} -- cgit v1.2.3 From e0681662b4cc311bca7e9433261960c766fab8a8 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 21 Mar 2018 05:23:26 +0100 Subject: Add Java 10 support (#629) --- .travis.sh | 8 +-- .travis.yml | 3 +- org.jacoco.build/pom.xml | 18 +++++ org.jacoco.core.test/pom.xml | 36 ++++++++++ .../src/org/jacoco/core/analysis/AnalyzerTest.java | 20 +++++- .../org/jacoco/core/instr/InstrumenterTest.java | 56 ++++++++++++--- .../jacoco/core/internal/BytecodeVersionTest.java | 62 +++++++++++++++++ .../core/internal/ContentTypeDetectorTest.java | 7 ++ .../org/jacoco/core/internal/data/CRC64Test.java | 6 +- .../instr/ProbeArrayStrategyFactoryTest.java | 4 +- .../runtime/ModifiedSystemClassRuntimeTest.java | 26 +++++++ .../org/jacoco/core/test/filter/FinallyTest.java | 7 +- .../jacoco/core/test/validation/FramesTest.java | 4 ++ .../test/validation/ResizeInstructionsTest.java | 14 +++- .../test/validation/StructuredLockingTest.java | 4 ++ .../src/org/jacoco/core/analysis/Analyzer.java | 15 +++- .../src/org/jacoco/core/instr/Instrumenter.java | 19 ++++- .../org/jacoco/core/internal/BytecodeVersion.java | 81 ++++++++++++++++++++++ .../jacoco/core/internal/ContentTypeDetector.java | 1 + .../internal/instr/ProbeArrayStrategyFactory.java | 16 ++--- .../core/runtime/ModifiedSystemClassRuntime.java | 10 ++- org.jacoco.doc/docroot/doc/changes.html | 2 + org.jacoco.doc/docroot/doc/faq.html | 2 +- 23 files changed, 378 insertions(+), 43 deletions(-) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/BytecodeVersionTest.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/BytecodeVersion.java diff --git a/.travis.sh b/.travis.sh index abf4f8d4..b4b58536 100755 --- a/.travis.sh +++ b/.travis.sh @@ -61,8 +61,8 @@ case "$JDK" in 9) install_jdk $JDK9_URL ;; -10-ea) - install_jdk $JDK10_EA_URL +10) + install_jdk $JDK10_URL ;; esac @@ -98,8 +98,8 @@ case "$JDK" in mvn -V -B -e verify -Dbytecode.version=1.9 \ -Dinvoker.mavenOpts="-Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts" ;; -10-ea) - mvn -V -B -e verify -Dbytecode.version=1.9 +10) + mvn -V -B -e verify -Dbytecode.version=10 ;; *) echo "Incorrect JDK [$JDK]" diff --git a/.travis.yml b/.travis.yml index f62f80e8..772382ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,11 +25,10 @@ env: ECJ=true - JDK=8-ea - JDK=9 - - JDK=10-ea + - JDK=10 matrix: allow_failures: - env: JDK=8-ea - - env: JDK=10-ea script: ./.travis.sh diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index 46536814..898e32be 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -742,6 +742,24 @@ 1.8 + + java10-validation + + + bytecode.version + 10 + + + + + 1.8 + 1.8 + + diff --git a/org.jacoco.core.test/pom.xml b/org.jacoco.core.test/pom.xml index 3e99fc69..4ff184df 100644 --- a/org.jacoco.core.test/pom.xml +++ b/org.jacoco.core.test/pom.xml @@ -138,6 +138,42 @@ + + java10-validation + + + + bytecode.version + 10 + + + + 10 + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-source + generate-sources + + add-source + + + + src-java7 + src-java8 + + + + + + + + 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 9d3ce065..fe69219d 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 @@ -36,12 +36,14 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.internal.BytecodeVersion; 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.rules.TemporaryFolder; +import org.objectweb.asm.ClassWriter; /** * Unit tests for {@link Analyzer}. @@ -73,6 +75,23 @@ public class AnalyzerTest { analyzer = new Analyzer(executionData, new EmptyStructureVisitor()); } + @Test + public void should_analyze_java10_class() throws Exception { + final byte[] bytes = createClass(BytecodeVersion.V10); + final long expectedClassId = CRC64.classId(bytes); + + analyzer.analyzeClass(bytes, ""); + + assertEquals(expectedClassId, classes.get("Foo").getId()); + } + + private static byte[] createClass(final int version) { + final ClassWriter cw = new ClassWriter(0); + cw.visit(version, 0, "Foo", null, "java/lang/Object", null); + cw.visitEnd(); + return cw.toByteArray(); + } + @Test public void testAnalyzeClassFromStream() throws IOException { analyzer.analyzeClass(TargetLoader.getClassData(AnalyzerTest.class), @@ -91,7 +110,6 @@ public class AnalyzerTest { @Test public void testAnalyzeClassIdMatch() throws IOException { - // class IDs are always calculated after downgrade of the version final byte[] bytes = TargetLoader .getClassDataAsBytes(AnalyzerTest.class); executionData.get(Long.valueOf(CRC64.classId(bytes)), 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 95960477..85882352 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 @@ -11,6 +11,7 @@ *******************************************************************************/ package org.jacoco.core.instr; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; @@ -34,12 +35,16 @@ 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.internal.BytecodeVersion; +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.After; import org.junit.Before; import org.junit.Test; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; /** * Unit tests for {@link Instrumenter}. @@ -66,20 +71,51 @@ public class InstrumenterTest { } - private SystemPropertiesRuntime runtime; + private static final class AccessorGenerator + implements IExecutionDataAccessorGenerator { + long classId; + + public int generateDataAccessor(final long classId, + final String classname, final int probeCount, + final MethodVisitor mv) { + this.classId = classId; + InstrSupport.push(mv, probeCount); + mv.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BOOLEAN); + return 1; + } + + } + + private AccessorGenerator accessorGenerator; private Instrumenter instrumenter; @Before public void setup() throws Exception { - runtime = new SystemPropertiesRuntime(); - instrumenter = new Instrumenter(runtime); - runtime.startup(new RuntimeData()); + accessorGenerator = new AccessorGenerator(); + instrumenter = new Instrumenter(accessorGenerator); + } + + @Test + public void should_instrument_java10_class() throws Exception { + final byte[] originalBytes = createClass(BytecodeVersion.V10); + final byte[] bytes = new byte[originalBytes.length]; + System.arraycopy(originalBytes, 0, bytes, 0, originalBytes.length); + final long expectedClassId = CRC64.classId(bytes); + + final byte[] instrumentedBytes = instrumenter.instrument(bytes, ""); + + assertArrayEquals(originalBytes, bytes); + assertEquals(BytecodeVersion.V10, + BytecodeVersion.get(instrumentedBytes)); + assertEquals(expectedClassId, accessorGenerator.classId); } - @After - public void teardown() { - runtime.shutdown(); + private static byte[] createClass(final int version) { + final ClassWriter cw = new ClassWriter(0); + cw.visit(version, 0, "Foo", null, "java/lang/Object", null); + cw.visitEnd(); + return cw.toByteArray(); } @Test diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/BytecodeVersionTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/BytecodeVersionTest.java new file mode 100644 index 00000000..6bc4ca9e --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/BytecodeVersionTest.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal; + +import org.junit.Test; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Opcodes; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; + +public class BytecodeVersionTest { + + @Test + public void should_get_and_set_major_version() { + final byte[] bytes = createClass(Opcodes.V1_1); + assertEquals(45, BytecodeVersion.get(bytes)); + + BytecodeVersion.set(bytes, Opcodes.V1_2); + assertEquals(46, BytecodeVersion.get(bytes)); + } + + @Test + public void should_return_original_when_not_java10() { + final byte[] originalBytes = createClass(Opcodes.V9); + + final byte[] bytes = BytecodeVersion.downgradeIfNeeded(Opcodes.V9, + originalBytes); + + assertSame(originalBytes, bytes); + } + + @Test + public void should_return_copy_when_java10() { + final byte[] originalBytes = createClass(BytecodeVersion.V10); + + final byte[] bytes = BytecodeVersion + .downgradeIfNeeded(BytecodeVersion.V10, originalBytes); + + assertNotSame(originalBytes, bytes); + assertEquals(Opcodes.V9, BytecodeVersion.get(bytes)); + assertEquals(BytecodeVersion.V10, BytecodeVersion.get(originalBytes)); + } + + private static byte[] createClass(final int version) { + final ClassWriter cw = new ClassWriter(0); + cw.visit(version, 0, "Foo", null, "java/lang/Object", null); + cw.visitEnd(); + return cw.toByteArray(); + } + +} 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 a61d6997..f3dde668 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 @@ -114,6 +114,13 @@ public class ContentTypeDetectorTest { assertContent(); } + @Test + public void should_detect_java_10() throws IOException { + initData(0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x36); + assertEquals(ContentTypeDetector.CLASSFILE, detector.getType()); + assertContent(); + } + @Test public void testMachObjectFile() throws IOException { initData(0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x02); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/data/CRC64Test.java b/org.jacoco.core.test/src/org/jacoco/core/internal/data/CRC64Test.java index 5b5f421a..39f7d508 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/data/CRC64Test.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/data/CRC64Test.java @@ -16,6 +16,7 @@ import static org.junit.Assert.assertEquals; import java.io.UnsupportedEncodingException; import org.jacoco.core.data.ExecutionDataWriter; +import org.jacoco.core.internal.BytecodeVersion; import org.junit.Test; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; @@ -26,7 +27,10 @@ import org.objectweb.asm.Opcodes; public class CRC64Test { @Test - public void testJava9() { + public void except_java_9_checksums_should_be_different_for_different_bytecode_versions() { + assertEquals(0x589E9080A572741EL, + CRC64.classId(createClass(BytecodeVersion.V10))); + // should remove workaround for Java 9 // during change of exec file version assertEquals(0x1007, ExecutionDataWriter.FORMAT_VERSION); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java index 6d9ed5ca..b83782c9 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java @@ -220,7 +220,7 @@ public class ProbeArrayStrategyFactoryTest { writer.visitEnd(); final IProbeArrayStrategy strategy = ProbeArrayStrategyFactory - .createFor(new ClassReader(writer.toByteArray()), generator); + .createFor(0, new ClassReader(writer.toByteArray()), generator); assertEquals(NoneProbeArrayStrategy.class, strategy.getClass()); } @@ -254,7 +254,7 @@ public class ProbeArrayStrategyFactoryTest { writer.visitEnd(); final IProbeArrayStrategy strategy = ProbeArrayStrategyFactory - .createFor(new ClassReader(writer.toByteArray()), generator); + .createFor(0, new ClassReader(writer.toByteArray()), generator); strategy.addMembers(cv, 123); return strategy; diff --git a/org.jacoco.core.test/src/org/jacoco/core/runtime/ModifiedSystemClassRuntimeTest.java b/org.jacoco.core.test/src/org/jacoco/core/runtime/ModifiedSystemClassRuntimeTest.java index 8a968840..03a58018 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/runtime/ModifiedSystemClassRuntimeTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/runtime/ModifiedSystemClassRuntimeTest.java @@ -25,8 +25,12 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; +import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.test.TargetLoader; import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.ClassNode; /** * Unit tests for {@link ModifiedSystemClassRuntime}. @@ -45,6 +49,28 @@ public class ModifiedSystemClassRuntimeTest extends RuntimeTestBase { ModifiedSystemClassRuntime.createFor(inst, TARGET_CLASS_NAME); } + @Test + public void should_instrument_java10_class() { + final byte[] bytes = createClass(BytecodeVersion.V10); + + byte[] instrumented = ModifiedSystemClassRuntime.instrument(bytes, + "accessField"); + + assertEquals(BytecodeVersion.V10, BytecodeVersion.get(instrumented)); + instrumented = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.V10, + instrumented); + final ClassNode classNode = new ClassNode(); + new ClassReader(instrumented).accept(classNode, 0); + assertEquals("accessField", classNode.fields.get(0).name); + } + + private static byte[] createClass(final int version) { + final ClassWriter cw = new ClassWriter(0); + cw.visit(version, 0, "Foo", null, "java/lang/Object", null); + cw.visitEnd(); + return cw.toByteArray(); + } + /** This static member emulate the instrumented system class. */ public static Object accessField; diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java index 0f44588e..9c6b2af4 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java @@ -18,6 +18,7 @@ import java.util.HashSet; import java.util.Set; import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.test.TargetLoader; import org.jacoco.core.test.filter.targets.Finally; import org.jacoco.core.test.validation.Source; @@ -181,9 +182,11 @@ public class FinallyTest extends ValidationTestBase { public void gotos() throws IOException { final Source source = Source.getSourceFor("src", Finally.class); + byte[] b = TargetLoader.getClassDataAsBytes(Finally.class); + b = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(b), b); + final ClassNode classNode = new ClassNode(); - new ClassReader(TargetLoader.getClassDataAsBytes(Finally.class)) - .accept(classNode, 0); + new ClassReader(b).accept(classNode, 0); final Set tags = new HashSet(); for (final MethodNode m : classNode.methods) { if ("main".equals(m.name)) { 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 35fdbf6a..9ab062b6 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 @@ -18,6 +18,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.instr.InstrSupport; import org.jacoco.core.runtime.IRuntime; import org.jacoco.core.runtime.SystemPropertiesRuntime; @@ -87,6 +88,9 @@ public class FramesTest { } private byte[] calculateFrames(byte[] source) { + source = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(source), + source); + ClassReader rc = new ClassReader(source); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java index 9ba6f613..571bb800 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java @@ -16,6 +16,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.instr.InstrSupport; import org.jacoco.core.runtime.IRuntime; import org.jacoco.core.runtime.RuntimeData; @@ -59,9 +60,13 @@ public class ResizeInstructionsTest { public void should_not_loose_InnerClasses_attribute() throws Exception { // FIXME fails without COMPUTE_FRAMES because of // https://gitlab.ow2.org/asm/asm/issues/317800 + + byte[] source = TargetLoader.getClassDataAsBytes(Inner.class); + final int version = BytecodeVersion.get(source); + source = BytecodeVersion.downgradeIfNeeded(version, source); + + final ClassReader cr = new ClassReader(source); final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - final ClassReader cr = new ClassReader( - TargetLoader.getClassDataAsBytes(Inner.class)); cr.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, cw) { @Override public void visitEnd() { @@ -75,7 +80,10 @@ public class ResizeInstructionsTest { super.visitEnd(); } }, 0); - final byte[] bytes = instrumenter.instrument(cw.toByteArray(), ""); + source = cw.toByteArray(); + BytecodeVersion.set(source, version); + + final byte[] bytes = instrumenter.instrument(source, ""); final TargetLoader targetLoader = new TargetLoader(); final Class outer = targetLoader.add(ResizeInstructionsTest.class, diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StructuredLockingTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StructuredLockingTest.java index 5640fdc7..823ab787 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StructuredLockingTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StructuredLockingTest.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Set; import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.runtime.IRuntime; import org.jacoco.core.runtime.SystemPropertiesRuntime; import org.jacoco.core.test.TargetLoader; @@ -67,6 +68,9 @@ public class StructuredLockingTest { Instrumenter instrumenter = new Instrumenter(runtime); byte[] instrumented = instrumenter.instrument(source, "TestTarget"); + final int version = BytecodeVersion.get(instrumented); + instrumented = BytecodeVersion.downgradeIfNeeded(version, instrumented); + ClassNode cn = new ClassNode(); new ClassReader(instrumented).accept(cn, 0); for (MethodNode mn : cn.methods) { 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 53dbf0c0..e703887b 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java @@ -22,6 +22,7 @@ import java.util.zip.ZipInputStream; import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.ContentTypeDetector; import org.jacoco.core.internal.InputStreams; import org.jacoco.core.internal.Pack200Streams; @@ -106,8 +107,16 @@ public class Analyzer { * reader with class definitions */ public void analyzeClass(final ClassReader reader) { - final ClassVisitor visitor = createAnalyzingVisitor( - CRC64.classId(reader.b), reader.getClassName()); + analyzeClass(reader.b); + } + + private void analyzeClass(final byte[] source) { + final long classId = CRC64.classId(source); + final int version = BytecodeVersion.get(source); + final byte[] b = BytecodeVersion.downgradeIfNeeded(version, source); + final ClassReader reader = new ClassReader(b); + final ClassVisitor visitor = createAnalyzingVisitor(classId, + reader.getClassName()); reader.accept(visitor, 0); } @@ -124,7 +133,7 @@ public class Analyzer { public void analyzeClass(final byte[] buffer, final String location) throws IOException { try { - analyzeClass(new ClassReader(buffer)); + analyzeClass(buffer); } catch (final RuntimeException cause) { throw analyzerError(location, cause); } 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 c8249784..85cba592 100644 --- a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java +++ b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java @@ -21,9 +21,11 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; +import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.ContentTypeDetector; import org.jacoco.core.internal.InputStreams; import org.jacoco.core.internal.Pack200Streams; +import org.jacoco.core.internal.data.CRC64; import org.jacoco.core.internal.flow.ClassProbesAdapter; import org.jacoco.core.internal.instr.ClassInstrumenter; import org.jacoco.core.internal.instr.IProbeArrayStrategy; @@ -76,6 +78,15 @@ public class Instrumenter { * */ public byte[] instrument(final ClassReader reader) { + return instrument(reader.b); + } + + private byte[] instrument(final byte[] source) { + final long classId = CRC64.classId(source); + final int originalVersion = BytecodeVersion.get(source); + final byte[] b = BytecodeVersion.downgradeIfNeeded(originalVersion, + source); + final ClassReader reader = new ClassReader(b); final ClassWriter writer = new ClassWriter(reader, 0) { @Override protected String getCommonSuperClass(final String type1, @@ -84,11 +95,13 @@ public class Instrumenter { } }; final IProbeArrayStrategy strategy = ProbeArrayStrategyFactory - .createFor(reader, accessorGenerator); + .createFor(classId, reader, accessorGenerator); final ClassVisitor visitor = new ClassProbesAdapter( new ClassInstrumenter(strategy, writer), true); reader.accept(visitor, ClassReader.EXPAND_FRAMES); - return writer.toByteArray(); + final byte[] instrumented = writer.toByteArray(); + BytecodeVersion.set(instrumented, originalVersion); + return instrumented; } /** @@ -105,7 +118,7 @@ public class Instrumenter { public byte[] instrument(final byte[] buffer, final String name) throws IOException { try { - return instrument(new ClassReader(buffer)); + return instrument(buffer); } catch (final RuntimeException e) { throw instrumentError(name, e); } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/BytecodeVersion.java b/org.jacoco.core/src/org/jacoco/core/internal/BytecodeVersion.java new file mode 100644 index 00000000..c24828b3 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/BytecodeVersion.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal; + +import org.objectweb.asm.Opcodes; + +/** + * Utilities to read and modify bytecode version in bytes of class. Main purpose + * of this class is to deal with bytecode versions which are not yet supported + * by ASM. + */ +public final class BytecodeVersion { + + private static final int VERSION_INDEX = 6; + + /** + * Version of the Java 10 class file format. + */ + public static final int V10 = Opcodes.V9 + 1; + + private BytecodeVersion() { + } + + /** + * Gets major of bytecode version number from given bytes of class. + * + * @param b + * bytes of class + * @return version of bytecode + */ + public static int get(final byte[] b) { + return (short) (((b[VERSION_INDEX] & 0xFF) << 8) + | (b[VERSION_INDEX + 1] & 0xFF)); + } + + /** + * Sets major of bytecode version in given bytes of class. + * + * @param b + * bytes of class + * @param version + * version of bytecode to set + */ + public static void set(final byte[] b, final int version) { + b[VERSION_INDEX] = (byte) (version >>> 8); + b[VERSION_INDEX + 1] = (byte) version; + } + + /** + * Returns given bytes of class if its major bytecode version is less that + * {@link #V10}, otherwise returns copy where major version set to + * {@link Opcodes#V9}. + * + * @param version + * version of bytecode + * @param source + * bytes of class + * @return given bytes of class if version is less than {@link #V10}, + * otherwise copy where version set to {@link Opcodes#V9} + */ + public static byte[] downgradeIfNeeded(final int version, + final byte[] source) { + if (V10 != version) { + return source; + } + final byte[] b = new byte[source.length]; + System.arraycopy(source, 0, b, 0, source.length); + set(b, Opcodes.V9); + return b; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java index ae665624..b30f6366 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java @@ -83,6 +83,7 @@ public class ContentTypeDetector { case Opcodes.V1_7: case Opcodes.V1_8: case Opcodes.V9: + case BytecodeVersion.V10: return CLASSFILE; } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java index 349840b0..38d572af 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java @@ -11,7 +11,7 @@ *******************************************************************************/ package org.jacoco.core.internal.instr; -import org.jacoco.core.internal.data.CRC64; +import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.flow.ClassProbesAdapter; import org.jacoco.core.runtime.IExecutionDataAccessorGenerator; import org.objectweb.asm.ClassReader; @@ -30,19 +30,21 @@ public final class ProbeArrayStrategyFactory { * Creates a suitable strategy instance for the class described by the given * reader. Created instance must be used only to process a class or * interface for which it has been created and must be used only once. - * + * + * @param classId + * class identifier * @param reader * reader to get information about the class * @param accessorGenerator * accessor to the coverage runtime * @return strategy instance */ - public static IProbeArrayStrategy createFor(final ClassReader reader, + public static IProbeArrayStrategy createFor(final long classId, + final ClassReader reader, final IExecutionDataAccessorGenerator accessorGenerator) { final String className = reader.getClassName(); - final int version = getVersion(reader); - final long classId = CRC64.classId(reader.b); + final int version = BytecodeVersion.get(reader.b); final boolean withFrames = version >= Opcodes.V1_6; if (isInterfaceOrModule(reader)) { @@ -68,10 +70,6 @@ public final class ProbeArrayStrategyFactory { & (Opcodes.ACC_INTERFACE | Opcodes.ACC_MODULE)) != 0; } - private static int getVersion(final ClassReader reader) { - return reader.readShort(6); - } - private static ProbeCounter getProbeCounter(final ClassReader reader) { final ProbeCounter counter = new ProbeCounter(); reader.accept(new ClassProbesAdapter(counter, false), 0); diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java index 6d31358f..e51242d8 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java @@ -19,6 +19,7 @@ import java.lang.instrument.Instrumentation; import java.lang.reflect.Field; import java.security.ProtectionDomain; +import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.instr.InstrSupport; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; @@ -153,7 +154,10 @@ public class ModifiedSystemClassRuntime extends AbstractRuntime { */ public static byte[] instrument(final byte[] source, final String accessFieldName) { - final ClassReader reader = new ClassReader(source); + final int originalVersion = BytecodeVersion.get(source); + final byte[] b = BytecodeVersion.downgradeIfNeeded(originalVersion, + source); + final ClassReader reader = new ClassReader(b); final ClassWriter writer = new ClassWriter(reader, 0); reader.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, writer) { @@ -164,7 +168,9 @@ public class ModifiedSystemClassRuntime extends AbstractRuntime { } }, ClassReader.EXPAND_FRAMES); - return writer.toByteArray(); + final byte[] instrumented = writer.toByteArray(); + BytecodeVersion.set(instrumented, originalVersion); + return instrumented; } private static void createDataField(final ClassVisitor visitor, diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index eebd90f7..43470ddf 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -22,6 +22,8 @@

New Features

    +
  • JaCoCo now supports Java 10 + (GitHub #629).
  • Empty constructor without parameters in enum is filtered out during generation of report (GitHub #649).
  • diff --git a/org.jacoco.doc/docroot/doc/faq.html b/org.jacoco.doc/docroot/doc/faq.html index adfa66dc..0e910fb0 100644 --- a/org.jacoco.doc/docroot/doc/faq.html +++ b/org.jacoco.doc/docroot/doc/faq.html @@ -45,7 +45,7 @@

    What Java versions are supported by JaCoCo?

    - JaCoCo supports Java class files from version 1.0 to 9. However the minimum + JaCoCo supports Java class files from version 1.0 to 10. However the minimum JRE version required by the JaCoCo runtime (e.g. the agent) and the JaCoCo tools is 1.5. Also note that class files under test from version 1.6 and above have to contain valid stackmap frames. -- cgit v1.2.3 From c45ecca43ad8d51b09d1b5e3846f8a8e10ae74d0 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 21 Mar 2018 09:58:44 +0100 Subject: Update version of commons-collections in jacoco-maven-plugin (#645) --- jacoco-maven-plugin/pom.xml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/jacoco-maven-plugin/pom.xml b/jacoco-maven-plugin/pom.xml index 0695eb2a..d14e484d 100644 --- a/jacoco-maven-plugin/pom.xml +++ b/jacoco-maven-plugin/pom.xml @@ -30,6 +30,22 @@ 2.2.1 + + + + + org.apache.maven.reporting + maven-reporting-impl + 2.1 + + + commons-collections + commons-collections + 3.2.2 + + + + org.apache.maven @@ -60,7 +76,6 @@ org.apache.maven.reporting maven-reporting-impl - 2.1 -- cgit v1.2.3 From 6d4d8530f972162cc3a58e2161cf6e01cc13123e Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 21 Mar 2018 10:16:58 +0100 Subject: Prepare release v0.8.1 --- jacoco-maven-plugin.test/pom.xml | 2 +- jacoco-maven-plugin/pom.xml | 2 +- jacoco/pom.xml | 2 +- org.jacoco.agent.rt.test/pom.xml | 2 +- org.jacoco.agent.rt/pom.xml | 2 +- org.jacoco.agent.test/pom.xml | 2 +- org.jacoco.agent/pom.xml | 2 +- org.jacoco.ant.test/pom.xml | 2 +- org.jacoco.ant/pom.xml | 2 +- org.jacoco.build/pom.xml | 2 +- org.jacoco.cli.test/pom.xml | 2 +- org.jacoco.cli/pom.xml | 2 +- org.jacoco.core.test/pom.xml | 2 +- org.jacoco.core/pom.xml | 2 +- org.jacoco.doc/docroot/doc/changes.html | 2 +- org.jacoco.doc/pom.xml | 2 +- org.jacoco.examples.test/pom.xml | 2 +- org.jacoco.examples/pom.xml | 2 +- org.jacoco.report.test/pom.xml | 2 +- org.jacoco.report/pom.xml | 2 +- org.jacoco.tests/pom.xml | 2 +- pom.xml | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/jacoco-maven-plugin.test/pom.xml b/jacoco-maven-plugin.test/pom.xml index 8b7d72ad..3afc5d16 100644 --- a/jacoco-maven-plugin.test/pom.xml +++ b/jacoco-maven-plugin.test/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.tests - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.tests diff --git a/jacoco-maven-plugin/pom.xml b/jacoco-maven-plugin/pom.xml index d14e484d..3297b47a 100644 --- a/jacoco-maven-plugin/pom.xml +++ b/jacoco-maven-plugin/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.build - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.build diff --git a/jacoco/pom.xml b/jacoco/pom.xml index 14d65663..a64a709e 100644 --- a/jacoco/pom.xml +++ b/jacoco/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.build diff --git a/org.jacoco.agent.rt.test/pom.xml b/org.jacoco.agent.rt.test/pom.xml index 7d81fd67..5e9c4459 100644 --- a/org.jacoco.agent.rt.test/pom.xml +++ b/org.jacoco.agent.rt.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.tests diff --git a/org.jacoco.agent.rt/pom.xml b/org.jacoco.agent.rt/pom.xml index 600a3e93..ac7b0854 100644 --- a/org.jacoco.agent.rt/pom.xml +++ b/org.jacoco.agent.rt/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.build diff --git a/org.jacoco.agent.test/pom.xml b/org.jacoco.agent.test/pom.xml index 4a09e496..6eddf9ea 100644 --- a/org.jacoco.agent.test/pom.xml +++ b/org.jacoco.agent.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.tests diff --git a/org.jacoco.agent/pom.xml b/org.jacoco.agent/pom.xml index 22235114..b6f23ec3 100644 --- a/org.jacoco.agent/pom.xml +++ b/org.jacoco.agent/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.build diff --git a/org.jacoco.ant.test/pom.xml b/org.jacoco.ant.test/pom.xml index d1063789..ff2df9af 100644 --- a/org.jacoco.ant.test/pom.xml +++ b/org.jacoco.ant.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.tests diff --git a/org.jacoco.ant/pom.xml b/org.jacoco.ant/pom.xml index 88c2e5a0..0d6dcec9 100644 --- a/org.jacoco.ant/pom.xml +++ b/org.jacoco.ant/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.build diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index 898e32be..1e9e442a 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -14,7 +14,7 @@ org.jacoco org.jacoco.build - 0.8.1-SNAPSHOT + 0.8.1 pom JaCoCo diff --git a/org.jacoco.cli.test/pom.xml b/org.jacoco.cli.test/pom.xml index 7c0512db..2ceadd38 100644 --- a/org.jacoco.cli.test/pom.xml +++ b/org.jacoco.cli.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.tests diff --git a/org.jacoco.cli/pom.xml b/org.jacoco.cli/pom.xml index ae2e0385..c2dca74f 100644 --- a/org.jacoco.cli/pom.xml +++ b/org.jacoco.cli/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.build diff --git a/org.jacoco.core.test/pom.xml b/org.jacoco.core.test/pom.xml index 4ff184df..c016023f 100644 --- a/org.jacoco.core.test/pom.xml +++ b/org.jacoco.core.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.tests diff --git a/org.jacoco.core/pom.xml b/org.jacoco.core/pom.xml index 0471ca43..fd73556c 100644 --- a/org.jacoco.core/pom.xml +++ b/org.jacoco.core/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.build diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 43470ddf..73932e0d 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -18,7 +18,7 @@

    Change History

    -

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

    +

    Release 0.8.1 (2018/03/21)

    New Features

      diff --git a/org.jacoco.doc/pom.xml b/org.jacoco.doc/pom.xml index b9b0e76a..3b9361bd 100644 --- a/org.jacoco.doc/pom.xml +++ b/org.jacoco.doc/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.build diff --git a/org.jacoco.examples.test/pom.xml b/org.jacoco.examples.test/pom.xml index f274f575..33edb0df 100644 --- a/org.jacoco.examples.test/pom.xml +++ b/org.jacoco.examples.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.tests diff --git a/org.jacoco.examples/pom.xml b/org.jacoco.examples/pom.xml index 4adb9ed5..501aa81c 100644 --- a/org.jacoco.examples/pom.xml +++ b/org.jacoco.examples/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.build diff --git a/org.jacoco.report.test/pom.xml b/org.jacoco.report.test/pom.xml index 7754b5b3..7620087f 100644 --- a/org.jacoco.report.test/pom.xml +++ b/org.jacoco.report.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.tests diff --git a/org.jacoco.report/pom.xml b/org.jacoco.report/pom.xml index e182c439..5baa73b6 100644 --- a/org.jacoco.report/pom.xml +++ b/org.jacoco.report/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.build diff --git a/org.jacoco.tests/pom.xml b/org.jacoco.tests/pom.xml index 6e899092..9d0cec6f 100644 --- a/org.jacoco.tests/pom.xml +++ b/org.jacoco.tests/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.build - 0.8.1-SNAPSHOT + 0.8.1 ../org.jacoco.build diff --git a/pom.xml b/pom.xml index 5e92d25a..12d4d7c9 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.jacoco root - 0.8.1-SNAPSHOT + 0.8.1 pom -- cgit v1.2.3 From b3da4221be975dd11001de9571ad96177c59c86d Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Thu, 22 Mar 2018 08:29:16 +0100 Subject: Prepare for next development iteration --- jacoco-maven-plugin.test/pom.xml | 2 +- jacoco-maven-plugin/pom.xml | 2 +- jacoco/pom.xml | 2 +- org.jacoco.agent.rt.test/pom.xml | 2 +- org.jacoco.agent.rt/pom.xml | 2 +- org.jacoco.agent.test/pom.xml | 2 +- org.jacoco.agent/pom.xml | 2 +- org.jacoco.ant.test/pom.xml | 2 +- org.jacoco.ant/pom.xml | 2 +- org.jacoco.build/pom.xml | 2 +- org.jacoco.cli.test/pom.xml | 2 +- org.jacoco.cli/pom.xml | 2 +- org.jacoco.core.test/pom.xml | 2 +- org.jacoco.core/pom.xml | 2 +- org.jacoco.doc/docroot/doc/changes.html | 2 ++ org.jacoco.doc/pom.xml | 2 +- org.jacoco.examples.test/pom.xml | 2 +- org.jacoco.examples/pom.xml | 2 +- org.jacoco.report.test/pom.xml | 2 +- org.jacoco.report/pom.xml | 2 +- org.jacoco.tests/pom.xml | 2 +- pom.xml | 2 +- 22 files changed, 23 insertions(+), 21 deletions(-) diff --git a/jacoco-maven-plugin.test/pom.xml b/jacoco-maven-plugin.test/pom.xml index 3afc5d16..f922eb57 100644 --- a/jacoco-maven-plugin.test/pom.xml +++ b/jacoco-maven-plugin.test/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.tests - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.tests diff --git a/jacoco-maven-plugin/pom.xml b/jacoco-maven-plugin/pom.xml index 3297b47a..4ce884f7 100644 --- a/jacoco-maven-plugin/pom.xml +++ b/jacoco-maven-plugin/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.build - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.build diff --git a/jacoco/pom.xml b/jacoco/pom.xml index a64a709e..21285ad3 100644 --- a/jacoco/pom.xml +++ b/jacoco/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.agent.rt.test/pom.xml b/org.jacoco.agent.rt.test/pom.xml index 5e9c4459..a52b505b 100644 --- a/org.jacoco.agent.rt.test/pom.xml +++ b/org.jacoco.agent.rt.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.agent.rt/pom.xml b/org.jacoco.agent.rt/pom.xml index ac7b0854..e9461ee6 100644 --- a/org.jacoco.agent.rt/pom.xml +++ b/org.jacoco.agent.rt/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.agent.test/pom.xml b/org.jacoco.agent.test/pom.xml index 6eddf9ea..195b56b5 100644 --- a/org.jacoco.agent.test/pom.xml +++ b/org.jacoco.agent.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.agent/pom.xml b/org.jacoco.agent/pom.xml index b6f23ec3..63e277da 100644 --- a/org.jacoco.agent/pom.xml +++ b/org.jacoco.agent/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.ant.test/pom.xml b/org.jacoco.ant.test/pom.xml index ff2df9af..bf843b14 100644 --- a/org.jacoco.ant.test/pom.xml +++ b/org.jacoco.ant.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.ant/pom.xml b/org.jacoco.ant/pom.xml index 0d6dcec9..734f78ec 100644 --- a/org.jacoco.ant/pom.xml +++ b/org.jacoco.ant/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index 1e9e442a..8931e170 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -14,7 +14,7 @@ org.jacoco org.jacoco.build - 0.8.1 + 0.8.2-SNAPSHOT pom JaCoCo diff --git a/org.jacoco.cli.test/pom.xml b/org.jacoco.cli.test/pom.xml index 2ceadd38..bed30a63 100644 --- a/org.jacoco.cli.test/pom.xml +++ b/org.jacoco.cli.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.cli/pom.xml b/org.jacoco.cli/pom.xml index c2dca74f..2b570f7c 100644 --- a/org.jacoco.cli/pom.xml +++ b/org.jacoco.cli/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.core.test/pom.xml b/org.jacoco.core.test/pom.xml index c016023f..45390d90 100644 --- a/org.jacoco.core.test/pom.xml +++ b/org.jacoco.core.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.core/pom.xml b/org.jacoco.core/pom.xml index fd73556c..93ee0e1f 100644 --- a/org.jacoco.core/pom.xml +++ b/org.jacoco.core/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 73932e0d..ee534423 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -18,6 +18,8 @@

      Change History

      +

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

      +

      Release 0.8.1 (2018/03/21)

      New Features

      diff --git a/org.jacoco.doc/pom.xml b/org.jacoco.doc/pom.xml index 3b9361bd..bd21643a 100644 --- a/org.jacoco.doc/pom.xml +++ b/org.jacoco.doc/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.examples.test/pom.xml b/org.jacoco.examples.test/pom.xml index 33edb0df..7bc59a13 100644 --- a/org.jacoco.examples.test/pom.xml +++ b/org.jacoco.examples.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.examples/pom.xml b/org.jacoco.examples/pom.xml index 501aa81c..d930b8e1 100644 --- a/org.jacoco.examples/pom.xml +++ b/org.jacoco.examples/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.report.test/pom.xml b/org.jacoco.report.test/pom.xml index 7620087f..3c26a0ed 100644 --- a/org.jacoco.report.test/pom.xml +++ b/org.jacoco.report.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.report/pom.xml b/org.jacoco.report/pom.xml index 5baa73b6..5086a406 100644 --- a/org.jacoco.report/pom.xml +++ b/org.jacoco.report/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.tests/pom.xml b/org.jacoco.tests/pom.xml index 9d0cec6f..7f071172 100644 --- a/org.jacoco.tests/pom.xml +++ b/org.jacoco.tests/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.build - 0.8.1 + 0.8.2-SNAPSHOT ../org.jacoco.build diff --git a/pom.xml b/pom.xml index 12d4d7c9..baffcaba 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.jacoco root - 0.8.1 + 0.8.2-SNAPSHOT pom -- cgit v1.2.3 From ac702e772b29a073da9d1b7b70d8b61610beedb3 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Thu, 29 Mar 2018 00:18:26 +0200 Subject: Fix badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c0685936..dc7b5720 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ JaCoCo Java Code Coverage Library [![Build Status](https://travis-ci.org/jacoco/jacoco.svg?branch=master)](https://travis-ci.org/jacoco/jacoco) [![Build status](https://ci.appveyor.com/api/projects/status/g28egytv4tb898d7/branch/master?svg=true)](https://ci.appveyor.com/project/JaCoCo/jacoco/branch/master) -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.jacoco/org.jacoco.core/badge.svg?style=flat)](http://search.maven.org/#search|ga|1|g%3Aorg.jacoco) +[![Maven Central](https://img.shields.io/maven-central/v/org.jacoco/jacoco.svg)](http://search.maven.org/#search|ga|1|g%3Aorg.jacoco) JaCoCo is a free Java code coverage library distributed under the Eclipse Public License. Check the [project homepage](http://www.jacoco.org/jacoco) -- cgit v1.2.3 From 65ad735cf564abeeb2517149843928d28740a559 Mon Sep 17 00:00:00 2001 From: "Marc R. Hoffmann" Date: Mon, 2 Apr 2018 22:07:10 +0200 Subject: Don't insert stackmap frames into class files with version < 1.6. (#667) For certain probes additional frames needs to be inserted, but only from class file version 1.6 on. --- .../core/internal/instr/InstrSupportTest.java | 22 +++++++ .../test/validation/ClassFileVersionsTest.java | 72 ++++++++++++++++++---- .../src/org/jacoco/core/instr/Instrumenter.java | 4 +- .../jacoco/core/internal/instr/InstrSupport.java | 16 ++++- .../internal/instr/ProbeArrayStrategyFactory.java | 3 +- org.jacoco.doc/docroot/doc/changes.html | 7 +++ 6 files changed, 107 insertions(+), 17 deletions(-) diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java index fb1cb3e3..95de8bd5 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java @@ -12,9 +12,13 @@ package org.jacoco.core.internal.instr; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.jacoco.core.internal.BytecodeVersion; import org.junit.Before; import org.junit.Test; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.util.Printer; import org.objectweb.asm.util.Textifier; import org.objectweb.asm.util.TraceMethodVisitor; @@ -33,6 +37,24 @@ public class InstrSupportTest { trace = new TraceMethodVisitor(printer); } + @Test + public void needFrames_should_return_false_for_versions_less_than_1_6() { + assertFalse(InstrSupport.needsFrames(Opcodes.V1_1)); + assertFalse(InstrSupport.needsFrames(Opcodes.V1_2)); + assertFalse(InstrSupport.needsFrames(Opcodes.V1_3)); + assertFalse(InstrSupport.needsFrames(Opcodes.V1_4)); + assertFalse(InstrSupport.needsFrames(Opcodes.V1_5)); + } + + @Test + public void needFrames_should_return_true_for_versions_greater_than_or_equal_to_1_6() { + assertTrue(InstrSupport.needsFrames(Opcodes.V1_6)); + assertTrue(InstrSupport.needsFrames(Opcodes.V1_7)); + assertTrue(InstrSupport.needsFrames(Opcodes.V1_8)); + assertTrue(InstrSupport.needsFrames(Opcodes.V9)); + assertTrue(InstrSupport.needsFrames(BytecodeVersion.V10)); + } + @Test public void testAssertNotIntrumentedPositive() { InstrSupport.assertNotInstrumented("run", "Foo"); 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 d73fc642..87d78a21 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 @@ -15,7 +15,12 @@ import static org.junit.Assert.assertEquals; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ACC_SUPER; import static org.objectweb.asm.Opcodes.ALOAD; +import static org.objectweb.asm.Opcodes.F_NEW; +import static org.objectweb.asm.Opcodes.IFEQ; +import static org.objectweb.asm.Opcodes.ILOAD; import static org.objectweb.asm.Opcodes.INVOKESPECIAL; +import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; +import static org.objectweb.asm.Opcodes.POP; import static org.objectweb.asm.Opcodes.RETURN; import static org.objectweb.asm.Opcodes.V1_1; import static org.objectweb.asm.Opcodes.V1_2; @@ -30,6 +35,7 @@ import static org.objectweb.asm.Opcodes.V9; import java.io.IOException; import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.instr.InstrSupport; import org.jacoco.core.runtime.IRuntime; import org.jacoco.core.runtime.SystemPropertiesRuntime; @@ -37,7 +43,9 @@ import org.junit.Test; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; /** * Test class inserted stackmap frames for different class file versions. @@ -85,12 +93,17 @@ public class ClassFileVersionsTest { } @Test - public void test_1_9() throws IOException { + public void test_9() throws IOException { testVersion(V9, true); } + @Test + public void test_10() throws IOException { + testVersion(BytecodeVersion.V10, true); + } + private void testVersion(int version, boolean frames) throws IOException { - final byte[] original = createClass(version); + final byte[] original = createClass(version, frames); IRuntime runtime = new SystemPropertiesRuntime(); Instrumenter instrumenter = new Instrumenter(runtime); @@ -99,30 +112,52 @@ public class ClassFileVersionsTest { assertFrames(instrumented, frames); } - private void assertFrames(byte[] source, boolean expected) { - final boolean[] hasFrames = new boolean[] { false }; + private void assertFrames(byte[] source, final boolean expected) { + int version = BytecodeVersion.get(source); + source = BytecodeVersion.downgradeIfNeeded(version, source); new ClassReader(source) .accept(new ClassVisitor(InstrSupport.ASM_API_VERSION) { @Override public MethodVisitor visitMethod(int access, String name, - String desc, String signature, String[] exceptions) { + String desc, String signature, + String[] exceptions) { return new MethodVisitor(InstrSupport.ASM_API_VERSION) { + boolean frames = false; @Override public void visitFrame(int type, int nLocal, - Object[] local, int nStack, Object[] stack) { - hasFrames[0] = true; + Object[] local, int nStack, + Object[] stack) { + frames = true; } + @Override + public void visitEnd() { + assertEquals(Boolean.valueOf(expected), + Boolean.valueOf(frames)); + } }; } - }, 0); - assertEquals(Boolean.valueOf(expected), Boolean.valueOf(hasFrames[0])); } - private byte[] createClass(int version) { + /** + * Creates a class that requires a frame before the return statement. Also + * for this class instrumentation should insert another frame. + * + *
      +	 * public class Sample {
      +	 *   public Sample(boolean b){
      +	 *     if(b){
      +	 *       toString();
      +	 *     }
      +	 *     return;
      +	 *   }
      +	 * }
      +	 * 
      + */ + private byte[] createClass(int version, boolean frames) { ClassWriter cw = new ClassWriter(0); MethodVisitor mv; @@ -130,13 +165,26 @@ public class ClassFileVersionsTest { cw.visit(version, ACC_PUBLIC + ACC_SUPER, "org/jacoco/test/Sample", null, "java/lang/Object", null); - mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv = cw.visitMethod(ACC_PUBLIC, "", "(Z)V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitVarInsn(ILOAD, 1); + Label l1 = new Label(); + mv.visitJumpInsn(IFEQ, l1); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", + "()Ljava/lang/String;", false); + mv.visitInsn(POP); + mv.visitLabel(l1); + if (frames) { + mv.visitFrame(F_NEW, 2, + new Object[] { "org/jacoco/test/Sample", Opcodes.INTEGER }, + 0, new Object[] {}); + } mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); + mv.visitMaxs(1, 2); mv.visitEnd(); cw.visitEnd(); 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 85cba592..da956fd9 100644 --- a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java +++ b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java @@ -29,6 +29,7 @@ import org.jacoco.core.internal.data.CRC64; import org.jacoco.core.internal.flow.ClassProbesAdapter; import org.jacoco.core.internal.instr.ClassInstrumenter; import org.jacoco.core.internal.instr.IProbeArrayStrategy; +import org.jacoco.core.internal.instr.InstrSupport; import org.jacoco.core.internal.instr.ProbeArrayStrategyFactory; import org.jacoco.core.internal.instr.SignatureRemover; import org.jacoco.core.runtime.IExecutionDataAccessorGenerator; @@ -97,7 +98,8 @@ public class Instrumenter { final IProbeArrayStrategy strategy = ProbeArrayStrategyFactory .createFor(classId, reader, accessorGenerator); final ClassVisitor visitor = new ClassProbesAdapter( - new ClassInstrumenter(strategy, writer), true); + new ClassInstrumenter(strategy, writer), + InstrSupport.needsFrames(originalVersion)); reader.accept(visitor, ClassReader.EXPAND_FRAMES); final byte[] instrumented = writer.toByteArray(); BytecodeVersion.set(instrumented, originalVersion); diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java index b6632c62..c7b7cf84 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java @@ -157,6 +157,18 @@ public final class InstrSupport { */ static final int CLINIT_ACC = Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC; + /** + * Determines whether the given class file version requires stackmap frames. + * + * @param version + * class file version + * @return true if frames are required + */ + public static boolean needsFrames(final int version) { + // consider major version only (due to 1.1 anomaly) + return (version & 0xff) >= Opcodes.V1_6; + } + /** * Ensures that the given member does not correspond to a internal member * created by the instrumentation process. This would mean that the class is @@ -173,8 +185,8 @@ public final class InstrSupport { public static void assertNotInstrumented(final String member, final String owner) throws IllegalStateException { if (member.equals(DATAFIELD_NAME) || member.equals(INITMETHOD_NAME)) { - throw new IllegalStateException(format( - "Class %s is already instrumented.", owner)); + throw new IllegalStateException( + format("Class %s is already instrumented.", owner)); } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java index 38d572af..a4fb82b0 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java @@ -45,7 +45,6 @@ public final class ProbeArrayStrategyFactory { final String className = reader.getClassName(); final int version = BytecodeVersion.get(reader.b); - final boolean withFrames = version >= Opcodes.V1_6; if (isInterfaceOrModule(reader)) { final ProbeCounter counter = getProbeCounter(reader); @@ -61,7 +60,7 @@ public final class ProbeArrayStrategyFactory { } } else { return new ClassFieldProbeArrayStrategy(className, classId, - withFrames, accessorGenerator); + InstrSupport.needsFrames(version), accessorGenerator); } } diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index ee534423..33fa7def 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -20,6 +20,13 @@

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

      +

      Fixed Bugs

      +
        +
      • Don't insert stackmap frames into class files with version < 1.6, + this fixes regression which was introduced in version 0.6.5 + (GitHub #667).
      • +
      +

      Release 0.8.1 (2018/03/21)

      New Features

      -- cgit v1.2.3 From 26a7a025377a31aeae710adc07729fb86666f2e5 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 4 Apr 2018 06:22:02 +0200 Subject: Do not analyze synthetic classes (#668) --- .../src/org/jacoco/core/analysis/AnalyzerTest.java | 14 ++++++++ .../jacoco/core/test/filter/EnumSwitchTest.java | 40 +++++++++++++++++++++ .../core/test/filter/targets/EnumSwitch.java | 42 ++++++++++++++++++++++ .../src/org/jacoco/core/analysis/Analyzer.java | 4 +++ org.jacoco.doc/docroot/doc/changes.html | 6 ++++ 5 files changed, 106 insertions(+) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumSwitchTest.java create mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumSwitch.java 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 fe69219d..4e5d81a8 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 @@ -44,6 +44,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Opcodes; /** * Unit tests for {@link Analyzer}. @@ -75,6 +76,19 @@ public class AnalyzerTest { analyzer = new Analyzer(executionData, new EmptyStructureVisitor()); } + @Test + public void should_ignore_synthetic_classes() throws Exception { + final ClassWriter cw = new ClassWriter(0); + cw.visit(Opcodes.V1_1, Opcodes.ACC_SYNTHETIC, "Foo", null, + "java/lang/Object", null); + cw.visitEnd(); + final byte[] bytes = cw.toByteArray(); + + analyzer.analyzeClass(bytes, ""); + + assertTrue(classes.isEmpty()); + } + @Test public void should_analyze_java10_class() throws Exception { final byte[] bytes = createClass(BytecodeVersion.V10); diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumSwitchTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumSwitchTest.java new file mode 100644 index 00000000..3708899a --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumSwitchTest.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.filter.targets.EnumSwitch; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.junit.Test; + +/** + * Test of filtering of a synthetic class that is generated by javac for a enum + * in switch statement. + */ +public class EnumSwitchTest extends ValidationTestBase { + + public EnumSwitchTest() { + super(EnumSwitch.class); + } + + @Test + public void testCoverageResult() { + if (isJDKCompiler && JAVA_VERSION.isBefore("1.6")) { + // class that holds "switch map" is not marked as synthetic when + // compiling with javac 1.5 + assertLine("switch", ICounter.PARTLY_COVERED, 0, 2); + } else { + assertLine("switch", ICounter.FULLY_COVERED, 0, 2); + } + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumSwitch.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumSwitch.java new file mode 100644 index 00000000..850ef295 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumSwitch.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target is a switch statement with a enum. + */ +public class EnumSwitch { + + private enum E { + V1, V2 + } + + private static void example(E e) { + switch (e) { // $line-switch$ + case V1: + nop("V1"); + break; + case V2: + default: + nop("V2"); + break; + } + } + + public static void main(String[] args) { + example(E.V1); + example(E.V2); + } + +} 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 e703887b..92d640d2 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java @@ -33,6 +33,7 @@ import org.jacoco.core.internal.data.CRC64; import org.jacoco.core.internal.flow.ClassProbesAdapter; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Opcodes; /** * An {@link Analyzer} instance processes a set of Java class files and @@ -115,6 +116,9 @@ public class Analyzer { final int version = BytecodeVersion.get(source); final byte[] b = BytecodeVersion.downgradeIfNeeded(version, source); final ClassReader reader = new ClassReader(b); + if ((reader.getAccess() & Opcodes.ACC_SYNTHETIC) != 0) { + return; + } final ClassVisitor visitor = createAnalyzingVisitor(classId, reader.getClassName()); reader.accept(visitor, 0); diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 33fa7def..4a02b4e0 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -20,6 +20,12 @@

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

      +

      New Features

      +
        +
      • Synthetic classes are filtered out during generation of report + (GitHub #668).
      • +
      +

      Fixed Bugs

      • Don't insert stackmap frames into class files with version < 1.6, -- cgit v1.2.3 From dc2d8e188b4b61df95c5e72b38c87b15ee6a8f4d Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 4 Apr 2018 15:49:05 +0200 Subject: Remove unused dependencies (#670) --- org.jacoco.core.test/pom.xml | 8 ++++++++ org.jacoco.core/pom.xml | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/org.jacoco.core.test/pom.xml b/org.jacoco.core.test/pom.xml index 45390d90..75d89481 100644 --- a/org.jacoco.core.test/pom.xml +++ b/org.jacoco.core.test/pom.xml @@ -32,6 +32,14 @@ ${project.groupId} org.jacoco.core + + org.ow2.asm + asm-analysis + + + org.ow2.asm + asm-util + junit junit diff --git a/org.jacoco.core/pom.xml b/org.jacoco.core/pom.xml index 93ee0e1f..30468f9a 100644 --- a/org.jacoco.core/pom.xml +++ b/org.jacoco.core/pom.xml @@ -37,14 +37,6 @@ org.ow2.asm asm-tree - - org.ow2.asm - asm-analysis - - - org.ow2.asm - asm-util - -- cgit v1.2.3 From 1a56c9619e03ee3e4e1b539e592e7d8b51f53a7b Mon Sep 17 00:00:00 2001 From: "Marc R. Hoffmann" Date: Sun, 15 Apr 2018 22:29:50 +0200 Subject: Question mark in filter expressions should match exactly one character (#672) --- .../jacoco/core/runtime/WildcardMatcherTest.java | 23 +++++++++++++--------- .../org/jacoco/core/runtime/WildcardMatcher.java | 9 +++++---- org.jacoco.doc/docroot/doc/changes.html | 2 ++ 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/org.jacoco.core.test/src/org/jacoco/core/runtime/WildcardMatcherTest.java b/org.jacoco.core.test/src/org/jacoco/core/runtime/WildcardMatcherTest.java index 21d50f80..f1b56474 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/runtime/WildcardMatcherTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/runtime/WildcardMatcherTest.java @@ -19,30 +19,31 @@ import org.junit.Test; public class WildcardMatcherTest { @Test - public void testEmpty() { + public void empty_expression_should_match_any_string() { assertTrue(new WildcardMatcher("").matches("")); assertFalse(new WildcardMatcher("").matches("abc")); } @Test - public void testExact() { + public void expressions_without_wildcards_should_match_exactly() { assertTrue(new WildcardMatcher("abc/def.txt").matches("abc/def.txt")); + assertFalse(new WildcardMatcher("abc/def.txt").matches("/abc/def.txt")); } @Test - public void testCaseSensitive() { + public void should_match_case_sensitive() { assertFalse(new WildcardMatcher("abcdef").matches("abcDef")); assertFalse(new WildcardMatcher("ABCDEF").matches("AbCDEF")); } @Test - public void testQuote() { + public void should_not_use_regex_characters() { assertFalse(new WildcardMatcher("rst.xyz").matches("rstAxyz")); assertTrue(new WildcardMatcher("(x)+").matches("(x)+")); } @Test - public void testWildcards() { + public void asterix_should_match_any_number_of_any_character() { assertTrue(new WildcardMatcher("*").matches("")); assertTrue(new WildcardMatcher("*").matches("java/lang/Object")); assertTrue(new WildcardMatcher("*Test").matches("jacoco/MatcherTest")); @@ -50,20 +51,24 @@ public class WildcardMatcherTest { assertTrue(new WildcardMatcher("Matcher*").matches("MatcherTest")); assertTrue(new WildcardMatcher("a*b*a").matches("a-b-b-a")); assertFalse(new WildcardMatcher("a*b*a").matches("alaska")); + } + + @Test + public void questionmark_should_match_any_single_character() { assertTrue(new WildcardMatcher("Hello?orld").matches("HelloWorld")); + assertFalse(new WildcardMatcher("Hello?orld").matches("Helloorld")); assertFalse(new WildcardMatcher("Hello?orld").matches("HelloWWWorld")); - assertTrue(new WildcardMatcher("?aco*").matches("jacoco")); } @Test - public void testMultiExpression() { - assertTrue(new WildcardMatcher("Hello:World").matches("World")); + public void should_match_any_expression_when_multiple_expressions_are_given() { assertTrue(new WildcardMatcher("Hello:World").matches("World")); assertTrue(new WildcardMatcher("*Test:*Foo").matches("UnitTest")); + assertFalse(new WildcardMatcher("foo:bar").matches("foo:bar")); } @Test - public void testDollar() { + public void should_match_dollar_sign() { assertTrue(new WildcardMatcher("*$*").matches("java/util/Map$Entry")); assertTrue(new WildcardMatcher("*$$$*") .matches("org/example/Enity$$$generated123")); diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java b/org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java index 2b52d4b8..14bbc2f1 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java @@ -14,9 +14,10 @@ package org.jacoco.core.runtime; import java.util.regex.Pattern; /** - * Matches strings against ?/* wildcard expressions. - * Multiple expressions can be separated with a colon (:). In this case the - * expression matches if at least one part matches. + * Matches strings against glob like wildcard expressions where ? + * matches any single character and * matches any number of any + * character. Multiple expressions can be separated with a colon (:). In this + * case the expression matches if at least one part matches. */ public class WildcardMatcher { @@ -47,7 +48,7 @@ public class WildcardMatcher { for (final char c : expression.toCharArray()) { switch (c) { case '?': - regex.append(".?"); + regex.append("."); break; case '*': regex.append(".*"); diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 4a02b4e0..6c6a48ed 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -31,6 +31,8 @@
      • Don't insert stackmap frames into class files with version < 1.6, this fixes regression which was introduced in version 0.6.5 (GitHub #667).
      • +
      • Question mark in filter expressions now correctly matches exactly one character + (GitHub #672).

      Release 0.8.1 (2018/03/21)

      -- cgit v1.2.3 From 281538bc74d9f09f5b0d83250a4435b5c2732e21 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Thu, 7 Jun 2018 03:39:28 +0300 Subject: Add filter for methods that Kotlin compiler generates (#689) --- .../core/internal/analysis/MethodAnalyzerTest.java | 14 ++- .../filter/EnumEmptyConstructorFilterTest.java | 24 ++-- .../internal/analysis/filter/EnumFilterTest.java | 15 ++- .../analysis/filter/FilterContextMock.java | 40 +++++++ .../analysis/filter/FinallyFilterTest.java | 2 +- .../analysis/filter/GroovyGeneratedFilterTest.java | 6 +- .../analysis/filter/KotlinGeneratedFilterTest.java | 128 +++++++++++++++++++++ .../analysis/filter/LombokGeneratedFilterTest.java | 6 +- .../PrivateEmptyNoArgConstructorFilterTest.java | 2 +- .../filter/StringSwitchJavacFilterTest.java | 4 +- .../analysis/filter/SynchronizedFilterTest.java | 6 +- .../analysis/filter/SyntheticFilterTest.java | 6 +- .../filter/TryWithResourcesEcjFilterTest.java | 4 +- .../filter/TryWithResourcesJavacFilterTest.java | 8 +- .../core/internal/analysis/ClassAnalyzer.java | 46 +++++++- .../core/internal/analysis/MethodAnalyzer.java | 28 ++--- .../filter/AbstractAnnotatedMethodFilter.java | 4 +- .../filter/EnumEmptyConstructorFilter.java | 15 +-- .../core/internal/analysis/filter/EnumFilter.java | 7 +- .../core/internal/analysis/filter/Filters.java | 9 +- .../internal/analysis/filter/FinallyFilter.java | 4 +- .../core/internal/analysis/filter/IFilter.java | 9 +- .../internal/analysis/filter/IFilterContext.java | 42 +++++++ .../analysis/filter/KotlinGeneratedFilter.java | 57 +++++++++ .../filter/PrivateEmptyNoArgConstructorFilter.java | 8 +- .../analysis/filter/StringSwitchJavacFilter.java | 4 +- .../analysis/filter/SynchronizedFilter.java | 8 +- .../internal/analysis/filter/SyntheticFilter.java | 4 +- .../analysis/filter/TryWithResourcesEcjFilter.java | 6 +- .../filter/TryWithResourcesJavacFilter.java | 11 +- org.jacoco.doc/docroot/doc/changes.html | 3 + 31 files changed, 422 insertions(+), 108 deletions(-) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilterTest.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilter.java diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java index c312e60c..114ebb59 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java @@ -17,8 +17,10 @@ import java.util.ArrayList; import org.jacoco.core.analysis.ILine; import org.jacoco.core.analysis.IMethodCoverage; +import org.jacoco.core.internal.analysis.filter.FilterContextMock; import org.jacoco.core.internal.analysis.filter.Filters; import org.jacoco.core.internal.analysis.filter.IFilter; +import org.jacoco.core.internal.analysis.filter.IFilterContext; import org.jacoco.core.internal.analysis.filter.IFilterOutput; import org.jacoco.core.internal.flow.IProbeIdGenerator; import org.jacoco.core.internal.flow.LabelFlowAnalyzer; @@ -109,8 +111,8 @@ public class MethodAnalyzerTest implements IProbeIdGenerator { /** Filters the NOP instructions as ignored */ private static final IFilter NOP_FILTER = new IFilter() { - public void filter(final String className, final String superClassName, - final MethodNode methodNode, final IFilterOutput output) { + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { final AbstractInsnNode i1 = methodNode.instructions.get(2); final AbstractInsnNode i2 = methodNode.instructions.get(3); assertEquals(Opcodes.NOP, i1.getOpcode()); @@ -777,8 +779,8 @@ public class MethodAnalyzerTest implements IProbeIdGenerator { } private static final IFilter TRY_FINALLY_FILTER = new IFilter() { - public void filter(final String className, final String superClassName, - final MethodNode methodNode, final IFilterOutput output) { + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { final AbstractInsnNode i1 = methodNode.instructions.get(2); final AbstractInsnNode i2 = methodNode.instructions.get(7); assertEquals(Opcodes.IFEQ, i1.getOpcode()); @@ -845,8 +847,8 @@ public class MethodAnalyzerTest implements IProbeIdGenerator { private void runMethodAnalzer(IFilter filter) { LabelFlowAnalyzer.markLabels(method); - final MethodAnalyzer analyzer = new MethodAnalyzer("Foo", - "java/lang/Object", "doit", "()V", null, probes, filter); + final MethodAnalyzer analyzer = new MethodAnalyzer("doit", "()V", null, + probes, filter, new FilterContextMock()); final MethodProbesAdapter probesAdapter = new MethodProbesAdapter( analyzer, this); // note that CheckMethodAdapter verifies that this test does not violate diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java index a2216546..961bd321 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java @@ -11,20 +11,22 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - public class EnumEmptyConstructorFilterTest implements IFilterOutput { private final EnumEmptyConstructorFilter filter = new EnumEmptyConstructorFilter(); + private final FilterContextMock context = new FilterContextMock(); + private AbstractInsnNode fromInclusive; private AbstractInsnNode toInclusive; @@ -39,8 +41,9 @@ public class EnumEmptyConstructorFilterTest implements IFilterOutput { m.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Enum", "", "(Ljava/lang/String;I)V", false); m.visitInsn(Opcodes.RETURN); + context.superClassName = "java/lang/Enum"; - filter.filter("Foo", "java/lang/Enum", m, this); + filter.filter(m, context, this); assertEquals(m.instructions.getFirst(), fromInclusive); assertEquals(m.instructions.getLast(), toInclusive); @@ -68,8 +71,9 @@ public class EnumEmptyConstructorFilterTest implements IFilterOutput { "(Ljava/lang/String;I)V", false); m.visitInsn(Opcodes.NOP); m.visitInsn(Opcodes.RETURN); + context.superClassName = "java/lang/Enum"; - filter.filter("Foo", "java/lang/Enum", m, this); + filter.filter(m, context, this); assertNull(fromInclusive); assertNull(toInclusive); @@ -95,8 +99,9 @@ public class EnumEmptyConstructorFilterTest implements IFilterOutput { m.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Enum", "", "(Ljava/lang/String;I)V", false); m.visitInsn(Opcodes.RETURN); + context.superClassName = "java/lang/Enum"; - filter.filter("Foo", "java/lang/Enum", m, this); + filter.filter(m, context, this); assertNull(fromInclusive); assertNull(toInclusive); @@ -117,8 +122,9 @@ public class EnumEmptyConstructorFilterTest implements IFilterOutput { Opcodes.ACC_PRIVATE, "method", "(Ljava/lang/String;I)V", null, null); m.visitInsn(Opcodes.NOP); + context.superClassName = "java/lang/Enum"; - filter.filter("Foo", "java/lang/Enum", m, this); + filter.filter(m, context, this); assertNull(fromInclusive); assertNull(toInclusive); @@ -131,7 +137,7 @@ public class EnumEmptyConstructorFilterTest implements IFilterOutput { null); m.visitInsn(Opcodes.NOP); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, context, this); assertNull(fromInclusive); assertNull(toInclusive); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java index 9d7fb2ca..eca9d445 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java @@ -25,6 +25,8 @@ public class EnumFilterTest implements IFilterOutput { private final EnumFilter filter = new EnumFilter(); + private final FilterContextMock context = new FilterContextMock(); + private AbstractInsnNode fromInclusive; private AbstractInsnNode toInclusive; @@ -33,8 +35,9 @@ public class EnumFilterTest implements IFilterOutput { final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, "values", "()[LFoo;", null, null); m.visitInsn(Opcodes.NOP); + context.superClassName = "java/lang/Enum"; - filter.filter("Foo", "java/lang/Enum", m, this); + filter.filter(m, context, this); assertEquals(m.instructions.getFirst(), fromInclusive); assertEquals(m.instructions.getLast(), toInclusive); @@ -46,7 +49,7 @@ public class EnumFilterTest implements IFilterOutput { "values", "()V", null, null); m.visitInsn(Opcodes.NOP); - filter.filter("Foo", "java/lang/Enum", m, this); + filter.filter(m, context, this); assertNull(fromInclusive); assertNull(toInclusive); @@ -57,8 +60,9 @@ public class EnumFilterTest implements IFilterOutput { final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, "valueOf", "(Ljava/lang/String;)LFoo;", null, null); m.visitInsn(Opcodes.NOP); + context.superClassName = "java/lang/Enum"; - filter.filter("Foo", "java/lang/Enum", m, this); + filter.filter(m, context, this); assertEquals(m.instructions.getFirst(), fromInclusive); assertEquals(m.instructions.getLast(), toInclusive); @@ -69,8 +73,9 @@ public class EnumFilterTest implements IFilterOutput { final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, "valueOf", "()V", null, null); m.visitInsn(Opcodes.NOP); + context.superClassName = "java/lang/Enum"; - filter.filter("Foo", "java/lang/Enum", m, this); + filter.filter(m, context, this); assertNull(fromInclusive); assertNull(toInclusive); @@ -82,7 +87,7 @@ public class EnumFilterTest implements IFilterOutput { "values", "()[LFoo;", null, null); m.visitInsn(Opcodes.NOP); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, context, this); assertNull(fromInclusive); assertNull(toInclusive); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java new file mode 100644 index 00000000..ce487a6e --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.internal.analysis.filter; + +import java.util.HashSet; +import java.util.Set; + +public class FilterContextMock implements IFilterContext { + + public String className = "Foo"; + public String superClassName = "java/lang/Object"; + public Set classAnnotations = new HashSet(); + public String sourceFileName = "Foo.java"; + + public String getClassName() { + return className; + } + + public String getSuperClassName() { + return superClassName; + } + + public Set getClassAnnotations() { + return classAnnotations; + } + + public String getSourceFileName() { + return sourceFileName; + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java index 5e0ed6c9..a2f5a73e 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java @@ -383,7 +383,7 @@ public class FinallyFilterTest implements IFilterOutput { } private void execute() { - filter.filter("", "", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals("ignored", toIndexes(expectedIgnored), toIndexes(actualIgnored)); assertEquals("merged", toIndexes(expectedMerged), diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilterTest.java index 6cf0febe..f890cde3 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilterTest.java @@ -36,7 +36,7 @@ public class GroovyGeneratedFilterTest implements IFilterOutput { m.visitInsn(Opcodes.ICONST_0); m.visitInsn(Opcodes.IRETURN); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertNull(fromInclusive); assertNull(toInclusive); @@ -51,7 +51,7 @@ public class GroovyGeneratedFilterTest implements IFilterOutput { m.visitInsn(Opcodes.ICONST_0); m.visitInsn(Opcodes.IRETURN); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertNull(fromInclusive); assertNull(toInclusive); @@ -66,7 +66,7 @@ public class GroovyGeneratedFilterTest implements IFilterOutput { m.visitInsn(Opcodes.ICONST_0); m.visitInsn(Opcodes.IRETURN); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals(m.instructions.getFirst(), fromInclusive); assertEquals(m.instructions.getLast(), toInclusive); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilterTest.java new file mode 100644 index 00000000..197f9d0f --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilterTest.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Nikolay Krasko - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class KotlinGeneratedFilterTest implements IFilterOutput { + + private final IFilter filter = new KotlinGeneratedFilter(); + + private final FilterContextMock context = new FilterContextMock(); + + private AbstractInsnNode fromInclusive; + private AbstractInsnNode toInclusive; + + @Test + public void testNoLinesForKotlinWithDebug() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "hashCode", "()I", null, null); + m.visitInsn(Opcodes.ICONST_0); + m.visitInsn(Opcodes.IRETURN); + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + + filter.filter(m, context, this); + + assertMethodSkipped(m); + } + + @Test + public void testWithLinesForKotlinWithDebug() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "hashCode", "()I", null, null); + m.visitAnnotation("Lother/Annotation;", false); + m.visitLineNumber(12, new Label()); + m.visitInsn(Opcodes.ICONST_0); + m.visitInsn(Opcodes.IRETURN); + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + + filter.filter(m, context, this); + + assertNotApplicable(); + } + + @Test + public void testNoLinesNonKotlinWithDebug() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "hashCode", "()I", null, null); + m.visitInsn(Opcodes.ICONST_0); + m.visitInsn(Opcodes.IRETURN); + + filter.filter(m, context, this); + + assertNotApplicable(); + } + + @Test + public void testNoLinesForKotlinNoDebug() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "hashCode", "()I", null, null); + m.visitInsn(Opcodes.ICONST_0); + m.visitInsn(Opcodes.IRETURN); + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + context.sourceFileName = null; + + filter.filter(m, context, this); + + assertNotApplicable(); + } + + @Test + public void testWithLinesForKotlinNoDebug() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "hashCode", "()I", null, null); + m.visitInsn(Opcodes.ICONST_0); + m.visitInsn(Opcodes.IRETURN); + m.visitLineNumber(12, new Label()); + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + context.sourceFileName = null; + + filter.filter(m, context, this); + + assertNotApplicable(); + } + + private void assertNotApplicable() { + assertNull(fromInclusive); + assertNull(toInclusive); + } + + private void assertMethodSkipped(MethodNode m) { + assertEquals(m.instructions.getFirst(), fromInclusive); + assertEquals(m.instructions.getLast(), toInclusive); + } + + public void ignore(final AbstractInsnNode fromInclusive, + final AbstractInsnNode toInclusive) { + assertNull(this.fromInclusive); + this.fromInclusive = fromInclusive; + this.toInclusive = toInclusive; + } + + public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { + fail(); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java index 3e2b497a..6821af12 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java @@ -36,7 +36,7 @@ public class LombokGeneratedFilterTest implements IFilterOutput { m.visitInsn(Opcodes.ICONST_0); m.visitInsn(Opcodes.IRETURN); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertNull(fromInclusive); assertNull(toInclusive); @@ -51,7 +51,7 @@ public class LombokGeneratedFilterTest implements IFilterOutput { m.visitInsn(Opcodes.ICONST_0); m.visitInsn(Opcodes.IRETURN); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertNull(fromInclusive); assertNull(toInclusive); @@ -66,7 +66,7 @@ public class LombokGeneratedFilterTest implements IFilterOutput { m.visitInsn(Opcodes.ICONST_0); m.visitInsn(Opcodes.IRETURN); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals(m.instructions.getFirst(), fromInclusive); assertEquals(m.instructions.getLast(), toInclusive); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java index 24c67609..d3db0423 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java @@ -37,7 +37,7 @@ public class PrivateEmptyNoArgConstructorFilterTest implements IFilterOutput { "()V", false); m.visitInsn(Opcodes.RETURN); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals(m.instructions.getFirst(), fromInclusive); assertEquals(m.instructions.getLast(), toInclusive); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java index 2dd9359d..ec976d52 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java @@ -92,7 +92,7 @@ public class StringSwitchJavacFilterTest implements IFilterOutput { m.visitTableSwitchInsn(0, 2, cases); m.visitLabel(cases); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals(fromInclusive, this.fromInclusive); assertEquals(toInclusive, this.toInclusive); @@ -140,7 +140,7 @@ public class StringSwitchJavacFilterTest implements IFilterOutput { m.visitLabel(cases); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertNull(this.fromInclusive); assertNull(this.toInclusive); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java index 5e2b4379..b0f5f3d0 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java @@ -64,7 +64,7 @@ public class SynchronizedFilterTest implements IFilterOutput { m.visitLabel(exit); m.visitInsn(Opcodes.RETURN); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals(handler.info, fromInclusive); assertEquals(((LabelNode) exit.info).getPrevious(), toInclusive); } @@ -117,7 +117,7 @@ public class SynchronizedFilterTest implements IFilterOutput { m.visitLabel(exit); m.visitInsn(Opcodes.RETURN); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertNull(fromInclusive); } @@ -152,7 +152,7 @@ public class SynchronizedFilterTest implements IFilterOutput { m.visitLabel(exit); m.visitInsn(Opcodes.RETURN); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals(handler.info, fromInclusive); assertEquals(((LabelNode) exit.info).getPrevious(), toInclusive); } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java index 06344d52..2574ca50 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java @@ -34,7 +34,7 @@ public class SyntheticFilterTest implements IFilterOutput { "name", "()V", null, null); m.visitInsn(Opcodes.NOP); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertNull(fromInclusive); assertNull(toInclusive); @@ -46,7 +46,7 @@ public class SyntheticFilterTest implements IFilterOutput { Opcodes.ACC_SYNTHETIC, "name", "()V", null, null); m.visitInsn(Opcodes.NOP); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals(m.instructions.getFirst(), fromInclusive); assertEquals(m.instructions.getLast(), toInclusive); @@ -58,7 +58,7 @@ public class SyntheticFilterTest implements IFilterOutput { Opcodes.ACC_SYNTHETIC, "lambda$1", "()V", null, null); m.visitInsn(Opcodes.NOP); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertNull(fromInclusive); assertNull(toInclusive); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilterTest.java index 248ca4e9..3a8bdf49 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilterTest.java @@ -310,7 +310,7 @@ public class TryWithResourcesEcjFilterTest implements IFilterOutput { // additional handlers m.visitInsn(Opcodes.NOP); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals(2, from.size()); @@ -598,7 +598,7 @@ public class TryWithResourcesEcjFilterTest implements IFilterOutput { // additional handlers m.visitInsn(Opcodes.NOP); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals(2, from.size()); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilterTest.java index 83109eae..7a7cc1ce 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilterTest.java @@ -219,7 +219,7 @@ public class TryWithResourcesJavacFilterTest implements IFilterOutput { m.visitVarInsn(Opcodes.ALOAD, 8); m.visitInsn(Opcodes.ATHROW); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals(4, from.size()); @@ -548,7 +548,7 @@ public class TryWithResourcesJavacFilterTest implements IFilterOutput { m.visitVarInsn(Opcodes.ALOAD, 11); m.visitInsn(Opcodes.ATHROW); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals(4, from.size()); @@ -726,7 +726,7 @@ public class TryWithResourcesJavacFilterTest implements IFilterOutput { m.visitLabel(end); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals(2, from.size()); @@ -794,7 +794,7 @@ public class TryWithResourcesJavacFilterTest implements IFilterOutput { m.visitVarInsn(Opcodes.ALOAD, 4); m.visitInsn(Opcodes.ATHROW); - filter.filter("Foo", "java/lang/Object", m, this); + filter.filter(m, new FilterContextMock(), this); assertEquals(0, from.size()); } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java index afcf387e..e40b66dc 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java @@ -11,22 +11,30 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis; +import java.util.HashSet; +import java.util.Set; + import org.jacoco.core.analysis.IMethodCoverage; import org.jacoco.core.internal.analysis.filter.Filters; +import org.jacoco.core.internal.analysis.filter.IFilterContext; import org.jacoco.core.internal.flow.ClassProbesVisitor; import org.jacoco.core.internal.flow.MethodProbesVisitor; import org.jacoco.core.internal.instr.InstrSupport; +import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.FieldVisitor; /** * Analyzes the structure of a class. */ -public class ClassAnalyzer extends ClassProbesVisitor { +public class ClassAnalyzer extends ClassProbesVisitor + implements IFilterContext { private final ClassCoverageImpl coverage; private final boolean[] probes; private final StringPool stringPool; + private final Set classAnnotations = new HashSet(); + /** * Creates a new analyzer that builds coverage data for a class. * @@ -53,6 +61,13 @@ public class ClassAnalyzer extends ClassProbesVisitor { coverage.setInterfaces(stringPool.get(interfaces)); } + @Override + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { + classAnnotations.add(desc); + return super.visitAnnotation(desc, visible); + } + @Override public void visitSource(final String source, final String debug) { coverage.setSourceFileName(stringPool.get(source)); @@ -60,18 +75,19 @@ public class ClassAnalyzer extends ClassProbesVisitor { @Override public MethodProbesVisitor visitMethod(final int access, final String name, - final String desc, final String signature, final String[] exceptions) { + final String desc, final String signature, + final String[] exceptions) { InstrSupport.assertNotInstrumented(name, coverage.getName()); - return new MethodAnalyzer(coverage.getName(), coverage.getSuperName(), - stringPool.get(name), stringPool.get(desc), - stringPool.get(signature), probes, Filters.ALL) { + return new MethodAnalyzer(stringPool.get(name), stringPool.get(desc), + stringPool.get(signature), probes, Filters.ALL, this) { @Override public void visitEnd() { super.visitEnd(); final IMethodCoverage methodCoverage = getCoverage(); - if (methodCoverage.getInstructionCounter().getTotalCount() > 0) { + if (methodCoverage.getInstructionCounter() + .getTotalCount() > 0) { // Only consider methods that actually contain code coverage.addMethod(methodCoverage); } @@ -91,4 +107,22 @@ public class ClassAnalyzer extends ClassProbesVisitor { // nothing to do } + // IFilterContext implementation + + public String getClassName() { + return coverage.getName(); + } + + public String getSuperClassName() { + return coverage.getSuperName(); + } + + public Set getClassAnnotations() { + return classAnnotations; + } + + public String getSourceFileName() { + return coverage.getSourceFileName(); + } + } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java index e10e5d9f..ba862adc 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java @@ -22,6 +22,7 @@ import org.jacoco.core.analysis.ICounter; import org.jacoco.core.analysis.IMethodCoverage; import org.jacoco.core.analysis.ISourceNode; import org.jacoco.core.internal.analysis.filter.IFilter; +import org.jacoco.core.internal.analysis.filter.IFilterContext; import org.jacoco.core.internal.analysis.filter.IFilterOutput; import org.jacoco.core.internal.flow.IFrame; import org.jacoco.core.internal.flow.Instruction; @@ -41,14 +42,12 @@ import org.objectweb.asm.tree.TryCatchBlockNode; public class MethodAnalyzer extends MethodProbesVisitor implements IFilterOutput { - private final String className; - - private final String superClassName; - private final boolean[] probes; private final IFilter filter; + private final IFilterContext filterContext; + private final MethodCoverageImpl coverage; private int currentLine = ISourceNode.UNKNOWN_LINE; @@ -74,11 +73,7 @@ public class MethodAnalyzer extends MethodProbesVisitor /** * New Method analyzer for the given probe data. - * - * @param className - * class name - * @param superClassName - * superclass name + * * @param name * method name * @param desc @@ -89,16 +84,17 @@ public class MethodAnalyzer extends MethodProbesVisitor * recorded probe date of the containing class or * null if the class is not executed at all * @param filter - * filter + * filter which should be applied + * @param filterContext + * class context information for the filter */ - MethodAnalyzer(final String className, final String superClassName, - final String name, final String desc, final String signature, - final boolean[] probes, final IFilter filter) { + MethodAnalyzer(final String name, final String desc, final String signature, + final boolean[] probes, final IFilter filter, + final IFilterContext filterContext) { super(); - this.className = className; - this.superClassName = superClassName; this.probes = probes; this.filter = filter; + this.filterContext = filterContext; this.coverage = new MethodCoverageImpl(name, desc, signature); } @@ -118,7 +114,7 @@ public class MethodAnalyzer extends MethodProbesVisitor @Override public void accept(final MethodNode methodNode, final MethodVisitor methodVisitor) { - filter.filter(className, superClassName, methodNode, this); + filter.filter(methodNode, filterContext, this); methodVisitor.visitCode(); for (final TryCatchBlockNode n : methodNode.tryCatchBlocks) { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractAnnotatedMethodFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractAnnotatedMethodFilter.java index 76b6b2f9..7981bc6a 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractAnnotatedMethodFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractAnnotatedMethodFilter.java @@ -32,8 +32,8 @@ abstract class AbstractAnnotatedMethodFilter implements IFilter { this.descType = "L" + annotationType + ";"; } - public void filter(final String className, final String superClassName, - final MethodNode methodNode, final IFilterOutput output) { + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { if (hasAnnotation(methodNode)) { output.ignore(methodNode.instructions.getFirst(), methodNode.instructions.getLast()); diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java index 9bdc5077..be79e328 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java @@ -33,24 +33,25 @@ public final class EnumEmptyConstructorFilter implements IFilter { private static final String CONSTRUCTOR_NAME = ""; private static final String CONSTRUCTOR_DESC = "(Ljava/lang/String;I)V"; - public void filter(String className, String superClassName, - MethodNode methodNode, IFilterOutput output) { - if ("java/lang/Enum".equals(superClassName) + private static final String ENUM_TYPE = "java/lang/Enum"; + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + if (ENUM_TYPE.equals(context.getSuperClassName()) && CONSTRUCTOR_NAME.equals(methodNode.name) && CONSTRUCTOR_DESC.equals(methodNode.desc) - && new Matcher().match(methodNode, superClassName)) { + && new Matcher().match(methodNode)) { output.ignore(methodNode.instructions.getFirst(), methodNode.instructions.getLast()); } } private static class Matcher extends AbstractMatcher { - private boolean match(final MethodNode methodNode, - final String superClassName) { + private boolean match(final MethodNode methodNode) { firstIsALoad0(methodNode); nextIs(Opcodes.ALOAD); nextIs(Opcodes.ILOAD); - nextIsInvokeSuper(superClassName, CONSTRUCTOR_DESC); + nextIsInvokeSuper(ENUM_TYPE, CONSTRUCTOR_DESC); nextIs(Opcodes.RETURN); return cursor != null; } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java index c5f1784c..e36376be 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java @@ -19,9 +19,10 @@ import org.objectweb.asm.tree.MethodNode; */ public final class EnumFilter implements IFilter { - public void filter(final String className, final String superClassName, - final MethodNode methodNode, final IFilterOutput output) { - if (isMethodFiltered(className, superClassName, methodNode.name, + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + if (isMethodFiltered(context.getClassName(), + context.getSuperClassName(), methodNode.name, methodNode.desc)) { output.ignore(methodNode.instructions.getFirst(), methodNode.instructions.getLast()); diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index 40c0dfc3..cafb1f77 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -31,7 +31,8 @@ public final class Filters implements IFilter { new TryWithResourcesJavacFilter(), new TryWithResourcesEcjFilter(), new FinallyFilter(), new PrivateEmptyNoArgConstructorFilter(), new StringSwitchJavacFilter(), new LombokGeneratedFilter(), - new GroovyGeneratedFilter(), new EnumEmptyConstructorFilter()); + new GroovyGeneratedFilter(), new EnumEmptyConstructorFilter(), + new KotlinGeneratedFilter()); private final IFilter[] filters; @@ -39,10 +40,10 @@ public final class Filters implements IFilter { this.filters = filters; } - public void filter(final String className, final String superClassName, - final MethodNode methodNode, final IFilterOutput output) { + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { for (final IFilter filter : filters) { - filter.filter(className, superClassName, methodNode, output); + filter.filter(methodNode, context, output); } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java index 830d0c28..50cb5703 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java @@ -67,8 +67,8 @@ import org.objectweb.asm.tree.VarInsnNode; */ public final class FinallyFilter implements IFilter { - public void filter(final String className, final String superClassName, - final MethodNode methodNode, final IFilterOutput output) { + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { for (final TryCatchBlockNode tryCatchBlock : methodNode.tryCatchBlocks) { if (tryCatchBlock.type == null) { filter(output, methodNode.tryCatchBlocks, tryCatchBlock); diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java index 82b7959a..2c64da1e 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java @@ -24,16 +24,13 @@ public interface IFilter { * expected to inspect the provided method and report its result to the * given {@link IFilterOutput} instance. * - * @param className - * class name - * @param superClassName - * superclass name * @param methodNode * method to inspect + * @param context + * context information for the method * @param output * callback to report filtering results to */ - void filter(String className, String superClassName, MethodNode methodNode, + void filter(MethodNode methodNode, IFilterContext context, IFilterOutput output); - } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java new file mode 100644 index 00000000..88c46483 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.internal.analysis.filter; + +import java.util.Set; + +/** + * Context information provided to filters. + */ +public interface IFilterContext { + + /** + * @return vm name of the enclosing class + */ + String getClassName(); + + /** + * @return vm name of the super class of the enclosing class + */ + String getSuperClassName(); + + /** + * @return vm names of the class annotations of the enclosing class + */ + Set getClassAnnotations(); + + /** + * @return file name of the corresponding source file or null + * if not available + */ + String getSourceFileName(); + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilter.java new file mode 100644 index 00000000..68331492 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilter.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Nikolay Krasko - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Filters methods generated by the Kotlin compiler. Kotlin classes are + * identified by the @kotlin.Metadata annotations. In such classes + * generated methods do not have line numbers. + */ +public class KotlinGeneratedFilter implements IFilter { + + static final String KOTLIN_METADATA_DESC = "Lkotlin/Metadata;"; + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + + if (context.getSourceFileName() == null) { + // probably full debug information is missing + // disabled filtering as all methods might be erroneously skipped + return; + } + + if (!context.getClassAnnotations().contains(KOTLIN_METADATA_DESC)) { + return; + } + + if (hasLineNumber(methodNode)) { + return; + } + + output.ignore(methodNode.instructions.getFirst(), + methodNode.instructions.getLast()); + } + + private boolean hasLineNumber(final MethodNode methodNode) { + for (AbstractInsnNode i = methodNode.instructions + .getFirst(); i != null; i = i.getNext()) { + if (AbstractInsnNode.LINE == i.getType()) { + return true; + } + } + return false; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java index 29214c5b..9634c149 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java @@ -22,12 +22,12 @@ public final class PrivateEmptyNoArgConstructorFilter implements IFilter { private static final String CONSTRUCTOR_NAME = ""; private static final String CONSTRUCTOR_DESC = "()V"; - public void filter(final String className, final String superClassName, - final MethodNode methodNode, final IFilterOutput output) { + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { if ((methodNode.access & Opcodes.ACC_PRIVATE) != 0 && CONSTRUCTOR_NAME.equals(methodNode.name) - && CONSTRUCTOR_DESC.equals(methodNode.desc) - && new Matcher().match(methodNode, superClassName)) { + && CONSTRUCTOR_DESC.equals(methodNode.desc) && new Matcher() + .match(methodNode, context.getSuperClassName())) { output.ignore(methodNode.instructions.getFirst(), methodNode.instructions.getLast()); } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java index e1d7a1cc..c61bc752 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java @@ -24,8 +24,8 @@ import org.objectweb.asm.tree.TableSwitchInsnNode; */ public final class StringSwitchJavacFilter implements IFilter { - public void filter(final String className, final String superClassName, - final MethodNode methodNode, final IFilterOutput output) { + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { AbstractInsnNode i = methodNode.instructions.getFirst(); while (i != null) { filter(i, output); diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java index 71ce0cfe..c3b5caa1 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java @@ -21,9 +21,9 @@ import org.objectweb.asm.tree.TryCatchBlockNode; */ public final class SynchronizedFilter implements IFilter { - public void filter(final String className, final String superClassName, - final MethodNode methodNode, final IFilterOutput output) { - for (TryCatchBlockNode tryCatch : methodNode.tryCatchBlocks) { + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + for (final TryCatchBlockNode tryCatch : methodNode.tryCatchBlocks) { if (tryCatch.type != null) { continue; } @@ -67,7 +67,7 @@ public final class SynchronizedFilter implements IFilter { nextIs(Opcodes.ALOAD); nextIs(Opcodes.MONITOREXIT); nextIs(Opcodes.ATHROW); - return cursor != null; + return cursor != null; } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java index afba0f00..52d38bd2 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java @@ -19,8 +19,8 @@ import org.objectweb.asm.tree.MethodNode; */ public final class SyntheticFilter implements IFilter { - public void filter(final String className, final String superClassName, - final MethodNode methodNode, final IFilterOutput output) { + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { if ((methodNode.access & Opcodes.ACC_SYNTHETIC) != 0 && !methodNode.name.startsWith("lambda$")) { output.ignore(methodNode.instructions.getFirst(), diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java index c25d61ff..1ead24b9 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java @@ -27,13 +27,13 @@ import org.objectweb.asm.tree.TryCatchBlockNode; */ public final class TryWithResourcesEcjFilter implements IFilter { - public void filter(final String className, final String superClassName, - final MethodNode methodNode, final IFilterOutput output) { + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { if (methodNode.tryCatchBlocks.isEmpty()) { return; } final Matcher matcher = new Matcher(output); - for (TryCatchBlockNode t : methodNode.tryCatchBlocks) { + for (final TryCatchBlockNode t : methodNode.tryCatchBlocks) { if (t.type == null) { matcher.start(t.handler); if (!matcher.matchEcj()) { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java index f3b33bc9..fea477f6 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java @@ -22,15 +22,16 @@ import org.objectweb.asm.tree.TryCatchBlockNode; */ public final class TryWithResourcesJavacFilter implements IFilter { - public void filter(final String className, final String superClassName, - final MethodNode methodNode, final IFilterOutput output) { + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { if (methodNode.tryCatchBlocks.isEmpty()) { return; } final Matcher matcher = new Matcher(output); - for (TryCatchBlockNode t : methodNode.tryCatchBlocks) { + for (final TryCatchBlockNode t : methodNode.tryCatchBlocks) { if ("java/lang/Throwable".equals(t.type)) { - for (Matcher.JavacPattern p : Matcher.JavacPattern.values()) { + for (final Matcher.JavacPattern p : Matcher.JavacPattern + .values()) { matcher.start(t.handler); if (matcher.matchJavac(p)) { break; @@ -195,7 +196,7 @@ public final class TryWithResourcesJavacFilter implements IFilter { final MethodInsnNode m = (MethodInsnNode) cursor; if ("$closeResource".equals(m.name) && "(Ljava/lang/Throwable;Ljava/lang/AutoCloseable;)V" - .equals(m.desc)) { + .equals(m.desc)) { return true; } cursor = null; diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 6c6a48ed..ce2475c3 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -24,6 +24,9 @@
      • Synthetic classes are filtered out during generation of report (GitHub #668).
      • +
      • Methods added by the Kotlin compiler are filtered out during generation + of report. Idea and implementation by Nikolay Krasko + (GitHub #689).

      Fixed Bugs

      -- cgit v1.2.3 From 09611b76d28ce048c64837ceddbca67834cf6fa8 Mon Sep 17 00:00:00 2001 From: "Marc R. Hoffmann" Date: Thu, 7 Jun 2018 21:39:18 +0200 Subject: Remove locale dependent checks from tests (#682) Our version of args4j issues locale dependent exception messages. Remove assertions on those to make build not fail on other locales than en. --- org.jacoco.cli.test/src/org/jacoco/cli/internal/MainTest.java | 2 +- .../src/org/jacoco/cli/internal/commands/ClassInfoTest.java | 2 +- org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/DumpTest.java | 2 +- .../src/org/jacoco/cli/internal/commands/ExecInfoTest.java | 2 +- .../src/org/jacoco/cli/internal/commands/InstrumentTest.java | 2 +- org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/MergeTest.java | 2 +- .../src/org/jacoco/cli/internal/commands/ReportTest.java | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/org.jacoco.cli.test/src/org/jacoco/cli/internal/MainTest.java b/org.jacoco.cli.test/src/org/jacoco/cli/internal/MainTest.java index 9c3d82bc..8750a3bc 100644 --- a/org.jacoco.cli.test/src/org/jacoco/cli/internal/MainTest.java +++ b/org.jacoco.cli.test/src/org/jacoco/cli/internal/MainTest.java @@ -24,7 +24,7 @@ public class MainTest extends CommandTestBase { assertFailure(); assertNoOutput(out); - assertContains("Argument \"\" is required", err); + assertContains("\"\"", err); assertContains("Usage: java -jar jacococli.jar --help | ", err); assertContains("Command line interface for JaCoCo.", err); diff --git a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/ClassInfoTest.java b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/ClassInfoTest.java index f972f9cb..5f69e326 100644 --- a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/ClassInfoTest.java +++ b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/ClassInfoTest.java @@ -25,7 +25,7 @@ public class ClassInfoTest extends CommandTestBase { execute("classinfo", "--invalid"); assertFailure(); - assertContains("\"--invalid\" is not a valid option", err); + assertContains("\"--invalid\"", err); assertContains( "java -jar jacococli.jar classinfo [ ...]", err); diff --git a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/DumpTest.java b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/DumpTest.java index 6fc89233..ae61571e 100644 --- a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/DumpTest.java +++ b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/DumpTest.java @@ -51,7 +51,7 @@ public class DumpTest extends CommandTestBase { throws Exception { execute("dump"); assertFailure(); - assertContains("Option \"--destfile\" is required", err); + assertContains("\"--destfile\"", err); assertContains("java -jar jacococli.jar dump [--address
      ]", err); } diff --git a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/ExecInfoTest.java b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/ExecInfoTest.java index d688625b..c98d918c 100644 --- a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/ExecInfoTest.java +++ b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/ExecInfoTest.java @@ -37,7 +37,7 @@ public class ExecInfoTest extends CommandTestBase { execute("execinfo", "--invalid"); assertFailure(); - assertContains("\"--invalid\" is not a valid option", err); + assertContains("\"--invalid\"", err); assertContains("java -jar jacococli.jar execinfo [ ...]", err); } diff --git a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/InstrumentTest.java b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/InstrumentTest.java index 75850c1e..40a3918f 100644 --- a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/InstrumentTest.java +++ b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/InstrumentTest.java @@ -47,7 +47,7 @@ public class InstrumentTest extends CommandTestBase { throws Exception { execute("instrument"); assertFailure(); - assertContains("Option \"--dest\" is required", err); + assertContains("\"--dest\"", err); assertContains( "Usage: java -jar jacococli.jar instrument [ ...]", err); diff --git a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/MergeTest.java b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/MergeTest.java index fd04a341..0e119748 100644 --- a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/MergeTest.java +++ b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/MergeTest.java @@ -43,7 +43,7 @@ public class MergeTest extends CommandTestBase { execute("merge"); assertFailure(); - assertContains("Option \"--destfile\" is required", err); + assertContains("\"--destfile\"", err); assertContains("java -jar jacococli.jar merge [ ...]", err); } diff --git a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/ReportTest.java b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/ReportTest.java index 4a941ccf..96e08ee3 100644 --- a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/ReportTest.java +++ b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/ReportTest.java @@ -37,7 +37,7 @@ public class ReportTest extends CommandTestBase { execute("report"); assertFailure(); - assertContains("Option \"--classfiles\" is required", err); + assertContains("\"--classfiles\"", err); assertContains( "Usage: java -jar jacococli.jar report [ ...]", err); } -- cgit v1.2.3 From 77b3c8bbe5ca29cf77da5522cbea9b29f43dab74 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Thu, 7 Jun 2018 22:35:25 +0200 Subject: Remove partial localization of CLI (#691) --- org.jacoco.cli/pom.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/org.jacoco.cli/pom.xml b/org.jacoco.cli/pom.xml index 2b570f7c..344e9b7d 100644 --- a/org.jacoco.cli/pom.xml +++ b/org.jacoco.cli/pom.xml @@ -101,6 +101,14 @@ + + + args4j:args4j + + **/Messages_*.properties + + + -- cgit v1.2.3 From 0bcd964b0b784a25c4fee410a0c163399384b69f Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 13 Jun 2018 15:29:54 +0200 Subject: Re-enable SonarQube analysis and fix link on its results (#694) --- .travis.sh | 5 ++++- org.jacoco.doc/docroot/doc/environment.html | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.sh b/.travis.sh index b4b58536..ea1209b1 100755 --- a/.travis.sh +++ b/.travis.sh @@ -77,8 +77,11 @@ case "$JDK" in 5) if [[ ${TRAVIS_PULL_REQUEST} == 'false' && ${TRAVIS_BRANCH} == 'master' ]] then + # Travis does shallow clone, but SonarQube performs "git blame" and so requires full history + git fetch --unshallow + # goal "deploy:deploy" used directly instead of "deploy" phase to avoid pollution of Maven repository by "install" phase - mvn -V -B -e -f org.jacoco.build verify deploy:deploy -DdeployAtEnd -Djdk.version=1.5 --toolchains=./.travis/toolchains.xml --settings=./.travis/settings.xml -Dsonar.host.url=${SONARQUBE_URL} -Dsonar.login=${SONARQUBE_TOKEN} + mvn -V -B -e -f org.jacoco.build verify sonar:sonar deploy:deploy -DdeployAtEnd -Djdk.version=1.5 --toolchains=./.travis/toolchains.xml --settings=./.travis/settings.xml -Dsonar.host.url=${SONARQUBE_URL} -Dsonar.login=${SONARQUBE_TOKEN} python ./.travis/trigger-site-deployment.py else mvn -V -B -e verify -Djdk.version=1.5 --toolchains=./.travis/toolchains.xml diff --git a/org.jacoco.doc/docroot/doc/environment.html b/org.jacoco.doc/docroot/doc/environment.html index 33df73ab..d2d426d5 100644 --- a/org.jacoco.doc/docroot/doc/environment.html +++ b/org.jacoco.doc/docroot/doc/environment.html @@ -115,7 +115,7 @@

      We track quality issues with our source code with - SonarQube. + SonarQube.

      Communication

      -- cgit v1.2.3 From 766763d0a128a1cda5fbff83ef6ecddfe7bede8e Mon Sep 17 00:00:00 2001 From: "Marc R. Hoffmann" Date: Wed, 27 Jun 2018 20:33:06 +0200 Subject: Improve error message displayed when processing instrumented classes (#703) --- .../core/internal/instr/InstrSupportTest.java | 23 +++++++++++++++++----- .../jacoco/core/internal/instr/InstrSupport.java | 5 +++-- org.jacoco.doc/docroot/doc/changes.html | 7 +++++++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java index 95de8bd5..b8a89cbc 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java @@ -17,7 +17,9 @@ import static org.junit.Assert.assertTrue; import org.jacoco.core.internal.BytecodeVersion; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.objectweb.asm.Opcodes; import org.objectweb.asm.util.Printer; import org.objectweb.asm.util.Textifier; @@ -31,6 +33,9 @@ public class InstrSupportTest { private Printer printer; private TraceMethodVisitor trace; + @Rule + public ExpectedException exception = ExpectedException.none(); + @Before public void setup() { printer = new Textifier(); @@ -56,17 +61,25 @@ public class InstrSupportTest { } @Test - public void testAssertNotIntrumentedPositive() { + public void assertNotIntrumented_should_accept_non_jacoco_memebers() { InstrSupport.assertNotInstrumented("run", "Foo"); } - @Test(expected = IllegalStateException.class) - public void testAssertNotIntrumentedField() { + @Test + public void assertNotIntrumented_should_throw_exception_when_jacoco_data_field_is_present() { + exception.expect(IllegalStateException.class); + exception.expectMessage( + "Cannot process instrumented class Foo. Please supply original non-instrumented classes."); + InstrSupport.assertNotInstrumented("$jacocoData", "Foo"); } - @Test(expected = IllegalStateException.class) - public void testAssertNotIntrumentedMethod() { + @Test + public void assertNotIntrumented_should_throw_exception_when_jacoco_init_method_is_present() { + exception.expect(IllegalStateException.class); + exception.expectMessage( + "Cannot process instrumented class Foo. Please supply original non-instrumented classes."); + InstrSupport.assertNotInstrumented("$jacocoInit", "Foo"); } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java index c7b7cf84..ed52bd37 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java @@ -185,8 +185,9 @@ public final class InstrSupport { public static void assertNotInstrumented(final String member, final String owner) throws IllegalStateException { if (member.equals(DATAFIELD_NAME) || member.equals(INITMETHOD_NAME)) { - throw new IllegalStateException( - format("Class %s is already instrumented.", owner)); + throw new IllegalStateException(format( + "Cannot process instrumented class %s. Please supply original non-instrumented classes.", + owner)); } } diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index ce2475c3..5299b4e3 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -38,6 +38,13 @@ (GitHub #672).
    +

    Non-functional Changes

    +
      +
    • Improved error message when already instrumented classes are used for + instrumentation or analysis + (GitHub #703).
    • +
    +

    Release 0.8.1 (2018/03/21)

    New Features

    -- cgit v1.2.3 From 5e1d3090d96c977df9cc330e6f12d505b4f604f4 Mon Sep 17 00:00:00 2001 From: "Marc R. Hoffmann" Date: Wed, 27 Jun 2018 21:20:20 +0200 Subject: Add new attribute "sourcefilename" to "class" element in XML report (#702) This allows to unambiguously relate classes to source files in case of multiple top level classes. --- org.jacoco.doc/docroot/doc/changes.html | 8 ++++++++ .../org/jacoco/report/internal/xml/XMLGroupVisitorTest.java | 6 +++--- .../src/org/jacoco/report/xml/XMLFormatterTest.java | 10 ++++++---- .../src/org/jacoco/report/internal/xml/XMLCoverageWriter.java | 1 + org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java | 2 +- org.jacoco.report/src/org/jacoco/report/xml/report.dtd | 4 +++- 6 files changed, 22 insertions(+), 9 deletions(-) diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 5299b4e3..bed7d9d3 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -45,6 +45,14 @@ (GitHub #703).
+

API Changes

+
    +
  • The XML report now has an optional attribute sourcefilename + on the class element to allow unambiguously relate classes + to source files. The JaCoCo DTD version has been updated to 1.1 + (GitHub #702).
  • +
+

Release 0.8.1 (2018/03/21)

New Features

diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLGroupVisitorTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLGroupVisitorTest.java index fb8771ea..e7eb78e6 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLGroupVisitorTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLGroupVisitorTest.java @@ -44,7 +44,7 @@ public class XMLGroupVisitorTest { public void setup() throws Exception { buffer = new StringWriter(); support = new XMLSupport(XMLFormatter.class); - root = new XMLDocument("report", "-//JACOCO//DTD Report 1.0//EN", + root = new XMLDocument("report", "-//JACOCO//DTD Report 1.1//EN", "report.dtd", "UTF-8", true, buffer); root.attr("name", "Report"); handler = new XMLGroupVisitor(root, null); @@ -77,8 +77,8 @@ public class XMLGroupVisitorTest { "//report/counter[@type='BRANCH']/@covered")); } - private Document getDocument() throws SAXException, IOException, - ParserConfigurationException { + private Document getDocument() + throws SAXException, IOException, ParserConfigurationException { return support.parse(buffer.toString()); } diff --git a/org.jacoco.report.test/src/org/jacoco/report/xml/XMLFormatterTest.java b/org.jacoco.report.test/src/org/jacoco/report/xml/XMLFormatterTest.java index c79078e1..c409589a 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/xml/XMLFormatterTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/xml/XMLFormatterTest.java @@ -98,6 +98,8 @@ public class XMLFormatterTest { assertPathMatches("org/jacoco/example", "/report/group/package/@name"); assertPathMatches("org/jacoco/example/FooClass", "/report/group/package/class/@name"); + assertPathMatches("FooClass.java", + "/report/group/package/class/@sourcefilename"); assertPathMatches("fooMethod", "/report/group/package/class/method/@name"); @@ -167,8 +169,8 @@ public class XMLFormatterTest { final IReportVisitor visitor = formatter.createVisitor(output); visitor.visitInfo(infos, data); driver.sendBundle(visitor); - final BufferedReader reader = new BufferedReader(new InputStreamReader( - output.getContentsAsStream(), "UTF-8")); + final BufferedReader reader = new BufferedReader( + new InputStreamReader(output.getContentsAsStream(), "UTF-8")); final String line = reader.readLine(); assertTrue(line, line.startsWith(" @@ -44,6 +44,8 @@ + + -- cgit v1.2.3 From 6cd17a80e311cb48ba00d57f4138ff84b949c619 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Tue, 3 Jul 2018 15:41:06 +0200 Subject: Upgrade ASM to 6.2 (#706) --- jacoco/pom.xml | 2 +- org.jacoco.build/pom.xml | 2 +- .../jacoco/core/test/validation/BootstrapMethodReferenceTest.java | 2 +- .../src/org/jacoco/core/analysis/AnalyzerTest.java | 2 +- .../jacoco/core/internal/instr/DuplicateFrameEliminatorTest.java | 4 ++-- .../org/jacoco/core/test/validation/ResizeInstructionsTest.java | 7 ++----- org.jacoco.doc/docroot/doc/changes.html | 2 ++ 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/jacoco/pom.xml b/jacoco/pom.xml index 21285ad3..887a2a31 100644 --- a/jacoco/pom.xml +++ b/jacoco/pom.xml @@ -110,7 +110,7 @@ - 4100000 + 4200000 3400000 ${project.build.directory}/jacoco-${qualified.bundle.version}.zip diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index 8931e170..ac4f3cc2 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -141,7 +141,7 @@ ${jvm.args} - 6.0 + 6.2 1.7.1 2.0.28 4.8.2 diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java index 79744248..dc20f0af 100644 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java +++ b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java @@ -97,7 +97,7 @@ public class BootstrapMethodReferenceTest { /** * Adds code that triggers usage of - * {@link org.objectweb.asm.MethodWriter#INSERTED_FRAMES} during + * {@link org.objectweb.asm.MethodWriter#COMPUTE_INSERTED_FRAMES} during * instrumentation. */ private static void addCauseOfResizeInstructions(final MethodVisitor mv) { 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 4e5d81a8..d8828340 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 @@ -79,7 +79,7 @@ public class AnalyzerTest { @Test public void should_ignore_synthetic_classes() throws Exception { final ClassWriter cw = new ClassWriter(0); - cw.visit(Opcodes.V1_1, Opcodes.ACC_SYNTHETIC, "Foo", null, + cw.visit(Opcodes.V1_5, Opcodes.ACC_SYNTHETIC, "Foo", null, "java/lang/Object", null); cw.visitEnd(); final byte[] bytes = cw.toByteArray(); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/DuplicateFrameEliminatorTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/DuplicateFrameEliminatorTest.java index 2042397b..34a7dee8 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/DuplicateFrameEliminatorTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/DuplicateFrameEliminatorTest.java @@ -101,7 +101,7 @@ public class DuplicateFrameEliminatorTest { @Test public void testInvokeDynamicInsn() { testInstructionBetweenFrames(new InvokeDynamicInsnNode("foo", "()V", - new Handle(0, null, null, null, false))); + new Handle(Opcodes.H_INVOKEVIRTUAL, null, null, null, false))); } @Test @@ -149,7 +149,7 @@ public class DuplicateFrameEliminatorTest { } private void frame(MethodVisitor mv) { - mv.visitFrame(Opcodes.NEW, 1, new Object[] { Opcodes.INTEGER }, 0, + mv.visitFrame(Opcodes.F_NEW, 1, new Object[] { Opcodes.INTEGER }, 0, new Object[0]); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java index 571bb800..fe6d134a 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java @@ -58,15 +58,12 @@ public class ResizeInstructionsTest { */ @Test public void should_not_loose_InnerClasses_attribute() throws Exception { - // FIXME fails without COMPUTE_FRAMES because of - // https://gitlab.ow2.org/asm/asm/issues/317800 - byte[] source = TargetLoader.getClassDataAsBytes(Inner.class); final int version = BytecodeVersion.get(source); source = BytecodeVersion.downgradeIfNeeded(version, source); final ClassReader cr = new ClassReader(source); - final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + final ClassWriter cw = new ClassWriter(0); cr.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, cw) { @Override public void visitEnd() { @@ -157,7 +154,7 @@ public class ResizeInstructionsTest { /** * Adds code that triggers usage of - * {@link org.objectweb.asm.MethodWriter#INSERTED_FRAMES} during + * {@link org.objectweb.asm.MethodWriter#COMPUTE_INSERTED_FRAMES} during * instrumentation. */ private static void addCauseOfResizeInstructions(final MethodVisitor mv) { diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index bed7d9d3..c5930d39 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -40,6 +40,8 @@

Non-functional Changes

    +
  • JaCoCo now depends on ASM 6.2 + (GitHub #706).
  • Improved error message when already instrumented classes are used for instrumentation or analysis (GitHub #703).
  • -- cgit v1.2.3 From b4e9b0ae88cc7b2b604ef44e9286f322acd079ae Mon Sep 17 00:00:00 2001 From: "Marc R. Hoffmann" Date: Thu, 5 Jul 2018 10:19:39 +0200 Subject: Cleanup internal XML generation framework (#652) * Combine XMLElement and XMLDocument to allow single schema specific subclass * Add subclass for JaCoCo report XML schema * Remove mostly unused return values * Remove unused Writer output * Cleanup unit tests * Use new test naming conventions --- .../org/jacoco/cli/internal/XmlDocumentation.java | 5 +- .../jacoco/report/ReportStructureTestDriver.java | 5 +- .../report/internal/html/HTMLDocumentTest.java | 85 --------- .../report/internal/html/HTMLElementTest.java | 207 ++++++++++----------- .../internal/html/page/SourceHighlighterTest.java | 52 +++--- .../report/internal/html/table/BarColumnTest.java | 54 +++--- .../internal/html/table/CounterColumnTest.java | 40 ++-- .../internal/html/table/LabelColumnTest.java | 31 +-- .../internal/html/table/PercentageColumnTest.java | 36 ++-- .../report/internal/html/table/TableTest.java | 54 +++--- .../report/internal/xml/XMLDocumentTest.java | 93 --------- .../jacoco/report/internal/xml/XMLElementTest.java | 129 ++++++++----- .../report/internal/xml/XMLGroupVisitorTest.java | 31 ++- .../org/jacoco/report/internal/xml/XMLSupport.java | 12 +- .../org/jacoco/report/xml/XMLFormatterTest.java | 16 +- .../jacoco/report/internal/html/HTMLDocument.java | 97 ---------- .../jacoco/report/internal/html/HTMLElement.java | 118 +++++++----- .../report/internal/html/page/ReportPage.java | 18 +- .../report/internal/html/page/SourceFilePage.java | 12 +- .../report/internal/html/page/TablePage.java | 6 +- .../report/internal/html/table/BarColumn.java | 5 +- .../jacoco/report/internal/xml/ReportElement.java | 203 ++++++++++++++++++++ .../report/internal/xml/XMLCoverageWriter.java | 67 ++----- .../jacoco/report/internal/xml/XMLDocument.java | 111 ----------- .../org/jacoco/report/internal/xml/XMLElement.java | 194 ++++++++++--------- .../report/internal/xml/XMLGroupVisitor.java | 12 +- .../src/org/jacoco/report/xml/XMLFormatter.java | 50 +++-- 27 files changed, 797 insertions(+), 946 deletions(-) delete mode 100644 org.jacoco.report.test/src/org/jacoco/report/internal/html/HTMLDocumentTest.java delete mode 100644 org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLDocumentTest.java delete mode 100644 org.jacoco.report/src/org/jacoco/report/internal/html/HTMLDocument.java create mode 100644 org.jacoco.report/src/org/jacoco/report/internal/xml/ReportElement.java delete mode 100644 org.jacoco.report/src/org/jacoco/report/internal/xml/XMLDocument.java diff --git a/org.jacoco.cli/src/org/jacoco/cli/internal/XmlDocumentation.java b/org.jacoco.cli/src/org/jacoco/cli/internal/XmlDocumentation.java index 3ed83e02..d58a6012 100644 --- a/org.jacoco.cli/src/org/jacoco/cli/internal/XmlDocumentation.java +++ b/org.jacoco.cli/src/org/jacoco/cli/internal/XmlDocumentation.java @@ -17,7 +17,6 @@ import java.io.IOException; import java.util.List; import org.jacoco.cli.internal.commands.AllCommands; -import org.jacoco.report.internal.xml.XMLDocument; import org.jacoco.report.internal.xml.XMLElement; import org.kohsuke.args4j.spi.OptionHandler; @@ -65,8 +64,8 @@ public final class XmlDocumentation { final File file = new File(args[0]); file.getParentFile().mkdirs(); - final XMLElement root = new XMLDocument("documentation", null, null, - "UTF-8", true, new FileOutputStream(file)); + final XMLElement root = new XMLElement("documentation", null, null, + true, "UTF-8", new FileOutputStream(file)); for (final Command c : AllCommands.get()) { writeCommand(c, root); diff --git a/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java b/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java index 1b9c80b1..203028fc 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java +++ b/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java @@ -69,7 +69,7 @@ public class ReportStructureTestDriver { m.increment(CounterImpl.getInstance(3, 5), CounterImpl.COUNTER_0_0, 1); m.increment(CounterImpl.getInstance(3, 5), CounterImpl.getInstance(1, 2), 2); - m.increment(CounterImpl.getInstance(4, 5), CounterImpl.COUNTER_0_0, 3); + m.increment(CounterImpl.getInstance(4, 5), CounterImpl.COUNTER_0_0, 4); m.incrementMethodCounter(); methodCoverage = m; @@ -119,7 +119,8 @@ public class ReportStructureTestDriver { reportVisitor.visitEnd(); } - public void sendBundle(IReportGroupVisitor groupVisitor) throws IOException { + public void sendBundle(IReportGroupVisitor groupVisitor) + throws IOException { groupVisitor.visitBundle(bundleCoverage, sourceFileLocator); } diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/HTMLDocumentTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/HTMLDocumentTest.java deleted file mode 100644 index 436fe9a9..00000000 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/HTMLDocumentTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.report.internal.html; - -import static org.junit.Assert.assertEquals; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.StringWriter; - -import org.junit.Test; - -/** - * Unit tests for {@link HTMLDocument}. - */ -public class HTMLDocumentTest { - - @Test - public void testWriter() throws IOException { - StringWriter buffer = new StringWriter(); - new HTMLDocument(buffer, "UTF-8").close(); - assertEquals( - "" - + "" - + "", - buffer.toString()); - } - - @Test - public void testStream() throws IOException { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - new HTMLDocument(buffer, "UTF-8").close(); - assertEquals( - "" - + "" - + "", - buffer.toString("UTF-8")); - } - - @Test - public void testHead() throws IOException { - StringWriter buffer = new StringWriter(); - final HTMLDocument doc = new HTMLDocument(buffer, "UTF-8"); - doc.head(); - doc.close(); - assertEquals( - "" - + "" - + "", - buffer.toString()); - } - - @Test - public void testBody() throws IOException { - StringWriter buffer = new StringWriter(); - final HTMLDocument doc = new HTMLDocument(buffer, "UTF-8"); - doc.body(); - doc.close(); - assertEquals( - "" - + "" - + "", - buffer.toString()); - } - - @Test - public void testMinimalHTMLDocument() throws Exception { - StringWriter buffer = new StringWriter(); - final HTMLDocument doc = new HTMLDocument(buffer, "UTF-8"); - doc.head().title(); - doc.body(); - doc.close(); - new HTMLSupport().parse(buffer.toString()); - } - -} diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/HTMLElementTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/HTMLElementTest.java index 2eff51a1..3608d382 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/HTMLElementTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/HTMLElementTest.java @@ -13,8 +13,8 @@ package org.jacoco.report.internal.html; import static org.junit.Assert.assertEquals; +import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.StringWriter; import org.junit.Before; import org.junit.Test; @@ -24,218 +24,215 @@ import org.junit.Test; */ public class HTMLElementTest { - private StringWriter buffer; + private static final String PREFIX = ""; + + private static final String SUFFIX = ""; + + private ByteArrayOutputStream buffer; private HTMLElement root; @Before - public void setUp() throws IOException { - buffer = new StringWriter(); - root = new HTMLElement(buffer, "root") { - { - beginOpenTag(); - } - }; + public void setup() throws IOException { + buffer = new ByteArrayOutputStream(); + root = new HTMLElement(buffer, "UTF-8"); } @Test - public void testMeta() throws IOException { - root.meta("key", "value"); + public void should_create_minimal_valid_html_document() throws Exception { + root.head().title(); + root.body(); root.close(); - assertEquals( - "", - buffer.toString()); + new HTMLSupport().parse(buffer); + } + + @Test + public void head_should_create_head_tag() throws IOException { + root.head(); + assertContent(""); + } + + @Test + public void meta_should_create_meta_tag_with_attributes() + throws IOException { + root.meta("key", "value"); + assertContent(""); } @Test - public void testLink() throws IOException { + public void body_should_create_body_tag() throws IOException { + root.body(); + assertContent(""); + } + + @Test + public void link_should_create_link_tag_with_attributes() + throws IOException { root.link("stylesheet", "style.css", "text/css"); - root.close(); - assertEquals( - "", - buffer.toString()); + assertContent( + ""); } @Test - public void testTitle() throws IOException { + public void title_should_create_title_tag() throws IOException { root.title(); - root.close(); - assertEquals("</root>", buffer.toString()); + assertContent("<title/>"); } @Test - public void testH1() throws IOException { + public void h1_should_create_h1_tag() throws IOException { root.h1(); - root.close(); - assertEquals("<root><h1/></root>", buffer.toString()); + assertContent("<h1/>"); } @Test - public void testP() throws IOException { + public void p_should_create_p_tag() throws IOException { root.p(); - root.close(); - assertEquals("<root><p/></root>", buffer.toString()); + assertContent("<p/>"); } @Test - public void testSpan1() throws IOException { + public void span_should_create_span_tag() throws IOException { root.span(); - root.close(); - assertEquals("<root><span/></root>", buffer.toString()); + assertContent("<span/>"); } @Test - public void testSpan2() throws IOException { + public void span_should_create_span_tag_with_class_attribute() + throws IOException { root.span("abc"); - root.close(); - assertEquals("<root><span class=\"abc\"/></root>", buffer.toString()); + assertContent("<span class=\"abc\"/>"); } @Test - public void testSpan3() throws IOException { + public void span_should_create_span_tag_with_class_and_id_attribute() + throws IOException { root.span("abc", "xy"); - root.close(); - assertEquals("<root><span class=\"abc\" id=\"xy\"/></root>", - buffer.toString()); + assertContent("<span class=\"abc\" id=\"xy\"/>"); } @Test - public void testPre() throws IOException { + public void pre_should_create_pre_tag_with_class_attribute() + throws IOException { root.pre("mystyle"); - root.close(); - assertEquals("<root><pre class=\"mystyle\"/></root>", buffer.toString()); + assertContent("<pre class=\"mystyle\"/>"); } @Test - public void testDiv() throws IOException { + public void div_should_create_div_tag_with_class_attribute() + throws IOException { root.div("mystyle"); - root.close(); - assertEquals("<root><div class=\"mystyle\"/></root>", buffer.toString()); + assertContent("<div class=\"mystyle\"/>"); } @Test - public void testCode() throws IOException { + public void code_should_create_code_tag() throws IOException { root.code().text("0xCAFEBABE"); - root.close(); - assertEquals("<root><code>0xCAFEBABE</code></root>", buffer.toString()); + assertContent("<code>0xCAFEBABE</code>"); } @Test - public void testA1() throws IOException { + public void a_should_create_a_tag_with_href_attribute() throws IOException { root.a("http://www.jacoco.org/"); - root.close(); - assertEquals("<root><a href=\"http://www.jacoco.org/\"/></root>", - buffer.toString()); + assertContent("<a href=\"http://www.jacoco.org/\"/>"); } @Test - public void testA2() throws IOException { + public void a_should_create_a_tag_with_href_and_class_attribute() + throws IOException { root.a("http://www.jacoco.org/", "extern"); - root.close(); - assertEquals( - "<root><a href=\"http://www.jacoco.org/\" class=\"extern\"/></root>", - buffer.toString()); + assertContent("<a href=\"http://www.jacoco.org/\" class=\"extern\"/>"); } @Test - public void testALinkable1() throws IOException { + public void a_should_create_span_tag_when_no_link_is_given() + throws IOException { root.a(new LinkableStub(null, "here", null), null); - root.close(); - assertEquals("<root><span>here</span></root>", buffer.toString()); + assertContent("<span>here</span>"); } @Test - public void testALinkable2() throws IOException { + public void a_should_create_span_tag_with_class_attribute_when_no_link_is_given() + throws IOException { root.a(new LinkableStub(null, "here", "blue"), null); - root.close(); - assertEquals("<root><span class=\"blue\">here</span></root>", - buffer.toString()); + assertContent("<span class=\"blue\">here</span>"); } @Test - public void testALinkable3() throws IOException { + public void a_should_create_a_tag_when_link_is_given() throws IOException { root.a(new LinkableStub("index.html", "here", null), null); - root.close(); - assertEquals("<root><a href=\"index.html\">here</a></root>", - buffer.toString()); + assertContent("<a href=\"index.html\">here</a>"); } @Test - public void testALinkable4() throws IOException { + public void a_should_create_a_tag_with_class_attribute_when_link_is_given() + throws IOException { root.a(new LinkableStub("index.html", "here", "red"), null); - root.close(); - assertEquals( - "<root><a href=\"index.html\" class=\"red\">here</a></root>", - buffer.toString()); + assertContent("<a href=\"index.html\" class=\"red\">here</a>"); } @Test - public void testTable() throws IOException { + public void table_should_create_table_tag_with_attributes() + throws IOException { root.table("tablestyle"); - root.close(); - assertEquals( - "<root><table class=\"tablestyle\" cellspacing=\"0\"/></root>", - buffer.toString()); + assertContent("<table class=\"tablestyle\" cellspacing=\"0\"/>"); } @Test - public void testThead() throws IOException { + public void thead_should_create_thead_tag() throws IOException { root.thead(); - root.close(); - assertEquals("<root><thead/></root>", buffer.toString()); + assertContent("<thead/>"); } @Test - public void testTfoot() throws IOException { + public void tfoot_should_create_tfoot_tag() throws IOException { root.tfoot(); - root.close(); - assertEquals("<root><tfoot/></root>", buffer.toString()); + assertContent("<tfoot/>"); } @Test - public void testTbody() throws IOException { + public void tbody_should_create_tbody_tag() throws IOException { root.tbody(); - root.close(); - assertEquals("<root><tbody/></root>", buffer.toString()); + assertContent("<tbody/>"); } @Test - public void testTr() throws IOException { + public void tr_should_create_tr_tag() throws IOException { root.tr(); - root.close(); - assertEquals("<root><tr/></root>", buffer.toString()); + assertContent("<tr/>"); } @Test - public void testTd1() throws IOException { + public void td_should_create_td_tag() throws IOException { root.td(); - root.close(); - assertEquals("<root><td/></root>", buffer.toString()); + assertContent("<td/>"); } @Test - public void testTd2() throws IOException { + public void td_should_create_td_tag_with_class_attribute() + throws IOException { root.td("mystyle"); - root.close(); - assertEquals("<root><td class=\"mystyle\"/></root>", buffer.toString()); + assertContent("<td class=\"mystyle\"/>"); } @Test - public void testImg() throws IOException { + public void img_should_create_img_tag_with_attributes() throws IOException { root.img("sample.gif", 16, 32, "Hello"); - root.close(); - assertEquals( - "<root><img src=\"sample.gif\" width=\"16\" height=\"32\" title=\"Hello\" alt=\"Hello\"/></root>", - buffer.toString()); + assertContent( + "<img src=\"sample.gif\" width=\"16\" height=\"32\" title=\"Hello\" alt=\"Hello\"/>"); } @Test - public void testScript() throws IOException { - root.script("text/javascript", "file.js"); + public void script_should_create_script_tag_with_attributes() + throws IOException { + root.script("file.js"); + assertContent( + "<script type=\"text/javascript\" src=\"file.js\"></script>"); + } + + private void assertContent(String expected) throws IOException { root.close(); - assertEquals( - "<root><script type=\"text/javascript\" src=\"file.js\"></script></root>", - buffer.toString()); + assertEquals(PREFIX + expected + SUFFIX, buffer.toString("UTF-8")); } } diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/SourceHighlighterTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/SourceHighlighterTest.java index ca9d4d70..6df6f8c1 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/SourceHighlighterTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/SourceHighlighterTest.java @@ -13,14 +13,13 @@ package org.jacoco.report.internal.html.page; import static org.junit.Assert.assertEquals; +import java.io.ByteArrayOutputStream; import java.io.StringReader; -import java.io.StringWriter; import java.util.Locale; import org.jacoco.core.analysis.ICoverageNode.ElementType; import org.jacoco.core.internal.analysis.CounterImpl; import org.jacoco.core.internal.analysis.SourceNodeImpl; -import org.jacoco.report.internal.html.HTMLDocument; import org.jacoco.report.internal.html.HTMLElement; import org.jacoco.report.internal.html.HTMLSupport; import org.jacoco.report.internal.html.resources.Styles; @@ -35,9 +34,9 @@ public class SourceHighlighterTest { private HTMLSupport htmlSupport; - private StringWriter buffer; + private ByteArrayOutputStream buffer; - private HTMLDocument html; + private HTMLElement html; private HTMLElement parent; @@ -49,8 +48,8 @@ public class SourceHighlighterTest { public void setup() throws Exception { htmlSupport = new HTMLSupport(); source = new SourceNodeImpl(ElementType.SOURCEFILE, "Foo.java"); - buffer = new StringWriter(); - html = new HTMLDocument(buffer, "UTF-8"); + buffer = new ByteArrayOutputStream(); + html = new HTMLElement(buffer, "UTF-8"); html.head().title(); parent = html.body(); sourceHighlighter = new SourceHighlighter(Locale.US); @@ -60,8 +59,7 @@ public class SourceHighlighterTest { public void testDefaultTabWidth() throws Exception { final String src = "\tA"; sourceHighlighter.render(parent, source, new StringReader(src)); - html.close(); - final Document doc = htmlSupport.parse(buffer.toString()); + final Document doc = parseDoc(); // Assert that we no longer replace tabs with spaces assertEquals("\tA\n", htmlSupport.findStr(doc, "//pre/text()")); @@ -70,8 +68,7 @@ public class SourceHighlighterTest { @Test public void testDefaultLanguage() throws Exception { sourceHighlighter.render(parent, source, new StringReader("")); - html.close(); - final Document doc = htmlSupport.parse(buffer.toString()); + final Document doc = parseDoc(); assertEquals("source lang-java linenums", htmlSupport.findStr(doc, "//pre/@class")); } @@ -80,8 +77,7 @@ public class SourceHighlighterTest { public void testSetLanguage() throws Exception { sourceHighlighter.setLanguage("scala"); sourceHighlighter.render(parent, source, new StringReader("")); - html.close(); - final Document doc = htmlSupport.parse(buffer.toString()); + final Document doc = parseDoc(); assertEquals("source lang-scala linenums", htmlSupport.findStr(doc, "//pre/@class")); } @@ -94,8 +90,7 @@ public class SourceHighlighterTest { source.increment(CounterImpl.COUNTER_0_1, CounterImpl.COUNTER_0_0, 2); source.increment(CounterImpl.COUNTER_0_1, CounterImpl.COUNTER_0_0, 3); sourceHighlighter.render(parent, source, new StringReader(src)); - html.close(); - final Document doc = htmlSupport.parse(buffer.toString()); + final Document doc = parseDoc(); assertEquals(Styles.NOT_COVERED, htmlSupport.findStr(doc, "//pre/span[text() = 'A']/@class")); assertEquals(Styles.PARTLY_COVERED, @@ -109,18 +104,16 @@ public class SourceHighlighterTest { @Test public void testHighlightNone() throws Exception { sourceHighlighter.highlight(parent, source.getLine(1), 1); - html.close(); - final Document doc = htmlSupport.parse(buffer.toString()); + final Document doc = parseDoc(); assertEquals("", htmlSupport.findStr(doc, "//pre")); } @Test public void testHighlightBranchesFC() throws Exception { - source.increment(CounterImpl.COUNTER_0_1, - CounterImpl.getInstance(0, 5), 1); + source.increment(CounterImpl.COUNTER_0_1, CounterImpl.getInstance(0, 5), + 1); sourceHighlighter.highlight(parent.pre(null), source.getLine(1), 1); - html.close(); - final Document doc = htmlSupport.parse(buffer.toString()); + final Document doc = parseDoc(); assertEquals("fc bfc", htmlSupport.findStr(doc, "//pre/span/@class")); assertEquals("All 5 branches covered.", htmlSupport.findStr(doc, "//pre/span/@title")); @@ -128,11 +121,10 @@ public class SourceHighlighterTest { @Test public void testHighlightBranchesPC() throws Exception { - source.increment(CounterImpl.COUNTER_0_1, - CounterImpl.getInstance(2, 3), 1); + source.increment(CounterImpl.COUNTER_0_1, CounterImpl.getInstance(2, 3), + 1); sourceHighlighter.highlight(parent.pre(null), source.getLine(1), 1); - html.close(); - final Document doc = htmlSupport.parse(buffer.toString()); + final Document doc = parseDoc(); assertEquals("pc bpc", htmlSupport.findStr(doc, "//pre/span/@class")); assertEquals("2 of 5 branches missed.", htmlSupport.findStr(doc, "//pre/span/@title")); @@ -140,14 +132,18 @@ public class SourceHighlighterTest { @Test public void testHighlightBranchesNC() throws Exception { - source.increment(CounterImpl.COUNTER_0_1, - CounterImpl.getInstance(5, 0), 1); + source.increment(CounterImpl.COUNTER_0_1, CounterImpl.getInstance(5, 0), + 1); sourceHighlighter.highlight(parent.pre(null), source.getLine(1), 1); - html.close(); - final Document doc = htmlSupport.parse(buffer.toString()); + final Document doc = parseDoc(); assertEquals("pc bnc", htmlSupport.findStr(doc, "//pre/span/@class")); assertEquals("All 5 branches missed.", htmlSupport.findStr(doc, "//pre/span/@title")); } + private Document parseDoc() throws Exception { + html.close(); + return htmlSupport.parse(buffer); + } + } diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/BarColumnTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/BarColumnTest.java index 97e7658e..1449ee80 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/BarColumnTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/BarColumnTest.java @@ -26,7 +26,6 @@ import org.jacoco.core.analysis.ICoverageNode.ElementType; import org.jacoco.core.internal.analysis.CounterImpl; import org.jacoco.report.MemoryMultiReportOutput; import org.jacoco.report.internal.ReportOutputFolder; -import org.jacoco.report.internal.html.HTMLDocument; import org.jacoco.report.internal.html.HTMLElement; import org.jacoco.report.internal.html.HTMLSupport; import org.jacoco.report.internal.html.resources.Resources; @@ -46,7 +45,7 @@ public class BarColumnTest { private Resources resources; - private HTMLDocument doc; + private HTMLElement html; private HTMLElement td; @@ -59,9 +58,9 @@ public class BarColumnTest { output = new MemoryMultiReportOutput(); root = new ReportOutputFolder(output); resources = new Resources(root); - doc = new HTMLDocument(root.createFile("Test.html"), "UTF-8"); - doc.head().title(); - td = doc.body().table("somestyle").tr().td(); + html = new HTMLElement(root.createFile("Test.html"), "UTF-8"); + html.head().title(); + td = html.body().table("somestyle").tr().td(); support = new HTMLSupport(); column = new BarColumn(CounterEntity.LINE, Locale.ENGLISH); } @@ -76,14 +75,13 @@ public class BarColumnTest { public void testInit() throws Exception { final ITableItem i = createItem(6, 24); assertTrue(column.init(Arrays.asList(i), i.getNode())); - doc.close(); + html.close(); } @Test public void testFooter() throws Exception { column.footer(td, createNode(15, 5), resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("15 of 20", support.findStr(doc, "/html/body/table/tr/td/text()")); } @@ -94,8 +92,7 @@ public class BarColumnTest { final ITableItem i2 = createItem(6, 24); column.init(Arrays.asList(i1, i2), createNode(21, 29)); column.item(td, i1, resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("2", support.findStr(doc, "count(/html/body/table/tr[1]/td/img)")); @@ -105,16 +102,16 @@ public class BarColumnTest { support.findStr(doc, "/html/body/table/tr[1]/td/img[1]/@src")); assertEquals("15", support.findStr(doc, "/html/body/table/tr[1]/td/img[1]/@alt")); - assertEquals("60", - support.findStr(doc, "/html/body/table/tr[1]/td/img[1]/@width")); + assertEquals("60", support.findStr(doc, + "/html/body/table/tr[1]/td/img[1]/@width")); // green bar assertEquals("jacoco-resources/greenbar.gif", support.findStr(doc, "/html/body/table/tr[1]/td/img[2]/@src")); assertEquals("5", support.findStr(doc, "/html/body/table/tr[1]/td/img[2]/@alt")); - assertEquals("20", - support.findStr(doc, "/html/body/table/tr[1]/td/img[2]/@width")); + assertEquals("20", support.findStr(doc, + "/html/body/table/tr[1]/td/img[2]/@width")); } @Test @@ -122,8 +119,7 @@ public class BarColumnTest { final ITableItem i1 = createItem(20, 0); column.init(Arrays.asList(i1), createNode(20, 0)); column.item(td, i1, resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("1", support.findStr(doc, "count(/html/body/table/tr[1]/td/img)")); @@ -133,8 +129,8 @@ public class BarColumnTest { support.findStr(doc, "/html/body/table/tr[1]/td/img[1]/@src")); assertEquals("20", support.findStr(doc, "/html/body/table/tr[1]/td/img[1]/@alt")); - assertEquals("120", - support.findStr(doc, "/html/body/table/tr[1]/td/img[1]/@width")); + assertEquals("120", support.findStr(doc, + "/html/body/table/tr[1]/td/img[1]/@width")); } @Test @@ -142,8 +138,7 @@ public class BarColumnTest { final ITableItem i1 = createItem(00, 20); column.init(Arrays.asList(i1), createNode(00, 20)); column.item(td, i1, resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("1", support.findStr(doc, "count(/html/body/table/tr[1]/td/img)")); @@ -153,8 +148,8 @@ public class BarColumnTest { support.findStr(doc, "/html/body/table/tr[1]/td/img[1]/@src")); assertEquals("20", support.findStr(doc, "/html/body/table/tr[1]/td/img[1]/@alt")); - assertEquals("120", - support.findStr(doc, "/html/body/table/tr[1]/td/img[1]/@width")); + assertEquals("120", support.findStr(doc, + "/html/body/table/tr[1]/td/img[1]/@width")); } @Test @@ -162,8 +157,7 @@ public class BarColumnTest { final ITableItem i1 = createItem(00, 00); column.init(Arrays.asList(i1), createNode(00, 00)); column.item(td, i1, resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("0", support.findStr(doc, "count(/html/body/table/tr[1]/td/img)")); @@ -175,8 +169,7 @@ public class BarColumnTest { final ITableItem i1 = createItem(0, 123456); col.init(Arrays.asList(i1), createNode(00, 20)); col.item(td, i1, resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("123\u00a0456", support.findStr(doc, "/html/body/table/tr[1]/td/img[1]/@alt")); @@ -190,7 +183,7 @@ public class BarColumnTest { assertTrue(c.compare(i1, i2) < 0); assertTrue(c.compare(i2, i1) > 0); assertEquals(0, c.compare(i1, i1)); - doc.close(); + html.close(); } @Test @@ -201,7 +194,7 @@ public class BarColumnTest { assertTrue(c.compare(i1, i2) < 0); assertTrue(c.compare(i2, i1) > 0); assertEquals(0, c.compare(i1, i1)); - doc.close(); + html.close(); } private ITableItem createItem(final int missed, final int covered) { @@ -233,4 +226,9 @@ public class BarColumnTest { }; } + private Document parseDoc() throws Exception { + html.close(); + return support.parse(output.getFile("Test.html")); + } + } diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/CounterColumnTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/CounterColumnTest.java index 7c68e118..d6ff8434 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/CounterColumnTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/CounterColumnTest.java @@ -28,7 +28,6 @@ import org.jacoco.core.analysis.ICoverageNode.ElementType; import org.jacoco.core.internal.analysis.CounterImpl; import org.jacoco.report.MemoryMultiReportOutput; import org.jacoco.report.internal.ReportOutputFolder; -import org.jacoco.report.internal.html.HTMLDocument; import org.jacoco.report.internal.html.HTMLElement; import org.jacoco.report.internal.html.HTMLSupport; import org.jacoco.report.internal.html.resources.Resources; @@ -48,7 +47,7 @@ public class CounterColumnTest { private Resources resources; - private HTMLDocument doc; + private HTMLElement html; private HTMLElement td; @@ -61,9 +60,9 @@ public class CounterColumnTest { output = new MemoryMultiReportOutput(); root = new ReportOutputFolder(output); resources = new Resources(root); - doc = new HTMLDocument(root.createFile("Test.html"), "UTF-8"); - doc.head().title(); - td = doc.body().table("somestyle").tr().td(); + html = new HTMLElement(root.createFile("Test.html"), "UTF-8"); + html.head().title(); + td = html.body().table("somestyle").tr().td(); support = new HTMLSupport(); locale = Locale.ENGLISH; } @@ -80,7 +79,7 @@ public class CounterColumnTest { locale); final ITableItem item = createItem(0, 3); assertTrue(column.init(Arrays.asList(item), item.getNode())); - doc.close(); + html.close(); } @Test @@ -89,7 +88,7 @@ public class CounterColumnTest { locale); final ITableItem item = createItem(0, 0); assertFalse(column.init(Arrays.asList(item), createNode(1, 0))); - doc.close(); + html.close(); } @Test @@ -99,8 +98,7 @@ public class CounterColumnTest { final ITableItem item = createItem(100, 50); column.init(Collections.singletonList(item), item.getNode()); column.item(td, item, resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("150", support.findStr(doc, "/html/body/table/tr/td[1]/text()")); } @@ -112,8 +110,7 @@ public class CounterColumnTest { final ITableItem item = createItem(100, 50); column.init(Collections.singletonList(item), item.getNode()); column.item(td, item, resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("100", support.findStr(doc, "/html/body/table/tr/td[1]/text()")); } @@ -125,8 +122,7 @@ public class CounterColumnTest { final ITableItem item = createItem(100, 50); column.init(Collections.singletonList(item), item.getNode()); column.item(td, item, resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("50", support.findStr(doc, "/html/body/table/tr/td[1]/text()")); } @@ -138,8 +134,7 @@ public class CounterColumnTest { final ITableItem item = createItem(1000, 0); column.init(Collections.singletonList(item), item.getNode()); column.item(td, item, resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("1.000", support.findStr(doc, "/html/body/table/tr/td[1]/text()")); } @@ -151,8 +146,7 @@ public class CounterColumnTest { final ITableItem item = createItem(20, 60); column.init(Collections.singletonList(item), item.getNode()); column.footer(td, item.getNode(), resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("80", support.findStr(doc, "/html/body/table/tr/td[1]/text()")); } @@ -167,7 +161,7 @@ public class CounterColumnTest { assertEquals(0, c.compare(i1, i1)); assertTrue(c.compare(i1, i2) > 0); assertTrue(c.compare(i2, i1) < 0); - doc.close(); + html.close(); } @Test @@ -180,7 +174,7 @@ public class CounterColumnTest { assertEquals(0, c.compare(i1, i1)); assertTrue(c.compare(i1, i2) > 0); assertTrue(c.compare(i2, i1) < 0); - doc.close(); + html.close(); } @Test @@ -193,7 +187,7 @@ public class CounterColumnTest { assertEquals(0, c.compare(i1, i1)); assertTrue(c.compare(i1, i2) > 0); assertTrue(c.compare(i2, i1) < 0); - doc.close(); + html.close(); } private ITableItem createItem(final int missed, final int covered) { @@ -224,4 +218,10 @@ public class CounterColumnTest { } }; } + + private Document parseDoc() throws Exception { + html.close(); + return support.parse(output.getFile("Test.html")); + } + } diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/LabelColumnTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/LabelColumnTest.java index adf4e243..f2910ff6 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/LabelColumnTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/LabelColumnTest.java @@ -21,7 +21,6 @@ import org.jacoco.core.analysis.ICoverageNode; import org.jacoco.core.analysis.ICoverageNode.ElementType; import org.jacoco.report.MemoryMultiReportOutput; import org.jacoco.report.internal.ReportOutputFolder; -import org.jacoco.report.internal.html.HTMLDocument; import org.jacoco.report.internal.html.HTMLElement; import org.jacoco.report.internal.html.HTMLSupport; import org.jacoco.report.internal.html.resources.Resources; @@ -41,7 +40,7 @@ public class LabelColumnTest { private Resources resources; - private HTMLDocument doc; + private HTMLElement html; private HTMLElement td; @@ -54,9 +53,9 @@ public class LabelColumnTest { output = new MemoryMultiReportOutput(); root = new ReportOutputFolder(output); resources = new Resources(root); - doc = new HTMLDocument(root.createFile("Test.html"), "UTF-8"); - doc.head().title(); - td = doc.body().table("somestyle").tr().td(); + html = new HTMLElement(root.createFile("Test.html"), "UTF-8"); + html.head().title(); + td = html.body().table("somestyle").tr().td(); support = new HTMLSupport(); column = new LabelColumn(); } @@ -70,15 +69,14 @@ public class LabelColumnTest { @Test public void testInit() throws Exception { assertTrue(column.init(null, null)); - doc.close(); + html.close(); } @Test public void testFooter() throws Exception { column.footer(td, new CoverageNodeImpl(ElementType.GROUP, "Foo"), resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("Total", support.findStr(doc, "/html/body/table/tr/td/text()")); } @@ -86,8 +84,7 @@ public class LabelColumnTest { @Test public void testItemWithoutLink() throws Exception { column.item(td, createItem("Abc", null), resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("Abc", support.findStr(doc, "/html/body/table/tr/td/span/text()")); assertEquals("el_group", @@ -97,8 +94,7 @@ public class LabelColumnTest { @Test public void testItemWithLink() throws Exception { column.item(td, createItem("Def", "def.html"), resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("Def", support.findStr(doc, "/html/body/table/tr/td/a/text()")); assertEquals("def.html", @@ -112,7 +108,7 @@ public class LabelColumnTest { final ITableItem i1 = createItem("abcdef", null); final ITableItem i2 = createItem("aBcDeF", null); assertEquals(0, column.getComparator().compare(i1, i2)); - doc.close(); + html.close(); } @Test @@ -121,11 +117,12 @@ public class LabelColumnTest { final ITableItem i2 = createItem("world", null); assertTrue(column.getComparator().compare(i1, i2) < 0); assertTrue(column.getComparator().compare(i2, i1) > 0); - doc.close(); + html.close(); } private ITableItem createItem(final String name, final String link) { - final ICoverageNode node = new CoverageNodeImpl(ElementType.GROUP, name); + final ICoverageNode node = new CoverageNodeImpl(ElementType.GROUP, + name); return new ITableItem() { public String getLinkLabel() { return name; @@ -145,4 +142,8 @@ public class LabelColumnTest { }; } + private Document parseDoc() throws Exception { + html.close(); + return support.parse(output.getFile("Test.html")); + } } diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/PercentageColumnTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/PercentageColumnTest.java index bff3d970..6f8874ec 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/PercentageColumnTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/PercentageColumnTest.java @@ -25,7 +25,6 @@ import org.jacoco.core.analysis.ICoverageNode.ElementType; import org.jacoco.core.internal.analysis.CounterImpl; import org.jacoco.report.MemoryMultiReportOutput; import org.jacoco.report.internal.ReportOutputFolder; -import org.jacoco.report.internal.html.HTMLDocument; import org.jacoco.report.internal.html.HTMLElement; import org.jacoco.report.internal.html.HTMLSupport; import org.jacoco.report.internal.html.resources.Resources; @@ -45,7 +44,7 @@ public class PercentageColumnTest { private Resources resources; - private HTMLDocument doc; + private HTMLElement html; private HTMLElement td; @@ -58,9 +57,9 @@ public class PercentageColumnTest { output = new MemoryMultiReportOutput(); root = new ReportOutputFolder(output); resources = new Resources(root); - doc = new HTMLDocument(root.createFile("Test.html"), "UTF-8"); - doc.head().title(); - td = doc.body().table("somestyle").tr().td(); + html = new HTMLElement(root.createFile("Test.html"), "UTF-8"); + html.head().title(); + td = html.body().table("somestyle").tr().td(); support = new HTMLSupport(); column = new PercentageColumn(CounterEntity.LINE, Locale.ENGLISH); } @@ -74,15 +73,14 @@ public class PercentageColumnTest { @Test public void testInit() throws Exception { assertTrue(column.init(null, null)); - doc.close(); + html.close(); } @Test public void testItem1() throws Exception { final ITableItem item = createItem(100, 50); column.item(td, item, resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("33%", support.findStr(doc, "/html/body/table/tr/td[1]/text()")); } @@ -91,8 +89,7 @@ public class PercentageColumnTest { public void testItem2() throws Exception { final ITableItem item = createItem(0, 0); column.item(td, item, resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("n/a", support.findStr(doc, "/html/body/table/tr/td[1]/text()")); } @@ -101,8 +98,7 @@ public class PercentageColumnTest { public void testRounding() throws Exception { final ITableItem item = createItem(1, 199); column.item(td, item, resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("99%", support.findStr(doc, "/html/body/table/tr/td[1]/text()")); } @@ -113,8 +109,7 @@ public class PercentageColumnTest { Locale.FRENCH); final ITableItem item = createItem(0, 1000); column.item(td, item, resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); // After integration of JEP 252 into JDK9, CLDR locale data is used by // default, which results in usage of non-breaking space below, while // the legacy locale data uses regular space: @@ -126,8 +121,7 @@ public class PercentageColumnTest { public void testFooter1() throws Exception { final ITableItem item = createItem(20, 60); column.footer(td, item.getNode(), resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("75%", support.findStr(doc, "/html/body/table/tr")); } @@ -135,8 +129,7 @@ public class PercentageColumnTest { public void testFooter2() throws Exception { final ITableItem item = createItem(0, 0); column.footer(td, item.getNode(), resources, root); - doc.close(); - final Document doc = support.parse(output.getFile("Test.html")); + final Document doc = parseDoc(); assertEquals("n/a", support.findStr(doc, "/html/body/table/tr")); } @@ -148,7 +141,7 @@ public class PercentageColumnTest { assertTrue(c.compare(i1, i2) < 0); assertTrue(c.compare(i2, i1) > 0); assertEquals(0, c.compare(i1, i1)); - doc.close(); + html.close(); } private ITableItem createItem(final int missed, final int covered) { @@ -179,4 +172,9 @@ public class PercentageColumnTest { } }; } + + private Document parseDoc() throws Exception { + html.close(); + return support.parse(output.getFile("Test.html")); + } } diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/TableTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/TableTest.java index 4e6e2ed6..0bb57ed8 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/TableTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/table/TableTest.java @@ -27,7 +27,6 @@ import org.jacoco.core.analysis.ICoverageNode.ElementType; import org.jacoco.core.internal.analysis.CounterImpl; import org.jacoco.report.MemoryMultiReportOutput; import org.jacoco.report.internal.ReportOutputFolder; -import org.jacoco.report.internal.html.HTMLDocument; import org.jacoco.report.internal.html.HTMLElement; import org.jacoco.report.internal.html.HTMLSupport; import org.jacoco.report.internal.html.resources.Resources; @@ -47,7 +46,7 @@ public class TableTest { private Resources resources; - private HTMLDocument doc; + private HTMLElement html; private HTMLElement body; @@ -58,9 +57,9 @@ public class TableTest { output = new MemoryMultiReportOutput(); root = new ReportOutputFolder(output); resources = new Resources(root); - doc = new HTMLDocument(root.createFile("Test.html"), "UTF-8"); - doc.head().title(); - body = doc.body(); + html = new HTMLElement(root.createFile("Test.html"), "UTF-8"); + html.head().title(); + body = html.body(); table = new Table(); } @@ -106,7 +105,7 @@ public class TableTest { createItem("B", 2), createItem("C", 3)); table.add("Header", null, recorder, false); table.render(body, items, createTotal("Sum", 6), resources, root); - doc.close(); + html.close(); assertEquals("init-footer-itemA-itemB-itemC-", recorder.toString()); } @@ -136,31 +135,35 @@ public class TableTest { final List<ITableItem> items = Arrays.asList(createItem("A", 1)); table.add("Header", null, column, false); table.render(body, items, createTotal("Sum", 1), resources, root); - doc.close(); + html.close(); } @Test(expected = IllegalStateException.class) public void testTwoDefaultSorts() throws IOException { - doc.close(); - table.add("Header1", null, new StubRenderer( - CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)), true); - table.add("Header2", null, new StubRenderer( - CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)), true); + html.close(); + table.add("Header1", null, + new StubRenderer( + CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)), + true); + table.add("Header2", null, + new StubRenderer( + CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)), + true); } @Test public void testSortIds() throws Exception { final List<ITableItem> items = Arrays.asList(createItem("C", 3), createItem("E", 4), createItem("A", 1), createItem("D", 2)); - table.add("Forward", null, new StubRenderer( - CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)), false); - table.add( - "Reverse", - null, - new StubRenderer(CounterComparator.TOTALITEMS.reverse().on( - CounterEntity.CLASS)), false); + table.add("Forward", null, + new StubRenderer( + CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)), + false); + table.add("Reverse", null, new StubRenderer( + CounterComparator.TOTALITEMS.reverse().on(CounterEntity.CLASS)), + false); table.render(body, items, createTotal("Sum", 6), resources, root); - doc.close(); + html.close(); final HTMLSupport support = new HTMLSupport(); final Document doc = support.parse(output.getFile("Test.html")); @@ -199,10 +202,12 @@ public class TableTest { final List<ITableItem> items = Arrays.asList(createItem("C", 3), createItem("E", 5), createItem("A", 1), createItem("D", 4), createItem("B", 2)); - table.add("Forward", null, new StubRenderer( - CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)), true); + table.add("Forward", null, + new StubRenderer( + CounterComparator.TOTALITEMS.on(CounterEntity.CLASS)), + true); table.render(body, items, createTotal("Sum", 1), resources, root); - doc.close(); + html.close(); final HTMLSupport support = new HTMLSupport(); final Document doc = support.parse(output.getFile("Test.html")); @@ -222,7 +227,8 @@ public class TableTest { } private ITableItem createItem(final String name, final int count) { - final ICoverageNode node = new CoverageNodeImpl(ElementType.GROUP, name) { + final ICoverageNode node = new CoverageNodeImpl(ElementType.GROUP, + name) { { this.classCounter = CounterImpl.getInstance(count, 0); } diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLDocumentTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLDocumentTest.java deleted file mode 100644 index cd3d985a..00000000 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLDocumentTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.report.internal.xml; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.StringWriter; - -import org.junit.Test; - -/** - * Unit tests for {@link XMLDocument}. - */ -public class XMLDocumentTest { - - @Test - public void testNoDoctype() throws IOException { - StringWriter writer = new StringWriter(); - new XMLDocument("test", null, null, "UTF-8", false, writer).close(); - assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test/>", - writer.toString()); - } - - @Test - public void testNoDoctypeStandalone() throws IOException { - StringWriter writer = new StringWriter(); - new XMLDocument("test", null, null, "UTF-8", true, writer).close(); - assertEquals( - "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" - + "<test/>", writer.toString()); - } - - @Test - public void testDoctype() throws IOException { - StringWriter writer = new StringWriter(); - new XMLDocument("test", "sample", "sample.dtd", "UTF-8", false, writer) - .close(); - assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" - + "<!DOCTYPE test PUBLIC \"sample\" \"sample.dtd\"><test/>", - writer.toString()); - } - - @Test - public void testDoctypeStandalone() throws IOException { - StringWriter writer = new StringWriter(); - new XMLDocument("test", "sample", "sample.dtd", "UTF-8", true, writer) - .close(); - assertEquals( - "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" - + "<!DOCTYPE test PUBLIC \"sample\" \"sample.dtd\">" - + "<test/>", writer.toString()); - } - - @Test - public void testStream() throws IOException { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - new XMLDocument("test", null, null, "UTF-8", false, buffer).text( - "\u00CD\u307e").close(); - assertEquals( - "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>\u00CD\u307e</test>", - buffer.toString("UTF-8")); - } - - @Test - public void testClose() throws IOException { - class CloseVerifier extends StringWriter { - - boolean closed = false; - - @Override - public void close() throws IOException { - closed = true; - super.close(); - } - } - CloseVerifier verifier = new CloseVerifier(); - new XMLDocument("test", null, null, "UTF-8", false, verifier).close(); - assertTrue(verifier.closed); - } - -} diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLElementTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLElementTest.java index 0ba4644e..9d924eea 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLElementTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLElementTest.java @@ -13,8 +13,8 @@ package org.jacoco.report.internal.xml; import static org.junit.Assert.assertEquals; +import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.StringWriter; import org.junit.Before; import org.junit.Test; @@ -24,123 +24,156 @@ import org.junit.Test; */ public class XMLElementTest { - private StringWriter buffer; + private static final String DECL = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; + + private ByteArrayOutputStream buffer; private XMLElement root; @Before - public void setUp() throws IOException { - buffer = new StringWriter(); - root = new XMLElement(buffer, "root"); - root.beginOpenTag(); + public void setup() throws IOException { + buffer = new ByteArrayOutputStream(); + root = new XMLElement("root", null, null, false, "UTF-8", buffer); + } + + @Test + public void init_should_write_doctype_when_given() throws IOException { + root = new XMLElement("root", "-//JACOCO//TEST", "test.dtd", false, + "UTF-8", buffer); + assertEquals(DECL + + "<!DOCTYPE root PUBLIC \"-//JACOCO//TEST\" \"test.dtd\"><root/>", + actual()); + } + + @Test + public void init_should_write_standalone_when_given() throws IOException { + root = new XMLElement("root", null, null, true, "UTF-8", buffer); + assertEquals( + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><root/>", + actual()); } @Test - public void testEmptyNode() throws IOException { + public void close_should_emit_empty_element_when_no_children_exist() + throws IOException { + assertContent("<root/>"); + } + + @Test + public void close_should_be_allowed_multiple_times() throws IOException { root.close(); - // Second close has no effect: root.close(); - assertEquals("<root/>", buffer.toString()); + assertContent("<root/>"); } @Test(expected = IOException.class) - public void testAddAttributeToClosedNode() throws IOException { + public void attr_should_throw_exception_when_closed() throws IOException { root.close(); root.attr("attr", "value"); } @Test(expected = IOException.class) - public void testAddChildToClosedNode() throws IOException { + public void element_should_throw_exception_when_closed() + throws IOException { root.close(); root.element("child"); } @Test(expected = IOException.class) - public void testAddTextToClosedNode() throws IOException { + public void text_should_throw_exception_when_closed() throws IOException { root.close(); root.text("text"); } @Test - public void testNestedElement() throws IOException { + public void element_should_emit_nested_element() throws IOException { root.element("world"); - root.close(); - assertEquals("<root><world/></root>", buffer.toString()); + assertContent("<root><world/></root>"); } @Test - public void test2NestedElements() throws IOException { + public void element_should_allow_multiple_nested_elements() + throws IOException { root.element("world"); root.element("universe"); - root.close(); - assertEquals("<root><world/><universe/></root>", buffer.toString()); + assertContent("<root><world/><universe/></root>"); } @Test - public void testText() throws IOException { + public void text_should_emit_text() throws IOException { root.text("world"); - root.close(); - assertEquals("<root>world</root>", buffer.toString()); + assertContent("<root>world</root>"); } @Test - public void testMixedContent() throws IOException { + public void text_should_allow_mixing_with_elements() throws IOException { root.element("tag1"); root.text("world"); root.element("tag2"); - root.close(); - assertEquals("<root><tag1/>world<tag2/></root>", buffer.toString()); + assertContent("<root><tag1/>world<tag2/></root>"); } @Test - public void testQuotedText() throws IOException { + public void test_should_be_quoted() throws IOException { root.text("<black&white\">"); - root.close(); - assertEquals("<root><black&white"></root>", - buffer.toString()); + assertContent("<root><black&white"></root>"); } @Test - public void testNullAttributes() throws IOException { + public void attr_should_ignore_call_when_value_is_null() + throws IOException { root.attr("id", null); - root.close(); - assertEquals("<root/>", buffer.toString()); + assertContent("<root/>"); } @Test - public void testStringAttributes() throws IOException { - root.attr("id", "12345").attr("quote", "<\">"); - root.close(); - assertEquals("<root id=\"12345\" quote=\"<">\"/>", - buffer.toString()); + public void attr_should_emit_string_value() throws IOException { + root.attr("id", "12345"); + assertContent("<root id=\"12345\"/>"); } @Test - public void testIntAttributes() throws IOException { - root.attr("missed", 0).attr("total", 123); - root.close(); - assertEquals("<root missed=\"0\" total=\"123\"/>", buffer.toString()); + public void attr_should_quote_string_value() throws IOException { + root.attr("quote", "<\">"); + assertContent("<root quote=\"<">\"/>"); } @Test - public void testLongAttributes() throws IOException { - root.attr("min", Long.MIN_VALUE).attr("max", Long.MAX_VALUE); - root.close(); - assertEquals( - "<root min=\"-9223372036854775808\" max=\"9223372036854775807\"/>", - buffer.toString()); + public void attr_should_emit_int_value() throws IOException { + root.attr("missed", 0); + root.attr("total", 123); + assertContent("<root missed=\"0\" total=\"123\"/>"); + } + + @Test + public void attr_should_emit_long_value() throws IOException { + root.attr("min", Long.MIN_VALUE); + root.attr("max", Long.MAX_VALUE); + assertContent( + "<root min=\"-9223372036854775808\" max=\"9223372036854775807\"/>"); } @Test(expected = IOException.class) - public void testInvalidAttributeOutput1() throws IOException { + public void attr_should_throw_exception_when_text_was_added() + throws IOException { root.text("text"); root.attr("id", "12345"); } @Test(expected = IOException.class) - public void testInvalidAttributeOutput2() throws IOException { + public void attr_should_throw_exception_when_child_was_added() + throws IOException { root.element("child"); root.attr("id", "12345"); } + private void assertContent(String expected) throws IOException { + assertEquals(DECL + expected, actual()); + } + + private String actual() throws IOException { + root.close(); + return buffer.toString("UTF-8"); + } + } diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLGroupVisitorTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLGroupVisitorTest.java index e7eb78e6..b6fed2e8 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLGroupVisitorTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLGroupVisitorTest.java @@ -13,26 +13,22 @@ package org.jacoco.report.internal.xml; import static org.junit.Assert.assertEquals; -import java.io.IOException; -import java.io.StringWriter; - -import javax.xml.parsers.ParserConfigurationException; +import java.io.ByteArrayOutputStream; import org.jacoco.report.ReportStructureTestDriver; import org.jacoco.report.xml.XMLFormatter; import org.junit.Before; import org.junit.Test; import org.w3c.dom.Document; -import org.xml.sax.SAXException; /** * Unit tests for {@link XMLGroupVisitor}. */ public class XMLGroupVisitorTest { - private XMLElement root; + private ReportElement root; - private StringWriter buffer; + private ByteArrayOutputStream buffer; private XMLSupport support; @@ -42,11 +38,9 @@ public class XMLGroupVisitorTest { @Before public void setup() throws Exception { - buffer = new StringWriter(); + buffer = new ByteArrayOutputStream(); support = new XMLSupport(XMLFormatter.class); - root = new XMLDocument("report", "-//JACOCO//DTD Report 1.1//EN", - "report.dtd", "UTF-8", true, buffer); - root.attr("name", "Report"); + root = new ReportElement("Report", buffer, "UTF-8"); handler = new XMLGroupVisitor(root, null); driver = new ReportStructureTestDriver(); } @@ -54,16 +48,14 @@ public class XMLGroupVisitorTest { @Test public void testVisitBundle() throws Exception { driver.sendBundle(handler); - root.close(); - final Document doc = getDocument(); + final Document doc = parseDoc(); assertEquals("bundle", support.findStr(doc, "//report/group/@name")); } @Test public void testVisitGroup() throws Exception { driver.sendGroup(handler); - root.close(); - final Document doc = getDocument(); + final Document doc = parseDoc(); assertEquals("group", support.findStr(doc, "//report/group/@name")); } @@ -71,15 +63,14 @@ public class XMLGroupVisitorTest { public void testVisitEnd() throws Exception { driver.sendBundle(handler); handler.visitEnd(); - root.close(); - final Document doc = getDocument(); + final Document doc = parseDoc(); assertEquals("2", support.findStr(doc, "//report/counter[@type='BRANCH']/@covered")); } - private Document getDocument() - throws SAXException, IOException, ParserConfigurationException { - return support.parse(buffer.toString()); + private Document parseDoc() throws Exception { + root.close(); + return support.parse(buffer); } } diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLSupport.java b/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLSupport.java index c95e7b4b..d8845a28 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLSupport.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/xml/XMLSupport.java @@ -14,8 +14,8 @@ package org.jacoco.report.internal.xml; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.StringReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -71,13 +71,13 @@ public class XMLSupport { return xpath; } - public Document parse(String document) throws SAXException, IOException, - ParserConfigurationException { - return builder.parse(new InputSource(new StringReader(document))); + public Document parse(ByteArrayOutputStream buffer) + throws SAXException, IOException, ParserConfigurationException { + return parse(buffer.toByteArray()); } - public Document parse(byte[] document) throws SAXException, IOException, - ParserConfigurationException { + public Document parse(byte[] document) + throws SAXException, IOException, ParserConfigurationException { return builder .parse(new InputSource(new ByteArrayInputStream(document))); } diff --git a/org.jacoco.report.test/src/org/jacoco/report/xml/XMLFormatterTest.java b/org.jacoco.report.test/src/org/jacoco/report/xml/XMLFormatterTest.java index c409589a..57552ce8 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/xml/XMLFormatterTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/xml/XMLFormatterTest.java @@ -162,6 +162,20 @@ public class XMLFormatterTest { assertPathMatches("1", "count(/report/counter[@type='CLASS'])"); assertPathMatches("0", "report/counter[@type='CLASS']/@missed"); assertPathMatches("1", "report/counter[@type='CLASS']/@covered"); + + assertPathMatches("1", + "report/package/sourcefile[@name='FooClass.java']/line[1]/@nr"); + assertPathMatches("3", + "report/package/sourcefile[@name='FooClass.java']/line[1]/@mi"); + assertPathMatches("2", + "report/package/sourcefile[@name='FooClass.java']/line[2]/@nr"); + assertPathMatches("2", + "report/package/sourcefile[@name='FooClass.java']/line[2]/@cb"); + // empty line is skipped + assertPathMatches("4", + "report/package/sourcefile[@name='FooClass.java']/line[3]/@nr"); + assertPathMatches("4", + "report/package/sourcefile[@name='FooClass.java']/line[3]/@mi"); } @Test @@ -192,7 +206,7 @@ public class XMLFormatterTest { private void assertPathMatches(String expected, String path) throws Exception { XMLSupport support = new XMLSupport(XMLFormatter.class); - Document document = support.parse(output.toByteArray()); + Document document = support.parse(output); assertEquals(expected, support.findStr(document, path)); } diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/HTMLDocument.java b/org.jacoco.report/src/org/jacoco/report/internal/html/HTMLDocument.java deleted file mode 100644 index fb461e1d..00000000 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/HTMLDocument.java +++ /dev/null @@ -1,97 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.report.internal.html; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; - -import org.jacoco.report.internal.xml.XMLDocument; - -/** - * {@link XMLDocument} that declares its content type to be XHTML 1.0 Strict and - * produces {@link HTMLElement}s as children. - */ -public class HTMLDocument extends XMLDocument { - - private static final String ROOT = "html"; - - private static final String PUBID = "-//W3C//DTD XHTML 1.0 Strict//EN"; - - private static final String SYSTEM = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"; - - private static final String XMLNS = "xmlns"; - - private static final String XHTML_NAMESPACE_URL = "http://www.w3.org/1999/xhtml"; - - /** - * Creates a new HTML document based on the given writer. - * - * @param writer - * writer for content output - * @param encoding - * document encoding - * @throws IOException - * in case of problems with the writer - */ - public HTMLDocument(final Writer writer, final String encoding) - throws IOException { - super(ROOT, PUBID, SYSTEM, encoding, false, writer); - attr(XMLNS, XHTML_NAMESPACE_URL); - } - - /** - * Creates a new HTML document based on the given stream. - * - * @param output - * stream for content output - * @param encoding - * document encoding - * @throws IOException - * in case of problems with the stream - */ - public HTMLDocument(final OutputStream output, final String encoding) - throws IOException { - super(ROOT, PUBID, SYSTEM, encoding, false, output); - attr(XMLNS, XHTML_NAMESPACE_URL); - } - - @Override - public HTMLElement element(final String name) throws IOException { - final HTMLElement element = new HTMLElement(writer, name); - addChildElement(element); - return element; - } - - /** - * Creates a 'head' element. - * - * @return 'head' element - * @throws IOException - * in case of problems with the writer - */ - public HTMLElement head() throws IOException { - return element("head"); - } - - /** - * Creates a 'body' element. - * - * @return 'body' element - * @throws IOException - * in case of problems with the writer - */ - public HTMLElement body() throws IOException { - return element("body"); - } - -} diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/HTMLElement.java b/org.jacoco.report/src/org/jacoco/report/internal/html/HTMLElement.java index 18f5bdd4..fc8f002b 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/HTMLElement.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/HTMLElement.java @@ -12,7 +12,7 @@ package org.jacoco.report.internal.html; import java.io.IOException; -import java.io.Writer; +import java.io.OutputStream; import org.jacoco.report.internal.ReportOutputFolder; import org.jacoco.report.internal.xml.XMLElement; @@ -23,29 +23,62 @@ import org.jacoco.report.internal.xml.XMLElement; */ public class HTMLElement extends XMLElement { + private static final String PUBID = "-//W3C//DTD XHTML 1.0 Strict//EN"; + + private static final String SYSTEM = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"; + /** - * Creates a new element for a HTML document. + * Creates a <code>html</code> root element of a XHTML document. * - * @param writer - * all output will be written directly to this - * @param name - * element name + * @param encoding + * character encoding used for output + * @param output + * output stream will be closed if the root element is closed + * @throws IOException + * in case of problems with the underlying output */ - protected HTMLElement(final Writer writer, final String name) { - super(writer, name); + public HTMLElement(final OutputStream output, final String encoding) + throws IOException { + super("html", PUBID, SYSTEM, false, encoding, output); + attr("xmlns", "http://www.w3.org/1999/xhtml"); + } + + private HTMLElement(final String name, final HTMLElement parent) + throws IOException { + super(name, parent); } @Override public HTMLElement element(final String name) throws IOException { - final HTMLElement element = new HTMLElement(writer, name); - addChildElement(element); - return element; + return new HTMLElement(name, this); } private void classattr(final String classattr) throws IOException { attr("class", classattr); } + /** + * Creates a 'head' element. + * + * @return 'head' element + * @throws IOException + * in case of problems with the underlying output + */ + public HTMLElement head() throws IOException { + return element("head"); + } + + /** + * Creates a 'body' element. + * + * @return 'body' element + * @throws IOException + * in case of problems with the underlying output + */ + public HTMLElement body() throws IOException { + return element("body"); + } + /** * Creates a 'meta' element. * @@ -55,10 +88,10 @@ public class HTMLElement extends XMLElement { * value for the content attribute * @return 'meta' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ - public HTMLElement meta(final String httpequivattr, final String contentattr) - throws IOException { + public HTMLElement meta(final String httpequivattr, + final String contentattr) throws IOException { final HTMLElement meta = element("meta"); meta.attr("http-equiv", httpequivattr); meta.attr("content", contentattr); @@ -76,7 +109,7 @@ public class HTMLElement extends XMLElement { * value for the type attribute * @return 'link' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement link(final String relattr, final String hrefattr, final String typeattr) throws IOException { @@ -92,7 +125,7 @@ public class HTMLElement extends XMLElement { * * @return 'title' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement title() throws IOException { return element("title"); @@ -103,7 +136,7 @@ public class HTMLElement extends XMLElement { * * @return 'h1' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement h1() throws IOException { return element("h1"); @@ -114,7 +147,7 @@ public class HTMLElement extends XMLElement { * * @return 'p' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement p() throws IOException { return element("p"); @@ -125,7 +158,7 @@ public class HTMLElement extends XMLElement { * * @return 'span' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement span() throws IOException { return element("span"); @@ -138,7 +171,7 @@ public class HTMLElement extends XMLElement { * value of the class attribute * @return 'span' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement span(final String classattr) throws IOException { final HTMLElement span = span(); @@ -155,7 +188,7 @@ public class HTMLElement extends XMLElement { * value of the id attribute * @return 'span' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement span(final String classattr, final String idattr) throws IOException { @@ -171,7 +204,7 @@ public class HTMLElement extends XMLElement { * value of the class attribute * @return 'div' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement div(final String classattr) throws IOException { final HTMLElement div = element("div"); @@ -184,7 +217,7 @@ public class HTMLElement extends XMLElement { * * @return 'code' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement code() throws IOException { return element("code"); @@ -197,7 +230,7 @@ public class HTMLElement extends XMLElement { * value of the class attribute * @return 'pre' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement pre(final String classattr) throws IOException { final HTMLElement pre = element("pre"); @@ -212,7 +245,7 @@ public class HTMLElement extends XMLElement { * value of the href attribute * @return 'a' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement a(final String hrefattr) throws IOException { final HTMLElement a = element("a"); @@ -229,7 +262,7 @@ public class HTMLElement extends XMLElement { * value of the class attribute * @return 'a' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement a(final String hrefattr, final String classattr) throws IOException { @@ -247,10 +280,10 @@ public class HTMLElement extends XMLElement { * base folder where the link should be placed * @return 'a' element or 'span' element, if the link target does not exist * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ - public HTMLElement a(final ILinkable linkable, final ReportOutputFolder base) - throws IOException { + public HTMLElement a(final ILinkable linkable, + final ReportOutputFolder base) throws IOException { final HTMLElement a; final String link = linkable.getLink(base); if (link == null) { @@ -269,7 +302,7 @@ public class HTMLElement extends XMLElement { * value of the class attribute * @return 'table' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement table(final String classattr) throws IOException { final HTMLElement table = element("table"); @@ -283,7 +316,7 @@ public class HTMLElement extends XMLElement { * * @return 'thead' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement thead() throws IOException { return element("thead"); @@ -294,7 +327,7 @@ public class HTMLElement extends XMLElement { * * @return 'tfoot' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement tfoot() throws IOException { return element("tfoot"); @@ -305,7 +338,7 @@ public class HTMLElement extends XMLElement { * * @return 'tbody' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement tbody() throws IOException { return element("tbody"); @@ -316,7 +349,7 @@ public class HTMLElement extends XMLElement { * * @return 'tr' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement tr() throws IOException { return element("tr"); @@ -327,7 +360,7 @@ public class HTMLElement extends XMLElement { * * @return 'td' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement td() throws IOException { return element("td"); @@ -340,7 +373,7 @@ public class HTMLElement extends XMLElement { * value of the class attribute * @return 'td' element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public HTMLElement td(final String classattr) throws IOException { final HTMLElement td = td(); @@ -360,7 +393,7 @@ public class HTMLElement extends XMLElement { * @param titleattr * value of the title and alt attribute * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public void img(final String srcattr, final int widthattr, final int heightattr, final String titleattr) throws IOException { @@ -374,19 +407,16 @@ public class HTMLElement extends XMLElement { } /** - * Creates a 'script' element. + * Creates a JavaScript 'script' element. * - * @param typeattr - * value of the type attribute * @param srcattr * value of the src attribute * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ - public void script(final String typeattr, final String srcattr) - throws IOException { + public void script(final String srcattr) throws IOException { final HTMLElement script = element("script"); - script.attr("type", typeattr); + script.attr("type", "text/javascript"); script.attr("src", srcattr); // Enforce open and closing tag otherwise it won't work in browsers: script.text(""); diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/ReportPage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/ReportPage.java index 7dfec534..4851c720 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/ReportPage.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/ReportPage.java @@ -15,7 +15,6 @@ import java.io.IOException; import org.jacoco.core.JaCoCo; import org.jacoco.report.internal.ReportOutputFolder; -import org.jacoco.report.internal.html.HTMLDocument; import org.jacoco.report.internal.html.HTMLElement; import org.jacoco.report.internal.html.IHTMLReportContext; import org.jacoco.report.internal.html.ILinkable; @@ -71,12 +70,12 @@ public abstract class ReportPage implements ILinkable { * if the page can't be written */ public void render() throws IOException { - final HTMLDocument doc = new HTMLDocument( + final HTMLElement html = new HTMLElement( folder.createFile(getFileName()), context.getOutputEncoding()); - doc.attr("lang", context.getLocale().getLanguage()); - head(doc.head()); - body(doc.body()); - doc.close(); + html.attr("lang", context.getLocale().getLanguage()); + head(html.head()); + body(html.body()); + html.close(); } /** @@ -130,8 +129,8 @@ public abstract class ReportPage implements ILinkable { span.a(context.getSessionsPage(), folder); } - private void breadcrumb(final HTMLElement div, final ReportOutputFolder base) - throws IOException { + private void breadcrumb(final HTMLElement div, + final ReportOutputFolder base) throws IOException { breadcrumbParent(parent, div, base); div.span(getLinkStyle()).text(getLinkLabel()); } @@ -151,7 +150,8 @@ public abstract class ReportPage implements ILinkable { final HTMLElement versioninfo = footer.span(Styles.RIGHT); versioninfo.text("Created with "); versioninfo.a(JaCoCo.HOMEURL).text("JaCoCo"); - versioninfo.text(" ").text(JaCoCo.VERSION); + versioninfo.text(" "); + versioninfo.text(JaCoCo.VERSION); footer.text(context.getFooterText()); } diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/SourceFilePage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/SourceFilePage.java index 8658d602..cc77d18b 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/SourceFilePage.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/SourceFilePage.java @@ -67,14 +67,10 @@ public class SourceFilePage extends NodePage<ISourceNode> { @Override protected void head(final HTMLElement head) throws IOException { super.head(head); - head.link( - "stylesheet", - context.getResources().getLink(folder, - Resources.PRETTIFY_STYLESHEET), "text/css"); - head.script( - "text/javascript", - context.getResources().getLink(folder, - Resources.PRETTIFY_SCRIPT)); + head.link("stylesheet", context.getResources().getLink(folder, + Resources.PRETTIFY_STYLESHEET), "text/css"); + head.script(context.getResources().getLink(folder, + Resources.PRETTIFY_SCRIPT)); } @Override diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/TablePage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/TablePage.java index 30c4cdcc..d411df11 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/TablePage.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/TablePage.java @@ -28,8 +28,8 @@ import org.jacoco.report.internal.html.table.ITableItem; * @param <NodeType> * type of the node represented by this page */ -public abstract class TablePage<NodeType extends ICoverageNode> extends - NodePage<NodeType> { +public abstract class TablePage<NodeType extends ICoverageNode> + extends NodePage<NodeType> { private final List<ITableItem> items = new ArrayList<ITableItem>(); @@ -64,7 +64,7 @@ public abstract class TablePage<NodeType extends ICoverageNode> extends @Override protected void head(final HTMLElement head) throws IOException { super.head(head); - head.script("text/javascript", + head.script( context.getResources().getLink(folder, Resources.SORT_SCRIPT)); } diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/table/BarColumn.java b/org.jacoco.report/src/org/jacoco/report/internal/html/table/BarColumn.java index de5cad29..1462ccbf 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/table/BarColumn.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/table/BarColumn.java @@ -76,8 +76,9 @@ public class BarColumn implements IColumnRenderer { final Resources resources, final ReportOutputFolder base) throws IOException { final ICounter counter = total.getCounter(entity); - td.text(integerFormat.format(counter.getMissedCount())).text(" of ") - .text(integerFormat.format(counter.getTotalCount())); + td.text(integerFormat.format(counter.getMissedCount())); + td.text(" of "); + td.text(integerFormat.format(counter.getTotalCount())); } public void item(final HTMLElement td, final ITableItem item, diff --git a/org.jacoco.report/src/org/jacoco/report/internal/xml/ReportElement.java b/org.jacoco.report/src/org/jacoco/report/internal/xml/ReportElement.java new file mode 100644 index 00000000..208ac558 --- /dev/null +++ b/org.jacoco.report/src/org/jacoco/report/internal/xml/ReportElement.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.report.internal.xml; + +import java.io.IOException; +import java.io.OutputStream; + +import org.jacoco.core.analysis.IClassCoverage; +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.analysis.ICoverageNode.CounterEntity; +import org.jacoco.core.analysis.ILine; +import org.jacoco.core.analysis.IMethodCoverage; +import org.jacoco.core.data.SessionInfo; + +/** + * A {@link XMLElement} with utility methods to create JaCoCo XML reports. + */ +public class ReportElement extends XMLElement { + + private static final String PUBID = "-//JACOCO//DTD Report 1.1//EN"; + + private static final String SYSTEM = "report.dtd"; + + /** + * Creates a <code>report</code> root element for a XML report. + * + * @param name + * value for the name attribute + * @param encoding + * character encoding used for output + * @param output + * output stream will be closed if the root element is closed + * @throws IOException + * in case of problems with the underlying output + */ + public ReportElement(final String name, final OutputStream output, + final String encoding) throws IOException { + super("report", PUBID, SYSTEM, true, encoding, output); + attr("name", name); + } + + private ReportElement(final String name, final ReportElement parent) + throws IOException { + super(name, parent); + } + + @Override + public ReportElement element(final String name) throws IOException { + return new ReportElement(name, this); + } + + private ReportElement namedElement(final String elementName, + final String name) throws IOException { + final ReportElement element = element(elementName); + element.attr("name", name); + return element; + } + + /** + * Creates a 'sessioninfo' element. + * + * @param info + * info object to write out + * @throws IOException + * in case of problems with the underlying output + */ + public void sessioninfo(final SessionInfo info) throws IOException { + final ReportElement sessioninfo = element("sessioninfo"); + sessioninfo.attr("id", info.getId()); + sessioninfo.attr("start", info.getStartTimeStamp()); + sessioninfo.attr("dump", info.getDumpTimeStamp()); + } + + /** + * Creates a 'group' element. + * + * @param name + * value for the name attribute + * @return 'group' element + * @throws IOException + * in case of problems with the underlying output + */ + public ReportElement group(final String name) throws IOException { + return namedElement("group", name); + } + + /** + * Creates a 'package' element. + * + * @param name + * value for the name attribute + * @return 'package' element + * @throws IOException + * in case of problems with the underlying output + */ + public ReportElement packageElement(final String name) throws IOException { + return namedElement("package", name); + } + + /** + * Creates a 'class' element. + * + * @param coverage + * class coverage node to write out + * @return 'class' element + * @throws IOException + * in case of problems with the underlying output + */ + public ReportElement classElement(final IClassCoverage coverage) + throws IOException { + final ReportElement element = namedElement("class", coverage.getName()); + element.attr("sourcefilename", coverage.getSourceFileName()); + return element; + } + + /** + * Creates a 'method' element. + * + * @param coverage + * method coverage node to write out + * @return 'method' element + * @throws IOException + * in case of problems with the underlying output + */ + public ReportElement method(final IMethodCoverage coverage) + throws IOException { + final ReportElement element = namedElement("method", + coverage.getName()); + element.attr("desc", coverage.getDesc()); + final int line = coverage.getFirstLine(); + if (line != -1) { + element.attr("line", line); + } + return element; + } + + /** + * Creates a 'sourcefile' element. + * + * @param name + * value for the name attribute + * @return 'sourcefile' element + * @throws IOException + * in case of problems with the underlying output + */ + public ReportElement sourcefile(final String name) throws IOException { + return namedElement("sourcefile", name); + } + + /** + * Creates a 'line' element. + * + * @param nr + * line number + * @param line + * line object to write out + * + * @throws IOException + * in case of problems with the underlying output + */ + public void line(final int nr, final ILine line) throws IOException { + final ReportElement element = element("line"); + element.attr("nr", nr); + counterAttributes(element, "mi", "ci", line.getInstructionCounter()); + counterAttributes(element, "mb", "cb", line.getBranchCounter()); + } + + /** + * Creates a 'counter' element. + * + * @param counterEntity + * entity of this counter + * + * @param counter + * counter object to write out + * + * @throws IOException + * in case of problems with the underlying output + */ + public void counter(final CounterEntity counterEntity, + final ICounter counter) throws IOException { + final ReportElement counterNode = element("counter"); + counterNode.attr("type", counterEntity.name()); + counterAttributes(counterNode, "missed", "covered", counter); + } + + private static void counterAttributes(final XMLElement element, + final String missedattr, final String coveredattr, + final ICounter counter) throws IOException { + element.attr(missedattr, counter.getMissedCount()); + element.attr(coveredattr, counter.getCoveredCount()); + } + +} diff --git a/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLCoverageWriter.java b/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLCoverageWriter.java index 14add6f7..e5045dad 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLCoverageWriter.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLCoverageWriter.java @@ -29,27 +29,6 @@ import org.jacoco.core.analysis.ISourceNode; */ public final class XMLCoverageWriter { - /** - * Creates a child element with a name attribute. - * - * @param parent - * parent element - * @param tagname - * name of the child tag - * @param name - * value of the name attribute - * @return child element - * @throws IOException - * if XML can't be written to the underlying output - * - */ - public static XMLElement createChild(final XMLElement parent, - final String tagname, final String name) throws IOException { - final XMLElement child = parent.element(tagname); - child.attr("name", name); - return child; - } - /** * Writes the structure of a given bundle. * @@ -61,7 +40,7 @@ public final class XMLCoverageWriter { * if XML can't be written to the underlying output */ public static void writeBundle(final IBundleCoverage bundle, - final XMLElement element) throws IOException { + final ReportElement element) throws IOException { for (final IPackageCoverage p : bundle.getPackages()) { writePackage(p, element); } @@ -69,8 +48,8 @@ public final class XMLCoverageWriter { } private static void writePackage(final IPackageCoverage p, - final XMLElement parent) throws IOException { - final XMLElement element = createChild(parent, "package", p.getName()); + final ReportElement parent) throws IOException { + final ReportElement element = parent.packageElement(p.getName()); for (final IClassCoverage c : p.getClasses()) { writeClass(c, element); } @@ -81,9 +60,8 @@ public final class XMLCoverageWriter { } private static void writeClass(final IClassCoverage c, - final XMLElement parent) throws IOException { - final XMLElement element = createChild(parent, "class", c.getName()); - element.attr("sourcefilename", c.getSourceFileName()); + final ReportElement parent) throws IOException { + final ReportElement element = parent.classElement(c); for (final IMethodCoverage m : c.getMethods()) { writeMethod(m, element); } @@ -91,20 +69,14 @@ public final class XMLCoverageWriter { } private static void writeMethod(final IMethodCoverage m, - final XMLElement parent) throws IOException { - final XMLElement element = createChild(parent, "method", m.getName()); - element.attr("desc", m.getDesc()); - final int line = m.getFirstLine(); - if (line != -1) { - element.attr("line", line); - } + final ReportElement parent) throws IOException { + final ReportElement element = parent.method(m); writeCounters(m, element); } private static void writeSourceFile(final ISourceFileCoverage s, - final XMLElement parent) throws IOException { - final XMLElement element = createChild(parent, "sourcefile", - s.getName()); + final ReportElement parent) throws IOException { + final ReportElement element = parent.sourcefile(s.getName()); writeLines(s, element); writeCounters(s, element); } @@ -120,39 +92,26 @@ public final class XMLCoverageWriter { * if XML can't be written to the underlying output */ public static void writeCounters(final ICoverageNode node, - final XMLElement parent) throws IOException { + final ReportElement parent) throws IOException { for (final CounterEntity counterEntity : CounterEntity.values()) { final ICounter counter = node.getCounter(counterEntity); if (counter.getTotalCount() > 0) { - final XMLElement counterNode = parent.element("counter"); - counterNode.attr("type", counterEntity.name()); - writeCounter(counterNode, "missed", "covered", counter); - counterNode.close(); + parent.counter(counterEntity, counter); } } } private static void writeLines(final ISourceNode source, - final XMLElement parent) throws IOException { + final ReportElement parent) throws IOException { final int last = source.getLastLine(); for (int nr = source.getFirstLine(); nr <= last; nr++) { final ILine line = source.getLine(nr); if (line.getStatus() != ICounter.EMPTY) { - final XMLElement element = parent.element("line"); - element.attr("nr", nr); - writeCounter(element, "mi", "ci", line.getInstructionCounter()); - writeCounter(element, "mb", "cb", line.getBranchCounter()); + parent.line(nr, line); } } } - private static void writeCounter(final XMLElement element, - final String missedattr, final String coveredattr, - final ICounter counter) throws IOException { - element.attr(missedattr, counter.getMissedCount()); - element.attr(coveredattr, counter.getCoveredCount()); - } - private XMLCoverageWriter() { } diff --git a/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLDocument.java b/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLDocument.java deleted file mode 100644 index 99cae7e0..00000000 --- a/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLDocument.java +++ /dev/null @@ -1,111 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.report.internal.xml; - -import static java.lang.String.format; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; - -/** - * Root element of an XML document. Each instance represents a separate output - * document. - * - * @see XMLElement - */ -public class XMLDocument extends XMLElement { - - /** XML header template */ - private static final String HEADER = "<?xml version=\"1.0\" encoding=\"%s\"?>"; - - /** XML header template for standalone documents */ - private static final String HEADER_STANDALONE = "<?xml version=\"1.0\" encoding=\"%s\" standalone=\"yes\"?>"; - - /** DOCTYPE declaration template */ - private static final String DOCTYPE = "<!DOCTYPE %s PUBLIC \"%s\" \"%s\">"; - - /** - * Writes a new document to the given writer. The document might contain a - * document type declaration. - * - * @param rootnode - * name of the root node - * @param pubId - * optional doctype identifier or <code>null</code> - * @param system - * system reference, required if doctype is given - * @param encoding - * encoding that will be specified in the header - * @param standalone - * <code>true</code> if this is a standalone document - * @param writer - * writer for content output - * @throws IOException - * in case of problems with the writer - */ - public XMLDocument(final String rootnode, final String pubId, - final String system, final String encoding, - final boolean standalone, final Writer writer) throws IOException { - super(writer, rootnode); - writeHeader(rootnode, pubId, system, encoding, standalone, writer); - beginOpenTag(); - } - - /** - * Writes a new document to the given binary stream. The document might - * contain a document type declaration. - * - * @param rootnode - * name of the root node - * @param pubId - * optional doctype identifier or <code>null</code> - * @param system - * system reference, required if doctype is given - * @param encoding - * encoding of the XML document - * @param standalone - * <code>true</code> if this is a standalone document - * @param output - * output for content output - * @throws IOException - * in case of problems with the writer - */ - public XMLDocument(final String rootnode, final String pubId, - final String system, final String encoding, - final boolean standalone, final OutputStream output) - throws IOException { - this(rootnode, pubId, system, encoding, standalone, - new OutputStreamWriter(output, encoding)); - } - - @Override - public void close() throws IOException { - super.close(); - writer.close(); - } - - private static void writeHeader(final String rootnode, final String pubId, - final String system, final String encoding, - final boolean standalone, final Writer writer) throws IOException { - if (standalone) { - writer.write(format(HEADER_STANDALONE, encoding)); - } else { - writer.write(format(HEADER, encoding)); - } - if (pubId != null) { - writer.write(format(DOCTYPE, rootnode, pubId, system)); - } - } - -} diff --git a/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLElement.java b/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLElement.java index 3b60a04e..159e10a5 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLElement.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLElement.java @@ -14,29 +14,26 @@ package org.jacoco.report.internal.xml; import static java.lang.String.format; import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.io.Writer; /** - * Simple API to create well formed XML streams. A {@link XMLElement} instance - * represents a single element in a XML document. - * - * @see XMLDocument + * Simple API to create well formed XML streams with minimal memory overhead. A + * {@link XMLElement} instance represents a single element in a XML document. + * {@link XMLElement} can be used directly or might be subclassed for schema + * specific convenience methods. */ public class XMLElement { - private static final char SPACE = ' '; + /** XML header template */ + private static final String HEADER = "<?xml version=\"1.0\" encoding=\"%s\"?>"; - private static final char EQ = '='; + /** XML header template for standalone documents */ + private static final String HEADER_STANDALONE = "<?xml version=\"1.0\" encoding=\"%s\" standalone=\"yes\"?>"; - private static final char LT = '<'; - - private static final char GT = '>'; - - private static final char QUOT = '"'; - - private static final char AMP = '&'; - - private static final char SLASH = '/'; + /** DOCTYPE declaration template */ + private static final String DOCTYPE = "<!DOCTYPE %s PUBLIC \"%s\" \"%s\">"; /** Writer for content output */ protected final Writer writer; @@ -49,51 +46,74 @@ public class XMLElement { private XMLElement lastchild; - /** - * Creates a new element for a XML document. - * - * @param writer - * all output will be written directly to this - * @param name - * element name - */ - protected XMLElement(final Writer writer, final String name) { + private final boolean root; + + private XMLElement(final Writer writer, final String name, + final boolean root) throws IOException { this.writer = writer; this.name = name; this.openTagDone = false; this.closed = false; this.lastchild = null; + this.root = root; } /** - * Emits the beginning of the open tag. This method has to be called before - * other other methods are called on this element. + * Creates a root element of a XML document. * + * @param name + * element name + * @param pubId + * optional schema public identifier + * @param system + * optional schema system identifier + * @param standalone + * if <code>true</code> the document is declared as standalone + * @param encoding + * character encoding used for output + * @param output + * output stream will be closed if the root element is closed * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ - protected void beginOpenTag() throws IOException { - writer.write(LT); - writer.write(name); - } - - private void finishOpenTag() throws IOException { - if (!openTagDone) { - writer.append(GT); - openTagDone = true; + public XMLElement(final String name, final String pubId, + final String system, final boolean standalone, + final String encoding, final OutputStream output) + throws IOException { + this(new OutputStreamWriter(output, encoding), name, true); + if (standalone) { + writer.write(format(HEADER_STANDALONE, encoding)); + } else { + writer.write(format(HEADER, encoding)); } + if (pubId != null) { + writer.write(format(DOCTYPE, name, pubId, system)); + } + writer.write('<'); + writer.write(name); } /** - * Adds the given child to this element. This will close all previous child - * elements. + * Creates a new child element within a XML document. May only be called + * before the parent element has been closed. * - * @param child - * child element to add + * @param name + * element name + * @param parent + * parent of this element * @throws IOException - * in case of invalid nesting or problems with the writer + * in case of problems with the underlying output or if the + * parent element is already closed */ - protected void addChildElement(final XMLElement child) throws IOException { + protected XMLElement(final String name, final XMLElement parent) + throws IOException { + this(parent.writer, name, false); + parent.addChildElement(this); + writer.write('<'); + writer.write(name); + } + + private void addChildElement(final XMLElement child) throws IOException { if (closed) { throw new IOException(format("Element %s already closed.", name)); } @@ -101,25 +121,31 @@ public class XMLElement { if (lastchild != null) { lastchild.close(); } - child.beginOpenTag(); lastchild = child; } + private void finishOpenTag() throws IOException { + if (!openTagDone) { + writer.append('>'); + openTagDone = true; + } + } + private void quote(final String text) throws IOException { final int len = text.length(); for (int i = 0; i < len; i++) { final char c = text.charAt(i); switch (c) { - case LT: + case '<': writer.write("<"); break; - case GT: + case '>': writer.write(">"); break; - case QUOT: + case '"': writer.write("""); break; - case AMP: + case '&': writer.write("&"); break; default: @@ -139,27 +165,25 @@ public class XMLElement { * attribute name * @param value * attribute value or <code>null</code> - * - * @return this element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output or if the + * element is already closed. */ - public XMLElement attr(final String name, final String value) + public final void attr(final String name, final String value) throws IOException { if (value == null) { - return this; + return; } if (closed || openTagDone) { - throw new IOException(format("Element %s already closed.", - this.name)); + throw new IOException( + format("Element %s already closed.", this.name)); } - writer.write(SPACE); + writer.write(' '); writer.write(name); - writer.write(EQ); - writer.write(QUOT); + writer.write('='); + writer.write('"'); quote(value); - writer.write(QUOT); - return this; + writer.write('"'); } /** @@ -171,14 +195,13 @@ public class XMLElement { * attribute name * @param value * attribute value - * - * @return this element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output or if the + * element is already closed. */ - public XMLElement attr(final String name, final int value) + public final void attr(final String name, final int value) throws IOException { - return attr(name, String.valueOf(value)); + attr(name, String.valueOf(value)); } /** @@ -190,26 +213,26 @@ public class XMLElement { * attribute name * @param value * attribute value - * - * @return this element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output or if the + * element is already closed. */ - public XMLElement attr(final String name, final long value) + public final void attr(final String name, final long value) throws IOException { - return attr(name, String.valueOf(value)); + attr(name, String.valueOf(value)); } /** - * Adds the given text as a child to this node. The text will be quoted. + * Adds the given text as a child to this node. The text will be quoted. May + * only be called before this element has been closed. * * @param text * text to add - * @return this element * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output or if the + * element is already closed. */ - public XMLElement text(final String text) throws IOException { + public final void text(final String text) throws IOException { if (closed) { throw new IOException(format("Element %s already closed.", name)); } @@ -218,45 +241,46 @@ public class XMLElement { lastchild.close(); } quote(text); - return this; } /** - * Creates a new child element for this element, + * Creates a new child element for this element. Might be overridden in + * subclasses to return a instance of the subclass. * * @param name * name of the child element * @return child element instance * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ public XMLElement element(final String name) throws IOException { - final XMLElement element = new XMLElement(writer, name); - addChildElement(element); - return element; + return new XMLElement(name, this); } /** * Closes this element if it has not been closed before. * * @throws IOException - * in case of problems with the writer + * in case of problems with the underlying output */ - public void close() throws IOException { + public final void close() throws IOException { if (!closed) { if (lastchild != null) { lastchild.close(); } if (openTagDone) { - writer.write(LT); - writer.write(SLASH); + writer.write('<'); + writer.write('/'); writer.write(name); } else { - writer.write(SLASH); + writer.write('/'); } - writer.write(GT); + writer.write('>'); closed = true; openTagDone = true; + if (root) { + writer.close(); + } } } diff --git a/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLGroupVisitor.java b/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLGroupVisitor.java index e6795b7f..9969f68f 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLGroupVisitor.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/xml/XMLGroupVisitor.java @@ -25,7 +25,7 @@ import org.jacoco.report.internal.AbstractGroupVisitor; public class XMLGroupVisitor extends AbstractGroupVisitor { /** XML element of this group */ - protected final XMLElement element; + protected final ReportElement element; /** * New handler for a group with the given name. @@ -38,7 +38,7 @@ public class XMLGroupVisitor extends AbstractGroupVisitor { * @throws IOException * in case of problems with the underlying writer */ - public XMLGroupVisitor(final XMLElement element, final String name) + public XMLGroupVisitor(final ReportElement element, final String name) throws IOException { super(name); this.element = element; @@ -47,14 +47,14 @@ public class XMLGroupVisitor extends AbstractGroupVisitor { @Override protected void handleBundle(final IBundleCoverage bundle, final ISourceFileLocator locator) throws IOException { - final XMLElement child = createChild(bundle.getName()); + final ReportElement child = element.group(bundle.getName()); XMLCoverageWriter.writeBundle(bundle, child); } @Override protected AbstractGroupVisitor handleGroup(final String name) throws IOException { - final XMLElement child = createChild(name); + final ReportElement child = element.group(name); return new XMLGroupVisitor(child, name); } @@ -63,8 +63,4 @@ public class XMLGroupVisitor extends AbstractGroupVisitor { XMLCoverageWriter.writeCounters(total, element); } - private XMLElement createChild(final String name) throws IOException { - return XMLCoverageWriter.createChild(element, "group", name); - } - } diff --git a/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java b/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java index 0f2bd1b0..b1e711a3 100644 --- a/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java +++ b/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java @@ -19,12 +19,11 @@ import java.util.List; import org.jacoco.core.analysis.IBundleCoverage; import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.SessionInfo; +import org.jacoco.report.IReportGroupVisitor; import org.jacoco.report.IReportVisitor; import org.jacoco.report.ISourceFileLocator; -import org.jacoco.report.internal.AbstractGroupVisitor; +import org.jacoco.report.internal.xml.ReportElement; import org.jacoco.report.internal.xml.XMLCoverageWriter; -import org.jacoco.report.internal.xml.XMLDocument; -import org.jacoco.report.internal.xml.XMLElement; import org.jacoco.report.internal.xml.XMLGroupVisitor; /** @@ -59,15 +58,11 @@ public class XMLFormatter { */ public IReportVisitor createVisitor(final OutputStream output) throws IOException { - final XMLElement root = new XMLDocument("report", PUBID, SYSTEM, - outputEncoding, true, output); - class RootVisitor extends XMLGroupVisitor implements IReportVisitor { - - RootVisitor(final XMLElement element) throws IOException { - super(element, null); - } + class RootVisitor implements IReportVisitor { + private ReportElement report; private List<SessionInfo> sessionInfos; + private XMLGroupVisitor groupVisitor; public void visitInfo(final List<SessionInfo> sessionInfos, final Collection<ExecutionData> executionData) @@ -75,36 +70,35 @@ public class XMLFormatter { this.sessionInfos = sessionInfos; } - @Override - protected void handleBundle(final IBundleCoverage bundle, + public void visitBundle(final IBundleCoverage bundle, final ISourceFileLocator locator) throws IOException { - writeHeader(bundle.getName()); - XMLCoverageWriter.writeBundle(bundle, element); + createRootElement(bundle.getName()); + XMLCoverageWriter.writeBundle(bundle, report); } - @Override - protected AbstractGroupVisitor handleGroup(final String name) + public IReportGroupVisitor visitGroup(final String name) throws IOException { - writeHeader(name); - return new XMLGroupVisitor(element, name); + createRootElement(name); + groupVisitor = new XMLGroupVisitor(report, name); + return groupVisitor; } - private void writeHeader(final String name) throws IOException { - element.attr("name", name); + private void createRootElement(final String name) + throws IOException { + report = new ReportElement(name, output, outputEncoding); for (final SessionInfo i : sessionInfos) { - final XMLElement sessioninfo = root.element("sessioninfo"); - sessioninfo.attr("id", i.getId()); - sessioninfo.attr("start", i.getStartTimeStamp()); - sessioninfo.attr("dump", i.getDumpTimeStamp()); + report.sessioninfo(i); } } - @Override - protected void handleEnd() throws IOException { - element.close(); + public void visitEnd() throws IOException { + if (groupVisitor != null) { + groupVisitor.visitEnd(); + } + report.close(); } } - return new RootVisitor(root); + return new RootVisitor(); } } -- cgit v1.2.3 From c8b8c9d3b7605fc09517c78f385fe31dccf04e31 Mon Sep 17 00:00:00 2001 From: "Marc R. Hoffmann" <hoffmann@mountainminds.com> Date: Thu, 5 Jul 2018 16:36:54 +0200 Subject: Remove unused constants (#708) This was forgotten in #652. --- org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java b/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java index b1e711a3..97410199 100644 --- a/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java +++ b/org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java @@ -31,10 +31,6 @@ import org.jacoco.report.internal.xml.XMLGroupVisitor; */ public class XMLFormatter { - private static final String PUBID = "-//JACOCO//DTD Report 1.1//EN"; - - private static final String SYSTEM = "report.dtd"; - private String outputEncoding = "UTF-8"; /** -- cgit v1.2.3 From ce7de98c76b8bd107c05a061193de76d21c4c205 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek <fabianishere@outlook.com> Date: Wed, 11 Jul 2018 21:36:11 +0200 Subject: Filter branch generated by kotlinc for reading lateinit properties (#707) --- .../analysis/filter/KotlinLateinitFilterTest.java | 74 ++++++++++++++++++++++ .../internal/analysis/filter/AbstractMatcher.java | 12 ++++ .../core/internal/analysis/filter/Filters.java | 2 +- .../analysis/filter/KotlinLateinitFilter.java | 57 +++++++++++++++++ org.jacoco.doc/docroot/doc/changes.html | 4 ++ 5 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java new file mode 100644 index 00000000..a2306f8a --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Fabian Mastenbroek - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class KotlinLateinitFilterTest implements IFilterOutput { + private final KotlinLateinitFilter filter = new KotlinLateinitFilter(); + + private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "name", "()V", null, null); + + private AbstractInsnNode fromInclusive; + private AbstractInsnNode toInclusive; + + @Test + public void testLateinitBranchIsFiltered() { + final Label l1 = new Label(); + final Label l2 = new Label(); + + m.visitLabel(l1); + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitFieldInsn(Opcodes.GETFIELD, + "com/better/alarm/background/VibrationService", "wakeLock", + "Landroid/os/PowerManager$WakeLock;"); + m.visitInsn(Opcodes.DUP); + m.visitJumpInsn(Opcodes.IFNONNULL, l2); + + final AbstractInsnNode expectedFrom = m.instructions.getLast(); + + m.visitLdcInsn("wakelock"); + m.visitMethodInsn(Opcodes.INVOKESTATIC, + "kotlin/jvm/internal/Intrinsics", + "throwUninitializedPropertyAccessException", + "Ljava/lang/String;", false); + final AbstractInsnNode expectedTo = m.instructions.getLast(); + m.visitLabel(l2); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, + "android/os/PowerManager$WakeLock", "acquire", "", false); + filter.filter(m, new FilterContextMock(), this); + + assertEquals(expectedFrom, fromInclusive); + assertEquals(expectedTo, toInclusive); + } + + public void ignore(AbstractInsnNode fromInclusive, + AbstractInsnNode toInclusive) { + assertNull(this.fromInclusive); + this.fromInclusive = fromInclusive; + this.toInclusive = toInclusive; + } + + public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { + fail(); + } +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java index fcd1c888..d4b421ef 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java @@ -67,6 +67,18 @@ abstract class AbstractMatcher { cursor = null; } + final void nextIsInvokeStatic(final String owner, final String name) { + nextIs(Opcodes.INVOKESTATIC); + if (cursor == null) { + return; + } + final MethodInsnNode m = (MethodInsnNode) cursor; + if (owner.equals(m.owner) && name.equals(m.name)) { + return; + } + cursor = null; + } + final void nextIsVar(final int opcode, final String name) { nextIs(opcode); if (cursor == null) { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index cafb1f77..b235e1e6 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -32,7 +32,7 @@ public final class Filters implements IFilter { new FinallyFilter(), new PrivateEmptyNoArgConstructorFilter(), new StringSwitchJavacFilter(), new LombokGeneratedFilter(), new GroovyGeneratedFilter(), new EnumEmptyConstructorFilter(), - new KotlinGeneratedFilter()); + new KotlinGeneratedFilter(), new KotlinLateinitFilter()); private final IFilter[] filters; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java new file mode 100644 index 00000000..c1aee3ad --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Fabian Mastenbroek - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Filters branch in bytecode that Kotlin compiler generates for reading from + * <code>lateinit</code> properties. + */ +public class KotlinLateinitFilter implements IFilter { + + private final static String OWNER = "kotlin/jvm/internal/Intrinsics"; + private final static String NAME = "throwUninitializedPropertyAccessException"; + + public void filter(final MethodNode methodNode, final IFilterContext context, + final IFilterOutput output) { + for (AbstractInsnNode i = methodNode.instructions + .getFirst(); i != null; i = i.getNext()) { + if (i.getOpcode() != Opcodes.IFNONNULL) { + continue; + } + + final AbstractInsnNode end = new Matcher(i).match(); + + if (end != null) { + output.ignore(i, end); + } + } + } + + private static class Matcher extends AbstractMatcher { + private final AbstractInsnNode start; + + private Matcher(final AbstractInsnNode start) { + this.start = start; + } + + private AbstractInsnNode match() { + cursor = start; + nextIs(Opcodes.LDC); + nextIsInvokeStatic(OWNER, NAME); + return cursor; + } + } +} diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index c5930d39..02dc8cb1 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -27,6 +27,10 @@ <li>Methods added by the Kotlin compiler are filtered out during generation of report. Idea and implementation by Nikolay Krasko (GitHub <a href="https://github.com/jacoco/jacoco/issues/689">#689</a>).</li> + <li>Branch added by the Kotlin compiler for reading from <code>lateinit</code> + property is filtered out during generation of report. Implementation by + Fabian Mastenbroek + (GitHub <a href="https://github.com/jacoco/jacoco/issues/707">#707</a>).</li> </ul> <h3>Fixed Bugs</h3> -- cgit v1.2.3 From 86f84b4a5f2820ae43a44ee6bfb12a43d7eaaf14 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <mandrikov@gmail.com> Date: Fri, 13 Jul 2018 23:28:19 +0200 Subject: Require at least JDK 8 and Maven 3.3.9 for build --- .travis.sh | 7 ++----- .travis/travis-toolchains.xml | 9 +++++++++ org.jacoco.build/pom.xml | 16 +++++++--------- org.jacoco.doc/docroot/doc/build.html | 8 ++++---- org.jacoco.doc/docroot/doc/environment.html | 3 ++- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/.travis.sh b/.travis.sh index ea1209b1..d01ac831 100755 --- a/.travis.sh +++ b/.travis.sh @@ -47,10 +47,7 @@ case "$JDK" in 5) install_jdk $JDK5_URL false ;; -6) - ;; -7) - jdk_switcher /usr/lib/jvm/java-7-openjdk-amd64 +6 | 7) ;; 8) jdk_switcher /usr/lib/jvm/java-8-oracle @@ -91,7 +88,7 @@ case "$JDK" in mvn -V -B -e verify -Djdk.version=1.6 -Dbytecode.version=1.6 --toolchains=./.travis/travis-toolchains.xml ;; 7) - mvn -V -B -e verify -Dbytecode.version=1.7 + mvn -V -B -e verify -Djdk.version=1.7 -Dbytecode.version=1.7 --toolchains=./.travis/travis-toolchains.xml ;; 8 | 8-ea) mvn -V -B -e verify -Dbytecode.version=1.8 -Decj=${ECJ:-} diff --git a/.travis/travis-toolchains.xml b/.travis/travis-toolchains.xml index 9eb8100a..7a50a3c3 100644 --- a/.travis/travis-toolchains.xml +++ b/.travis/travis-toolchains.xml @@ -10,4 +10,13 @@ <jdkHome>/usr/lib/jvm/java-6-openjdk-amd64</jdkHome> </configuration> </toolchain> + <toolchain> + <type>jdk</type> + <provides> + <version>1.7</version> + </provides> + <configuration> + <jdkHome>/usr/lib/jvm/java-7-openjdk-amd64</jdkHome> + </configuration> + </toolchain> </toolchains> diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index ac4f3cc2..c691585e 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -83,10 +83,6 @@ </contributor> </contributors> - <prerequisites> - <maven>3.0</maven> - </prerequisites> - <modules> <!-- Order is important: org.jacoco.agent.rt embeds into org.jacoco.agent and JaCoCo Agent used during tests --> <module>../org.jacoco.core</module> @@ -323,7 +319,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> - <version>1.0.1</version> + <version>3.0.0-M2</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -524,6 +520,12 @@ </goals> <configuration> <rules> + <requireJavaVersion> + <version>1.8</version> + </requireJavaVersion> + <requireMavenVersion> + <version>3.3.9</version> + </requireMavenVersion> <requireNoRepositories> <message>The rules for repo1.maven.org are that pom.xml files should not include repository definitions.</message> <banRepositories>true</banRepositories> @@ -533,10 +535,6 @@ <message>No SNAPSHOT versions allowed for dependencies</message> <onlyWhenRelease>true</onlyWhenRelease> </requireReleaseDeps> - <requireMavenVersion> - <!-- Maven 3.0.3 contains bug - see http://jira.codehaus.org/browse/MINVOKER-107 --> - <version>[3.0.0,3.0.3),[3.0.4,)</version> - </requireMavenVersion> </rules> </configuration> </execution> diff --git a/org.jacoco.doc/docroot/doc/build.html b/org.jacoco.doc/docroot/doc/build.html index 89df34c3..3a125e0f 100644 --- a/org.jacoco.doc/docroot/doc/build.html +++ b/org.jacoco.doc/docroot/doc/build.html @@ -23,10 +23,10 @@ <p> The JaCoCo build is based on <a href="http://maven.apache.org/">Maven</a> and can be locally executed on every machine with a proper - <a href="environment.html">environment setup</a>. In particular you need a - <a href="http://maven.apache.org/">Maven 3</a> installation. Developers are - encouraged to run the build before every commit to ensure consistency of the - source tree. + <a href="environment.html">environment setup</a>. In particular you need at + least <a href="http://maven.apache.org/">Maven 3.3.9</a> installation. + Developers are encouraged to run the build before every commit to ensure + consistency of the source tree. </p> diff --git a/org.jacoco.doc/docroot/doc/environment.html b/org.jacoco.doc/docroot/doc/environment.html index d2d426d5..bcc59534 100644 --- a/org.jacoco.doc/docroot/doc/environment.html +++ b/org.jacoco.doc/docroot/doc/environment.html @@ -74,7 +74,8 @@ <h3>Build</h3> <p> - The JaCoCo build is based on <a href="http://maven.apache.org/">Maven 3</a>. + The JaCoCo build is based on <a href="http://maven.apache.org/">Maven</a> + and requires at least Maven 3.3.9. See the <a href="build.html">build description</a> for details. </p> -- cgit v1.2.3 From 753d6532d56892d037ff7958ea30c9bc27f6e8e4 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <mandrikov@gmail.com> Date: Sat, 14 Jul 2018 01:37:09 +0200 Subject: Upgrade maven-bundle-plugin to 3.5.1 --- org.jacoco.build/pom.xml | 31 +++++++------------------------ org.jacoco.core.test/pom.xml | 3 --- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index c691585e..16e6a5c0 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -444,8 +444,7 @@ <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> - <!-- newer versions require Java 7 --> - <version>2.5.4</version> + <version>3.5.1</version> </plugin> </plugins> </pluginManagement> @@ -722,24 +721,6 @@ <maven.compiler.target>${bytecode.version}</maven.compiler.target> </properties> </profile> - <profile> - <id>java9-validation</id> - <activation> - <property> - <name>bytecode.version</name> - <value>1.9</value> - </property> - </activation> - <properties> - <!-- - Compile into bytecode version 8 by default, - because maven-bundle-plugin is unable to proceess bytecode version >=9, - this is overridden for tests - --> - <maven.compiler.source>1.8</maven.compiler.source> - <maven.compiler.target>1.8</maven.compiler.target> - </properties> - </profile> <profile> <id>java10-validation</id> <activation> @@ -750,12 +731,14 @@ </activation> <properties> <!-- - Compile into bytecode version 8 by default, - because maven-bundle-plugin is unable to proceess bytecode version >=9, + Compile into bytecode version 9 by default, + because bytecode version 10 can't be processed by + maven-shade-plugin (https://issues.apache.org/jira/browse/MSHADE-289) + and maven-plugin-plugin (https://issues.apache.org/jira/browse/MPLUGIN-335), this is overridden for tests --> - <maven.compiler.source>1.8</maven.compiler.source> - <maven.compiler.target>1.8</maven.compiler.target> + <maven.compiler.source>1.9</maven.compiler.source> + <maven.compiler.target>1.9</maven.compiler.target> </properties> </profile> diff --git a/org.jacoco.core.test/pom.xml b/org.jacoco.core.test/pom.xml index 75d89481..0c6a4920 100644 --- a/org.jacoco.core.test/pom.xml +++ b/org.jacoco.core.test/pom.xml @@ -119,9 +119,6 @@ <value>1.9</value> </property> </activation> - <properties> - <maven.compiler.target>1.9</maven.compiler.target> - </properties> <build> <plugins> <plugin> -- cgit v1.2.3 From 88e67b3f121121161f29f15ab8c45e6fc7ecd6d4 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <Godin@users.noreply.github.com> Date: Sat, 21 Jul 2018 22:47:34 +0200 Subject: Extract "validation" tests into separate modules (#711) --- .appveyor.yml | 2 +- .travis.sh | 33 +-- .travis/appveyor-toolchains.xml | 4 +- .travis/toolchains.xml | 4 +- .travis/travis-toolchains.xml | 27 +- jacoco-maven-plugin.test/it/it-java9/pom.xml | 3 +- org.jacoco.build/pom.xml | 129 +++++++-- org.jacoco.core.test.validation.java5/.classpath | 20 ++ org.jacoco.core.test.validation.java5/.project | 30 +++ org.jacoco.core.test.validation.java5/pom.xml | 33 +++ .../jacoco/core/test/filter/ConstructorTest.java | 63 +++++ .../core/test/filter/EnumConstructorTest.java | 62 +++++ .../jacoco/core/test/filter/EnumSwitchTest.java | 40 +++ .../org/jacoco/core/test/filter/FinallyTest.java | 270 +++++++++++++++++++ .../jacoco/core/test/filter/SynchronizedTest.java | 74 ++++++ .../org/jacoco/core/test/filter/SyntheticTest.java | 38 +++ .../core/test/filter/targets/Constructor.java | 77 ++++++ .../core/test/filter/targets/EnumConstructor.java | 49 ++++ .../core/test/filter/targets/EnumSwitch.java | 42 +++ .../jacoco/core/test/filter/targets/Finally.java | 148 +++++++++++ .../core/test/filter/targets/Synchronized.java | 60 +++++ .../jacoco/core/test/filter/targets/Synthetic.java | 64 +++++ .../test/validation/AnnotationInitializerTest.java | 47 ++++ .../core/test/validation/BadCycleClassTest.java | 39 +++ .../test/validation/BooleanExpressionsTest.java | 79 ++++++ .../test/validation/ClassFileVersionsTest.java | 195 ++++++++++++++ .../core/test/validation/ClassInitializerTest.java | 44 ++++ .../test/validation/ControlStructuresTest.java | 137 ++++++++++ .../test/validation/CyclomaticComplexityTest.java | 280 ++++++++++++++++++++ .../test/validation/EnumImplicitMethodsTest.java | 41 +++ .../core/test/validation/ExceptionsTest.java | 132 ++++++++++ .../test/validation/ExplicitInitialFrameTest.java | 34 +++ .../FieldInitializationInTwoConstructorsTest.java | 38 +++ .../jacoco/core/test/validation/FramesTest.java | 179 +++++++++++++ .../validation/ImplicitDefaultConstructorTest.java | 36 +++ .../ImplicitFieldInitializationTest.java | 38 +++ .../validation/InterfaceClassInitializerTest.java | 43 +++ .../PrivateEmptyDefaultConstructorTest.java | 38 +++ .../ProbesBeforeSuperConstructorTest.java | 34 +++ .../test/validation/ResizeInstructionsTest.java | 171 ++++++++++++ .../test/validation/StructuredLockingTest.java | 202 ++++++++++++++ .../validation/targets/AnnotationInitializer.java | 23 ++ .../test/validation/targets/BadCycleClass.java | 44 ++++ .../validation/targets/EnumImplicitMethods.java | 48 ++++ .../core/test/validation/targets/Target01.java | 293 +++++++++++++++++++++ .../core/test/validation/targets/Target02.java | 120 +++++++++ .../core/test/validation/targets/Target03.java | 142 ++++++++++ .../core/test/validation/targets/Target04.java | 33 +++ .../core/test/validation/targets/Target05.java | 51 ++++ .../core/test/validation/targets/Target06.java | 25 ++ .../core/test/validation/targets/Target07.java | 27 ++ .../core/test/validation/targets/Target08.java | 31 +++ .../core/test/validation/targets/Target09.java | 34 +++ .../core/test/validation/targets/Target10.java | 33 +++ .../core/test/validation/targets/Target11.java | 31 +++ .../core/test/validation/targets/Target12.java | 46 ++++ org.jacoco.core.test.validation.java7/.classpath | 20 ++ org.jacoco.core.test.validation.java7/.project | 30 +++ org.jacoco.core.test.validation.java7/pom.xml | 37 +++ .../jacoco/core/test/filter/StringSwitchTest.java | 66 +++++ .../core/test/filter/TryWithResourcesTest.java | 178 +++++++++++++ .../core/test/filter/targets/StringSwitch.java | 96 +++++++ .../core/test/filter/targets/TryWithResources.java | 204 ++++++++++++++ org.jacoco.core.test.validation.java8/.classpath | 20 ++ org.jacoco.core.test.validation.java8/.project | 30 +++ org.jacoco.core.test.validation.java8/pom.xml | 37 +++ .../validation/AnnotationOnLocalVariableTest.java | 35 +++ .../test/validation/BadCycleInterfaceTest.java | 49 ++++ .../validation/BootstrapMethodReferenceTest.java | 126 +++++++++ .../validation/InterfaceDefaultMethodsTest.java | 34 +++ .../InterfaceOnlyDefaultMethodsTest.java | 33 +++ .../test/validation/LambdaExpressionsTest.java | 36 +++ .../test/validation/LambdaInInterfaceTest.java | 40 +++ .../targets/AnnotationOnLocalVariableTarget.java | 40 +++ .../test/validation/targets/BadCycleInterface.java | 48 ++++ .../targets/InterfaceDefaultMethodsTarget.java | 42 +++ .../targets/InterfaceOnlyDefaultMethodsTarget.java | 40 +++ .../targets/LambdaExpressionsTarget.java | 35 +++ .../targets/LambdaInInterfaceTarget.java | 25 ++ org.jacoco.core.test.validation/.project | 24 ++ org.jacoco.core.test.validation/pom.xml | 176 +++++++++++++ org.jacoco.core.test/pom.xml | 135 ---------- .../jacoco/core/test/filter/StringSwitchTest.java | 66 ----- .../core/test/filter/TryWithResourcesTest.java | 178 ------------- .../core/test/filter/targets/StringSwitch.java | 96 ------- .../core/test/filter/targets/TryWithResources.java | 204 -------------- .../validation/AnnotationOnLocalVariableTest.java | 35 --- .../test/validation/BadCycleInterfaceTest.java | 49 ---- .../validation/BootstrapMethodReferenceTest.java | 126 --------- .../validation/InterfaceDefaultMethodsTest.java | 34 --- .../InterfaceOnlyDefaultMethodsTest.java | 33 --- .../test/validation/LambdaExpressionsTest.java | 36 --- .../test/validation/LambdaInInterfaceTest.java | 40 --- .../targets/AnnotationOnLocalVariableTarget.java | 40 --- .../test/validation/targets/BadCycleInterface.java | 48 ---- .../targets/InterfaceDefaultMethodsTarget.java | 42 --- .../targets/InterfaceOnlyDefaultMethodsTarget.java | 40 --- .../targets/LambdaExpressionsTarget.java | 35 --- .../targets/LambdaInInterfaceTarget.java | 25 -- .../jacoco/core/test/filter/ConstructorTest.java | 63 ----- .../core/test/filter/EnumConstructorTest.java | 62 ----- .../jacoco/core/test/filter/EnumSwitchTest.java | 40 --- .../org/jacoco/core/test/filter/FinallyTest.java | 270 ------------------- .../jacoco/core/test/filter/SynchronizedTest.java | 74 ------ .../org/jacoco/core/test/filter/SyntheticTest.java | 38 --- .../core/test/filter/targets/Constructor.java | 77 ------ .../core/test/filter/targets/EnumConstructor.java | 49 ---- .../core/test/filter/targets/EnumSwitch.java | 42 --- .../jacoco/core/test/filter/targets/Finally.java | 148 ----------- .../core/test/filter/targets/Synchronized.java | 60 ----- .../jacoco/core/test/filter/targets/Synthetic.java | 64 ----- .../test/validation/AnnotationInitializerTest.java | 47 ---- .../core/test/validation/BadCycleClassTest.java | 39 --- .../test/validation/BooleanExpressionsTest.java | 79 ------ .../test/validation/ClassFileVersionsTest.java | 195 -------------- .../core/test/validation/ClassInitializerTest.java | 44 ---- .../test/validation/ControlStructuresTest.java | 137 ---------- .../test/validation/CyclomaticComplexityTest.java | 280 -------------------- .../test/validation/EnumImplicitMethodsTest.java | 41 --- .../core/test/validation/ExceptionsTest.java | 132 ---------- .../test/validation/ExplicitInitialFrameTest.java | 34 --- .../FieldInitializationInTwoConstructorsTest.java | 38 --- .../jacoco/core/test/validation/FramesTest.java | 179 ------------- .../validation/ImplicitDefaultConstructorTest.java | 36 --- .../ImplicitFieldInitializationTest.java | 38 --- .../validation/InterfaceClassInitializerTest.java | 43 --- .../PrivateEmptyDefaultConstructorTest.java | 38 --- .../ProbesBeforeSuperConstructorTest.java | 34 --- .../test/validation/ResizeInstructionsTest.java | 171 ------------ .../test/validation/StructuredLockingTest.java | 202 -------------- .../core/test/validation/ValidationTestBase.java | 11 +- .../validation/targets/AnnotationInitializer.java | 23 -- .../test/validation/targets/BadCycleClass.java | 44 ---- .../validation/targets/EnumImplicitMethods.java | 48 ---- .../core/test/validation/targets/Target01.java | 293 --------------------- .../core/test/validation/targets/Target02.java | 120 --------- .../core/test/validation/targets/Target03.java | 142 ---------- .../core/test/validation/targets/Target04.java | 33 --- .../core/test/validation/targets/Target05.java | 51 ---- .../core/test/validation/targets/Target06.java | 25 -- .../core/test/validation/targets/Target07.java | 27 -- .../core/test/validation/targets/Target08.java | 31 --- .../core/test/validation/targets/Target09.java | 34 --- .../core/test/validation/targets/Target10.java | 33 --- .../core/test/validation/targets/Target11.java | 31 --- .../core/test/validation/targets/Target12.java | 46 ---- org.jacoco.doc/docroot/doc/build.html | 156 +++++------ org.jacoco.doc/docroot/doc/changes.html | 2 + org.jacoco.doc/docroot/doc/environment.html | 8 +- org.jacoco.tests/pom.xml | 1 + 150 files changed, 5583 insertions(+), 5193 deletions(-) create mode 100644 org.jacoco.core.test.validation.java5/.classpath create mode 100644 org.jacoco.core.test.validation.java5/.project create mode 100644 org.jacoco.core.test.validation.java5/pom.xml create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/ConstructorTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumConstructorTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumSwitchTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/FinallyTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SynchronizedTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SyntheticTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Constructor.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumConstructor.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumSwitch.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Finally.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synchronized.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synthetic.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/AnnotationInitializerTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BadCycleClassTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BooleanExpressionsTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassInitializerTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ControlStructuresTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExceptionsTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExplicitInitialFrameTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FieldInitializationInTwoConstructorsTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FramesTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitDefaultConstructorTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitFieldInitializationTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/InterfaceClassInitializerTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ProbesBeforeSuperConstructorTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/StructuredLockingTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/AnnotationInitializer.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/BadCycleClass.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target01.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target02.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target03.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target04.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target05.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target06.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target07.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target08.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target09.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target10.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target11.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target12.java create mode 100644 org.jacoco.core.test.validation.java7/.classpath create mode 100644 org.jacoco.core.test.validation.java7/.project create mode 100644 org.jacoco.core.test.validation.java7/pom.xml create mode 100644 org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/StringSwitchTest.java create mode 100644 org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/TryWithResourcesTest.java create mode 100644 org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/StringSwitch.java create mode 100644 org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/TryWithResources.java create mode 100644 org.jacoco.core.test.validation.java8/.classpath create mode 100644 org.jacoco.core.test.validation.java8/.project create mode 100644 org.jacoco.core.test.validation.java8/pom.xml create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BadCycleInterfaceTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaExpressionsTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaInInterfaceTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/BadCycleInterface.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaExpressionsTarget.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaInInterfaceTarget.java create mode 100644 org.jacoco.core.test.validation/.project create mode 100644 org.jacoco.core.test.validation/pom.xml delete mode 100644 org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/StringSwitchTest.java delete mode 100644 org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/TryWithResourcesTest.java delete mode 100644 org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/targets/StringSwitch.java delete mode 100644 org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/targets/TryWithResources.java delete mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java delete mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BadCycleInterfaceTest.java delete mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java delete mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java delete mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java delete mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/LambdaExpressionsTest.java delete mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/LambdaInInterfaceTest.java delete mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java delete mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/BadCycleInterface.java delete mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java delete mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java delete mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/LambdaExpressionsTarget.java delete mode 100644 org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/LambdaInInterfaceTarget.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/ConstructorTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumConstructorTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumSwitchTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/SynchronizedTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/SyntheticTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Constructor.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumConstructor.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumSwitch.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Finally.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synchronized.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synthetic.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/AnnotationInitializerTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/BadCycleClassTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/BooleanExpressionsTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassInitializerTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/ControlStructuresTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/ExceptionsTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/ExplicitInitialFrameTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/FieldInitializationInTwoConstructorsTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/FramesTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/ImplicitDefaultConstructorTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/ImplicitFieldInitializationTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/InterfaceClassInitializerTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/ProbesBeforeSuperConstructorTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/StructuredLockingTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/AnnotationInitializer.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/BadCycleClass.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target01.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target02.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target03.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target04.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target05.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target06.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target07.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target08.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target09.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target10.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target11.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target12.java diff --git a/.appveyor.yml b/.appveyor.yml index 7ab0b103..d8efac61 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -11,7 +11,7 @@ install: build_script: # Maven 3.3.9 requires Java >= 7, but generation of Javadocs requires Java <= 6 (https://github.com/jacoco/jacoco/issues/110) - - mvn -V -B -e verify -Djdk.version=1.6 --toolchains=.travis\appveyor-toolchains.xml + - mvn -V -B -e verify -Djdk.version=6 --toolchains=.travis\appveyor-toolchains.xml artifacts: - path: jacoco\target\*.zip diff --git a/.travis.sh b/.travis.sh index d01ac831..ffeff4ce 100755 --- a/.travis.sh +++ b/.travis.sh @@ -43,20 +43,19 @@ function install_jdk { fi } +# Preinstalled JDKs: +ls -lA /usr/lib/jvm/ + + case "$JDK" in 5) install_jdk $JDK5_URL false ;; -6 | 7) - ;; -8) +6 | 7 | 8) jdk_switcher /usr/lib/jvm/java-8-oracle ;; -8-ea) - install_jdk $JDK8_EA_URL - ;; 9) - install_jdk $JDK9_URL + jdk_switcher /usr/lib/jvm/java-9-oracle ;; 10) install_jdk $JDK10_URL @@ -69,7 +68,6 @@ esac export MAVEN_SKIP_RC=true # Build: -# TODO(Godin): see https://github.com/jacoco/jacoco/issues/300 about "bytecode.version" case "$JDK" in 5) if [[ ${TRAVIS_PULL_REQUEST} == 'false' && ${TRAVIS_BRANCH} == 'master' ]] @@ -78,25 +76,14 @@ case "$JDK" in git fetch --unshallow # goal "deploy:deploy" used directly instead of "deploy" phase to avoid pollution of Maven repository by "install" phase - mvn -V -B -e -f org.jacoco.build verify sonar:sonar deploy:deploy -DdeployAtEnd -Djdk.version=1.5 --toolchains=./.travis/toolchains.xml --settings=./.travis/settings.xml -Dsonar.host.url=${SONARQUBE_URL} -Dsonar.login=${SONARQUBE_TOKEN} + mvn -V -B -e -f org.jacoco.build verify sonar:sonar deploy:deploy -DdeployAtEnd -Djdk.version=5 --toolchains=./.travis/toolchains.xml --settings=./.travis/settings.xml -Dsonar.host.url=${SONARQUBE_URL} -Dsonar.login=${SONARQUBE_TOKEN} python ./.travis/trigger-site-deployment.py else - mvn -V -B -e verify -Djdk.version=1.5 --toolchains=./.travis/toolchains.xml + mvn -V -B -e verify -Djdk.version=5 --toolchains=./.travis/toolchains.xml fi ;; -6) - mvn -V -B -e verify -Djdk.version=1.6 -Dbytecode.version=1.6 --toolchains=./.travis/travis-toolchains.xml - ;; -7) - mvn -V -B -e verify -Djdk.version=1.7 -Dbytecode.version=1.7 --toolchains=./.travis/travis-toolchains.xml - ;; -8 | 8-ea) - mvn -V -B -e verify -Dbytecode.version=1.8 -Decj=${ECJ:-} - ;; -9) - export MAVEN_OPTS="-Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts" - mvn -V -B -e verify -Dbytecode.version=1.9 \ - -Dinvoker.mavenOpts="-Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts" +6 | 7 | 8 | 9) + mvn -V -B -e verify -Djdk.version=${JDK} -Dbytecode.version=${JDK} -Decj=${ECJ:-} --toolchains=./.travis/travis-toolchains.xml ;; 10) mvn -V -B -e verify -Dbytecode.version=10 diff --git a/.travis/appveyor-toolchains.xml b/.travis/appveyor-toolchains.xml index 6e91e4b4..79fae7dd 100644 --- a/.travis/appveyor-toolchains.xml +++ b/.travis/appveyor-toolchains.xml @@ -1,15 +1,17 @@ <?xml version="1.0" encoding="UTF8"?> <toolchains xmlns="http://maven.apache.org/TOOLCHAINS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/TOOLCHAINS/1.1.0 http://maven.apache.org/xsd/toolchains-1.1.0.xsd"> + <toolchain> <type>jdk</type> <provides> <id>java16</id> - <version>1.6</version> + <version>6</version> <vendor>oracle</vendor> </provides> <configuration> <jdkHome>C:\Program Files\Java\jdk1.6.0</jdkHome> </configuration> </toolchain> + </toolchains> diff --git a/.travis/toolchains.xml b/.travis/toolchains.xml index 59383f36..dcf1b8c7 100644 --- a/.travis/toolchains.xml +++ b/.travis/toolchains.xml @@ -1,15 +1,17 @@ <?xml version="1.0" encoding="UTF8"?> <toolchains xmlns="http://maven.apache.org/TOOLCHAINS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/TOOLCHAINS/1.1.0 http://maven.apache.org/xsd/toolchains-1.1.0.xsd"> + <toolchain> <type>jdk</type> <provides> <id>java15</id> - <version>1.5</version> + <version>5</version> <vendor>sun</vendor> </provides> <configuration> <jdkHome>/tmp/jdk/5</jdkHome> </configuration> </toolchain> + </toolchains> diff --git a/.travis/travis-toolchains.xml b/.travis/travis-toolchains.xml index 7a50a3c3..8079e745 100644 --- a/.travis/travis-toolchains.xml +++ b/.travis/travis-toolchains.xml @@ -1,22 +1,45 @@ <?xml version="1.0" encoding="UTF8"?> <toolchains xmlns="http://maven.apache.org/TOOLCHAINS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/TOOLCHAINS/1.1.0 http://maven.apache.org/xsd/toolchains-1.1.0.xsd"> + <toolchain> <type>jdk</type> <provides> - <version>1.6</version> + <version>6</version> </provides> <configuration> <jdkHome>/usr/lib/jvm/java-6-openjdk-amd64</jdkHome> </configuration> </toolchain> + <toolchain> <type>jdk</type> <provides> - <version>1.7</version> + <version>7</version> </provides> <configuration> <jdkHome>/usr/lib/jvm/java-7-openjdk-amd64</jdkHome> </configuration> </toolchain> + + <toolchain> + <type>jdk</type> + <provides> + <version>8</version> + </provides> + <configuration> + <jdkHome>/usr/lib/jvm/java-8-oracle</jdkHome> + </configuration> + </toolchain> + + <toolchain> + <type>jdk</type> + <provides> + <version>9</version> + </provides> + <configuration> + <jdkHome>/usr/lib/jvm/java-9-oracle</jdkHome> + </configuration> + </toolchain> + </toolchains> diff --git a/jacoco-maven-plugin.test/it/it-java9/pom.xml b/jacoco-maven-plugin.test/it/it-java9/pom.xml index a0511f87..77503567 100644 --- a/jacoco-maven-plugin.test/it/it-java9/pom.xml +++ b/jacoco-maven-plugin.test/it/it-java9/pom.xml @@ -28,7 +28,8 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> - <target>1.9</target> + <source>9</source> + <target>9</target> </configuration> </plugin> <plugin> diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index 16e6a5c0..02dc806e 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -130,8 +130,9 @@ <jacoco.home.url>http://www.jacoco.org/jacoco</jacoco.home.url> <copyright.years>${project.inceptionYear}, 2018</copyright.years> - <maven.compiler.source>1.5</maven.compiler.source> - <maven.compiler.target>1.5</maven.compiler.target> + <bytecode.version>1.5</bytecode.version> + <maven.compiler.source>${bytecode.version}</maven.compiler.source> + <maven.compiler.target>${bytecode.version}</maven.compiler.target> <jvm.args></jvm.args> <argLine>${jvm.args}</argLine> @@ -674,7 +675,18 @@ </build> <profiles> - <!-- This profile is used to launch tests with different JDK versions. --> + <profile> + <id>maven-jdk9</id> + <activation> + <jdk>[9,)</jdk> + </activation> + <properties> + <!-- http://openjdk.java.net/jeps/182 --> + <bytecode.version>6</bytecode.version> + </properties> + </profile> + + <!-- This profile enables use of JDK from Maven Toolchains --> <profile> <id>integration-tests</id> <activation> @@ -708,41 +720,58 @@ </build> </profile> - <!-- This profile is used to launch tests with compilation into specific bytecode version. --> + <!-- + Following profiles enable compilation into bytecode version 9 + when requested "bytecode.version" greater than 9, + because this is maximum that can be processed by + maven-shade-plugin (https://issues.apache.org/jira/browse/MSHADE-289) + and maven-plugin-plugin (https://issues.apache.org/jira/browse/MPLUGIN-335), + This is overridden for tests. + --> + <profile> - <id>bytecode</id> + <id>java10-bytecode</id> <activation> <property> <name>bytecode.version</name> + <value>10</value> </property> </activation> <properties> - <maven.compiler.source>${bytecode.version}</maven.compiler.source> - <maven.compiler.target>${bytecode.version}</maven.compiler.target> + <maven.compiler.source>9</maven.compiler.source> + <maven.compiler.target>9</maven.compiler.target> </properties> </profile> + <profile> - <id>java10-validation</id> + <id>java11-bytecode</id> <activation> <property> <name>bytecode.version</name> - <value>10</value> + <value>11</value> </property> </activation> <properties> - <!-- - Compile into bytecode version 9 by default, - because bytecode version 10 can't be processed by - maven-shade-plugin (https://issues.apache.org/jira/browse/MSHADE-289) - and maven-plugin-plugin (https://issues.apache.org/jira/browse/MPLUGIN-335), - this is overridden for tests - --> - <maven.compiler.source>1.9</maven.compiler.source> - <maven.compiler.target>1.9</maven.compiler.target> + <maven.compiler.source>9</maven.compiler.source> + <maven.compiler.target>9</maven.compiler.target> </properties> </profile> - <!-- This profile is used for compilation with ECJ. --> + <profile> + <id>java12-bytecode</id> + <activation> + <property> + <name>bytecode.version</name> + <value>12</value> + </property> + </activation> + <properties> + <maven.compiler.source>9</maven.compiler.source> + <maven.compiler.target>9</maven.compiler.target> + </properties> + </profile> + + <!-- This profile enables use of ECJ --> <profile> <id>ecj</id> <activation> @@ -758,6 +787,8 @@ <version>3.6.0</version> <configuration> <compilerId>eclipse</compilerId> + <source>1.8</source> + <target>1.8</target> </configuration> <dependencies> <dependency> @@ -776,12 +807,16 @@ </build> </profile> + <!-- + Profiles for different JDK versions: + --> + <profile> - <id>jdk16</id> + <id>jdk6</id> <activation> <property> <name>jdk.version</name> - <value>1.6</value> + <value>6</value> </property> </activation> <properties> @@ -790,11 +825,11 @@ </profile> <profile> - <id>jdk17</id> + <id>jdk7</id> <activation> <property> <name>jdk.version</name> - <value>1.7</value> + <value>7</value> </property> </activation> <properties> @@ -803,11 +838,11 @@ </profile> <profile> - <id>jdk18</id> + <id>jdk8</id> <activation> <property> <name>jdk.version</name> - <value>1.8</value> + <value>8</value> </property> </activation> <properties> @@ -820,14 +855,54 @@ <activation> <property> <name>jdk.version</name> - <value>1.9</value> + <value>9</value> </property> </activation> <properties> - <jvm.args>-XX:-FailOverToOldVerifier -Xverify:all</jvm.args> + <bytecode.version>6</bytecode.version> + </properties> + </profile> + + <profile> + <id>jdk10</id> + <activation> + <property> + <name>jdk.version</name> + <value>10</value> + </property> + </activation> + <properties> + <bytecode.version>6</bytecode.version> + </properties> + </profile> + + <profile> + <id>jdk11</id> + <activation> + <property> + <name>jdk.version</name> + <value>11</value> + </property> + </activation> + <properties> + <bytecode.version>6</bytecode.version> + </properties> + </profile> + + <profile> + <id>jdk12</id> + <activation> + <property> + <name>jdk.version</name> + <value>12</value> + </property> + </activation> + <properties> + <bytecode.version>6</bytecode.version> </properties> </profile> + <!-- This profile enables generation of JARs with sources and javadocs --> <profile> <id>sources</id> <activation> diff --git a/org.jacoco.core.test.validation.java5/.classpath b/org.jacoco.core.test.validation.java5/.classpath new file mode 100644 index 00000000..ebe550b7 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/.classpath @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="src" output="target/classes" path="src"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="output" path="target/classes"/> +</classpath> diff --git a/org.jacoco.core.test.validation.java5/.project b/org.jacoco.core.test.validation.java5/.project new file mode 100644 index 00000000..cfbae43e --- /dev/null +++ b/org.jacoco.core.test.validation.java5/.project @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.jacoco.core.test.validation.java5</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.m2e.core.maven2Builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.m2e.core.maven2Nature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> + <linkedResources> + <link> + <name>.settings</name> + <type>2</type> + <locationURI>PARENT-1-PROJECT_LOC/org.jacoco.core.test/.settings</locationURI> + </link> + </linkedResources> +</projectDescription> diff --git a/org.jacoco.core.test.validation.java5/pom.xml b/org.jacoco.core.test.validation.java5/pom.xml new file mode 100644 index 00000000..241dbc36 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/pom.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2009, 2018 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: + Evgeny Mandrikov - initial API and implementation +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.jacoco</groupId> + <artifactId>org.jacoco.core.test.validation</artifactId> + <version>0.8.2-SNAPSHOT</version> + <relativePath>../org.jacoco.core.test.validation</relativePath> + </parent> + + <artifactId>org.jacoco.core.test.validation.java5</artifactId> + + <name>JaCoCo :: Test :: Core :: Validation Java 5</name> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.core.test</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project> diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/ConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/ConstructorTest.java new file mode 100644 index 00000000..1dffc684 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/ConstructorTest.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.filter.targets.Constructor; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.junit.Test; + +/** + * Test of filtering of a bytecode that is generated for a private empty + * constructors that do not have no arguments. + */ +public class ConstructorTest extends ValidationTestBase { + + public ConstructorTest() { + super(Constructor.class); + } + + @Test + public void testCoverageResult() { + // not filtered because not private: + assertLine("packageLocal", ICounter.FULLY_COVERED); + + // not filtered because has argument: + assertLine("arg", ICounter.FULLY_COVERED); + + // not filtered because not empty - prepares arguments for super + // constructor: + assertLine("super", ICounter.FULLY_COVERED); + + // not filtered because contains initialization of a field to hold + // reference to an instance of outer class that is passed as an + // argument: + assertLine("inner", ICounter.FULLY_COVERED); + + // not filtered because not empty - contains initialization of + // a field: + assertLine("innerStatic", ICounter.FULLY_COVERED); + + // not filtered because default constructor for not private inner + // classes is not private: + assertLine("publicDefault", ICounter.FULLY_COVERED); + assertLine("packageLocalDefault", ICounter.FULLY_COVERED); + + assertLine("privateDefault", ICounter.EMPTY); + + assertLine("privateNonEmptyNoArg", ICounter.FULLY_COVERED); + + assertLine("privateEmptyNoArg", ICounter.EMPTY); + assertLine("return", ICounter.EMPTY); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumConstructorTest.java new file mode 100644 index 00000000..fd88787b --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumConstructorTest.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.filter.targets.EnumConstructor; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.junit.Test; + +/** + * Test of filtering of enum constructors. + */ +public class EnumConstructorTest extends ValidationTestBase { + + public EnumConstructorTest() { + super(EnumConstructor.class); + } + + /** + * {@link EnumConstructor.ImplicitConstructor} + */ + @Test + public void implicit_constructor_should_be_filtered() { + // without filter next line is partly covered: + assertLine("implicitConstructor", ICounter.FULLY_COVERED); + } + + /** + * {@link EnumConstructor.ExplicitNonEmptyConstructor#ExplicitNonEmptyConstructor()} + */ + @Test + public void explicit_non_empty_constructor_should_not_be_filtered() { + assertLine("explicitNonEmptyConstructor", ICounter.NOT_COVERED); + } + + /** + * {@link EnumConstructor.ExplicitEmptyConstructor#ExplicitEmptyConstructor()} + */ + @Test + public void explicit_empty_constructor_should_be_filtered() { + // without filter next line is not covered: + assertLine("explicitEmptyConstructor", ICounter.EMPTY); + } + + /** + * {@link EnumConstructor.ExplicitEmptyConstructor#ExplicitEmptyConstructor(Object)} + */ + @Test + public void explicit_empty_constructor_with_parameters_should_not_be_filtered() { + assertLine("explicitEmptyConstructorWithParameter", ICounter.NOT_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumSwitchTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumSwitchTest.java new file mode 100644 index 00000000..3708899a --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumSwitchTest.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.filter.targets.EnumSwitch; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.junit.Test; + +/** + * Test of filtering of a synthetic class that is generated by javac for a enum + * in switch statement. + */ +public class EnumSwitchTest extends ValidationTestBase { + + public EnumSwitchTest() { + super(EnumSwitch.class); + } + + @Test + public void testCoverageResult() { + if (isJDKCompiler && JAVA_VERSION.isBefore("1.6")) { + // class that holds "switch map" is not marked as synthetic when + // compiling with javac 1.5 + assertLine("switch", ICounter.PARTLY_COVERED, 0, 2); + } else { + assertLine("switch", ICounter.FULLY_COVERED, 0, 2); + } + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/FinallyTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/FinallyTest.java new file mode 100644 index 00000000..9c6b2af4 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/FinallyTest.java @@ -0,0 +1,270 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.internal.BytecodeVersion; +import org.jacoco.core.test.TargetLoader; +import org.jacoco.core.test.filter.targets.Finally; +import org.jacoco.core.test.validation.Source; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.LineNumberNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Test of filtering of duplicated bytecode that is generated for finally block. + */ +public class FinallyTest extends ValidationTestBase { + + public FinallyTest() { + super(Finally.class); + } + + /** + * {@link Finally#example(boolean)} + */ + @Test + public void example() { + if (isJDKCompiler) { + assertLine("example.0", ICounter.EMPTY); + } else { + assertLine("example.0", ICounter.FULLY_COVERED); + } + assertLine("example.1", ICounter.FULLY_COVERED, 0, 2); + assertLine("example.2", ICounter.FULLY_COVERED); + assertLine("example.3", ICounter.EMPTY); + assertLine("example.4", ICounter.EMPTY); + } + + /** + * GOTO instructions at the end of duplicates of finally block might have + * line number of a last instruction of finally block and hence lead to + * unexpected coverage results, like for example in case of ECJ for + * {@link Finally#catchNotExecuted()}, {@link Finally#emptyCatch()}. So we + * decided to ignore them, even if they can correspond to a real break + * statement. + * <p> + * See also <a href= + * "https://bugs.openjdk.java.net/browse/JDK-8180141">JDK-8180141</a> and + * <a href= + * "https://bugs.openjdk.java.net/browse/JDK-7008643">JDK-7008643</a>. + * <p> + * {@link Finally#breakStatement()} + */ + @Test + public void breakStatement() { + assertLine("breakStatement", ICounter.EMPTY); + + assertLine("breakStatement.1", ICounter.FULLY_COVERED); + assertLine("breakStatement.2", ICounter.EMPTY); + } + + /** + * {@link Finally#catchNotExecuted()} + */ + @Test + public void catchNotExecuted() { + assertLine("catchNotExecuted.catch", ICounter.NOT_COVERED); + assertLine("catchNotExecuted.0", ICounter.EMPTY); + assertLine("catchNotExecuted.1", ICounter.FULLY_COVERED); + assertLine("catchNotExecuted.2", ICounter.EMPTY); + } + + /** + * {@link Finally#emptyCatch()} + */ + @Test + public void emptyCatch() { + assertLine("emptyCatch.0", ICounter.EMPTY); + assertLine("emptyCatch.1", ICounter.FULLY_COVERED); + assertLine("emptyCatch.2", ICounter.EMPTY); + } + + /** + * {@link Finally#twoRegions()} + */ + @Test + public void twoRegions() { + assertLine("twoRegions.0", ICounter.EMPTY); + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { + // https://bugs.openjdk.java.net/browse/JDK-7008643 + assertLine("twoRegions.1", ICounter.PARTLY_COVERED); + assertLine("twoRegions.return.1", ICounter.EMPTY); + assertLine("twoRegions.return.2", ICounter.EMPTY); + } else { + assertLine("twoRegions.1", ICounter.FULLY_COVERED); + assertLine("twoRegions.return.1", ICounter.FULLY_COVERED); + assertLine("twoRegions.return.2", ICounter.NOT_COVERED); + } + assertLine("twoRegions.2", ICounter.EMPTY); + + assertLine("twoRegions.if", ICounter.FULLY_COVERED); + assertLine("twoRegions.region.1", ICounter.FULLY_COVERED); + assertLine("twoRegions.region.2", ICounter.NOT_COVERED); + } + + /** + * {@link Finally#nested()} + */ + @Test + public void nested() { + if (isJDKCompiler) { + assertLine("nested.0", ICounter.EMPTY); + } else { + assertLine("nested.0", ICounter.FULLY_COVERED); + } + assertLine("nested.1", ICounter.EMPTY); + assertLine("nested.2", ICounter.FULLY_COVERED); + if (isJDKCompiler) { + assertLine("nested.3", ICounter.EMPTY); + } else { + assertLine("nested.3", ICounter.FULLY_COVERED); + } + assertLine("nested.4", ICounter.FULLY_COVERED); + } + + /** + * {@link Finally#emptyTry()} + */ + @Test + public void emptyTry() { + assertLine("emptyTry.0", ICounter.EMPTY); + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { + // compiler bug fixed in javac >= 1.8: + assertLine("emptyTry.1", ICounter.PARTLY_COVERED); + assertLine("emptyTry.2", ICounter.FULLY_COVERED); + } else { + assertLine("emptyTry.1", ICounter.FULLY_COVERED); + assertLine("emptyTry.2", ICounter.EMPTY); + } + } + + /** + * {@link Finally#alwaysCompletesAbruptly()} + */ + @Test + public void alwaysCompletesAbruptly() { + if (isJDKCompiler) { + // uncovered case: + assertLine("alwaysCompletesAbruptly.0", ICounter.EMPTY); + assertLine("alwaysCompletesAbruptly.1", ICounter.PARTLY_COVERED); + } else { + assertLine("alwaysCompletesAbruptly.0", ICounter.PARTLY_COVERED); + assertLine("alwaysCompletesAbruptly.1", ICounter.FULLY_COVERED); + } + assertLine("alwaysCompletesAbruptly.2", ICounter.EMPTY); + } + + /** + * This test studies placement of GOTO instructions. + */ + @Test + public void gotos() throws IOException { + final Source source = Source.getSourceFor("src", Finally.class); + + byte[] b = TargetLoader.getClassDataAsBytes(Finally.class); + b = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(b), b); + + final ClassNode classNode = new ClassNode(); + new ClassReader(b).accept(classNode, 0); + final Set<String> tags = new HashSet<String>(); + for (final MethodNode m : classNode.methods) { + if ("main".equals(m.name)) { + // skip it + continue; + } + int lineNumber = -1; + for (AbstractInsnNode i = m.instructions + .getFirst(); i != null; i = i.getNext()) { + if (AbstractInsnNode.LINE == i.getType()) { + lineNumber = ((LineNumberNode) i).line; + } + if (Opcodes.GOTO == i.getOpcode()) { + final String line = source.getLine(lineNumber); + if (line.indexOf('$') < 0) { + throw new AssertionError( + "No tag at line " + lineNumber); + } + final String tag = line.substring( + line.indexOf('$') + "$line-".length(), + line.lastIndexOf('$')); + tags.add(tag); + } + } + } + + final Set<String> expected = new HashSet<String>(); + + if (isJDKCompiler) { + expected.add("example.2"); + } else { + expected.add("example.0"); + } + + expected.add("breakStatement.for"); + if (isJDKCompiler) { + if (JAVA_VERSION.isBefore("10")) { + // https://bugs.openjdk.java.net/browse/JDK-8180141 + expected.add("breakStatement.1"); + } else { + expected.add("breakStatement"); + } + expected.add("breakStatement.2"); + } else { + expected.add("breakStatement"); + } + + if (isJDKCompiler) { + expected.add("emptyCatch.2"); + } else { + expected.add("emptyCatch"); + expected.add("emptyCatch.1"); + } + + if (isJDKCompiler) { + expected.add("catchNotExecuted.2"); + } else { + expected.add("catchNotExecuted"); + expected.add("catchNotExecuted.1"); + } + + if (isJDKCompiler) { + expected.add("nested.5"); + expected.add("nested.6"); + } else { + expected.add("nested.0"); + expected.add("nested.3"); + } + + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { + expected.add("emptyTry.2"); + } + + if (!isJDKCompiler) { + expected.add("alwaysCompletesAbruptly.0"); + } + + assertEquals(expected, tags); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SynchronizedTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SynchronizedTest.java new file mode 100644 index 00000000..2d0fa973 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SynchronizedTest.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.filter.targets.Synchronized; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.junit.Test; + +/** + * Test of filtering of a bytecode that is generated for a synchronized + * statement. + */ +public class SynchronizedTest extends ValidationTestBase { + + public SynchronizedTest() { + super(Synchronized.class); + } + + /** + * {@link Synchronized#normal()} + */ + @Test + public void normal() { + assertLine("before", ICounter.FULLY_COVERED); + // when compiled with ECJ next line covered partly without filter: + assertLine("monitorEnter", ICounter.FULLY_COVERED); + assertLine("body", ICounter.FULLY_COVERED); + if (isJDKCompiler) { + // without filter next line covered partly: + assertLine("monitorExit", ICounter.FULLY_COVERED); + } else { + assertLine("monitorExit", ICounter.EMPTY); + } + assertLine("after", ICounter.FULLY_COVERED); + } + + /** + * {@link Synchronized#explicitException()} + */ + @Test + public void explicitException() { + assertLine("explicitException.monitorEnter", ICounter.FULLY_COVERED); + assertLine("explicitException.exception", ICounter.FULLY_COVERED); + // when compiled with javac next line covered fully without filter: + assertLine("explicitException.monitorExit", ICounter.EMPTY); + } + + /** + * {@link Synchronized#implicitException()} + */ + @Test + public void implicitException() { + assertLine("implicitException.monitorEnter", isJDKCompiler + ? ICounter.FULLY_COVERED : ICounter.PARTLY_COVERED); + assertLine("implicitException.exception", ICounter.NOT_COVERED); + if (isJDKCompiler) { + // without filter next line covered partly: + assertLine("implicitException.monitorExit", ICounter.NOT_COVERED); + } else { + assertLine("implicitException.monitorExit", ICounter.EMPTY); + } + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SyntheticTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SyntheticTest.java new file mode 100644 index 00000000..f439736b --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SyntheticTest.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.filter.targets.Synthetic; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.junit.Test; + +/** + * Test of filtering of synthetic methods. + */ +public class SyntheticTest extends ValidationTestBase { + + public SyntheticTest() { + super(Synthetic.class); + } + + @Test + public void testCoverageResult() { + assertMethodCount(5); + + assertLine("classdef", ICounter.EMPTY); + assertLine("field", ICounter.EMPTY); + + assertLine("inner.classdef", ICounter.EMPTY); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Constructor.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Constructor.java new file mode 100644 index 00000000..8a3e394a --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Constructor.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target is a constructors. + */ +public class Constructor { + + Constructor() { // $line-packageLocal$ + } + + private Constructor(Object arg) { // $line-arg$ + } + + private static class Super extends Constructor { + private Super() { + super(null); // $line-super$ + } + } + + private class Inner { + private Inner() { // $line-inner$ + } + } + + private static class InnerStatic { + @SuppressWarnings("unused") + private final Object field = this; + + private InnerStatic() { // $line-innerStatic$ + } + } + + public static class PublicDefault { // $line-publicDefault$ + } + + static class PackageLocalDefault { // $line-packageLocalDefault$ + } + + private static class PrivateDefault { // $line-privateDefault$ + } + + private static class PrivateNonEmptyNoArg { + private PrivateNonEmptyNoArg() { + nop(); // $line-privateNonEmptyNoArg$ + } + } + + private static class PrivateEmptyNoArg { + private PrivateEmptyNoArg() { // $line-privateEmptyNoArg$ + } // $line-return$ + } + + public static void main(String[] args) { + new Super(); + new Constructor().new Inner(); + new InnerStatic(); + new PublicDefault(); + new PackageLocalDefault(); + new PrivateDefault(); + new PrivateNonEmptyNoArg(); + new PrivateEmptyNoArg(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumConstructor.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumConstructor.java new file mode 100644 index 00000000..c6eb1c53 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumConstructor.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target is an enum constructor. + */ +public class EnumConstructor { + + private enum ImplicitConstructor { // $line-implicitConstructor$ + } + + private enum ExplicitNonEmptyConstructor { + ; + + ExplicitNonEmptyConstructor() { + nop(); // $line-explicitNonEmptyConstructor$ + } + } + + @SuppressWarnings("unused") + private enum ExplicitEmptyConstructor { + ; + + ExplicitEmptyConstructor() { + } // $line-explicitEmptyConstructor$ + + ExplicitEmptyConstructor(Object p) { + } // $line-explicitEmptyConstructorWithParameter$ + } + + public static void main(String[] args) { + ImplicitConstructor.values(); + ExplicitEmptyConstructor.values(); + ExplicitNonEmptyConstructor.values(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumSwitch.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumSwitch.java new file mode 100644 index 00000000..850ef295 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumSwitch.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target is a switch statement with a enum. + */ +public class EnumSwitch { + + private enum E { + V1, V2 + } + + private static void example(E e) { + switch (e) { // $line-switch$ + case V1: + nop("V1"); + break; + case V2: + default: + nop("V2"); + break; + } + } + + public static void main(String[] args) { + example(E.V1); + example(E.V2); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Finally.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Finally.java new file mode 100644 index 00000000..6471a809 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Finally.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.ex; +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.nop; +import static org.jacoco.core.test.validation.targets.Stubs.t; + +public class Finally { + + /** + * <pre> + * InputStream in = null; + * try { + * in = ...; + * ... + * } finally { + * if (in != null) { + * in.close(); + * } + * } + * </pre> + */ + private static void example(boolean t) { + Object in = null; + try { + in = open(t); + } finally { // $line-example.0$ + if (in != null) { // $line-example.1$ + nop(); // $line-example.2$ + } // $line-example.3$ + } // $line-example.4$ + } + + private static Object open(boolean t) { + ex(t); + return new Object(); + } + + private static void breakStatement() { + for (int i = 0; i < 1; i++) { // $line-breakStatement.for$ + try { + if (f()) { + break; // $line-breakStatement$ + } + } finally { + nop("finally"); // $line-breakStatement.1$ + } // $line-breakStatement.2$ + } + } + + private static void catchNotExecuted() { + try { + nop("try"); + } catch (Exception e) { // $line-catchNotExecuted$ + nop("catch"); // $line-catchNotExecuted.catch$ + } finally { // $line-catchNotExecuted.0$ + nop("finally"); // $line-catchNotExecuted.1$ + } // $line-catchNotExecuted.2$ + } + + private static void emptyCatch() { + try { + nop("try"); + } catch (Exception e) { // $line-emptyCatch$ + // empty + } finally { // $line-emptyCatch.0$ + nop("finally"); // $line-emptyCatch.1$ + } // $line-emptyCatch.2$ + } + + private static void twoRegions() { + try { + // jump to another region associated with same handler: + if (t()) { // $line-twoRegions.if$ + nop(); // $line-twoRegions.region.1$ + return; // $line-twoRegions.return.1$ + } else { + nop(); // $line-twoRegions.region.2$ + return; // $line-twoRegions.return.2$ + } + } finally { // $line-twoRegions.0$ + nop(); // $line-twoRegions.1$ + } // $line-twoRegions.2$ + } + + private static void nested() { + try { + nop(); + } finally { // $line-nested.0$ + try { // $line-nested.1$ + nop(); // $line-nested.2$ + } finally { // $line-nested.3$ + nop(); // $line-nested.4$ + } // $line-nested.5$ + } // $line-nested.6$ + } + + private static void emptyTry() { + try { + // empty + } finally { // $line-emptyTry.0$ + nop(); // $line-emptyTry.1$ + } // $line-emptyTry.2$ + } + + @SuppressWarnings("finally") + private static void alwaysCompletesAbruptly() { + try { + nop(); + } finally { // $line-alwaysCompletesAbruptly.0$ + return; // $line-alwaysCompletesAbruptly.1$ + } // $line-alwaysCompletesAbruptly.2$ + } + + public static void main(String[] args) { + example(false); + try { + example(true); + } catch (Exception ignore) { + } + + breakStatement(); + + catchNotExecuted(); + + emptyCatch(); + + twoRegions(); + + nested(); + + emptyTry(); + + alwaysCompletesAbruptly(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synchronized.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synchronized.java new file mode 100644 index 00000000..b2d503f8 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synchronized.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.ex; +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +import org.jacoco.core.test.validation.targets.Stubs.StubException; + +/** + * This test target is a synchronized statement. + */ +public class Synchronized { + + private static final Object lock = new Object(); + + private static void normal() { + nop(); // $line-before$ + synchronized (lock) { // $line-monitorEnter$ + nop(); // $line-body$ + } // $line-monitorExit$ + nop(); // $line-after$ + } + + private static void explicitException() { + synchronized (lock) { // $line-explicitException.monitorEnter$ + throw new StubException(); // $line-explicitException.exception$ + } // $line-explicitException.monitorExit$ + } + + private static void implicitException() { + synchronized (lock) { // $line-implicitException.monitorEnter$ + ex(); // $line-implicitException.exception$ + } // $line-implicitException.monitorExit$ + } + + public static void main(String[] args) { + normal(); + + try { + explicitException(); + } catch (StubException e) { + } + + try { + implicitException(); + } catch (StubException e) { + } + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synthetic.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synthetic.java new file mode 100644 index 00000000..6e2f6266 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synthetic.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter.targets; + +/** + * This test target is synthetic methods. + */ +public class Synthetic { // $line-classdef$ + + private static int counter; // $line-field$ + + /** + * {@link org.jacoco.core.test.validation.targets.Target06 Default + * constructor will refer to a line of class definition}, so that we define + * constructor explicitly in order to verify that we filter all other + * constructions here that might refer to line of class definition. + */ + private Synthetic() { + } + + static class Inner extends Synthetic { // $line-inner.classdef$ + + Inner() { + } + + /** + * Access to private field of outer class causes creation of synthetic + * methods in it. In case of javac those methods refer to the line of + * outer class definition, in case of ECJ - to the line of field. + */ + private static void inc() { + counter = counter + 2; + } + + /** + * Difference of return type with overridden method causes creation of + * synthetic bridge method in this class. In case of javac this method + * refers to the line of inner class definition, in case of EJC - to the + * first line of file. + */ + @Override + public String get() { + return null; + } + } + + public Object get() { + return null; + } + + public static void main(String[] args) { + Inner.inc(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/AnnotationInitializerTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/AnnotationInitializerTest.java new file mode 100644 index 00000000..60a38339 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/AnnotationInitializerTest.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.AnnotationInitializer; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Test of initializer in annotations. + */ +public class AnnotationInitializerTest extends ValidationTestBase { + + public AnnotationInitializerTest() { + super(AnnotationInitializer.class); + } + + @Override + protected void run(Class<?> targetClass) throws Exception { + // Instrumentation should not add members, + // otherwise sun.reflect.annotation.AnnotationInvocationHandler + // can throw java.lang.annotation.AnnotationFormatError + assertEquals(1, targetClass.getDeclaredFields().length); + assertEquals(1, targetClass.getDeclaredMethods().length); + + // Force initialization + targetClass.getField("CONST").get(null); + } + + @Test + public void testCoverageResult() { + assertLine("const", ICounter.FULLY_COVERED); + assertLine("value", ICounter.EMPTY); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BadCycleClassTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BadCycleClassTest.java new file mode 100644 index 00000000..aa646ddf --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BadCycleClassTest.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.BadCycleClass; +import org.junit.Test; + +/** + * Test of "bad cycles" with classes. + */ +public class BadCycleClassTest extends ValidationTestBase { + + public BadCycleClassTest() throws Exception { + super(BadCycleClass.class); + } + + @Test + public void test() throws Exception { + assertLine("childinit", ICounter.FULLY_COVERED); + assertLine("childsomeMethod", ICounter.FULLY_COVERED); + assertLine("childclinit", ICounter.FULLY_COVERED); + + // The cycle causes a constructor and instance method to be called + // before the static initializer of a class: + assertLogEvents("childinit", "childsomeMethod", "childclinit", + "childinit"); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BooleanExpressionsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BooleanExpressionsTest.java new file mode 100644 index 00000000..64dee474 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BooleanExpressionsTest.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.Target02; +import org.junit.Test; + +/** + * Tests of basic Java boolean expressions. + */ +public class BooleanExpressionsTest extends ValidationTestBase { + + public BooleanExpressionsTest() { + super(Target02.class); + } + + @Test + public void testCoverageResult() { + + // 1. Boolean comparison result (one case) + assertLine("booleancmp1", ICounter.PARTLY_COVERED, 1, 1); + + // 2. Boolean comparison result (both cases) + assertLine("booleancmp2", ICounter.FULLY_COVERED, 0, 2); + + // 3. And + assertLine("andFF", ICounter.FULLY_COVERED, 1, 1); + assertLine("andFT", ICounter.FULLY_COVERED, 1, 1); + assertLine("andTF", ICounter.FULLY_COVERED, 1, 1); + assertLine("andTT", ICounter.FULLY_COVERED, 1, 1); + + // 4. Conditional And + assertLine("conditionalandFF", ICounter.PARTLY_COVERED, 3, 1); + assertLine("conditionalandFT", ICounter.PARTLY_COVERED, 3, 1); + assertLine("conditionalandTF", ICounter.FULLY_COVERED, 2, 2); + assertLine("conditionalandTT", ICounter.FULLY_COVERED, 2, 2); + + // 5. Or + assertLine("orFF", ICounter.FULLY_COVERED, 1, 1); + assertLine("orFT", ICounter.FULLY_COVERED, 1, 1); + assertLine("orTF", ICounter.FULLY_COVERED, 1, 1); + assertLine("orTT", ICounter.FULLY_COVERED, 1, 1); + + // 6. Conditional Or + assertLine("conditionalorFF", ICounter.FULLY_COVERED, 2, 2); + assertLine("conditionalorFT", ICounter.FULLY_COVERED, 2, 2); + assertLine("conditionalorTF", ICounter.PARTLY_COVERED, 3, 1); + assertLine("conditionalorTT", ICounter.PARTLY_COVERED, 3, 1); + + // 7. Exclusive Or + assertLine("xorFF", ICounter.FULLY_COVERED, 1, 1); + assertLine("xorFT", ICounter.FULLY_COVERED, 1, 1); + assertLine("xorTF", ICounter.FULLY_COVERED, 1, 1); + assertLine("xorTT", ICounter.FULLY_COVERED, 1, 1); + + // 8. Conditional Operator + assertLine("condT", ICounter.PARTLY_COVERED, 1, 1); + assertLine("condF", ICounter.PARTLY_COVERED, 1, 1); + + // 9. Not (one case) + assertLine("notT", ICounter.PARTLY_COVERED, 1, 1); + assertLine("notF", ICounter.PARTLY_COVERED, 1, 1); + + // 10. Not (both cases) + assertLine("notTF", ICounter.FULLY_COVERED, 0, 2); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java new file mode 100644 index 00000000..87d78a21 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java @@ -0,0 +1,195 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import static org.junit.Assert.assertEquals; +import static org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static org.objectweb.asm.Opcodes.ACC_SUPER; +import static org.objectweb.asm.Opcodes.ALOAD; +import static org.objectweb.asm.Opcodes.F_NEW; +import static org.objectweb.asm.Opcodes.IFEQ; +import static org.objectweb.asm.Opcodes.ILOAD; +import static org.objectweb.asm.Opcodes.INVOKESPECIAL; +import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; +import static org.objectweb.asm.Opcodes.POP; +import static org.objectweb.asm.Opcodes.RETURN; +import static org.objectweb.asm.Opcodes.V1_1; +import static org.objectweb.asm.Opcodes.V1_2; +import static org.objectweb.asm.Opcodes.V1_3; +import static org.objectweb.asm.Opcodes.V1_4; +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 static org.objectweb.asm.Opcodes.V1_8; +import static org.objectweb.asm.Opcodes.V9; + +import java.io.IOException; + +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.BytecodeVersion; +import org.jacoco.core.internal.instr.InstrSupport; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.SystemPropertiesRuntime; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Test class inserted stackmap frames for different class file versions. + */ +public class ClassFileVersionsTest { + + @Test + public void test_1_1() throws IOException { + testVersion(V1_1, false); + } + + @Test + public void test_1_2() throws IOException { + testVersion(V1_2, false); + } + + @Test + public void test_1_3() throws IOException { + testVersion(V1_3, false); + } + + @Test + public void test_1_4() throws IOException { + testVersion(V1_4, false); + } + + @Test + public void test_1_5() throws IOException { + testVersion(V1_5, false); + } + + @Test + public void test_1_6() throws IOException { + testVersion(V1_6, true); + } + + @Test + public void test_1_7() throws IOException { + testVersion(V1_7, true); + } + + @Test + public void test_1_8() throws IOException { + testVersion(V1_8, true); + } + + @Test + public void test_9() throws IOException { + testVersion(V9, true); + } + + @Test + public void test_10() throws IOException { + testVersion(BytecodeVersion.V10, true); + } + + private void testVersion(int version, boolean frames) throws IOException { + final byte[] original = createClass(version, frames); + + IRuntime runtime = new SystemPropertiesRuntime(); + Instrumenter instrumenter = new Instrumenter(runtime); + byte[] instrumented = instrumenter.instrument(original, "TestTarget"); + + assertFrames(instrumented, frames); + } + + private void assertFrames(byte[] source, final boolean expected) { + int version = BytecodeVersion.get(source); + source = BytecodeVersion.downgradeIfNeeded(version, source); + new ClassReader(source) + .accept(new ClassVisitor(InstrSupport.ASM_API_VERSION) { + + @Override + public MethodVisitor visitMethod(int access, String name, + String desc, String signature, + String[] exceptions) { + return new MethodVisitor(InstrSupport.ASM_API_VERSION) { + boolean frames = false; + + @Override + public void visitFrame(int type, int nLocal, + Object[] local, int nStack, + Object[] stack) { + frames = true; + } + + @Override + public void visitEnd() { + assertEquals(Boolean.valueOf(expected), + Boolean.valueOf(frames)); + } + }; + } + }, 0); + } + + /** + * Creates a class that requires a frame before the return statement. Also + * for this class instrumentation should insert another frame. + * + * <code><pre> + * public class Sample { + * public Sample(boolean b){ + * if(b){ + * toString(); + * } + * return; + * } + * } + * </pre></code> + */ + private byte[] createClass(int version, boolean frames) { + + ClassWriter cw = new ClassWriter(0); + MethodVisitor mv; + + cw.visit(version, ACC_PUBLIC + ACC_SUPER, "org/jacoco/test/Sample", + null, "java/lang/Object", null); + + mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Z)V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", + false); + mv.visitVarInsn(ILOAD, 1); + Label l1 = new Label(); + mv.visitJumpInsn(IFEQ, l1); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", + "()Ljava/lang/String;", false); + mv.visitInsn(POP); + mv.visitLabel(l1); + if (frames) { + mv.visitFrame(F_NEW, 2, + new Object[] { "org/jacoco/test/Sample", Opcodes.INTEGER }, + 0, new Object[] {}); + } + mv.visitInsn(RETURN); + mv.visitMaxs(1, 2); + mv.visitEnd(); + + cw.visitEnd(); + + return cw.toByteArray(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassInitializerTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassInitializerTest.java new file mode 100644 index 00000000..f87e705c --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassInitializerTest.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.Target05; +import org.junit.Test; + +/** + * Tests of static initializer in classes. + */ +public class ClassInitializerTest extends ValidationTestBase { + + public ClassInitializerTest() { + super(Target05.class); + } + + @Test + public void testCoverageResult() { + + assertLine("const1", ICounter.EMPTY); + assertLine("const2", ICounter.EMPTY); + + assertLine("const3", ICounter.FULLY_COVERED); + assertLine("const4", ICounter.FULLY_COVERED); + + assertLine("field1", ICounter.FULLY_COVERED); + assertLine("field2", ICounter.FULLY_COVERED); + assertLine("field3", ICounter.FULLY_COVERED); + assertLine("field4", ICounter.FULLY_COVERED); + + assertLine("staticblock", ICounter.FULLY_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ControlStructuresTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ControlStructuresTest.java new file mode 100644 index 00000000..37db4c14 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ControlStructuresTest.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.Target01; +import org.junit.Test; + +/** + * Tests of basic Java control structures. + */ +public class ControlStructuresTest extends ValidationTestBase { + + public ControlStructuresTest() { + super(Target01.class); + } + + @Test + public void testCoverageResult() { + + // 1. Direct unconditional execution + assertLine("unconditional", ICounter.FULLY_COVERED); + + // 2. Missed if block + assertLine("iffalse", ICounter.FULLY_COVERED, 1, 1); + assertLine("missedif", ICounter.NOT_COVERED); + assertLine("executedelse", ICounter.FULLY_COVERED); + + // 3. Executed if block + assertLine("iftrue", ICounter.FULLY_COVERED, 1, 1); + assertLine("executedif", ICounter.FULLY_COVERED); + assertLine("missedelse", ICounter.NOT_COVERED); + + // 4. Missed while block + assertLine("whilefalse", ICounter.FULLY_COVERED, 1, 1); + assertLine("missedwhile", ICounter.NOT_COVERED); + + // 5. Always true while block + assertLine("whiletrue", ICounter.FULLY_COVERED, 1, 1); + + // 6. Executed while block + assertLine("whiletruefalse", ICounter.FULLY_COVERED, 0, 2); + assertLine("executedwhile", ICounter.FULLY_COVERED); + + // 7. Executed do while block + assertLine("executeddowhile", ICounter.FULLY_COVERED); + assertLine("executeddowhilefalse", ICounter.FULLY_COVERED, 1, 1); + + // 8. Missed for block + assertLine("missedforincrementer", ICounter.PARTLY_COVERED, 1, 1); + assertLine("missedfor", ICounter.NOT_COVERED); + + // 9. Executed for block + assertLine("executedforincrementer", ICounter.FULLY_COVERED, 0, 2); + assertLine("executedfor", ICounter.FULLY_COVERED); + + // 10. Missed for each block + assertLine("missedforeachincrementer", ICounter.PARTLY_COVERED, 1, 1); + assertLine("missedforeach", ICounter.NOT_COVERED); + + // 11. Executed for each block + assertLine("executedforeachincrementer", ICounter.FULLY_COVERED, 0, 2); + assertLine("executedforeach", ICounter.FULLY_COVERED); + + // 12. Table switch with hit + assertLine("tswitch1", ICounter.FULLY_COVERED, 3, 1); + assertLine("tswitch1case1", ICounter.NOT_COVERED); + assertLine("tswitch1case2", ICounter.FULLY_COVERED); + assertLine("tswitch1case3", ICounter.NOT_COVERED); + assertLine("tswitch1default", ICounter.NOT_COVERED); + + // 13. Continued table switch with hit + assertLine("tswitch2", ICounter.FULLY_COVERED, 3, 1); + assertLine("tswitch2case1", ICounter.NOT_COVERED); + assertLine("tswitch2case2", ICounter.FULLY_COVERED); + assertLine("tswitch2case3", ICounter.FULLY_COVERED); + assertLine("tswitch2default", ICounter.FULLY_COVERED); + + // 14. Table switch without hit + assertLine("tswitch2", ICounter.FULLY_COVERED, 3, 1); + assertLine("tswitch3case1", ICounter.NOT_COVERED); + assertLine("tswitch3case2", ICounter.NOT_COVERED); + assertLine("tswitch3case3", ICounter.NOT_COVERED); + assertLine("tswitch3default", ICounter.FULLY_COVERED); + + // 15. Lookup switch with hit + assertLine("lswitch1", ICounter.FULLY_COVERED, 3, 1); + assertLine("lswitch1case1", ICounter.NOT_COVERED); + assertLine("lswitch1case2", ICounter.FULLY_COVERED); + assertLine("lswitch1case3", ICounter.NOT_COVERED); + assertLine("lswitch1default", ICounter.NOT_COVERED); + + // 16. Continued lookup switch with hit + assertLine("lswitch2", ICounter.FULLY_COVERED, 3, 1); + assertLine("lswitch2case1", ICounter.NOT_COVERED); + assertLine("lswitch2case2", ICounter.FULLY_COVERED); + assertLine("lswitch2case3", ICounter.FULLY_COVERED); + assertLine("lswitch2default", ICounter.FULLY_COVERED); + + // 17. Lookup switch without hit + assertLine("lswitch3", ICounter.FULLY_COVERED, 3, 1); + assertLine("lswitch3case1", ICounter.NOT_COVERED); + assertLine("lswitch3case2", ICounter.NOT_COVERED); + assertLine("lswitch3case3", ICounter.NOT_COVERED); + assertLine("lswitch3default", ICounter.FULLY_COVERED); + + // 18. Break statement + assertLine("executedbreak", ICounter.FULLY_COVERED); + assertLine("missedafterbreak", ICounter.NOT_COVERED); + + // 19. Continue statement + assertLine("executedcontinue", ICounter.FULLY_COVERED); + assertLine("missedaftercontinue", ICounter.NOT_COVERED); + + // 20. Conditional return statement + assertLine("conditionalreturn", ICounter.FULLY_COVERED); + assertLine("afterconditionalreturn", ICounter.NOT_COVERED); + + // 21. Implicit return + assertLine("implicitreturn", ICounter.FULLY_COVERED); + + // 22. Explicit return + assertLine("explicitreturn", ICounter.FULLY_COVERED); + assertLine("afterexplicitreturn", ICounter.EMPTY); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java new file mode 100644 index 00000000..122612ce --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.Collection; + +import org.jacoco.core.analysis.Analyzer; +import org.jacoco.core.analysis.CoverageBuilder; +import org.jacoco.core.analysis.IClassCoverage; +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.analysis.IMethodCoverage; +import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.data.SessionInfoStore; +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.analysis.CounterImpl; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.RuntimeData; +import org.jacoco.core.runtime.SystemPropertiesRuntime; +import org.jacoco.core.test.TargetLoader; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Various tests for cyclomatic complexity of methods. + */ +public class CyclomaticComplexityTest { + + public interface Target { + public void test(int arg); + } + + private RuntimeData data; + private IRuntime runtime; + private byte[] bytes; + private Target target; + + @Before + public void setup() throws Exception { + data = new RuntimeData(); + runtime = new SystemPropertiesRuntime(); + runtime.startup(data); + } + + @After + public void teardown() { + runtime.shutdown(); + } + + public static class Simple implements Target { + public void test(int arg) { + nop(); + nop(); + nop(); + } + } + + @Test + public void testSimple1() throws Exception { + instrument(Simple.class); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(1, 0), complexity); + } + + @Test + public void testSimple2() throws Exception { + instrument(Simple.class); + target.test(0); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(0, 1), complexity); + } + + public static class If implements Target { + public void test(int arg) { + if (arg == 0) { + nop(); + } + } + } + + @Test + public void testIf1() throws Exception { + instrument(If.class); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(2, 0), complexity); + } + + @Test + public void testIf2() throws Exception { + instrument(If.class); + target.test(0); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(1, 1), complexity); + } + + @Test + public void testIf3() throws Exception { + instrument(If.class); + target.test(0); + target.test(1); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(0, 2), complexity); + } + + public static class TwoIf implements Target { + public void test(int arg) { + if (arg < 0) { + nop(); + } + if (arg > 0) { + nop(); + } + } + } + + @Test + public void testTwoIf1() throws Exception { + instrument(TwoIf.class); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(3, 0), complexity); + } + + @Test + public void testTwoIf2() throws Exception { + instrument(TwoIf.class); + target.test(-1); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(2, 1), complexity); + } + + @Test + public void testTwoIf3() throws Exception { + instrument(TwoIf.class); + target.test(-1); + target.test(0); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(1, 2), complexity); + } + + @Test + public void testTwoIf4() throws Exception { + instrument(TwoIf.class); + target.test(-1); + target.test(+1); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(0, 3), complexity); + } + + public static class NestedIf implements Target { + public void test(int arg) { + if (arg >= 0) { + if (arg == 0) { + nop(); + } + nop(); + } + } + } + + @Test + public void testNestedIf1() throws Exception { + instrument(NestedIf.class); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(3, 0), complexity); + } + + @Test + public void testNestedIf2() throws Exception { + instrument(NestedIf.class); + target.test(-1); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(2, 1), complexity); + } + + @Test + public void testNestedIf3() throws Exception { + instrument(NestedIf.class); + target.test(-1); + target.test(0); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(1, 2), complexity); + } + + @Test + public void testNestedIf4() throws Exception { + instrument(NestedIf.class); + target.test(-1); + target.test(0); + target.test(+1); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(0, 3), complexity); + } + + public static class Switch implements Target { + public void test(int arg) { + switch (arg) { + case 1: + nop(); + break; + case 2: + nop(); + break; + } + } + } + + @Test + public void testSwitch1() throws Exception { + instrument(Switch.class); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(3, 0), complexity); + } + + @Test + public void testSwitch2() throws Exception { + instrument(Switch.class); + target.test(0); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(2, 1), complexity); + } + + @Test + public void testSwitch3() throws Exception { + instrument(Switch.class); + target.test(0); + target.test(1); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(1, 2), complexity); + } + + @Test + public void testSwitch4() throws Exception { + instrument(Switch.class); + target.test(0); + target.test(1); + target.test(2); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(0, 3), complexity); + } + + private void instrument(final Class<? extends Target> clazz) + throws Exception { + bytes = TargetLoader.getClassDataAsBytes(clazz); + final byte[] instrumented = new Instrumenter(runtime).instrument(bytes, + "TestTarget"); + final TargetLoader loader = new TargetLoader(); + target = (Target) loader.add(clazz, instrumented).newInstance(); + } + + private ICounter analyze() throws IOException { + final CoverageBuilder builder = new CoverageBuilder(); + final ExecutionDataStore store = new ExecutionDataStore(); + data.collect(store, new SessionInfoStore(), false); + final Analyzer analyzer = new Analyzer(store, builder); + analyzer.analyzeClass(bytes, "TestTarget"); + final Collection<IClassCoverage> classes = builder.getClasses(); + assertEquals(1, classes.size(), 0.0); + final IClassCoverage classCoverage = classes.iterator().next(); + for (final IMethodCoverage m : classCoverage.getMethods()) { + if (m.getName().equals("test")) { + return m.getComplexityCounter(); + } + } + throw new AssertionError("No test() method."); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java new file mode 100644 index 00000000..fbd9e540 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.EnumImplicitMethods; +import org.junit.Test; + +/** + * Test of an implicit methods and static initializer in enums. + */ +public class EnumImplicitMethodsTest extends ValidationTestBase { + + public EnumImplicitMethodsTest() { + super(EnumImplicitMethods.class); + } + + @Test + public void testCoverageResult() { + assertMethodCount(5); + + assertLine("classdef", ICounter.FULLY_COVERED); + assertLine("customValueOfMethod", ICounter.NOT_COVERED); + assertLine("customValuesMethod", ICounter.NOT_COVERED); + + assertLine("const", ICounter.PARTLY_COVERED); + assertLine("staticblock", ICounter.FULLY_COVERED); + assertLine("super", ICounter.FULLY_COVERED); + assertLine("constructor", ICounter.FULLY_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExceptionsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExceptionsTest.java new file mode 100644 index 00000000..c68bd374 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExceptionsTest.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.Target03; +import org.junit.Test; + +/** + * Tests of exception based control flow. + */ +public class ExceptionsTest extends ValidationTestBase { + + public ExceptionsTest() { + super(Target03.class); + } + + @Test + public void testCoverageResult() { + + // 0. Implicit NullPointerException + // Currently no coverage at all, as we don't see when a block aborts + // somewhere in the middle. + assertLine("implicitNullPointerException.before", ICounter.NOT_COVERED); + assertLine("implicitNullPointerException.exception", + ICounter.NOT_COVERED); + assertLine("implicitNullPointerException.after", ICounter.NOT_COVERED); + + // 1. Implicit Exception + assertLine("implicitException.before", ICounter.FULLY_COVERED); + assertLine("implicitException.exception", ICounter.NOT_COVERED); + assertLine("implicitException.after", ICounter.NOT_COVERED); + + // 2. Explicit Exception + // Full coverage, as we recognize throw statements as block boundaries. + assertLine("explicitException.before", ICounter.FULLY_COVERED); + assertLine("explicitException.throw", ICounter.FULLY_COVERED); + + // 3. Try/Catch Block Without Exception Thrown + assertLine("noExceptionTryCatch.beforeBlock", ICounter.FULLY_COVERED); + assertLine("noExceptionTryCatch.tryBlock", ICounter.FULLY_COVERED); + assertLine("noExceptionTryCatch.catch", + isJDKCompiler ? ICounter.NOT_COVERED : ICounter.PARTLY_COVERED); + assertLine("noExceptionTryCatch.catchBlock", ICounter.NOT_COVERED); + assertLine("noExceptionTryCatch.catchBlockEnd", + isJDKCompiler ? ICounter.FULLY_COVERED : ICounter.EMPTY); + assertLine("noExceptionTryCatch.afterBlock", ICounter.FULLY_COVERED); + + // 4. Try/Catch Block With Exception Thrown Implicitly + assertLine("implicitExceptionTryCatch.beforeBlock", + ICounter.FULLY_COVERED); + assertLine("implicitExceptionTryCatch.before", ICounter.FULLY_COVERED); + assertLine("implicitExceptionTryCatch.exception", ICounter.NOT_COVERED); + assertLine("implicitExceptionTryCatch.after", ICounter.NOT_COVERED); + assertLine("implicitExceptionTryCatch.catch", isJDKCompiler + ? ICounter.FULLY_COVERED : ICounter.PARTLY_COVERED); + assertLine("implicitExceptionTryCatch.catchBlock", + ICounter.FULLY_COVERED); + assertLine("implicitExceptionTryCatch.catchBlockEnd", + isJDKCompiler ? ICounter.NOT_COVERED : ICounter.EMPTY); + assertLine("implicitExceptionTryCatch.afterBlock", + ICounter.FULLY_COVERED); + + // 5. Try/Catch Block With Exception Thrown Implicitly After Condition + // As the try/catch block is entered at one branch of the condition + // should be marked as executed + assertLine("implicitExceptionTryCatchAfterCondition.condition", + ICounter.FULLY_COVERED, 1, 1); + assertLine("implicitExceptionTryCatchAfterCondition.exception", + ICounter.NOT_COVERED); + assertLine("implicitExceptionTryCatchAfterCondition.catchBlock", + ICounter.FULLY_COVERED); + + // 6. Try/Catch Block With Exception Thrown Explicitly + assertLine("explicitExceptionTryCatch.beforeBlock", + ICounter.FULLY_COVERED); + assertLine("explicitExceptionTryCatch.before", ICounter.FULLY_COVERED); + assertLine("explicitExceptionTryCatch.throw", ICounter.FULLY_COVERED); + assertLine("explicitExceptionTryCatch.catch", ICounter.FULLY_COVERED); + assertLine("explicitExceptionTryCatch.catchBlock", + ICounter.FULLY_COVERED); + assertLine("explicitExceptionTryCatch.catchBlockEnd", ICounter.EMPTY); + assertLine("explicitExceptionTryCatch.afterBlock", + ICounter.FULLY_COVERED); + + // 7. Finally Block Without Exception Thrown + assertLine("noExceptionFinally.beforeBlock", ICounter.FULLY_COVERED); + assertLine("noExceptionFinally.tryBlock", ICounter.FULLY_COVERED); + assertLine("noExceptionFinally.finally", + isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); + assertLine("noExceptionFinally.finallyBlock", ICounter.FULLY_COVERED); + assertLine("noExceptionFinally.finallyBlockEnd", ICounter.EMPTY); + assertLine("noExceptionFinally.afterBlock", ICounter.FULLY_COVERED); + + // 8. Finally Block With Implicit Exception + assertLine("implicitExceptionFinally.beforeBlock", + ICounter.FULLY_COVERED); + assertLine("implicitExceptionFinally.before", ICounter.FULLY_COVERED); + assertLine("implicitExceptionFinally.exception", ICounter.NOT_COVERED); + assertLine("implicitExceptionFinally.after", ICounter.NOT_COVERED); + assertLine("implicitExceptionFinally.finally", + isJDKCompiler ? ICounter.EMPTY : ICounter.NOT_COVERED); + assertLine("implicitExceptionFinally.finallyBlock", + ICounter.FULLY_COVERED); + assertLine("implicitExceptionFinally.finallyBlockEnd", ICounter.EMPTY); + assertLine("implicitExceptionFinally.afterBlock", ICounter.NOT_COVERED); + + // 9. Finally Block With Exception Thrown Explicitly + assertLine("explicitExceptionFinally.beforeBlock", + ICounter.FULLY_COVERED); + assertLine("explicitExceptionFinally.before", ICounter.FULLY_COVERED); + assertLine("explicitExceptionFinally.throw", ICounter.FULLY_COVERED); + assertLine("explicitExceptionFinally.finally", + isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); + assertLine("explicitExceptionFinally.finallyBlock", + ICounter.FULLY_COVERED); + assertLine("explicitExceptionFinally.finallyBlockEnd", + isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); + assertLine("explicitExceptionFinally.afterBlock", ICounter.EMPTY); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExplicitInitialFrameTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExplicitInitialFrameTest.java new file mode 100644 index 00000000..1c0a02f1 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExplicitInitialFrameTest.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.Target11; +import org.junit.Test; + +/** + * Test for a methods having a explicit initial frame. + */ +public class ExplicitInitialFrameTest extends ValidationTestBase { + + public ExplicitInitialFrameTest() { + super(Target11.class); + } + + @Test + public void testCoverageResult() { + + assertLine("dowhilebody", ICounter.FULLY_COVERED); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FieldInitializationInTwoConstructorsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FieldInitializationInTwoConstructorsTest.java new file mode 100644 index 00000000..6896bf6d --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FieldInitializationInTwoConstructorsTest.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.Target09; +import org.junit.Test; + +/** + * Test of field initialization in two constructors. + */ +public class FieldInitializationInTwoConstructorsTest extends + ValidationTestBase { + + public FieldInitializationInTwoConstructorsTest() { + super(Target09.class); + } + + @Test + public void testCoverageResult() { + + assertLine("field1", ICounter.PARTLY_COVERED); + assertLine("field2", ICounter.PARTLY_COVERED); + assertLine("constr1", ICounter.FULLY_COVERED); + assertLine("constr2", ICounter.NOT_COVERED); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FramesTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FramesTest.java new file mode 100644 index 00000000..9ab062b6 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FramesTest.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.BytecodeVersion; +import org.jacoco.core.internal.instr.InstrSupport; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.SystemPropertiesRuntime; +import org.jacoco.core.test.TargetLoader; +import org.jacoco.core.test.validation.targets.Target01; +import org.jacoco.core.test.validation.targets.Target02; +import org.jacoco.core.test.validation.targets.Target03; +import org.jacoco.core.test.validation.targets.Target04; +import org.jacoco.core.test.validation.targets.Target05; +import org.jacoco.core.test.validation.targets.Target06; +import org.jacoco.core.test.validation.targets.Target07; +import org.jacoco.core.test.validation.targets.Target08; +import org.jacoco.core.test.validation.targets.Target09; +import org.jacoco.core.test.validation.targets.Target10; +import org.jacoco.core.test.validation.targets.Target11; +import org.jacoco.core.test.validation.targets.Target12; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.util.TraceClassVisitor; + +/** + * Tests whether stackmap frames are correctly adjusted. + */ +public class FramesTest { + + /** + * Stack sizes calculated for instrumented classes might be sometimes bigger + * than actually needed. This is an acceptable tradeoff in favor of keeping + * track of the actual stack sizes. For test assertions we need to replace + * max stack sizes with constant value. + */ + private static class MaxStackEliminator extends ClassVisitor { + public MaxStackEliminator(ClassVisitor cv) { + super(InstrSupport.ASM_API_VERSION, cv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { + final MethodVisitor mv = super.visitMethod(access, name, desc, + signature, exceptions); + return new MethodVisitor(InstrSupport.ASM_API_VERSION, mv) { + @Override + public void visitMaxs(int maxStack, int maxLocals) { + super.visitMaxs(-1, maxLocals); + } + }; + } + } + + private void testFrames(Class<?> target) throws IOException { + testFrames(TargetLoader.getClassDataAsBytes(target)); + } + + private void testFrames(byte[] source) throws IOException { + IRuntime runtime = new SystemPropertiesRuntime(); + Instrumenter instrumenter = new Instrumenter(runtime); + source = calculateFrames(source); + byte[] actual = instrumenter.instrument(source, "TestTarget"); + byte[] expected = calculateFrames(actual); + + assertEquals(dump(expected), dump(actual)); + } + + private byte[] calculateFrames(byte[] source) { + source = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(source), + source); + + ClassReader rc = new ClassReader(source); + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + + // Adjust Version to 1.6 to enable frames: + rc.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, cw) { + + @Override + public void visit(int version, int access, String name, + String signature, String superName, String[] interfaces) { + super.visit(Opcodes.V1_6, access, name, signature, superName, + interfaces); + } + }, 0); + return cw.toByteArray(); + } + + private String dump(byte[] bytes) { + final StringWriter buffer = new StringWriter(); + final PrintWriter writer = new PrintWriter(buffer); + new ClassReader(bytes).accept( + new MaxStackEliminator(new TraceClassVisitor(writer)), + ClassReader.EXPAND_FRAMES); + return buffer.toString(); + } + + @Test + public void testTarget01() throws IOException { + testFrames(Target01.class); + } + + @Test + public void testTarget02() throws IOException { + testFrames(Target02.class); + } + + @Test + public void testTarget03() throws IOException { + testFrames(Target03.class); + } + + @Test + public void testTarget04() throws IOException { + testFrames(Target04.class); + } + + @Test + public void testTarget05() throws IOException { + testFrames(Target05.class); + } + + @Test + public void testTarget06() throws IOException { + testFrames(Target06.class); + } + + @Test + public void testTarget07() throws IOException { + testFrames(Target07.class); + } + + @Test + public void testTarget08() throws IOException { + testFrames(Target08.class); + } + + @Test + public void testTarget09() throws IOException { + testFrames(Target09.class); + } + + @Test + public void testTarget10() throws IOException { + testFrames(Target10.class); + } + + @Test + public void testTarget11() throws IOException { + testFrames(Target11.class); + } + + @Test + public void testTarget12() throws IOException { + testFrames(Target12.class); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitDefaultConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitDefaultConstructorTest.java new file mode 100644 index 00000000..09872e8d --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitDefaultConstructorTest.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.Target06; +import org.junit.Test; + +/** + * Test of a implicit default constructor. + * + * @see PrivateEmptyDefaultConstructorTest + */ +public class ImplicitDefaultConstructorTest extends ValidationTestBase { + + public ImplicitDefaultConstructorTest() { + super(Target06.class); + } + + @Test + public void testCoverageResult() { + + assertLine("classdef", ICounter.FULLY_COVERED); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitFieldInitializationTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitFieldInitializationTest.java new file mode 100644 index 00000000..769593d7 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitFieldInitializationTest.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.Target08; +import org.junit.Test; + +/** + * Test of a implicit field initialization. + */ +public class ImplicitFieldInitializationTest extends ValidationTestBase { + + public ImplicitFieldInitializationTest() { + super(Target08.class); + } + + @Test + public void testCoverageResult() { + + assertLine("classdef", ICounter.FULLY_COVERED); + assertLine("field1", ICounter.EMPTY); + assertLine("field2", ICounter.FULLY_COVERED); + assertLine("field3", ICounter.EMPTY); + assertLine("field4", ICounter.FULLY_COVERED); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/InterfaceClassInitializerTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/InterfaceClassInitializerTest.java new file mode 100644 index 00000000..5675dbb0 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/InterfaceClassInitializerTest.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.Target04; +import org.junit.Test; + +/** + * Tests of static initializer in interfaces. + */ +public class InterfaceClassInitializerTest extends ValidationTestBase { + + public InterfaceClassInitializerTest() { + super(Target04.class); + } + + @Override + protected void run(final Class<?> targetClass) throws Exception { + // Force class initialization + targetClass.getField("CONST1").get(null); + } + + @Test + public void testCoverageResult() { + + assertLine("const1", ICounter.EMPTY); + assertLine("const2", ICounter.EMPTY); + + assertLine("const3", ICounter.FULLY_COVERED); + assertLine("const4", ICounter.FULLY_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java new file mode 100644 index 00000000..1d144b7d --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.Target07; +import org.junit.Test; + +/** + * Test of a private empty default constructor. + * + * @see ImplicitDefaultConstructorTest + */ +public class PrivateEmptyDefaultConstructorTest extends ValidationTestBase { + + public PrivateEmptyDefaultConstructorTest() { + super(Target07.class); + } + + @Test + public void testCoverageResult() { + + assertLine("classdef", ICounter.EMPTY); + assertLine("super", ICounter.EMPTY); + assertLine("constructor", ICounter.EMPTY); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ProbesBeforeSuperConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ProbesBeforeSuperConstructorTest.java new file mode 100644 index 00000000..88b1ae54 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ProbesBeforeSuperConstructorTest.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.Target10; +import org.junit.Test; + +/** + * Test of probes before the super constructor call. + */ +public class ProbesBeforeSuperConstructorTest extends ValidationTestBase { + + public ProbesBeforeSuperConstructorTest() { + super(Target10.class); + } + + @Test + public void testCoverageResult() { + + assertLine("super", ICounter.PARTLY_COVERED, 3, 1); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java new file mode 100644 index 00000000..fe6d134a --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java @@ -0,0 +1,171 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.BytecodeVersion; +import org.jacoco.core.internal.instr.InstrSupport; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.RuntimeData; +import org.jacoco.core.runtime.SystemPropertiesRuntime; +import org.jacoco.core.test.TargetLoader; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class ResizeInstructionsTest { + + private final IRuntime runtime = new SystemPropertiesRuntime(); + private final Instrumenter instrumenter = new Instrumenter(runtime); + + private boolean computedCommonSuperClass = false; + + @Before + public void setup() throws Exception { + runtime.startup(new RuntimeData()); + } + + @After + public void teardown() { + runtime.shutdown(); + } + + private class Inner { + } + + /** + * Test of ASM bug + * <a href="https://gitlab.ow2.org/asm/asm/issues/317792">#317792</a>. + */ + @Test + public void should_not_loose_InnerClasses_attribute() throws Exception { + byte[] source = TargetLoader.getClassDataAsBytes(Inner.class); + final int version = BytecodeVersion.get(source); + source = BytecodeVersion.downgradeIfNeeded(version, source); + + final ClassReader cr = new ClassReader(source); + final ClassWriter cw = new ClassWriter(0); + cr.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, cw) { + @Override + public void visitEnd() { + final MethodVisitor mv = cv.visitMethod(0, "m", "()V", null, + null); + mv.visitCode(); + addCauseOfResizeInstructions(mv); + mv.visitInsn(Opcodes.NOP); + mv.visitMaxs(2, 1); + mv.visitEnd(); + super.visitEnd(); + } + }, 0); + source = cw.toByteArray(); + BytecodeVersion.set(source, version); + + final byte[] bytes = instrumenter.instrument(source, ""); + + final TargetLoader targetLoader = new TargetLoader(); + final Class<?> outer = targetLoader.add(ResizeInstructionsTest.class, + TargetLoader.getClassDataAsBytes(ResizeInstructionsTest.class)); + final Class<?> inner = targetLoader.add(Inner.class, bytes); + assertSame(outer, inner.getEnclosingClass()); + assertNotNull(inner.getEnclosingClass()); + assertSame(outer, inner.getDeclaringClass()); + assertNotNull(inner.getDeclaringClass()); + } + + /** + * Test of ASM bug + * <a href= "https://gitlab.ow2.org/asm/asm/issues/317630">#317630</a> that + * caused {@code java.lang.ClassNotFoundException}. + */ + @Test + public void should_not_require_computation_of_common_superclass() + throws Exception { + final String className = "Example"; + + final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES) { + @Override + protected String getCommonSuperClass(final String type1, + final String type2) { + computedCommonSuperClass |= className.equals(type1) + || className.equals(type2); + return "java/lang/Object"; + } + }; + cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, className, null, + "java/lang/Object", null); + final MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "m", "()V", + null, null); + mv.visitCode(); + addCauseOfResizeInstructions(mv); + addCauseOfGetCommonSuperClass(mv); + mv.visitMaxs(1, 1); + mv.visitEnd(); + cw.visitEnd(); + final byte[] original = cw.toByteArray(); + assertTrue(computedCommonSuperClass); + new TargetLoader().add(className, original); + + final byte[] instrumented = instrumenter.instrument(original, + className); + new TargetLoader().add(className, instrumented); + } + + /** + * Adds code that requires + * {@link ClassWriter#getCommonSuperClass(String, String)}. + * + * <pre> + * Object o = this; + * while (true) { + * o = (Integer) null; + * } + * </pre> + */ + private static void addCauseOfGetCommonSuperClass(final MethodVisitor mv) { + mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitVarInsn(Opcodes.ASTORE, 1); + Label label = new Label(); + mv.visitLabel(label); + mv.visitInsn(Opcodes.ACONST_NULL); + mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Integer"); + mv.visitVarInsn(Opcodes.ASTORE, 1); + mv.visitJumpInsn(Opcodes.GOTO, label); + } + + /** + * Adds code that triggers usage of + * {@link org.objectweb.asm.MethodWriter#COMPUTE_INSERTED_FRAMES} during + * instrumentation. + */ + private static void addCauseOfResizeInstructions(final MethodVisitor mv) { + mv.visitInsn(Opcodes.ICONST_0); + mv.visitInsn(Opcodes.ICONST_1); + final Label target = new Label(); + mv.visitJumpInsn(Opcodes.IFLE, target); + for (int i = 0; i < Short.MAX_VALUE; i++) { + mv.visitInsn(Opcodes.NOP); + } + mv.visitLabel(target); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/StructuredLockingTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/StructuredLockingTest.java new file mode 100644 index 00000000..823ab787 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/StructuredLockingTest.java @@ -0,0 +1,202 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.BytecodeVersion; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.SystemPropertiesRuntime; +import org.jacoco.core.test.TargetLoader; +import org.jacoco.core.test.validation.targets.Target12; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TryCatchBlockNode; +import org.objectweb.asm.tree.VarInsnNode; +import org.objectweb.asm.tree.analysis.Analyzer; +import org.objectweb.asm.tree.analysis.AnalyzerException; +import org.objectweb.asm.tree.analysis.BasicInterpreter; +import org.objectweb.asm.tree.analysis.BasicValue; +import org.objectweb.asm.tree.analysis.Frame; +import org.objectweb.asm.tree.analysis.Interpreter; + +/** + * Tests that the invariants specified in <a href= + * "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-2.html#jvms-2.11.10">chapter + * 2.11.10 of the JVM Spec</a> do also hold for instrumented classes. + * + * This is important because JIT compiler in HotSpot JVM ignores methods with + * unstructured locking, so that they executed by interpreter. Android Runtime + * also doesn't optimize such methods. + * + * TODO verification implemented here is incomplete - in particular it is unable + * to catch problem described in https://github.com/jacoco/jacoco/issues/626 + */ +public class StructuredLockingTest { + + @Test + public void testTarget12() throws Exception { + testMonitorExit(Target12.class); + } + + private void testMonitorExit(Class<?> target) throws Exception { + assertStructuredLocking(TargetLoader.getClassDataAsBytes(target)); + } + + private void assertStructuredLocking(byte[] source) throws Exception { + IRuntime runtime = new SystemPropertiesRuntime(); + Instrumenter instrumenter = new Instrumenter(runtime); + byte[] instrumented = instrumenter.instrument(source, "TestTarget"); + + final int version = BytecodeVersion.get(instrumented); + instrumented = BytecodeVersion.downgradeIfNeeded(version, instrumented); + + ClassNode cn = new ClassNode(); + new ClassReader(instrumented).accept(cn, 0); + for (MethodNode mn : cn.methods) { + assertStructuredLocking(cn.name, mn); + } + } + + private void assertStructuredLocking(String owner, MethodNode mn) + throws Exception { + Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>( + new BasicInterpreter()) { + + @Override + protected Frame<BasicValue> newFrame(int nLocals, int nStack) { + return new LockFrame(nLocals, nStack); + } + + @Override + protected Frame<BasicValue> newFrame(Frame<? extends BasicValue> src) { + return new LockFrame(src); + } + }; + + Frame<BasicValue>[] frames = analyzer.analyze(owner, mn); + + // Make sure no locks are left when method exits: + for (int i = 0; i < frames.length; i++) { + AbstractInsnNode insn = mn.instructions.get(i); + switch (insn.getOpcode()) { + case Opcodes.IRETURN: + case Opcodes.LRETURN: + case Opcodes.FRETURN: + case Opcodes.DRETURN: + case Opcodes.ARETURN: + case Opcodes.RETURN: + ((LockFrame) frames[i]).assertNoLock("Exit with lock"); + break; + case Opcodes.ATHROW: + List<TryCatchBlockNode> handlers = analyzer.getHandlers(i); + if (handlers == null || handlers.isEmpty()) { + ((LockFrame) frames[i]).assertNoLock("Exit with lock"); + } + break; + } + } + + // Only instructions protected by a catch-all handler can hold locks: + for (int i = 0; i < frames.length; i++) { + AbstractInsnNode insn = mn.instructions.get(i); + if (insn.getOpcode() > 0) { + boolean catchAll = false; + List<TryCatchBlockNode> handlers = analyzer.getHandlers(i); + if (handlers != null) { + for (TryCatchBlockNode node : handlers) { + catchAll |= node.type == null; + } + } + if (!catchAll) { + ((LockFrame) frames[i]) + .assertNoLock("No handlers for insn with lock"); + } + } + } + + } + + /** + * A Frame implementation that keeps track of the locking state. It is + * assumed that the monitor objects are stored in local variables. + */ + private static class LockFrame extends Frame<BasicValue> { + + Set<Integer> locks; + + public LockFrame(final int nLocals, final int nStack) { + super(nLocals, nStack); + locks = new HashSet<Integer>(); + } + + public LockFrame(Frame<? extends BasicValue> src) { + super(src); + } + + @Override + public Frame<BasicValue> init(Frame<? extends BasicValue> src) { + locks = new HashSet<Integer>(((LockFrame) src).locks); + return super.init(src); + } + + @Override + public void execute(AbstractInsnNode insn, + Interpreter<BasicValue> interpreter) throws AnalyzerException { + super.execute(insn, interpreter); + switch (insn.getOpcode()) { + case Opcodes.MONITORENTER: + // Lock is stored in a local variable: + enter(((VarInsnNode) insn.getPrevious()).var); + break; + case Opcodes.MONITOREXIT: + // Lock is stored in a local variable: + exit(((VarInsnNode) insn.getPrevious()).var); + break; + } + } + + void enter(int lock) { + assertTrue("multiple ENTER for lock " + lock, + locks.add(Integer.valueOf(lock))); + } + + void exit(int lock) { + assertTrue("invalid EXIT for lock " + lock, + locks.remove(Integer.valueOf(lock))); + } + + @Override + public boolean merge(Frame<? extends BasicValue> frame, + Interpreter<BasicValue> interpreter) throws AnalyzerException { + this.locks.addAll(((LockFrame) frame).locks); + return super.merge(frame, interpreter); + } + + void assertNoLock(String message) { + assertEquals(message, Collections.emptySet(), locks); + + } + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/AnnotationInitializer.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/AnnotationInitializer.java new file mode 100644 index 00000000..f7b9e0af --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/AnnotationInitializer.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.targets; + +/** + * This test target is an annotation with an initializer. + */ +public @interface AnnotationInitializer { + + Object CONST = new Object(); // $line-const$ + + int value() default 0; // $line-value$ + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/BadCycleClass.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/BadCycleClass.java new file mode 100644 index 00000000..c1826646 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/BadCycleClass.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.targets; + +public class BadCycleClass { + + public static class Base { + static final Child b = new Child(); + + static { + b.someMethod(); + } + } + + public static class Child extends Base { + + static { + Stubs.logEvent("childclinit"); // $line-childclinit$ + } + + public Child() { + Stubs.logEvent("childinit"); // $line-childinit$ + } + + void someMethod() { + Stubs.logEvent("childsomeMethod"); // $line-childsomeMethod$ + } + + } + + public static void main(String[] args) { + new Child(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java new file mode 100644 index 00000000..afbc46fd --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.targets; + +public enum EnumImplicitMethods { // $line-classdef$ + + CONST(Stubs.f() ? new Object() : new Object()); // $line-const$ + + static { + } // $line-staticblock$ + + /** + * Unlike in {@link Target07 regular classes}, even if enum has explicit + * constructor, {@code clinit} method in any case has a reference to the + * line of enum definition. + */ + EnumImplicitMethods(Object o) { // $line-super$ + } // $line-constructor$ + + /** + * This method should not be excluded from analysis unlike implicitly + * created {@link #valueOf(String)} method that refers to the line of enum + * definition in case of javac and to the first line in case of ECJ. + */ + public void valueOf() { + } // $line-customValueOfMethod$ + + /** + * This method should not be excluded from analysis unlike implicitly + * created {@link #values()} method that refers to the line of enum + * definition in case of javac and to the first line in case of ECJ. + */ + public void values(Object o) { + } // $line-customValuesMethod$ + + public static void main(String[] args) { + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target01.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target01.java new file mode 100644 index 00000000..81d00fa5 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target01.java @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.i2; +import static org.jacoco.core.test.validation.targets.Stubs.nop; +import static org.jacoco.core.test.validation.targets.Stubs.t; + +import java.util.Collections; + +/** + * This target exercises a set of common Java control structures. + */ +public class Target01 { + + public static void main(String[] args) { + + unconditionalExecution(); + missedIfBlock(); + executedIfBlock(); + missedWhileBlock(); + alwaysExecutedWhileBlock(); + executedWhileBlock(); + executedDoWhileBlock(); + missedForBlock(); + executedForBlock(); + missedForEachBlock(); + executedForEachBlock(); + tableSwitchWithHit(); + continuedTableSwitchWithHit(); + tableSwitchWithoutHit(); + lookupSwitchWithHit(); + continuedLookupSwitchWithHit(); + lookupSwitchWithoutHit(); + breakStatement(); + continueStatement(); + conditionalReturn(); + implicitReturn(); + explicitReturn(); + + } + + private static void unconditionalExecution() { + + nop(); // $line-unconditional$ + + } + + private static void missedIfBlock() { + + if (f()) { // $line-iffalse$ + nop(); // $line-missedif$ + } else { + nop(); // $line-executedelse$ + } + + } + + private static void executedIfBlock() { + + if (t()) { // $line-iftrue$ + nop(); // $line-executedif$ + } else { + nop(); // $line-missedelse$ + } + + } + + private static void missedWhileBlock() { + + while (f()) { // $line-whilefalse$ + nop(); // $line-missedwhile$ + } + + } + + private static void alwaysExecutedWhileBlock() { + + while (t()) { // $line-whiletrue$ + if (t()) { + break; + } + } + + } + + private static void executedWhileBlock() { + + int i = 0; + while (i++ < 3) { // $line-whiletruefalse$ + nop(); // $line-executedwhile$ + } + + } + + private static void executedDoWhileBlock() { + + do { + nop(); // $line-executeddowhile$ + } while (f()); // $line-executeddowhilefalse$ + + } + + private static void missedForBlock() { + + for (nop(); f(); nop()) { // $line-missedforincrementer$ + nop(); // $line-missedfor$ + } + + } + + private static void executedForBlock() { + + for (int j = 0; j < 1; j++) { // $line-executedforincrementer$ + nop(); // $line-executedfor$ + } + + } + + private static void missedForEachBlock() { + + for (Object o : Collections.emptyList()) { // $line-missedforeachincrementer$ + nop(o); // $line-missedforeach$ + } + + } + + private static void executedForEachBlock() { + + for (Object o : Collections.singleton(new Object())) { // $line-executedforeachincrementer$ + nop(o); // $line-executedforeach$ + } + + } + + private static void tableSwitchWithHit() { + + switch (i2()) { // $line-tswitch1$ + case 1: + nop(); // $line-tswitch1case1$ + break; + case 2: + nop(); // $line-tswitch1case2$ + break; + case 3: + nop(); // $line-tswitch1case3$ + break; + default: + nop(); // $line-tswitch1default$ + break; + } + + } + + private static void continuedTableSwitchWithHit() { + + switch (i2()) { // $line-tswitch2$ + case 1: + nop(); // $line-tswitch2case1$ + case 2: + nop(); // $line-tswitch2case2$ + case 3: + nop(); // $line-tswitch2case3$ + default: + nop(); // $line-tswitch2default$ + } + + } + + private static void tableSwitchWithoutHit() { + + switch (i2()) { // $line-tswitch3$ + case 3: + nop(); // $line-tswitch3case1$ + break; + case 4: + nop(); // $line-tswitch3case2$ + break; + case 5: + nop(); // $line-tswitch3case3$ + break; + default: + nop(); // $line-tswitch3default$ + break; + } + + } + + private static void lookupSwitchWithHit() { + + switch (i2()) { // $line-lswitch1$ + case -123: + nop(); // $line-lswitch1case1$ + break; + case 2: + nop(); // $line-lswitch1case2$ + break; + case 456: + nop(); // $line-lswitch1case3$ + break; + default: + nop(); // $line-lswitch1default$ + break; + } + + } + + private static void continuedLookupSwitchWithHit() { + + switch (i2()) { // $line-lswitch2$ + case -123: + nop(); // $line-lswitch2case1$ + case 2: + nop(); // $line-lswitch2case2$ + case 456: + nop(); // $line-lswitch2case3$ + default: + nop(); // $line-lswitch2default$ + } + + } + + private static void lookupSwitchWithoutHit() { + + switch (i2()) { // $line-lswitch3$ + case -123: + nop(); // $line-lswitch3case1$ + break; + case 456: + nop(); // $line-lswitch3case2$ + break; + case 789: + nop(); // $line-lswitch3case3$ + break; + default: + nop(); // $line-lswitch3default$ + break; + } + + } + + private static void breakStatement() { + + while (true) { + if (t()) { + break; // $line-executedbreak$ + } + nop(); // $line-missedafterbreak$ + } + + } + + private static void continueStatement() { + + for (int j = 0; j < 1; j++) { + if (t()) { + continue; // $line-executedcontinue$ + } + nop(); // $line-missedaftercontinue$ + } + + } + + private static void conditionalReturn() { + + if (t()) { + return; // $line-conditionalreturn$ + } + nop(); // $line-afterconditionalreturn$ + + } + + private static void implicitReturn() { + + } // $line-implicitreturn$ + + private static void explicitReturn() { + + return; // $line-explicitreturn$ + + } // $line-afterexplicitreturn$ + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target02.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target02.java new file mode 100644 index 00000000..62e22ef9 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target02.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.i1; +import static org.jacoco.core.test.validation.targets.Stubs.i2; +import static org.jacoco.core.test.validation.targets.Stubs.nop; +import static org.jacoco.core.test.validation.targets.Stubs.t; + +/** + * This target exercises boolean expressions. + */ +public class Target02 { + + public static void main(String[] args) { + + // 1. Boolean comparison result (one case) + nop(i2() > 3); // $line-booleancmp1$ + + // 2. Boolean comparison result (both cases) + for (int i = 0; i < 2; i++) { + nop(i < 1); // $line-booleancmp2$ + } + + // 3. And + if (f() & f()) { // $line-andFF$ + nop(); + } + if (f() & t()) { // $line-andFT$ + nop(); + } + if (t() & f()) { // $line-andTF$ + nop(); + } + if (t() & t()) { // $line-andTT$ + nop(); + } + + // 4. Conditional And + if (f() && f()) { // $line-conditionalandFF$ + nop(); + } + if (f() && t()) { // $line-conditionalandFT$ + nop(); + } + if (t() && f()) { // $line-conditionalandTF$ + nop(); + } + if (t() && t()) { // $line-conditionalandTT$ + nop(); + } + + // 5. Or + if (f() | f()) { // $line-orFF$ + nop(); + } + if (f() | t()) { // $line-orFT$ + nop(); + } + if (t() | f()) { // $line-orTF$ + nop(); + } + if (t() | t()) { // $line-orTT$ + nop(); + } + + // 6. Conditional Or + if (f() || f()) { // $line-conditionalorFF$ + nop(); + } + if (f() || t()) { // $line-conditionalorFT$ + nop(); + } + if (t() || f()) { // $line-conditionalorTF$ + nop(); + } + if (t() || t()) { // $line-conditionalorTT$ + nop(); + } + + // 7. Exclusive Or + if (f() ^ f()) { // $line-xorFF$ + nop(); + } + if (f() ^ t()) { // $line-xorFT$ + nop(); + } + if (t() ^ f()) { // $line-xorTF$ + nop(); + } + if (t() ^ t()) { // $line-xorTT$ + nop(); + } + + // 8. Conditional Operator + nop(t() ? i1() : i2()); // $line-condT$ + nop(f() ? i1() : i2()); // $line-condF$ + + // 9. Not (one case) + nop(!t()); // $line-notT$ + nop(!f()); // $line-notF$ + + // 10. Not (both cases) + for (boolean b : new boolean[] { true, false }) { + nop(!b); // $line-notTF$ + } + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target03.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target03.java new file mode 100644 index 00000000..b4418edd --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target03.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.ex; +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +import org.jacoco.core.test.validation.targets.Stubs.StubException; + +/** + * This target produces exception based control flow examples. + */ +public class Target03 { + + public static void main(String[] args) { + + try { + implicitNullPointerException(null); + } catch (NullPointerException e) { + } + try { + implicitException(); + } catch (StubException e) { + } + try { + explicitException(); + } catch (StubException e) { + } + noExceptionTryCatch(); + implicitExceptionTryCatch(); + implicitExceptionTryCatchAfterCondition(); + explicitExceptionTryCatch(); + noExceptionFinally(); + try { + explicitExceptionFinally(); + } catch (StubException e) { + } + try { + implicitExceptionFinally(); + } catch (StubException e) { + } + } + + private static void implicitNullPointerException(int[] a) { + nop(); // $line-implicitNullPointerException.before$ + a[0] = 0; // $line-implicitNullPointerException.exception$ + nop(); // $line-implicitNullPointerException.after$ + } + + private static void implicitException() { + nop(); // $line-implicitException.before$ + ex(); // $line-implicitException.exception$ + nop(); // $line-implicitException.after$ + } + + private static void explicitException() { + nop(); // $line-explicitException.before$ + throw new StubException(); // $line-explicitException.throw$ + } + + private static void noExceptionTryCatch() { + nop(); // $line-noExceptionTryCatch.beforeBlock$ + try { + nop(); // $line-noExceptionTryCatch.tryBlock$ + } catch (StubException e) { // $line-noExceptionTryCatch.catch$ + nop(); // $line-noExceptionTryCatch.catchBlock$ + } // $line-noExceptionTryCatch.catchBlockEnd$ + } // $line-noExceptionTryCatch.afterBlock$ + + private static void implicitExceptionTryCatch() { + nop(); // $line-implicitExceptionTryCatch.beforeBlock$ + try { + nop(); // $line-implicitExceptionTryCatch.before$ + ex(); // $line-implicitExceptionTryCatch.exception$ + nop(); // $line-implicitExceptionTryCatch.after$ + } catch (StubException e) { // $line-implicitExceptionTryCatch.catch$ + nop(); // $line-implicitExceptionTryCatch.catchBlock$ + } // $line-implicitExceptionTryCatch.catchBlockEnd$ + } // $line-implicitExceptionTryCatch.afterBlock$ + + private static void implicitExceptionTryCatchAfterCondition() { + if (f()) { // $line-implicitExceptionTryCatchAfterCondition.condition$ + return; + } + try { + ex(); // $line-implicitExceptionTryCatchAfterCondition.exception$ + } catch (StubException e) { + nop(); // $line-implicitExceptionTryCatchAfterCondition.catchBlock$ + } + } + + private static void explicitExceptionTryCatch() { + nop(); // $line-explicitExceptionTryCatch.beforeBlock$ + try { + nop(); // $line-explicitExceptionTryCatch.before$ + throw new StubException(); // $line-explicitExceptionTryCatch.throw$ + } catch (StubException e) { // $line-explicitExceptionTryCatch.catch$ + nop(); // $line-explicitExceptionTryCatch.catchBlock$ + } // $line-explicitExceptionTryCatch.catchBlockEnd$ + } // $line-explicitExceptionTryCatch.afterBlock$ + + private static void noExceptionFinally() { + nop(); // $line-noExceptionFinally.beforeBlock$ + try { + nop(); // $line-noExceptionFinally.tryBlock$ + } finally { // $line-noExceptionFinally.finally$ + nop(); // $line-noExceptionFinally.finallyBlock$ + } // $line-noExceptionFinally.finallyBlockEnd$ + } // $line-noExceptionFinally.afterBlock$ + + private static void implicitExceptionFinally() { + nop(); // $line-implicitExceptionFinally.beforeBlock$ + try { + nop(); // $line-implicitExceptionFinally.before$ + ex(); // $line-implicitExceptionFinally.exception$ + nop(); // $line-implicitExceptionFinally.after$ + } finally { // $line-implicitExceptionFinally.finally$ + nop(); // $line-implicitExceptionFinally.finallyBlock$ + } // $line-implicitExceptionFinally.finallyBlockEnd$ + } // $line-implicitExceptionFinally.afterBlock$ + + private static void explicitExceptionFinally() { + nop(); // $line-explicitExceptionFinally.beforeBlock$ + try { + nop(); // $line-explicitExceptionFinally.before$ + throw new StubException(); // $line-explicitExceptionFinally.throw$ + } finally { // $line-explicitExceptionFinally.finally$ + nop(); // $line-explicitExceptionFinally.finallyBlock$ + } // $line-explicitExceptionFinally.finallyBlockEnd$ + } // $line-explicitExceptionFinally.afterBlock$ + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target04.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target04.java new file mode 100644 index 00000000..8384744b --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target04.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.i1; + +/** + * This test target is an interface with a class initializer. + */ +public interface Target04 { + + // No code required to initialize these fields: + + static final int CONST1 = 12345; // $line-const1$ + + static final String CONST2 = "const"; // $line-const2$ + + // These fields are initialized within <clinit> + + static final int CONST3 = i1(); // $line-const3$ + + static final Object CONST4 = new Object(); // $line-const4$ + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target05.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target05.java new file mode 100644 index 00000000..ef5c3989 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target05.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.i1; + +/** + * This test target is a class with a static initializer. + */ +public class Target05 { + + // No code required to initialize these fields: + + public static final int CONST1 = 3; // $line-const1$ + + public static final String CONST2 = "Hello"; // $line-const2$ + + // These fields are initialized within <clinit> + + public static final int CONST3 = i1(); // $line-const3$ + + public static final Object CONST4 = new Object(); // $line-const4$ + + public static int field1 = 3; // $line-field1$ + + public static String field2 = "Hello"; // $line-field2$ + + public static int field3 = i1(); // $line-field3$ + + public static Object field4 = new Object(); // $line-field4$ + + static { + Stubs.nop(); // $line-staticblock$ + } + + private Target05() { + } + + public static void main(String[] args) { + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target06.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target06.java new file mode 100644 index 00000000..f6bc75e8 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target06.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +/** + * This test target is a class with a implicit default constructor. + * + * @see Target07 explicit constructor + */ +public class Target06 { // $line-classdef$ + + public static void main(String[] args) { + new Target06(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target07.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target07.java new file mode 100644 index 00000000..18c3ba52 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target07.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +/** + * This test target is a private empty default constructor. + * + * @see Target06 implicit constructor + */ +public class Target07 { // $line-classdef$ + + private Target07() { // $line-super$ + } // $line-constructor$ + + public static void main(String[] args) { + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target08.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target08.java new file mode 100644 index 00000000..1fe938aa --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target08.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +/** + * This test target has instance members with implicit initializers. + */ +public class Target08 { // $line-classdef$ + + Object field1; // $line-field1$ + + Object field2 = this; // $line-field2$ + + int field3; // $line-field3$ + + int field4 = 2000; // $line-field4$ + + public static void main(String[] args) { + new Target08(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target09.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target09.java new file mode 100644 index 00000000..a8589d1d --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target09.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +/** + * This test target has instance members with initialization in two + * constructors. + */ +public class Target09 { + + Object field1 = null; // $line-field1$ + + int field2 = 123; // $line-field2$ + + public Target09() { + } // $line-constr1$ + + public Target09(String arg) { + } // $line-constr2$ + + public static void main(String[] args) { + new Target09(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target10.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target10.java new file mode 100644 index 00000000..bb4496e9 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target10.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.t; + +import org.jacoco.core.test.validation.targets.Stubs.SuperClass; + +/** + * This test target has a constructor containing control structures before the + * superclass constructor is called. + */ +public class Target10 extends SuperClass { + + public Target10() { + super(t() || f()); // $line-super$ + } + + public static void main(String[] args) { + new Target10(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target11.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target11.java new file mode 100644 index 00000000..d393cb7f --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target11.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target needs an explicit initial frame as the first instruction + * already is a jump target. + */ +public class Target11 { + + public static void main(String[] args) { + + do { + nop(); // $line-dowhilebody$ + } while (f()); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target12.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target12.java new file mode 100644 index 00000000..5ee2e324 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target12.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This target uses synchronized blocks which compile to try/catch statements. + */ +public class Target12 { + + static void simple() { + Object lock1 = new Object(); + synchronized (lock1) { + nop(); + } + } + + static void nested() { + Object lock1 = new Object(); + synchronized (lock1) { + nop(); + Object lock2 = new Object(); + synchronized (lock2) { + nop(); + } + nop(); + } + + } + + public static void main(String[] args) { + simple(); + nested(); + } + +} diff --git a/org.jacoco.core.test.validation.java7/.classpath b/org.jacoco.core.test.validation.java7/.classpath new file mode 100644 index 00000000..c60c5daa --- /dev/null +++ b/org.jacoco.core.test.validation.java7/.classpath @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="src" output="target/classes" path="src"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="output" path="target/classes"/> +</classpath> diff --git a/org.jacoco.core.test.validation.java7/.project b/org.jacoco.core.test.validation.java7/.project new file mode 100644 index 00000000..5ce971fb --- /dev/null +++ b/org.jacoco.core.test.validation.java7/.project @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.jacoco.core.test.validation.java7</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.m2e.core.maven2Builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.m2e.core.maven2Nature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> + <linkedResources> + <link> + <name>.settings</name> + <type>2</type> + <locationURI>PARENT-1-PROJECT_LOC/org.jacoco.core.test/.settings</locationURI> + </link> + </linkedResources> +</projectDescription> diff --git a/org.jacoco.core.test.validation.java7/pom.xml b/org.jacoco.core.test.validation.java7/pom.xml new file mode 100644 index 00000000..d2136541 --- /dev/null +++ b/org.jacoco.core.test.validation.java7/pom.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2009, 2018 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: + Evgeny Mandrikov - initial API and implementation +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.jacoco</groupId> + <artifactId>org.jacoco.core.test.validation</artifactId> + <version>0.8.2-SNAPSHOT</version> + <relativePath>../org.jacoco.core.test.validation</relativePath> + </parent> + + <artifactId>org.jacoco.core.test.validation.java7</artifactId> + + <name>JaCoCo :: Test :: Core :: Validation Java 7</name> + + <properties> + <bytecode.version>7</bytecode.version> + </properties> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.core.test</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project> diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/StringSwitchTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/StringSwitchTest.java new file mode 100644 index 00000000..15181359 --- /dev/null +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/StringSwitchTest.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.filter.targets.StringSwitch; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.junit.Test; + +/** + * Test of filtering of a bytecode that is generated for a String in switch + * statement. + */ +public class StringSwitchTest extends ValidationTestBase { + + public StringSwitchTest() { + super(StringSwitch.class); + } + + /** + * {@link StringSwitch#covered(String)} + */ + @Test + public void covered() { + if (isJDKCompiler) { + assertLine("covered.switch", ICounter.FULLY_COVERED, 0, 4); + } else { + assertLine("covered.switch", ICounter.PARTLY_COVERED, 2, 7); + } + assertLine("covered.case1", ICounter.FULLY_COVERED, 0, 0); + assertLine("covered.case2", ICounter.FULLY_COVERED, 0, 0); + assertLine("covered.case3", ICounter.FULLY_COVERED, 0, 0); + assertLine("covered.default", ICounter.FULLY_COVERED, 0, 0); + } + + /** + * {@link StringSwitch#notCovered(String)} + */ + @Test + public void notCovered() { + assertLine("notCovered", ICounter.NOT_COVERED, isJDKCompiler ? 4 : 9, + 0); + } + + /** + * {@link StringSwitch#handwritten(String)} + */ + @Test + public void handwritten() { + assertLine("handwritten.firstSwitch", ICounter.FULLY_COVERED, 2, 1); + assertLine("handwritten.ignored", ICounter.FULLY_COVERED); + assertLine("handwritten.secondSwitch", ICounter.FULLY_COVERED, 3, 1); + assertLine("handwritten.case1", ICounter.FULLY_COVERED); + assertLine("handwritten.case2", ICounter.NOT_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/TryWithResourcesTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/TryWithResourcesTest.java new file mode 100644 index 00000000..fe441164 --- /dev/null +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/TryWithResourcesTest.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.filter.targets.TryWithResources; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.junit.Test; + +/** + * Test of filtering of a bytecode that is generated for a try-with-resources + * statement. + */ +public class TryWithResourcesTest extends ValidationTestBase { + + public TryWithResourcesTest() { + super(TryWithResources.class); + } + + /** + * {@link TryWithResources#test()} + */ + @Test + public void test() { + assertLine("test.before", ICounter.FULLY_COVERED); + // without filter next line covered partly: + assertLine("test.try", ICounter.FULLY_COVERED); + assertLine("test.open1", ICounter.FULLY_COVERED); + assertLine("test.open2", ICounter.FULLY_COVERED); + assertLine("test.open3", ICounter.FULLY_COVERED); + assertLine("test.body", ICounter.FULLY_COVERED); + // without filter next line has branches: + assertLine("test.close", ICounter.EMPTY); + assertLine("test.catch", ICounter.NOT_COVERED); + assertLine("test.finally", ICounter.FULLY_COVERED); + } + + /** + * {@link TryWithResources#test2()} + */ + @Test + public void test2() { + assertLine("test2.before", ICounter.FULLY_COVERED); + // without filter next line covered partly: + assertLine("test2.try", ICounter.FULLY_COVERED); + assertLine("test2.open1", ICounter.FULLY_COVERED); + assertLine("test2.open2", ICounter.FULLY_COVERED); + assertLine("test2.open3", ICounter.FULLY_COVERED); + assertLine("test2.body", ICounter.FULLY_COVERED); + // without filter next line has branches: + assertLine("test2.close", ICounter.EMPTY); + assertLine("test2.catch", ICounter.NOT_COVERED); + assertLine("test2.finally", ICounter.FULLY_COVERED); + assertLine("test2.after", ICounter.FULLY_COVERED); + } + + /** + * {@link TryWithResources#returnInBody()} + */ + @Test + public void returnInBody() { + // without filter next line covered partly: + assertLine("returnInBody.try", ICounter.FULLY_COVERED); + assertLine("returnInBody.open", ICounter.FULLY_COVERED); + + // without filter next line has branches: + if (isJDKCompiler) { + // https://bugs.openjdk.java.net/browse/JDK-8134759 + // javac 7 and 8 up to 8u92 are affected + if (JAVA_VERSION.isBefore("1.8.0_92")) { + assertLine("returnInBody.close", ICounter.FULLY_COVERED, 0, 0); + } else { + assertLine("returnInBody.close", ICounter.EMPTY); + } + } else { + assertLine("returnInBody.close", ICounter.EMPTY); + } + + assertLine("returnInBody.return", ICounter.FULLY_COVERED); + } + + /** + * {@link TryWithResources#nested()} + */ + @Test + public void nested() { + // without filter next line covered partly: + assertLine("nested.try1", ICounter.FULLY_COVERED); + assertLine("nested.open1", ICounter.FULLY_COVERED); + assertLine("nested.catch1", ICounter.NOT_COVERED); + + // without filter next line covered partly: + assertLine("nested.try2", ICounter.FULLY_COVERED); + assertLine("nested.body", ICounter.FULLY_COVERED); + assertLine("nested.catch2", ICounter.NOT_COVERED); + assertLine("nested.finally2", ICounter.FULLY_COVERED); + + // next lines not covered on exceptional path: + assertLine("nested.try3", ICounter.FULLY_COVERED, 0, 0); + assertLine("nested.open3", ICounter.FULLY_COVERED, 0, 0); + assertLine("nested.body3", ICounter.FULLY_COVERED, 0, 0); + assertLine("nested.catch3", ICounter.NOT_COVERED); + assertLine("nested.finally3", ICounter.FULLY_COVERED, 0, 0); + + // without filter next lines have branches: + assertLine("nested.close3", ICounter.EMPTY); + assertLine("nested.close2", ICounter.EMPTY); + assertLine("nested.close1", ICounter.EMPTY); + } + + /** + * {@link TryWithResources#returnInCatch()} + */ + @Test + public void returnInCatch() { + // without filter next line covered partly: + assertLine("returnInCatch.try1", ICounter.FULLY_COVERED); + assertLine("returnInCatch.open", ICounter.FULLY_COVERED); + assertLine("returnInCatch.finally1", ICounter.PARTLY_COVERED, 1, 1); + // without filter next line has branches: + assertLine("returnInCatch.close", ICounter.EMPTY); + + assertLine("returnInCatch.try2", ICounter.EMPTY); + assertLine("returnInCatch.finally2", ICounter.PARTLY_COVERED, 1, 1); + } + + /* + * Corner cases + */ + + /** + * {@link TryWithResources#handwritten()} + */ + @Test + public void handwritten() { + if (isJDKCompiler) { + assertLine("handwritten", /* partly when ECJ: */ICounter.EMPTY); + } + } + + /** + * {@link TryWithResources#empty()} + */ + @Test + public void empty() { + assertLine("empty.try", ICounter.FULLY_COVERED, 0, 0); + assertLine("empty.open", ICounter.FULLY_COVERED); + // empty when EJC: + if (isJDKCompiler) { + if (JAVA_VERSION.isBefore("9")) { + // branches with javac 7 and 8 + assertLine("empty.close", ICounter.PARTLY_COVERED); + } else { + assertLine("empty.close", ICounter.FULLY_COVERED, 0, 0); + } + } + } + + /** + * {@link TryWithResources#throwInBody()} + */ + @Test + public void throwInBody() { + // not filtered + assertLine("throwInBody.try", ICounter.NOT_COVERED); + assertLine("throwInBody.close", ICounter.NOT_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/StringSwitch.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/StringSwitch.java new file mode 100644 index 00000000..c8b9a232 --- /dev/null +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/StringSwitch.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target is a switch statement with a String. + */ +public class StringSwitch { + + private static void covered(Object s) { + switch (String.valueOf(s)) { // $line-covered.switch$ + case "a": + nop("case a"); // $line-covered.case1$ + break; + case "b": + nop("case b"); // $line-covered.case2$ + break; + case "\0a": + nop("case \0a"); // $line-covered.case3$ + break; + default: + nop("case default"); // $line-covered.default$ + break; + } + } + + private static void notCovered(Object s) { + switch (String.valueOf(s)) { // $line-notCovered$ + case "a": + nop("case a"); + break; + case "b": + nop("case b"); + break; + case "\0a": + nop("case \0a"); + break; + default: + nop("default"); + break; + } + } + + private static void handwritten(String s) { + int c = -1; + switch (s.hashCode()) { // $line-handwritten.firstSwitch$ + case 97: + if ("a".equals(s)) { // $line-handwritten.ignored$ + c = 0; + } else if ("\0a".equals(s)) { + c = 1; + } + break; + case 98: + if ("b".equals(s)) { + c = 2; + } + break; + } + switch (c) { // $line-handwritten.secondSwitch$ + case 0: + nop("case a"); // $line-handwritten.case1$ + break; + case 1: + nop("case \0a"); // $line-handwritten.case2$ + break; + case 2: + nop("case b"); + break; + default: + nop("default"); + break; + } + } + + public static void main(String[] args) { + covered(""); + covered("a"); + covered("b"); + covered("\0a"); + + handwritten("a"); + } + +} diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/TryWithResources.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/TryWithResources.java new file mode 100644 index 00000000..3d3a30db --- /dev/null +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/TryWithResources.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.filter.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +import java.io.Closeable; +import java.io.IOException; + +/** + * This test target is a try-with-resources statement. + */ +public class TryWithResources { + + private static class Resource implements Closeable { + @Override + public void close() { + } + } + + /** + * Closing performed using {@link org.objectweb.asm.Opcodes#INVOKEVIRTUAL} + * or {@link org.objectweb.asm.Opcodes#INVOKEINTERFACE} depending on a class + * of resource. + */ + private static Object test() throws Exception { + nop(); // $line-test.before$ + try ( // $line-test.try$ + Resource r1 = new Resource(); // $line-test.open1$ + Closeable r2 = new Resource(); // $line-test.open2$ + AutoCloseable r3 = new Resource() // $line-test.open3$ + ) { + return read(r1, r2, r3); // $line-test.body$ + } // $line-test.close$ + catch (Exception e) { + nop(); // $line-test.catch$ + throw e; + } finally { + nop(); // $line-test.finally$ + } + } + + private static void test2() throws Exception { + nop(); // $line-test2.before$ + try ( // $line-test2.try$ + Resource r1 = new Resource(); // $line-test2.open1$ + Closeable r2 = new Resource(); // $line-test2.open2$ + AutoCloseable r3 = new Resource() // $line-test2.open3$ + ) { + read(r1, r2, r3); // $line-test2.body$ + } // $line-test2.close$ + catch (Exception e) { + nop(); // $line-test2.catch$ + } finally { + nop(); // $line-test2.finally$ + } + nop(); // $line-test2.after$ + } + + private static Object returnInBody() throws IOException { + try ( // $line-returnInBody.try$ + Closeable r = new Resource() // $line-returnInBody.open$ + ) { + return read(r); // $line-returnInBody.return$ + } // $line-returnInBody.close$ + } + + private static void nested() { + try ( // $line-nested.try1$ + Resource r1 = new Resource() // $line-nested.open1$ + ) { + + try ( // $line-nested.try2$ + Resource r2 = new Resource() // $line-nested.open2$ + ) { + nop(r1.toString() + r2.toString()); // $line-nested.body$ + } // $line-nested.close2$ + catch (Exception e) { + nop(); // $line-nested.catch2$ + } finally { + nop(); // $line-nested.finally2$ + } + + } // $line-nested.close1$ + catch (Exception e) { + nop(); // $line-nested.catch1$ + } finally { + + try ( // $line-nested.try3$ + Resource r2 = new Resource() // $line-nested.open3$ + ) { + nop(r2); // $line-nested.body3$ + } // $line-nested.close3$ + catch (Exception e) { + nop(); // $line-nested.catch3$ + } finally { + nop(); // $line-nested.finally3$ + } + + } + } + + /** + * In this case bytecode will contain 3 copies of <code>finally</code> + * block, each containing 2 branches, resulting in 6 branches in total. One + * could think that this is artifact of try-with-resources, but the same + * happens without it. + */ + private static Object returnInCatch() { + try ( // $line-returnInCatch.try1$ + Resource r = new Resource() // $line-returnInCatch.open$ + ) { + read(r); + } // $line-returnInCatch.close$ + catch (Exception e) { + return null; + } finally { + nop(!f()); // $line-returnInCatch.finally1$ + } + + try { // $line-returnInCatch.try2$ + read(new Resource()); + } catch (Exception e) { + return null; + } finally { + nop(!f()); // $line-returnInCatch.finally2$ + } + + return null; + } + + private static Object read(Object r1, Object r2, Object r3) { + return r1.toString() + r2.toString() + r3.toString(); + } + + private static Object read(Object r1) { + return r1.toString(); + } + + public static void main(String[] args) throws Exception { + test(); + test2(); + returnInBody(); + nested(); + + returnInCatch(); + + empty(); + handwritten(); + } + + /* + * Corner cases + */ + + private static void empty() throws Exception { + try ( // $line-empty.try$ + Closeable r = new Resource() // $line-empty.open$ + ) { + } // $line-empty.close$ + } + + private static void handwritten() throws IOException { + Closeable r = new Resource(); + Throwable primaryExc = null; + try { + nop(r); + } catch (Throwable t) { + primaryExc = t; + throw t; + } finally { + if (r != null) { // $line-handwritten$ + if (primaryExc != null) { + try { + r.close(); + } catch (Throwable suppressedExc) { + primaryExc.addSuppressed(suppressedExc); + } + } else { + r.close(); + } + } + } + } + + private static void throwInBody() throws IOException { + try ( // $line-throwInBody.try$ + Closeable r = new Resource()) { + nop(r); + throw new RuntimeException(); + } // $line-throwInBody.close$ + } + +} diff --git a/org.jacoco.core.test.validation.java8/.classpath b/org.jacoco.core.test.validation.java8/.classpath new file mode 100644 index 00000000..9f0c38ba --- /dev/null +++ b/org.jacoco.core.test.validation.java8/.classpath @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="src" output="target/classes" path="src"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="output" path="target/classes"/> +</classpath> diff --git a/org.jacoco.core.test.validation.java8/.project b/org.jacoco.core.test.validation.java8/.project new file mode 100644 index 00000000..deab0f76 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/.project @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.jacoco.core.test.validation.java8</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.m2e.core.maven2Builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.m2e.core.maven2Nature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> + <linkedResources> + <link> + <name>.settings</name> + <type>2</type> + <locationURI>PARENT-1-PROJECT_LOC/org.jacoco.core.test/.settings</locationURI> + </link> + </linkedResources> +</projectDescription> diff --git a/org.jacoco.core.test.validation.java8/pom.xml b/org.jacoco.core.test.validation.java8/pom.xml new file mode 100644 index 00000000..b682ab88 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/pom.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2009, 2018 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: + Evgeny Mandrikov - initial API and implementation +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.jacoco</groupId> + <artifactId>org.jacoco.core.test.validation</artifactId> + <version>0.8.2-SNAPSHOT</version> + <relativePath>../org.jacoco.core.test.validation</relativePath> + </parent> + + <artifactId>org.jacoco.core.test.validation.java8</artifactId> + + <name>JaCoCo :: Test :: Core :: Validation Java 8</name> + + <properties> + <bytecode.version>8</bytecode.version> + </properties> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.core.test</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project> diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java new file mode 100644 index 00000000..64e8fafa --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.AnnotationOnLocalVariableTarget; +import org.junit.Test; + +/** + * Test of ASM bug + * <a href="https://gitlab.ow2.org/asm/asm/issues/317815">#317815</a> + */ +public class AnnotationOnLocalVariableTest extends ValidationTestBase { + + public AnnotationOnLocalVariableTest() { + super(AnnotationOnLocalVariableTarget.class); + } + + @Test + public void testCoverageResult() { + + assertLine("var", ICounter.FULLY_COVERED); + + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BadCycleInterfaceTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BadCycleInterfaceTest.java new file mode 100644 index 00000000..a8ab6727 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BadCycleInterfaceTest.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.BadCycleInterface; +import org.junit.Test; + +/** + * Test of "bad cycles" with interfaces. + */ +public class BadCycleInterfaceTest extends ValidationTestBase { + + public BadCycleInterfaceTest() throws Exception { + super(BadCycleInterface.class); + } + + @Test + public void test() throws Exception { + if (JAVA_VERSION.isBefore("1.8.0_152")) { + // Incorrect interpetation of JVMS 5.5 in JDK 8 causes a default + // method to be called before the static initializer of an interface + // (see JDK-8098557 and JDK-8164302): + assertLine("baseclinit", ICounter.FULLY_COVERED); + assertLine("childdefault", ICounter.FULLY_COVERED); + + assertLogEvents("baseclinit", "childdefaultmethod", "childclinit", + "childstaticmethod"); + } else { + // This shouldn't happen with JDK 9 (see also JDK-8043275) + // and starting with JDK 8u152 (see JDK-8167607): + assertLine("baseclinit", ICounter.EMPTY); + assertLine("childdefault", ICounter.NOT_COVERED); + assertLogEvents("childclinit", "childstaticmethod"); + } + assertLine("childclinit", ICounter.FULLY_COVERED); + assertLine("childstatic", ICounter.FULLY_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java new file mode 100644 index 00000000..dc20f0af --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import static org.junit.Assert.assertEquals; + +import java.lang.invoke.CallSite; +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.InvocationTargetException; + +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.RuntimeData; +import org.jacoco.core.runtime.SystemPropertiesRuntime; +import org.jacoco.core.test.TargetLoader; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Test of ASM bug + * <a href="https://gitlab.ow2.org/asm/asm/issues/317748">#317748</a> that + * caused + * {@code java.lang.ClassFormatError: Short length on BootstrapMethods in class file} + * during instrumentation. + */ +public class BootstrapMethodReferenceTest { + + private final IRuntime runtime = new SystemPropertiesRuntime(); + private final Instrumenter instrumenter = new Instrumenter(runtime); + + @Before + public void setup() throws Exception { + runtime.startup(new RuntimeData()); + } + + @After + public void teardown() { + runtime.shutdown(); + } + + @Test + public void test() throws Exception { + final String className = "Example"; + + final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + cw.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, className, null, + "java/lang/Object", null); + + final MethodVisitor mv = cw.visitMethod( + Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "run", "()I", null, + null); + mv.visitCode(); + addCauseOfResizeInstructions(mv); + final MethodType methodType = MethodType.methodType(CallSite.class, + MethodHandles.Lookup.class, String.class, MethodType.class); + final Handle handle = new Handle(Opcodes.H_INVOKESTATIC, + this.getClass().getCanonicalName().replace('.', '/'), + "bootstrap", methodType.toMethodDescriptorString(), false); + mv.visitInvokeDynamicInsn("invoke", "()I", handle); + mv.visitInsn(Opcodes.IRETURN); + mv.visitMaxs(1, 0); + mv.visitEnd(); + + cw.visitEnd(); + + final byte[] original = cw.toByteArray(); + assertEquals(42, run(className, original)); + + final byte[] instrumented = instrumenter.instrument(original, + className); + assertEquals(42, run(className, instrumented)); + } + + private static int run(final String className, final byte[] bytes) + throws ClassNotFoundException, NoSuchMethodException, + InvocationTargetException, IllegalAccessException { + return (Integer) new TargetLoader().add(className, bytes) + .getMethod("run").invoke(null); + } + + /** + * Adds code that triggers usage of + * {@link org.objectweb.asm.MethodWriter#COMPUTE_INSERTED_FRAMES} during + * instrumentation. + */ + private static void addCauseOfResizeInstructions(final MethodVisitor mv) { + mv.visitInsn(Opcodes.ICONST_0); + mv.visitInsn(Opcodes.ICONST_1); + final Label target = new Label(); + mv.visitJumpInsn(Opcodes.IFLE, target); + for (int i = 0; i < Short.MAX_VALUE; i++) { + mv.visitInsn(Opcodes.NOP); + } + mv.visitLabel(target); + } + + @SuppressWarnings("unused") + public static CallSite bootstrap(final MethodHandles.Lookup caller, + final String name, final MethodType type) throws Exception { + return new ConstantCallSite(caller.findStatic(BootstrapMethodReferenceTest.class, + "callTarget", MethodType.methodType(int.class))); + } + + @SuppressWarnings("unused") + public static int callTarget() { + return 42; + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java new file mode 100644 index 00000000..4611d782 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.InterfaceDefaultMethodsTarget; +import org.junit.Test; + +/** + * Tests of static initializer and default methods in interfaces. + */ +public class InterfaceDefaultMethodsTest extends ValidationTestBase { + + public InterfaceDefaultMethodsTest() { + super(InterfaceDefaultMethodsTarget.class); + } + + @Test + public void testCoverageResult() { + assertLine("clinit", ICounter.FULLY_COVERED); + assertLine("m1", ICounter.FULLY_COVERED); + assertLine("m2", ICounter.NOT_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java new file mode 100644 index 00000000..bbb7f0ed --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.InterfaceOnlyDefaultMethodsTarget; +import org.junit.Test; + +/** + * Tests of default methods in interfaces. + */ +public class InterfaceOnlyDefaultMethodsTest extends ValidationTestBase { + + public InterfaceOnlyDefaultMethodsTest() { + super(InterfaceOnlyDefaultMethodsTarget.class); + } + + @Test + public void testCoverageResult() { + assertLine("m1", ICounter.FULLY_COVERED); + assertLine("m2", ICounter.NOT_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaExpressionsTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaExpressionsTest.java new file mode 100644 index 00000000..f1344991 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaExpressionsTest.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.LambdaExpressionsTarget; +import org.junit.Test; + +/** + * Tests for different lambda expressions. + */ +public class LambdaExpressionsTest extends ValidationTestBase { + + public LambdaExpressionsTest() { + super(LambdaExpressionsTarget.class); + } + + @Test + public void testCoverageResult() { + + // Coverage of lambda bodies + assertLine("executedlambdabody", ICounter.FULLY_COVERED); + assertLine("notexecutedlambdabody", ICounter.NOT_COVERED); + + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaInInterfaceTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaInInterfaceTest.java new file mode 100644 index 00000000..759a78fc --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaInInterfaceTest.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.LambdaInInterfaceTarget; +import org.junit.Test; + +/** + * Tests a constant with a lambda value in an interface. + */ +public class LambdaInInterfaceTest extends ValidationTestBase { + + public LambdaInInterfaceTest() { + super(LambdaInInterfaceTarget.class); + } + + @Override + protected void run(final Class<?> targetClass) throws Exception { + ((Runnable) targetClass.getField("RUN").get(null)).run(); + } + + @Test + public void testCoverageResult() { + + // Coverage of lambda body + assertLine("lambdabody", ICounter.FULLY_COVERED); + + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java new file mode 100644 index 00000000..3417c098 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.targets; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This test target contains annotation on local variable. + */ +public class AnnotationOnLocalVariableTarget { + + @Documented + @Retention(RetentionPolicy.CLASS) + @Target(ElementType.TYPE_USE) + @interface NonNull { + } + + private static Object legacy() { + return new Object(); + } + + public static void main(String[] args) { + @NonNull + Object o = legacy(); // $line-var$ + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/BadCycleInterface.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/BadCycleInterface.java new file mode 100644 index 00000000..d7e7a746 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/BadCycleInterface.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.targets; + +public class BadCycleInterface { + + public interface Base { + static final Object BASE_CONST = new Child() { + { + Stubs.logEvent("baseclinit"); // $line-baseclinit$ + } + }.childDefaultMethod(); + + default void baseDefaultMethod() { + } + } + + public interface Child extends Base { + static final Object CHILD_CONST = new Object() { + { + Stubs.logEvent("childclinit"); // $line-childclinit$ + } + }; + + default Object childDefaultMethod() { + Stubs.logEvent("childdefaultmethod"); // $line-childdefault$ + return null; + } + + static void childStaticMethod() { + Stubs.logEvent("childstaticmethod"); // $line-childstatic$ + } + } + + public static void main(String[] args) { + Child.childStaticMethod(); + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java new file mode 100644 index 00000000..2e952995 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.i1; + +/** + * This test target is an interface with a class initializer and default methods. + */ +public interface InterfaceDefaultMethodsTarget { + + public static final int CONST = i1(); // $line-clinit$ + + default void m1() { + return; // $line-m1$ + } + + default void m2() { + return; // $line-m2$ + } + + public class Impl implements InterfaceDefaultMethodsTarget { + + public Impl() { + m1(); + } + } + + public static void main(String[] args) { + new Impl(); + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java new file mode 100644 index 00000000..5fa48fb8 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.targets; + +/** + * This test target is an interface with only default methods. + */ +public interface InterfaceOnlyDefaultMethodsTarget { + + // no <clinit>, only default methods: + + default void m1() { + return; // $line-m1$ + } + + default void m2() { + return; // $line-m2$ + } + + public class Impl implements InterfaceOnlyDefaultMethodsTarget { + + public Impl() { + m1(); + } + } + + public static void main(String[] args) { + new Impl(); + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaExpressionsTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaExpressionsTarget.java new file mode 100644 index 00000000..bcb65b60 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaExpressionsTarget.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.exec; +import static org.jacoco.core.test.validation.targets.Stubs.noexec; +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target contains different lambda expressions. + */ +public class LambdaExpressionsTarget { + + public static void main(String[] args) { + + exec(() -> { + nop(); // $line-executedlambdabody$ + }); + + noexec(() -> { + nop(); // $line-notexecutedlambdabody$ + }); + + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaInInterfaceTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaInInterfaceTarget.java new file mode 100644 index 00000000..23edc6dd --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaInInterfaceTarget.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target builds a constant with a lambda value in an interface. + */ +public interface LambdaInInterfaceTarget { + + public static final Runnable RUN = () -> { + nop(); // $line-lambdabody$ + }; + +} diff --git a/org.jacoco.core.test.validation/.project b/org.jacoco.core.test.validation/.project new file mode 100644 index 00000000..576c6146 --- /dev/null +++ b/org.jacoco.core.test.validation/.project @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.jacoco.core.test.validation</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.m2e.core.maven2Builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.m2e.core.maven2Nature</nature> + </natures> + <linkedResources> + <link> + <name>.settings</name> + <type>2</type> + <locationURI>PARENT-1-PROJECT_LOC/org.jacoco.core.test/.settings</locationURI> + </link> + </linkedResources> +</projectDescription> diff --git a/org.jacoco.core.test.validation/pom.xml b/org.jacoco.core.test.validation/pom.xml new file mode 100644 index 00000000..691de9ac --- /dev/null +++ b/org.jacoco.core.test.validation/pom.xml @@ -0,0 +1,176 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2009, 2018 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: + Evgeny Mandrikov - initial API and implementation +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.jacoco</groupId> + <artifactId>org.jacoco.tests</artifactId> + <version>0.8.2-SNAPSHOT</version> + <relativePath>../org.jacoco.tests</relativePath> + </parent> + + <artifactId>org.jacoco.core.test.validation</artifactId> + <packaging>pom</packaging> + + <name>JaCoCo :: Test :: Core :: Validation</name> + + <modules> + <module>../org.jacoco.core.test.validation.java5</module> + </modules> + + <properties> + <jacoco.skip>true</jacoco.skip> + </properties> + + <profiles> + <profile> + <id>java5-bytecode</id> + <activation> + <property> + <name>bytecode.version</name> + <value>5</value> + </property> + </activation> + </profile> + + <profile> + <id>jdk5</id> + <activation> + <property> + <name>jdk.version</name> + <value>5</value> + </property> + </activation> + </profile> + + <profile> + <id>java6-bytecode</id> + <activation> + <property> + <name>bytecode.version</name> + <value>6</value> + </property> + </activation> + </profile> + + <profile> + <id>jdk6</id> + <activation> + <property> + <name>jdk.version</name> + <value>6</value> + </property> + </activation> + </profile> + + <profile> + <id>java7-bytecode</id> + <activation> + <property> + <name>bytecode.version</name> + <value>7</value> + </property> + </activation> + <modules> + <module>../org.jacoco.core.test.validation.java7</module> + </modules> + </profile> + + <profile> + <id>jdk7</id> + <activation> + <property> + <name>jdk.version</name> + <value>7</value> + </property> + </activation> + <modules> + <module>../org.jacoco.core.test.validation.java7</module> + </modules> + </profile> + + <profile> + <id>java8-bytecode</id> + <activation> + <activeByDefault>true</activeByDefault> + <property> + <name>bytecode.version</name> + <value>8</value> + </property> + </activation> + <modules> + <module>../org.jacoco.core.test.validation.java7</module> + <module>../org.jacoco.core.test.validation.java8</module> + </modules> + </profile> + + <profile> + <id>java10-bytecode</id> + <activation> + <property> + <name>bytecode.version</name> + <value>10</value> + </property> + </activation> + <properties> + <!-- see respective profile in org.jacoco.build about this override --> + <maven.compiler.source>10</maven.compiler.source> + <maven.compiler.target>10</maven.compiler.target> + </properties> + <modules> + <module>../org.jacoco.core.test.validation.java7</module> + <module>../org.jacoco.core.test.validation.java8</module> + </modules> + </profile> + + <profile> + <id>java11-bytecode</id> + <activation> + <property> + <name>bytecode.version</name> + <value>11</value> + </property> + </activation> + <properties> + <!-- see respective profile in org.jacoco.build about this override --> + <maven.compiler.source>11</maven.compiler.source> + <maven.compiler.target>11</maven.compiler.target> + </properties> + <modules> + <module>../org.jacoco.core.test.validation.java7</module> + <module>../org.jacoco.core.test.validation.java8</module> + </modules> + </profile> + + <profile> + <id>java12-bytecode</id> + <activation> + <property> + <name>bytecode.version</name> + <value>12</value> + </property> + </activation> + <properties> + <!-- see respective profile in org.jacoco.build about this override --> + <maven.compiler.source>12</maven.compiler.source> + <maven.compiler.target>12</maven.compiler.target> + </properties> + <modules> + <module>../org.jacoco.core.test.validation.java7</module> + <module>../org.jacoco.core.test.validation.java8</module> + </modules> + </profile> + </profiles> + +</project> diff --git a/org.jacoco.core.test/pom.xml b/org.jacoco.core.test/pom.xml index 0c6a4920..9e80508e 100644 --- a/org.jacoco.core.test/pom.xml +++ b/org.jacoco.core.test/pom.xml @@ -46,139 +46,4 @@ </dependency> </dependencies> - <profiles> - <profile> - <id>java7-validation</id> - <activation> - <property> - <name>bytecode.version</name> - <value>1.7</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <id>add-source</id> - <phase>generate-sources</phase> - <goals> - <goal>add-source</goal> - </goals> - <configuration> - <sources> - <source>src-java7</source> - </sources> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>java8-validation</id> - <activation> - <property> - <name>bytecode.version</name> - <value>1.8</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <id>add-source</id> - <phase>generate-sources</phase> - <goals> - <goal>add-source</goal> - </goals> - <configuration> - <sources> - <source>src-java7</source> - <source>src-java8</source> - </sources> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>java9-validation</id> - <activation> - <!-- for some reason activation should be presented here, even if already defined in parent --> - <property> - <name>bytecode.version</name> - <value>1.9</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <id>add-source</id> - <phase>generate-sources</phase> - <goals> - <goal>add-source</goal> - </goals> - <configuration> - <sources> - <source>src-java7</source> - <source>src-java8</source> - </sources> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>java10-validation</id> - <activation> - <!-- for some reason activation should be presented here, even if already defined in parent --> - <property> - <name>bytecode.version</name> - <value>10</value> - </property> - </activation> - <properties> - <maven.compiler.target>10</maven.compiler.target> - </properties> - <build> - <plugins> - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>build-helper-maven-plugin</artifactId> - <executions> - <execution> - <id>add-source</id> - <phase>generate-sources</phase> - <goals> - <goal>add-source</goal> - </goals> - <configuration> - <sources> - <source>src-java7</source> - <source>src-java8</source> - </sources> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - </profiles> - </project> diff --git a/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/StringSwitchTest.java b/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/StringSwitchTest.java deleted file mode 100644 index eefff0fb..00000000 --- a/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/StringSwitchTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.StringSwitch; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of a bytecode that is generated for a String in switch - * statement. - */ -public class StringSwitchTest extends ValidationTestBase { - - public StringSwitchTest() { - super("src-java7", StringSwitch.class); - } - - /** - * {@link StringSwitch#covered(String)} - */ - @Test - public void covered() { - if (isJDKCompiler) { - assertLine("covered.switch", ICounter.FULLY_COVERED, 0, 4); - } else { - assertLine("covered.switch", ICounter.PARTLY_COVERED, 2, 7); - } - assertLine("covered.case1", ICounter.FULLY_COVERED, 0, 0); - assertLine("covered.case2", ICounter.FULLY_COVERED, 0, 0); - assertLine("covered.case3", ICounter.FULLY_COVERED, 0, 0); - assertLine("covered.default", ICounter.FULLY_COVERED, 0, 0); - } - - /** - * {@link StringSwitch#notCovered(String)} - */ - @Test - public void notCovered() { - assertLine("notCovered", ICounter.NOT_COVERED, isJDKCompiler ? 4 : 9, - 0); - } - - /** - * {@link StringSwitch#handwritten(String)} - */ - @Test - public void handwritten() { - assertLine("handwritten.firstSwitch", ICounter.FULLY_COVERED, 2, 1); - assertLine("handwritten.ignored", ICounter.FULLY_COVERED); - assertLine("handwritten.secondSwitch", ICounter.FULLY_COVERED, 3, 1); - assertLine("handwritten.case1", ICounter.FULLY_COVERED); - assertLine("handwritten.case2", ICounter.NOT_COVERED); - } - -} diff --git a/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/TryWithResourcesTest.java b/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/TryWithResourcesTest.java deleted file mode 100644 index ddafd69b..00000000 --- a/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/TryWithResourcesTest.java +++ /dev/null @@ -1,178 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.TryWithResources; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of a bytecode that is generated for a try-with-resources - * statement. - */ -public class TryWithResourcesTest extends ValidationTestBase { - - public TryWithResourcesTest() { - super("src-java7", TryWithResources.class); - } - - /** - * {@link TryWithResources#test()} - */ - @Test - public void test() { - assertLine("test.before", ICounter.FULLY_COVERED); - // without filter next line covered partly: - assertLine("test.try", ICounter.FULLY_COVERED); - assertLine("test.open1", ICounter.FULLY_COVERED); - assertLine("test.open2", ICounter.FULLY_COVERED); - assertLine("test.open3", ICounter.FULLY_COVERED); - assertLine("test.body", ICounter.FULLY_COVERED); - // without filter next line has branches: - assertLine("test.close", ICounter.EMPTY); - assertLine("test.catch", ICounter.NOT_COVERED); - assertLine("test.finally", ICounter.FULLY_COVERED); - } - - /** - * {@link TryWithResources#test2()} - */ - @Test - public void test2() { - assertLine("test2.before", ICounter.FULLY_COVERED); - // without filter next line covered partly: - assertLine("test2.try", ICounter.FULLY_COVERED); - assertLine("test2.open1", ICounter.FULLY_COVERED); - assertLine("test2.open2", ICounter.FULLY_COVERED); - assertLine("test2.open3", ICounter.FULLY_COVERED); - assertLine("test2.body", ICounter.FULLY_COVERED); - // without filter next line has branches: - assertLine("test2.close", ICounter.EMPTY); - assertLine("test2.catch", ICounter.NOT_COVERED); - assertLine("test2.finally", ICounter.FULLY_COVERED); - assertLine("test2.after", ICounter.FULLY_COVERED); - } - - /** - * {@link TryWithResources#returnInBody()} - */ - @Test - public void returnInBody() { - // without filter next line covered partly: - assertLine("returnInBody.try", ICounter.FULLY_COVERED); - assertLine("returnInBody.open", ICounter.FULLY_COVERED); - - // without filter next line has branches: - if (isJDKCompiler) { - // https://bugs.openjdk.java.net/browse/JDK-8134759 - // javac 7 and 8 up to 8u92 are affected - if (JAVA_VERSION.isBefore("1.8.0_92")) { - assertLine("returnInBody.close", ICounter.FULLY_COVERED, 0, 0); - } else { - assertLine("returnInBody.close", ICounter.EMPTY); - } - } else { - assertLine("returnInBody.close", ICounter.EMPTY); - } - - assertLine("returnInBody.return", ICounter.FULLY_COVERED); - } - - /** - * {@link TryWithResources#nested()} - */ - @Test - public void nested() { - // without filter next line covered partly: - assertLine("nested.try1", ICounter.FULLY_COVERED); - assertLine("nested.open1", ICounter.FULLY_COVERED); - assertLine("nested.catch1", ICounter.NOT_COVERED); - - // without filter next line covered partly: - assertLine("nested.try2", ICounter.FULLY_COVERED); - assertLine("nested.body", ICounter.FULLY_COVERED); - assertLine("nested.catch2", ICounter.NOT_COVERED); - assertLine("nested.finally2", ICounter.FULLY_COVERED); - - // next lines not covered on exceptional path: - assertLine("nested.try3", ICounter.FULLY_COVERED, 0, 0); - assertLine("nested.open3", ICounter.FULLY_COVERED, 0, 0); - assertLine("nested.body3", ICounter.FULLY_COVERED, 0, 0); - assertLine("nested.catch3", ICounter.NOT_COVERED); - assertLine("nested.finally3", ICounter.FULLY_COVERED, 0, 0); - - // without filter next lines have branches: - assertLine("nested.close3", ICounter.EMPTY); - assertLine("nested.close2", ICounter.EMPTY); - assertLine("nested.close1", ICounter.EMPTY); - } - - /** - * {@link TryWithResources#returnInCatch()} - */ - @Test - public void returnInCatch() { - // without filter next line covered partly: - assertLine("returnInCatch.try1", ICounter.FULLY_COVERED); - assertLine("returnInCatch.open", ICounter.FULLY_COVERED); - assertLine("returnInCatch.finally1", ICounter.PARTLY_COVERED, 1, 1); - // without filter next line has branches: - assertLine("returnInCatch.close", ICounter.EMPTY); - - assertLine("returnInCatch.try2", ICounter.EMPTY); - assertLine("returnInCatch.finally2", ICounter.PARTLY_COVERED, 1, 1); - } - - /* - * Corner cases - */ - - /** - * {@link TryWithResources#handwritten()} - */ - @Test - public void handwritten() { - if (isJDKCompiler) { - assertLine("handwritten", /* partly when ECJ: */ICounter.EMPTY); - } - } - - /** - * {@link TryWithResources#empty()} - */ - @Test - public void empty() { - assertLine("empty.try", ICounter.FULLY_COVERED, 0, 0); - assertLine("empty.open", ICounter.FULLY_COVERED); - // empty when EJC: - if (isJDKCompiler) { - if (JAVA_VERSION.isBefore("9")) { - // branches with javac 7 and 8 - assertLine("empty.close", ICounter.PARTLY_COVERED); - } else { - assertLine("empty.close", ICounter.FULLY_COVERED, 0, 0); - } - } - } - - /** - * {@link TryWithResources#throwInBody()} - */ - @Test - public void throwInBody() { - // not filtered - assertLine("throwInBody.try", ICounter.NOT_COVERED); - assertLine("throwInBody.close", ICounter.NOT_COVERED); - } - -} diff --git a/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/targets/StringSwitch.java b/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/targets/StringSwitch.java deleted file mode 100644 index c8b9a232..00000000 --- a/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/targets/StringSwitch.java +++ /dev/null @@ -1,96 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target is a switch statement with a String. - */ -public class StringSwitch { - - private static void covered(Object s) { - switch (String.valueOf(s)) { // $line-covered.switch$ - case "a": - nop("case a"); // $line-covered.case1$ - break; - case "b": - nop("case b"); // $line-covered.case2$ - break; - case "\0a": - nop("case \0a"); // $line-covered.case3$ - break; - default: - nop("case default"); // $line-covered.default$ - break; - } - } - - private static void notCovered(Object s) { - switch (String.valueOf(s)) { // $line-notCovered$ - case "a": - nop("case a"); - break; - case "b": - nop("case b"); - break; - case "\0a": - nop("case \0a"); - break; - default: - nop("default"); - break; - } - } - - private static void handwritten(String s) { - int c = -1; - switch (s.hashCode()) { // $line-handwritten.firstSwitch$ - case 97: - if ("a".equals(s)) { // $line-handwritten.ignored$ - c = 0; - } else if ("\0a".equals(s)) { - c = 1; - } - break; - case 98: - if ("b".equals(s)) { - c = 2; - } - break; - } - switch (c) { // $line-handwritten.secondSwitch$ - case 0: - nop("case a"); // $line-handwritten.case1$ - break; - case 1: - nop("case \0a"); // $line-handwritten.case2$ - break; - case 2: - nop("case b"); - break; - default: - nop("default"); - break; - } - } - - public static void main(String[] args) { - covered(""); - covered("a"); - covered("b"); - covered("\0a"); - - handwritten("a"); - } - -} diff --git a/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/targets/TryWithResources.java b/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/targets/TryWithResources.java deleted file mode 100644 index 3d3a30db..00000000 --- a/org.jacoco.core.test/src-java7/org/jacoco/core/test/filter/targets/TryWithResources.java +++ /dev/null @@ -1,204 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -import java.io.Closeable; -import java.io.IOException; - -/** - * This test target is a try-with-resources statement. - */ -public class TryWithResources { - - private static class Resource implements Closeable { - @Override - public void close() { - } - } - - /** - * Closing performed using {@link org.objectweb.asm.Opcodes#INVOKEVIRTUAL} - * or {@link org.objectweb.asm.Opcodes#INVOKEINTERFACE} depending on a class - * of resource. - */ - private static Object test() throws Exception { - nop(); // $line-test.before$ - try ( // $line-test.try$ - Resource r1 = new Resource(); // $line-test.open1$ - Closeable r2 = new Resource(); // $line-test.open2$ - AutoCloseable r3 = new Resource() // $line-test.open3$ - ) { - return read(r1, r2, r3); // $line-test.body$ - } // $line-test.close$ - catch (Exception e) { - nop(); // $line-test.catch$ - throw e; - } finally { - nop(); // $line-test.finally$ - } - } - - private static void test2() throws Exception { - nop(); // $line-test2.before$ - try ( // $line-test2.try$ - Resource r1 = new Resource(); // $line-test2.open1$ - Closeable r2 = new Resource(); // $line-test2.open2$ - AutoCloseable r3 = new Resource() // $line-test2.open3$ - ) { - read(r1, r2, r3); // $line-test2.body$ - } // $line-test2.close$ - catch (Exception e) { - nop(); // $line-test2.catch$ - } finally { - nop(); // $line-test2.finally$ - } - nop(); // $line-test2.after$ - } - - private static Object returnInBody() throws IOException { - try ( // $line-returnInBody.try$ - Closeable r = new Resource() // $line-returnInBody.open$ - ) { - return read(r); // $line-returnInBody.return$ - } // $line-returnInBody.close$ - } - - private static void nested() { - try ( // $line-nested.try1$ - Resource r1 = new Resource() // $line-nested.open1$ - ) { - - try ( // $line-nested.try2$ - Resource r2 = new Resource() // $line-nested.open2$ - ) { - nop(r1.toString() + r2.toString()); // $line-nested.body$ - } // $line-nested.close2$ - catch (Exception e) { - nop(); // $line-nested.catch2$ - } finally { - nop(); // $line-nested.finally2$ - } - - } // $line-nested.close1$ - catch (Exception e) { - nop(); // $line-nested.catch1$ - } finally { - - try ( // $line-nested.try3$ - Resource r2 = new Resource() // $line-nested.open3$ - ) { - nop(r2); // $line-nested.body3$ - } // $line-nested.close3$ - catch (Exception e) { - nop(); // $line-nested.catch3$ - } finally { - nop(); // $line-nested.finally3$ - } - - } - } - - /** - * In this case bytecode will contain 3 copies of <code>finally</code> - * block, each containing 2 branches, resulting in 6 branches in total. One - * could think that this is artifact of try-with-resources, but the same - * happens without it. - */ - private static Object returnInCatch() { - try ( // $line-returnInCatch.try1$ - Resource r = new Resource() // $line-returnInCatch.open$ - ) { - read(r); - } // $line-returnInCatch.close$ - catch (Exception e) { - return null; - } finally { - nop(!f()); // $line-returnInCatch.finally1$ - } - - try { // $line-returnInCatch.try2$ - read(new Resource()); - } catch (Exception e) { - return null; - } finally { - nop(!f()); // $line-returnInCatch.finally2$ - } - - return null; - } - - private static Object read(Object r1, Object r2, Object r3) { - return r1.toString() + r2.toString() + r3.toString(); - } - - private static Object read(Object r1) { - return r1.toString(); - } - - public static void main(String[] args) throws Exception { - test(); - test2(); - returnInBody(); - nested(); - - returnInCatch(); - - empty(); - handwritten(); - } - - /* - * Corner cases - */ - - private static void empty() throws Exception { - try ( // $line-empty.try$ - Closeable r = new Resource() // $line-empty.open$ - ) { - } // $line-empty.close$ - } - - private static void handwritten() throws IOException { - Closeable r = new Resource(); - Throwable primaryExc = null; - try { - nop(r); - } catch (Throwable t) { - primaryExc = t; - throw t; - } finally { - if (r != null) { // $line-handwritten$ - if (primaryExc != null) { - try { - r.close(); - } catch (Throwable suppressedExc) { - primaryExc.addSuppressed(suppressedExc); - } - } else { - r.close(); - } - } - } - } - - private static void throwInBody() throws IOException { - try ( // $line-throwInBody.try$ - Closeable r = new Resource()) { - nop(r); - throw new RuntimeException(); - } // $line-throwInBody.close$ - } - -} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java deleted file mode 100644 index 64720491..00000000 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.AnnotationOnLocalVariableTarget; -import org.junit.Test; - -/** - * Test of ASM bug - * <a href="https://gitlab.ow2.org/asm/asm/issues/317815">#317815</a> - */ -public class AnnotationOnLocalVariableTest extends ValidationTestBase { - - public AnnotationOnLocalVariableTest() { - super("src-java8", AnnotationOnLocalVariableTarget.class); - } - - @Test - public void testCoverageResult() { - - assertLine("var", ICounter.FULLY_COVERED); - - } - -} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BadCycleInterfaceTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BadCycleInterfaceTest.java deleted file mode 100644 index fdd7e001..00000000 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BadCycleInterfaceTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.BadCycleInterface; -import org.junit.Test; - -/** - * Test of "bad cycles" with interfaces. - */ -public class BadCycleInterfaceTest extends ValidationTestBase { - - public BadCycleInterfaceTest() throws Exception { - super("src-java8", BadCycleInterface.class); - } - - @Test - public void test() throws Exception { - if (JAVA_VERSION.isBefore("1.8.0_152")) { - // Incorrect interpetation of JVMS 5.5 in JDK 8 causes a default - // method to be called before the static initializer of an interface - // (see JDK-8098557 and JDK-8164302): - assertLine("baseclinit", ICounter.FULLY_COVERED); - assertLine("childdefault", ICounter.FULLY_COVERED); - - assertLogEvents("baseclinit", "childdefaultmethod", "childclinit", - "childstaticmethod"); - } else { - // This shouldn't happen with JDK 9 (see also JDK-8043275) - // and starting with JDK 8u152 (see JDK-8167607): - assertLine("baseclinit", ICounter.EMPTY); - assertLine("childdefault", ICounter.NOT_COVERED); - assertLogEvents("childclinit", "childstaticmethod"); - } - assertLine("childclinit", ICounter.FULLY_COVERED); - assertLine("childstatic", ICounter.FULLY_COVERED); - } - -} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java deleted file mode 100644 index dc20f0af..00000000 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java +++ /dev/null @@ -1,126 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import static org.junit.Assert.assertEquals; - -import java.lang.invoke.CallSite; -import java.lang.invoke.ConstantCallSite; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.InvocationTargetException; - -import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.runtime.IRuntime; -import org.jacoco.core.runtime.RuntimeData; -import org.jacoco.core.runtime.SystemPropertiesRuntime; -import org.jacoco.core.test.TargetLoader; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -/** - * Test of ASM bug - * <a href="https://gitlab.ow2.org/asm/asm/issues/317748">#317748</a> that - * caused - * {@code java.lang.ClassFormatError: Short length on BootstrapMethods in class file} - * during instrumentation. - */ -public class BootstrapMethodReferenceTest { - - private final IRuntime runtime = new SystemPropertiesRuntime(); - private final Instrumenter instrumenter = new Instrumenter(runtime); - - @Before - public void setup() throws Exception { - runtime.startup(new RuntimeData()); - } - - @After - public void teardown() { - runtime.shutdown(); - } - - @Test - public void test() throws Exception { - final String className = "Example"; - - final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, className, null, - "java/lang/Object", null); - - final MethodVisitor mv = cw.visitMethod( - Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "run", "()I", null, - null); - mv.visitCode(); - addCauseOfResizeInstructions(mv); - final MethodType methodType = MethodType.methodType(CallSite.class, - MethodHandles.Lookup.class, String.class, MethodType.class); - final Handle handle = new Handle(Opcodes.H_INVOKESTATIC, - this.getClass().getCanonicalName().replace('.', '/'), - "bootstrap", methodType.toMethodDescriptorString(), false); - mv.visitInvokeDynamicInsn("invoke", "()I", handle); - mv.visitInsn(Opcodes.IRETURN); - mv.visitMaxs(1, 0); - mv.visitEnd(); - - cw.visitEnd(); - - final byte[] original = cw.toByteArray(); - assertEquals(42, run(className, original)); - - final byte[] instrumented = instrumenter.instrument(original, - className); - assertEquals(42, run(className, instrumented)); - } - - private static int run(final String className, final byte[] bytes) - throws ClassNotFoundException, NoSuchMethodException, - InvocationTargetException, IllegalAccessException { - return (Integer) new TargetLoader().add(className, bytes) - .getMethod("run").invoke(null); - } - - /** - * Adds code that triggers usage of - * {@link org.objectweb.asm.MethodWriter#COMPUTE_INSERTED_FRAMES} during - * instrumentation. - */ - private static void addCauseOfResizeInstructions(final MethodVisitor mv) { - mv.visitInsn(Opcodes.ICONST_0); - mv.visitInsn(Opcodes.ICONST_1); - final Label target = new Label(); - mv.visitJumpInsn(Opcodes.IFLE, target); - for (int i = 0; i < Short.MAX_VALUE; i++) { - mv.visitInsn(Opcodes.NOP); - } - mv.visitLabel(target); - } - - @SuppressWarnings("unused") - public static CallSite bootstrap(final MethodHandles.Lookup caller, - final String name, final MethodType type) throws Exception { - return new ConstantCallSite(caller.findStatic(BootstrapMethodReferenceTest.class, - "callTarget", MethodType.methodType(int.class))); - } - - @SuppressWarnings("unused") - public static int callTarget() { - return 42; - } - -} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java deleted file mode 100644 index 56998513..00000000 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.InterfaceDefaultMethodsTarget; -import org.junit.Test; - -/** - * Tests of static initializer and default methods in interfaces. - */ -public class InterfaceDefaultMethodsTest extends ValidationTestBase { - - public InterfaceDefaultMethodsTest() { - super("src-java8", InterfaceDefaultMethodsTarget.class); - } - - @Test - public void testCoverageResult() { - assertLine("clinit", ICounter.FULLY_COVERED); - assertLine("m1", ICounter.FULLY_COVERED); - assertLine("m2", ICounter.NOT_COVERED); - } - -} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java deleted file mode 100644 index e572c630..00000000 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.InterfaceOnlyDefaultMethodsTarget; -import org.junit.Test; - -/** - * Tests of default methods in interfaces. - */ -public class InterfaceOnlyDefaultMethodsTest extends ValidationTestBase { - - public InterfaceOnlyDefaultMethodsTest() { - super("src-java8", InterfaceOnlyDefaultMethodsTarget.class); - } - - @Test - public void testCoverageResult() { - assertLine("m1", ICounter.FULLY_COVERED); - assertLine("m2", ICounter.NOT_COVERED); - } - -} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/LambdaExpressionsTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/LambdaExpressionsTest.java deleted file mode 100644 index 2e8da872..00000000 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/LambdaExpressionsTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.LambdaExpressionsTarget; -import org.junit.Test; - -/** - * Tests for different lambda expressions. - */ -public class LambdaExpressionsTest extends ValidationTestBase { - - public LambdaExpressionsTest() { - super("src-java8", LambdaExpressionsTarget.class); - } - - @Test - public void testCoverageResult() { - - // Coverage of lambda bodies - assertLine("executedlambdabody", ICounter.FULLY_COVERED); - assertLine("notexecutedlambdabody", ICounter.NOT_COVERED); - - } - -} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/LambdaInInterfaceTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/LambdaInInterfaceTest.java deleted file mode 100644 index afa2e986..00000000 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/LambdaInInterfaceTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.LambdaInInterfaceTarget; -import org.junit.Test; - -/** - * Tests a constant with a lambda value in an interface. - */ -public class LambdaInInterfaceTest extends ValidationTestBase { - - public LambdaInInterfaceTest() { - super("src-java8", LambdaInInterfaceTarget.class); - } - - @Override - protected void run(final Class<?> targetClass) throws Exception { - ((Runnable) targetClass.getField("RUN").get(null)).run(); - } - - @Test - public void testCoverageResult() { - - // Coverage of lambda body - assertLine("lambdabody", ICounter.FULLY_COVERED); - - } - -} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java deleted file mode 100644 index 3417c098..00000000 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation.targets; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This test target contains annotation on local variable. - */ -public class AnnotationOnLocalVariableTarget { - - @Documented - @Retention(RetentionPolicy.CLASS) - @Target(ElementType.TYPE_USE) - @interface NonNull { - } - - private static Object legacy() { - return new Object(); - } - - public static void main(String[] args) { - @NonNull - Object o = legacy(); // $line-var$ - } - -} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/BadCycleInterface.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/BadCycleInterface.java deleted file mode 100644 index d7e7a746..00000000 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/BadCycleInterface.java +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation.targets; - -public class BadCycleInterface { - - public interface Base { - static final Object BASE_CONST = new Child() { - { - Stubs.logEvent("baseclinit"); // $line-baseclinit$ - } - }.childDefaultMethod(); - - default void baseDefaultMethod() { - } - } - - public interface Child extends Base { - static final Object CHILD_CONST = new Object() { - { - Stubs.logEvent("childclinit"); // $line-childclinit$ - } - }; - - default Object childDefaultMethod() { - Stubs.logEvent("childdefaultmethod"); // $line-childdefault$ - return null; - } - - static void childStaticMethod() { - Stubs.logEvent("childstaticmethod"); // $line-childstatic$ - } - } - - public static void main(String[] args) { - Child.childStaticMethod(); - } - -} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java deleted file mode 100644 index 2e952995..00000000 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.i1; - -/** - * This test target is an interface with a class initializer and default methods. - */ -public interface InterfaceDefaultMethodsTarget { - - public static final int CONST = i1(); // $line-clinit$ - - default void m1() { - return; // $line-m1$ - } - - default void m2() { - return; // $line-m2$ - } - - public class Impl implements InterfaceDefaultMethodsTarget { - - public Impl() { - m1(); - } - } - - public static void main(String[] args) { - new Impl(); - } - -} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java deleted file mode 100644 index 5fa48fb8..00000000 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation.targets; - -/** - * This test target is an interface with only default methods. - */ -public interface InterfaceOnlyDefaultMethodsTarget { - - // no <clinit>, only default methods: - - default void m1() { - return; // $line-m1$ - } - - default void m2() { - return; // $line-m2$ - } - - public class Impl implements InterfaceOnlyDefaultMethodsTarget { - - public Impl() { - m1(); - } - } - - public static void main(String[] args) { - new Impl(); - } - -} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/LambdaExpressionsTarget.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/LambdaExpressionsTarget.java deleted file mode 100644 index bcb65b60..00000000 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/LambdaExpressionsTarget.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.exec; -import static org.jacoco.core.test.validation.targets.Stubs.noexec; -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target contains different lambda expressions. - */ -public class LambdaExpressionsTarget { - - public static void main(String[] args) { - - exec(() -> { - nop(); // $line-executedlambdabody$ - }); - - noexec(() -> { - nop(); // $line-notexecutedlambdabody$ - }); - - } - -} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/LambdaInInterfaceTarget.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/LambdaInInterfaceTarget.java deleted file mode 100644 index 23edc6dd..00000000 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/LambdaInInterfaceTarget.java +++ /dev/null @@ -1,25 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target builds a constant with a lambda value in an interface. - */ -public interface LambdaInInterfaceTarget { - - public static final Runnable RUN = () -> { - nop(); // $line-lambdabody$ - }; - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/ConstructorTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/ConstructorTest.java deleted file mode 100644 index 1dffc684..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/ConstructorTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.Constructor; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of a bytecode that is generated for a private empty - * constructors that do not have no arguments. - */ -public class ConstructorTest extends ValidationTestBase { - - public ConstructorTest() { - super(Constructor.class); - } - - @Test - public void testCoverageResult() { - // not filtered because not private: - assertLine("packageLocal", ICounter.FULLY_COVERED); - - // not filtered because has argument: - assertLine("arg", ICounter.FULLY_COVERED); - - // not filtered because not empty - prepares arguments for super - // constructor: - assertLine("super", ICounter.FULLY_COVERED); - - // not filtered because contains initialization of a field to hold - // reference to an instance of outer class that is passed as an - // argument: - assertLine("inner", ICounter.FULLY_COVERED); - - // not filtered because not empty - contains initialization of - // a field: - assertLine("innerStatic", ICounter.FULLY_COVERED); - - // not filtered because default constructor for not private inner - // classes is not private: - assertLine("publicDefault", ICounter.FULLY_COVERED); - assertLine("packageLocalDefault", ICounter.FULLY_COVERED); - - assertLine("privateDefault", ICounter.EMPTY); - - assertLine("privateNonEmptyNoArg", ICounter.FULLY_COVERED); - - assertLine("privateEmptyNoArg", ICounter.EMPTY); - assertLine("return", ICounter.EMPTY); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumConstructorTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumConstructorTest.java deleted file mode 100644 index fd88787b..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumConstructorTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.EnumConstructor; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of enum constructors. - */ -public class EnumConstructorTest extends ValidationTestBase { - - public EnumConstructorTest() { - super(EnumConstructor.class); - } - - /** - * {@link EnumConstructor.ImplicitConstructor} - */ - @Test - public void implicit_constructor_should_be_filtered() { - // without filter next line is partly covered: - assertLine("implicitConstructor", ICounter.FULLY_COVERED); - } - - /** - * {@link EnumConstructor.ExplicitNonEmptyConstructor#ExplicitNonEmptyConstructor()} - */ - @Test - public void explicit_non_empty_constructor_should_not_be_filtered() { - assertLine("explicitNonEmptyConstructor", ICounter.NOT_COVERED); - } - - /** - * {@link EnumConstructor.ExplicitEmptyConstructor#ExplicitEmptyConstructor()} - */ - @Test - public void explicit_empty_constructor_should_be_filtered() { - // without filter next line is not covered: - assertLine("explicitEmptyConstructor", ICounter.EMPTY); - } - - /** - * {@link EnumConstructor.ExplicitEmptyConstructor#ExplicitEmptyConstructor(Object)} - */ - @Test - public void explicit_empty_constructor_with_parameters_should_not_be_filtered() { - assertLine("explicitEmptyConstructorWithParameter", ICounter.NOT_COVERED); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumSwitchTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumSwitchTest.java deleted file mode 100644 index 3708899a..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/EnumSwitchTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.EnumSwitch; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of a synthetic class that is generated by javac for a enum - * in switch statement. - */ -public class EnumSwitchTest extends ValidationTestBase { - - public EnumSwitchTest() { - super(EnumSwitch.class); - } - - @Test - public void testCoverageResult() { - if (isJDKCompiler && JAVA_VERSION.isBefore("1.6")) { - // class that holds "switch map" is not marked as synthetic when - // compiling with javac 1.5 - assertLine("switch", ICounter.PARTLY_COVERED, 0, 2); - } else { - assertLine("switch", ICounter.FULLY_COVERED, 0, 2); - } - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java deleted file mode 100644 index 9c6b2af4..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/FinallyTest.java +++ /dev/null @@ -1,270 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.internal.BytecodeVersion; -import org.jacoco.core.test.TargetLoader; -import org.jacoco.core.test.filter.targets.Finally; -import org.jacoco.core.test.validation.Source; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.LineNumberNode; -import org.objectweb.asm.tree.MethodNode; - -/** - * Test of filtering of duplicated bytecode that is generated for finally block. - */ -public class FinallyTest extends ValidationTestBase { - - public FinallyTest() { - super(Finally.class); - } - - /** - * {@link Finally#example(boolean)} - */ - @Test - public void example() { - if (isJDKCompiler) { - assertLine("example.0", ICounter.EMPTY); - } else { - assertLine("example.0", ICounter.FULLY_COVERED); - } - assertLine("example.1", ICounter.FULLY_COVERED, 0, 2); - assertLine("example.2", ICounter.FULLY_COVERED); - assertLine("example.3", ICounter.EMPTY); - assertLine("example.4", ICounter.EMPTY); - } - - /** - * GOTO instructions at the end of duplicates of finally block might have - * line number of a last instruction of finally block and hence lead to - * unexpected coverage results, like for example in case of ECJ for - * {@link Finally#catchNotExecuted()}, {@link Finally#emptyCatch()}. So we - * decided to ignore them, even if they can correspond to a real break - * statement. - * <p> - * See also <a href= - * "https://bugs.openjdk.java.net/browse/JDK-8180141">JDK-8180141</a> and - * <a href= - * "https://bugs.openjdk.java.net/browse/JDK-7008643">JDK-7008643</a>. - * <p> - * {@link Finally#breakStatement()} - */ - @Test - public void breakStatement() { - assertLine("breakStatement", ICounter.EMPTY); - - assertLine("breakStatement.1", ICounter.FULLY_COVERED); - assertLine("breakStatement.2", ICounter.EMPTY); - } - - /** - * {@link Finally#catchNotExecuted()} - */ - @Test - public void catchNotExecuted() { - assertLine("catchNotExecuted.catch", ICounter.NOT_COVERED); - assertLine("catchNotExecuted.0", ICounter.EMPTY); - assertLine("catchNotExecuted.1", ICounter.FULLY_COVERED); - assertLine("catchNotExecuted.2", ICounter.EMPTY); - } - - /** - * {@link Finally#emptyCatch()} - */ - @Test - public void emptyCatch() { - assertLine("emptyCatch.0", ICounter.EMPTY); - assertLine("emptyCatch.1", ICounter.FULLY_COVERED); - assertLine("emptyCatch.2", ICounter.EMPTY); - } - - /** - * {@link Finally#twoRegions()} - */ - @Test - public void twoRegions() { - assertLine("twoRegions.0", ICounter.EMPTY); - if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { - // https://bugs.openjdk.java.net/browse/JDK-7008643 - assertLine("twoRegions.1", ICounter.PARTLY_COVERED); - assertLine("twoRegions.return.1", ICounter.EMPTY); - assertLine("twoRegions.return.2", ICounter.EMPTY); - } else { - assertLine("twoRegions.1", ICounter.FULLY_COVERED); - assertLine("twoRegions.return.1", ICounter.FULLY_COVERED); - assertLine("twoRegions.return.2", ICounter.NOT_COVERED); - } - assertLine("twoRegions.2", ICounter.EMPTY); - - assertLine("twoRegions.if", ICounter.FULLY_COVERED); - assertLine("twoRegions.region.1", ICounter.FULLY_COVERED); - assertLine("twoRegions.region.2", ICounter.NOT_COVERED); - } - - /** - * {@link Finally#nested()} - */ - @Test - public void nested() { - if (isJDKCompiler) { - assertLine("nested.0", ICounter.EMPTY); - } else { - assertLine("nested.0", ICounter.FULLY_COVERED); - } - assertLine("nested.1", ICounter.EMPTY); - assertLine("nested.2", ICounter.FULLY_COVERED); - if (isJDKCompiler) { - assertLine("nested.3", ICounter.EMPTY); - } else { - assertLine("nested.3", ICounter.FULLY_COVERED); - } - assertLine("nested.4", ICounter.FULLY_COVERED); - } - - /** - * {@link Finally#emptyTry()} - */ - @Test - public void emptyTry() { - assertLine("emptyTry.0", ICounter.EMPTY); - if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { - // compiler bug fixed in javac >= 1.8: - assertLine("emptyTry.1", ICounter.PARTLY_COVERED); - assertLine("emptyTry.2", ICounter.FULLY_COVERED); - } else { - assertLine("emptyTry.1", ICounter.FULLY_COVERED); - assertLine("emptyTry.2", ICounter.EMPTY); - } - } - - /** - * {@link Finally#alwaysCompletesAbruptly()} - */ - @Test - public void alwaysCompletesAbruptly() { - if (isJDKCompiler) { - // uncovered case: - assertLine("alwaysCompletesAbruptly.0", ICounter.EMPTY); - assertLine("alwaysCompletesAbruptly.1", ICounter.PARTLY_COVERED); - } else { - assertLine("alwaysCompletesAbruptly.0", ICounter.PARTLY_COVERED); - assertLine("alwaysCompletesAbruptly.1", ICounter.FULLY_COVERED); - } - assertLine("alwaysCompletesAbruptly.2", ICounter.EMPTY); - } - - /** - * This test studies placement of GOTO instructions. - */ - @Test - public void gotos() throws IOException { - final Source source = Source.getSourceFor("src", Finally.class); - - byte[] b = TargetLoader.getClassDataAsBytes(Finally.class); - b = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(b), b); - - final ClassNode classNode = new ClassNode(); - new ClassReader(b).accept(classNode, 0); - final Set<String> tags = new HashSet<String>(); - for (final MethodNode m : classNode.methods) { - if ("main".equals(m.name)) { - // skip it - continue; - } - int lineNumber = -1; - for (AbstractInsnNode i = m.instructions - .getFirst(); i != null; i = i.getNext()) { - if (AbstractInsnNode.LINE == i.getType()) { - lineNumber = ((LineNumberNode) i).line; - } - if (Opcodes.GOTO == i.getOpcode()) { - final String line = source.getLine(lineNumber); - if (line.indexOf('$') < 0) { - throw new AssertionError( - "No tag at line " + lineNumber); - } - final String tag = line.substring( - line.indexOf('$') + "$line-".length(), - line.lastIndexOf('$')); - tags.add(tag); - } - } - } - - final Set<String> expected = new HashSet<String>(); - - if (isJDKCompiler) { - expected.add("example.2"); - } else { - expected.add("example.0"); - } - - expected.add("breakStatement.for"); - if (isJDKCompiler) { - if (JAVA_VERSION.isBefore("10")) { - // https://bugs.openjdk.java.net/browse/JDK-8180141 - expected.add("breakStatement.1"); - } else { - expected.add("breakStatement"); - } - expected.add("breakStatement.2"); - } else { - expected.add("breakStatement"); - } - - if (isJDKCompiler) { - expected.add("emptyCatch.2"); - } else { - expected.add("emptyCatch"); - expected.add("emptyCatch.1"); - } - - if (isJDKCompiler) { - expected.add("catchNotExecuted.2"); - } else { - expected.add("catchNotExecuted"); - expected.add("catchNotExecuted.1"); - } - - if (isJDKCompiler) { - expected.add("nested.5"); - expected.add("nested.6"); - } else { - expected.add("nested.0"); - expected.add("nested.3"); - } - - if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { - expected.add("emptyTry.2"); - } - - if (!isJDKCompiler) { - expected.add("alwaysCompletesAbruptly.0"); - } - - assertEquals(expected, tags); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/SynchronizedTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/SynchronizedTest.java deleted file mode 100644 index 2d0fa973..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/SynchronizedTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.Synchronized; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of a bytecode that is generated for a synchronized - * statement. - */ -public class SynchronizedTest extends ValidationTestBase { - - public SynchronizedTest() { - super(Synchronized.class); - } - - /** - * {@link Synchronized#normal()} - */ - @Test - public void normal() { - assertLine("before", ICounter.FULLY_COVERED); - // when compiled with ECJ next line covered partly without filter: - assertLine("monitorEnter", ICounter.FULLY_COVERED); - assertLine("body", ICounter.FULLY_COVERED); - if (isJDKCompiler) { - // without filter next line covered partly: - assertLine("monitorExit", ICounter.FULLY_COVERED); - } else { - assertLine("monitorExit", ICounter.EMPTY); - } - assertLine("after", ICounter.FULLY_COVERED); - } - - /** - * {@link Synchronized#explicitException()} - */ - @Test - public void explicitException() { - assertLine("explicitException.monitorEnter", ICounter.FULLY_COVERED); - assertLine("explicitException.exception", ICounter.FULLY_COVERED); - // when compiled with javac next line covered fully without filter: - assertLine("explicitException.monitorExit", ICounter.EMPTY); - } - - /** - * {@link Synchronized#implicitException()} - */ - @Test - public void implicitException() { - assertLine("implicitException.monitorEnter", isJDKCompiler - ? ICounter.FULLY_COVERED : ICounter.PARTLY_COVERED); - assertLine("implicitException.exception", ICounter.NOT_COVERED); - if (isJDKCompiler) { - // without filter next line covered partly: - assertLine("implicitException.monitorExit", ICounter.NOT_COVERED); - } else { - assertLine("implicitException.monitorExit", ICounter.EMPTY); - } - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/SyntheticTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/SyntheticTest.java deleted file mode 100644 index f439736b..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/SyntheticTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.Synthetic; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of synthetic methods. - */ -public class SyntheticTest extends ValidationTestBase { - - public SyntheticTest() { - super(Synthetic.class); - } - - @Test - public void testCoverageResult() { - assertMethodCount(5); - - assertLine("classdef", ICounter.EMPTY); - assertLine("field", ICounter.EMPTY); - - assertLine("inner.classdef", ICounter.EMPTY); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Constructor.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Constructor.java deleted file mode 100644 index 8a3e394a..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Constructor.java +++ /dev/null @@ -1,77 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target is a constructors. - */ -public class Constructor { - - Constructor() { // $line-packageLocal$ - } - - private Constructor(Object arg) { // $line-arg$ - } - - private static class Super extends Constructor { - private Super() { - super(null); // $line-super$ - } - } - - private class Inner { - private Inner() { // $line-inner$ - } - } - - private static class InnerStatic { - @SuppressWarnings("unused") - private final Object field = this; - - private InnerStatic() { // $line-innerStatic$ - } - } - - public static class PublicDefault { // $line-publicDefault$ - } - - static class PackageLocalDefault { // $line-packageLocalDefault$ - } - - private static class PrivateDefault { // $line-privateDefault$ - } - - private static class PrivateNonEmptyNoArg { - private PrivateNonEmptyNoArg() { - nop(); // $line-privateNonEmptyNoArg$ - } - } - - private static class PrivateEmptyNoArg { - private PrivateEmptyNoArg() { // $line-privateEmptyNoArg$ - } // $line-return$ - } - - public static void main(String[] args) { - new Super(); - new Constructor().new Inner(); - new InnerStatic(); - new PublicDefault(); - new PackageLocalDefault(); - new PrivateDefault(); - new PrivateNonEmptyNoArg(); - new PrivateEmptyNoArg(); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumConstructor.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumConstructor.java deleted file mode 100644 index c6eb1c53..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumConstructor.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target is an enum constructor. - */ -public class EnumConstructor { - - private enum ImplicitConstructor { // $line-implicitConstructor$ - } - - private enum ExplicitNonEmptyConstructor { - ; - - ExplicitNonEmptyConstructor() { - nop(); // $line-explicitNonEmptyConstructor$ - } - } - - @SuppressWarnings("unused") - private enum ExplicitEmptyConstructor { - ; - - ExplicitEmptyConstructor() { - } // $line-explicitEmptyConstructor$ - - ExplicitEmptyConstructor(Object p) { - } // $line-explicitEmptyConstructorWithParameter$ - } - - public static void main(String[] args) { - ImplicitConstructor.values(); - ExplicitEmptyConstructor.values(); - ExplicitNonEmptyConstructor.values(); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumSwitch.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumSwitch.java deleted file mode 100644 index 850ef295..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/EnumSwitch.java +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target is a switch statement with a enum. - */ -public class EnumSwitch { - - private enum E { - V1, V2 - } - - private static void example(E e) { - switch (e) { // $line-switch$ - case V1: - nop("V1"); - break; - case V2: - default: - nop("V2"); - break; - } - } - - public static void main(String[] args) { - example(E.V1); - example(E.V2); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Finally.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Finally.java deleted file mode 100644 index 6471a809..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Finally.java +++ /dev/null @@ -1,148 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.ex; -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.nop; -import static org.jacoco.core.test.validation.targets.Stubs.t; - -public class Finally { - - /** - * <pre> - * InputStream in = null; - * try { - * in = ...; - * ... - * } finally { - * if (in != null) { - * in.close(); - * } - * } - * </pre> - */ - private static void example(boolean t) { - Object in = null; - try { - in = open(t); - } finally { // $line-example.0$ - if (in != null) { // $line-example.1$ - nop(); // $line-example.2$ - } // $line-example.3$ - } // $line-example.4$ - } - - private static Object open(boolean t) { - ex(t); - return new Object(); - } - - private static void breakStatement() { - for (int i = 0; i < 1; i++) { // $line-breakStatement.for$ - try { - if (f()) { - break; // $line-breakStatement$ - } - } finally { - nop("finally"); // $line-breakStatement.1$ - } // $line-breakStatement.2$ - } - } - - private static void catchNotExecuted() { - try { - nop("try"); - } catch (Exception e) { // $line-catchNotExecuted$ - nop("catch"); // $line-catchNotExecuted.catch$ - } finally { // $line-catchNotExecuted.0$ - nop("finally"); // $line-catchNotExecuted.1$ - } // $line-catchNotExecuted.2$ - } - - private static void emptyCatch() { - try { - nop("try"); - } catch (Exception e) { // $line-emptyCatch$ - // empty - } finally { // $line-emptyCatch.0$ - nop("finally"); // $line-emptyCatch.1$ - } // $line-emptyCatch.2$ - } - - private static void twoRegions() { - try { - // jump to another region associated with same handler: - if (t()) { // $line-twoRegions.if$ - nop(); // $line-twoRegions.region.1$ - return; // $line-twoRegions.return.1$ - } else { - nop(); // $line-twoRegions.region.2$ - return; // $line-twoRegions.return.2$ - } - } finally { // $line-twoRegions.0$ - nop(); // $line-twoRegions.1$ - } // $line-twoRegions.2$ - } - - private static void nested() { - try { - nop(); - } finally { // $line-nested.0$ - try { // $line-nested.1$ - nop(); // $line-nested.2$ - } finally { // $line-nested.3$ - nop(); // $line-nested.4$ - } // $line-nested.5$ - } // $line-nested.6$ - } - - private static void emptyTry() { - try { - // empty - } finally { // $line-emptyTry.0$ - nop(); // $line-emptyTry.1$ - } // $line-emptyTry.2$ - } - - @SuppressWarnings("finally") - private static void alwaysCompletesAbruptly() { - try { - nop(); - } finally { // $line-alwaysCompletesAbruptly.0$ - return; // $line-alwaysCompletesAbruptly.1$ - } // $line-alwaysCompletesAbruptly.2$ - } - - public static void main(String[] args) { - example(false); - try { - example(true); - } catch (Exception ignore) { - } - - breakStatement(); - - catchNotExecuted(); - - emptyCatch(); - - twoRegions(); - - nested(); - - emptyTry(); - - alwaysCompletesAbruptly(); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synchronized.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synchronized.java deleted file mode 100644 index b2d503f8..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synchronized.java +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.ex; -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -import org.jacoco.core.test.validation.targets.Stubs.StubException; - -/** - * This test target is a synchronized statement. - */ -public class Synchronized { - - private static final Object lock = new Object(); - - private static void normal() { - nop(); // $line-before$ - synchronized (lock) { // $line-monitorEnter$ - nop(); // $line-body$ - } // $line-monitorExit$ - nop(); // $line-after$ - } - - private static void explicitException() { - synchronized (lock) { // $line-explicitException.monitorEnter$ - throw new StubException(); // $line-explicitException.exception$ - } // $line-explicitException.monitorExit$ - } - - private static void implicitException() { - synchronized (lock) { // $line-implicitException.monitorEnter$ - ex(); // $line-implicitException.exception$ - } // $line-implicitException.monitorExit$ - } - - public static void main(String[] args) { - normal(); - - try { - explicitException(); - } catch (StubException e) { - } - - try { - implicitException(); - } catch (StubException e) { - } - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synthetic.java b/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synthetic.java deleted file mode 100644 index 6e2f6266..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/filter/targets/Synthetic.java +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -/** - * This test target is synthetic methods. - */ -public class Synthetic { // $line-classdef$ - - private static int counter; // $line-field$ - - /** - * {@link org.jacoco.core.test.validation.targets.Target06 Default - * constructor will refer to a line of class definition}, so that we define - * constructor explicitly in order to verify that we filter all other - * constructions here that might refer to line of class definition. - */ - private Synthetic() { - } - - static class Inner extends Synthetic { // $line-inner.classdef$ - - Inner() { - } - - /** - * Access to private field of outer class causes creation of synthetic - * methods in it. In case of javac those methods refer to the line of - * outer class definition, in case of ECJ - to the line of field. - */ - private static void inc() { - counter = counter + 2; - } - - /** - * Difference of return type with overridden method causes creation of - * synthetic bridge method in this class. In case of javac this method - * refers to the line of inner class definition, in case of EJC - to the - * first line of file. - */ - @Override - public String get() { - return null; - } - } - - public Object get() { - return null; - } - - public static void main(String[] args) { - Inner.inc(); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/AnnotationInitializerTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/AnnotationInitializerTest.java deleted file mode 100644 index 60a38339..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/AnnotationInitializerTest.java +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.AnnotationInitializer; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * Test of initializer in annotations. - */ -public class AnnotationInitializerTest extends ValidationTestBase { - - public AnnotationInitializerTest() { - super(AnnotationInitializer.class); - } - - @Override - protected void run(Class<?> targetClass) throws Exception { - // Instrumentation should not add members, - // otherwise sun.reflect.annotation.AnnotationInvocationHandler - // can throw java.lang.annotation.AnnotationFormatError - assertEquals(1, targetClass.getDeclaredFields().length); - assertEquals(1, targetClass.getDeclaredMethods().length); - - // Force initialization - targetClass.getField("CONST").get(null); - } - - @Test - public void testCoverageResult() { - assertLine("const", ICounter.FULLY_COVERED); - assertLine("value", ICounter.EMPTY); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/BadCycleClassTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/BadCycleClassTest.java deleted file mode 100644 index aa646ddf..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/BadCycleClassTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.BadCycleClass; -import org.junit.Test; - -/** - * Test of "bad cycles" with classes. - */ -public class BadCycleClassTest extends ValidationTestBase { - - public BadCycleClassTest() throws Exception { - super(BadCycleClass.class); - } - - @Test - public void test() throws Exception { - assertLine("childinit", ICounter.FULLY_COVERED); - assertLine("childsomeMethod", ICounter.FULLY_COVERED); - assertLine("childclinit", ICounter.FULLY_COVERED); - - // The cycle causes a constructor and instance method to be called - // before the static initializer of a class: - assertLogEvents("childinit", "childsomeMethod", "childclinit", - "childinit"); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/BooleanExpressionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/BooleanExpressionsTest.java deleted file mode 100644 index 64dee474..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/BooleanExpressionsTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target02; -import org.junit.Test; - -/** - * Tests of basic Java boolean expressions. - */ -public class BooleanExpressionsTest extends ValidationTestBase { - - public BooleanExpressionsTest() { - super(Target02.class); - } - - @Test - public void testCoverageResult() { - - // 1. Boolean comparison result (one case) - assertLine("booleancmp1", ICounter.PARTLY_COVERED, 1, 1); - - // 2. Boolean comparison result (both cases) - assertLine("booleancmp2", ICounter.FULLY_COVERED, 0, 2); - - // 3. And - assertLine("andFF", ICounter.FULLY_COVERED, 1, 1); - assertLine("andFT", ICounter.FULLY_COVERED, 1, 1); - assertLine("andTF", ICounter.FULLY_COVERED, 1, 1); - assertLine("andTT", ICounter.FULLY_COVERED, 1, 1); - - // 4. Conditional And - assertLine("conditionalandFF", ICounter.PARTLY_COVERED, 3, 1); - assertLine("conditionalandFT", ICounter.PARTLY_COVERED, 3, 1); - assertLine("conditionalandTF", ICounter.FULLY_COVERED, 2, 2); - assertLine("conditionalandTT", ICounter.FULLY_COVERED, 2, 2); - - // 5. Or - assertLine("orFF", ICounter.FULLY_COVERED, 1, 1); - assertLine("orFT", ICounter.FULLY_COVERED, 1, 1); - assertLine("orTF", ICounter.FULLY_COVERED, 1, 1); - assertLine("orTT", ICounter.FULLY_COVERED, 1, 1); - - // 6. Conditional Or - assertLine("conditionalorFF", ICounter.FULLY_COVERED, 2, 2); - assertLine("conditionalorFT", ICounter.FULLY_COVERED, 2, 2); - assertLine("conditionalorTF", ICounter.PARTLY_COVERED, 3, 1); - assertLine("conditionalorTT", ICounter.PARTLY_COVERED, 3, 1); - - // 7. Exclusive Or - assertLine("xorFF", ICounter.FULLY_COVERED, 1, 1); - assertLine("xorFT", ICounter.FULLY_COVERED, 1, 1); - assertLine("xorTF", ICounter.FULLY_COVERED, 1, 1); - assertLine("xorTT", ICounter.FULLY_COVERED, 1, 1); - - // 8. Conditional Operator - assertLine("condT", ICounter.PARTLY_COVERED, 1, 1); - assertLine("condF", ICounter.PARTLY_COVERED, 1, 1); - - // 9. Not (one case) - assertLine("notT", ICounter.PARTLY_COVERED, 1, 1); - assertLine("notF", ICounter.PARTLY_COVERED, 1, 1); - - // 10. Not (both cases) - assertLine("notTF", ICounter.FULLY_COVERED, 0, 2); - - } - -} 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 deleted file mode 100644 index 87d78a21..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java +++ /dev/null @@ -1,195 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import static org.junit.Assert.assertEquals; -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import static org.objectweb.asm.Opcodes.ACC_SUPER; -import static org.objectweb.asm.Opcodes.ALOAD; -import static org.objectweb.asm.Opcodes.F_NEW; -import static org.objectweb.asm.Opcodes.IFEQ; -import static org.objectweb.asm.Opcodes.ILOAD; -import static org.objectweb.asm.Opcodes.INVOKESPECIAL; -import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; -import static org.objectweb.asm.Opcodes.POP; -import static org.objectweb.asm.Opcodes.RETURN; -import static org.objectweb.asm.Opcodes.V1_1; -import static org.objectweb.asm.Opcodes.V1_2; -import static org.objectweb.asm.Opcodes.V1_3; -import static org.objectweb.asm.Opcodes.V1_4; -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 static org.objectweb.asm.Opcodes.V1_8; -import static org.objectweb.asm.Opcodes.V9; - -import java.io.IOException; - -import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.internal.BytecodeVersion; -import org.jacoco.core.internal.instr.InstrSupport; -import org.jacoco.core.runtime.IRuntime; -import org.jacoco.core.runtime.SystemPropertiesRuntime; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -/** - * Test class inserted stackmap frames for different class file versions. - */ -public class ClassFileVersionsTest { - - @Test - public void test_1_1() throws IOException { - testVersion(V1_1, false); - } - - @Test - public void test_1_2() throws IOException { - testVersion(V1_2, false); - } - - @Test - public void test_1_3() throws IOException { - testVersion(V1_3, false); - } - - @Test - public void test_1_4() throws IOException { - testVersion(V1_4, false); - } - - @Test - public void test_1_5() throws IOException { - testVersion(V1_5, false); - } - - @Test - public void test_1_6() throws IOException { - testVersion(V1_6, true); - } - - @Test - public void test_1_7() throws IOException { - testVersion(V1_7, true); - } - - @Test - public void test_1_8() throws IOException { - testVersion(V1_8, true); - } - - @Test - public void test_9() throws IOException { - testVersion(V9, true); - } - - @Test - public void test_10() throws IOException { - testVersion(BytecodeVersion.V10, true); - } - - private void testVersion(int version, boolean frames) throws IOException { - final byte[] original = createClass(version, frames); - - IRuntime runtime = new SystemPropertiesRuntime(); - Instrumenter instrumenter = new Instrumenter(runtime); - byte[] instrumented = instrumenter.instrument(original, "TestTarget"); - - assertFrames(instrumented, frames); - } - - private void assertFrames(byte[] source, final boolean expected) { - int version = BytecodeVersion.get(source); - source = BytecodeVersion.downgradeIfNeeded(version, source); - new ClassReader(source) - .accept(new ClassVisitor(InstrSupport.ASM_API_VERSION) { - - @Override - public MethodVisitor visitMethod(int access, String name, - String desc, String signature, - String[] exceptions) { - return new MethodVisitor(InstrSupport.ASM_API_VERSION) { - boolean frames = false; - - @Override - public void visitFrame(int type, int nLocal, - Object[] local, int nStack, - Object[] stack) { - frames = true; - } - - @Override - public void visitEnd() { - assertEquals(Boolean.valueOf(expected), - Boolean.valueOf(frames)); - } - }; - } - }, 0); - } - - /** - * Creates a class that requires a frame before the return statement. Also - * for this class instrumentation should insert another frame. - * - * <code><pre> - * public class Sample { - * public Sample(boolean b){ - * if(b){ - * toString(); - * } - * return; - * } - * } - * </pre></code> - */ - private byte[] createClass(int version, boolean frames) { - - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - - cw.visit(version, ACC_PUBLIC + ACC_SUPER, "org/jacoco/test/Sample", - null, "java/lang/Object", null); - - mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Z)V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", - false); - mv.visitVarInsn(ILOAD, 1); - Label l1 = new Label(); - mv.visitJumpInsn(IFEQ, l1); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitInsn(POP); - mv.visitLabel(l1); - if (frames) { - mv.visitFrame(F_NEW, 2, - new Object[] { "org/jacoco/test/Sample", Opcodes.INTEGER }, - 0, new Object[] {}); - } - mv.visitInsn(RETURN); - mv.visitMaxs(1, 2); - mv.visitEnd(); - - cw.visitEnd(); - - return cw.toByteArray(); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassInitializerTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassInitializerTest.java deleted file mode 100644 index f87e705c..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ClassInitializerTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target05; -import org.junit.Test; - -/** - * Tests of static initializer in classes. - */ -public class ClassInitializerTest extends ValidationTestBase { - - public ClassInitializerTest() { - super(Target05.class); - } - - @Test - public void testCoverageResult() { - - assertLine("const1", ICounter.EMPTY); - assertLine("const2", ICounter.EMPTY); - - assertLine("const3", ICounter.FULLY_COVERED); - assertLine("const4", ICounter.FULLY_COVERED); - - assertLine("field1", ICounter.FULLY_COVERED); - assertLine("field2", ICounter.FULLY_COVERED); - assertLine("field3", ICounter.FULLY_COVERED); - assertLine("field4", ICounter.FULLY_COVERED); - - assertLine("staticblock", ICounter.FULLY_COVERED); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ControlStructuresTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ControlStructuresTest.java deleted file mode 100644 index 37db4c14..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ControlStructuresTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target01; -import org.junit.Test; - -/** - * Tests of basic Java control structures. - */ -public class ControlStructuresTest extends ValidationTestBase { - - public ControlStructuresTest() { - super(Target01.class); - } - - @Test - public void testCoverageResult() { - - // 1. Direct unconditional execution - assertLine("unconditional", ICounter.FULLY_COVERED); - - // 2. Missed if block - assertLine("iffalse", ICounter.FULLY_COVERED, 1, 1); - assertLine("missedif", ICounter.NOT_COVERED); - assertLine("executedelse", ICounter.FULLY_COVERED); - - // 3. Executed if block - assertLine("iftrue", ICounter.FULLY_COVERED, 1, 1); - assertLine("executedif", ICounter.FULLY_COVERED); - assertLine("missedelse", ICounter.NOT_COVERED); - - // 4. Missed while block - assertLine("whilefalse", ICounter.FULLY_COVERED, 1, 1); - assertLine("missedwhile", ICounter.NOT_COVERED); - - // 5. Always true while block - assertLine("whiletrue", ICounter.FULLY_COVERED, 1, 1); - - // 6. Executed while block - assertLine("whiletruefalse", ICounter.FULLY_COVERED, 0, 2); - assertLine("executedwhile", ICounter.FULLY_COVERED); - - // 7. Executed do while block - assertLine("executeddowhile", ICounter.FULLY_COVERED); - assertLine("executeddowhilefalse", ICounter.FULLY_COVERED, 1, 1); - - // 8. Missed for block - assertLine("missedforincrementer", ICounter.PARTLY_COVERED, 1, 1); - assertLine("missedfor", ICounter.NOT_COVERED); - - // 9. Executed for block - assertLine("executedforincrementer", ICounter.FULLY_COVERED, 0, 2); - assertLine("executedfor", ICounter.FULLY_COVERED); - - // 10. Missed for each block - assertLine("missedforeachincrementer", ICounter.PARTLY_COVERED, 1, 1); - assertLine("missedforeach", ICounter.NOT_COVERED); - - // 11. Executed for each block - assertLine("executedforeachincrementer", ICounter.FULLY_COVERED, 0, 2); - assertLine("executedforeach", ICounter.FULLY_COVERED); - - // 12. Table switch with hit - assertLine("tswitch1", ICounter.FULLY_COVERED, 3, 1); - assertLine("tswitch1case1", ICounter.NOT_COVERED); - assertLine("tswitch1case2", ICounter.FULLY_COVERED); - assertLine("tswitch1case3", ICounter.NOT_COVERED); - assertLine("tswitch1default", ICounter.NOT_COVERED); - - // 13. Continued table switch with hit - assertLine("tswitch2", ICounter.FULLY_COVERED, 3, 1); - assertLine("tswitch2case1", ICounter.NOT_COVERED); - assertLine("tswitch2case2", ICounter.FULLY_COVERED); - assertLine("tswitch2case3", ICounter.FULLY_COVERED); - assertLine("tswitch2default", ICounter.FULLY_COVERED); - - // 14. Table switch without hit - assertLine("tswitch2", ICounter.FULLY_COVERED, 3, 1); - assertLine("tswitch3case1", ICounter.NOT_COVERED); - assertLine("tswitch3case2", ICounter.NOT_COVERED); - assertLine("tswitch3case3", ICounter.NOT_COVERED); - assertLine("tswitch3default", ICounter.FULLY_COVERED); - - // 15. Lookup switch with hit - assertLine("lswitch1", ICounter.FULLY_COVERED, 3, 1); - assertLine("lswitch1case1", ICounter.NOT_COVERED); - assertLine("lswitch1case2", ICounter.FULLY_COVERED); - assertLine("lswitch1case3", ICounter.NOT_COVERED); - assertLine("lswitch1default", ICounter.NOT_COVERED); - - // 16. Continued lookup switch with hit - assertLine("lswitch2", ICounter.FULLY_COVERED, 3, 1); - assertLine("lswitch2case1", ICounter.NOT_COVERED); - assertLine("lswitch2case2", ICounter.FULLY_COVERED); - assertLine("lswitch2case3", ICounter.FULLY_COVERED); - assertLine("lswitch2default", ICounter.FULLY_COVERED); - - // 17. Lookup switch without hit - assertLine("lswitch3", ICounter.FULLY_COVERED, 3, 1); - assertLine("lswitch3case1", ICounter.NOT_COVERED); - assertLine("lswitch3case2", ICounter.NOT_COVERED); - assertLine("lswitch3case3", ICounter.NOT_COVERED); - assertLine("lswitch3default", ICounter.FULLY_COVERED); - - // 18. Break statement - assertLine("executedbreak", ICounter.FULLY_COVERED); - assertLine("missedafterbreak", ICounter.NOT_COVERED); - - // 19. Continue statement - assertLine("executedcontinue", ICounter.FULLY_COVERED); - assertLine("missedaftercontinue", ICounter.NOT_COVERED); - - // 20. Conditional return statement - assertLine("conditionalreturn", ICounter.FULLY_COVERED); - assertLine("afterconditionalreturn", ICounter.NOT_COVERED); - - // 21. Implicit return - assertLine("implicitreturn", ICounter.FULLY_COVERED); - - // 22. Explicit return - assertLine("explicitreturn", ICounter.FULLY_COVERED); - assertLine("afterexplicitreturn", ICounter.EMPTY); - - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java deleted file mode 100644 index 122612ce..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java +++ /dev/null @@ -1,280 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; -import static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.util.Collection; - -import org.jacoco.core.analysis.Analyzer; -import org.jacoco.core.analysis.CoverageBuilder; -import org.jacoco.core.analysis.IClassCoverage; -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.analysis.IMethodCoverage; -import org.jacoco.core.data.ExecutionDataStore; -import org.jacoco.core.data.SessionInfoStore; -import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.internal.analysis.CounterImpl; -import org.jacoco.core.runtime.IRuntime; -import org.jacoco.core.runtime.RuntimeData; -import org.jacoco.core.runtime.SystemPropertiesRuntime; -import org.jacoco.core.test.TargetLoader; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Various tests for cyclomatic complexity of methods. - */ -public class CyclomaticComplexityTest { - - public interface Target { - public void test(int arg); - } - - private RuntimeData data; - private IRuntime runtime; - private byte[] bytes; - private Target target; - - @Before - public void setup() throws Exception { - data = new RuntimeData(); - runtime = new SystemPropertiesRuntime(); - runtime.startup(data); - } - - @After - public void teardown() { - runtime.shutdown(); - } - - public static class Simple implements Target { - public void test(int arg) { - nop(); - nop(); - nop(); - } - } - - @Test - public void testSimple1() throws Exception { - instrument(Simple.class); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(1, 0), complexity); - } - - @Test - public void testSimple2() throws Exception { - instrument(Simple.class); - target.test(0); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(0, 1), complexity); - } - - public static class If implements Target { - public void test(int arg) { - if (arg == 0) { - nop(); - } - } - } - - @Test - public void testIf1() throws Exception { - instrument(If.class); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(2, 0), complexity); - } - - @Test - public void testIf2() throws Exception { - instrument(If.class); - target.test(0); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(1, 1), complexity); - } - - @Test - public void testIf3() throws Exception { - instrument(If.class); - target.test(0); - target.test(1); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(0, 2), complexity); - } - - public static class TwoIf implements Target { - public void test(int arg) { - if (arg < 0) { - nop(); - } - if (arg > 0) { - nop(); - } - } - } - - @Test - public void testTwoIf1() throws Exception { - instrument(TwoIf.class); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(3, 0), complexity); - } - - @Test - public void testTwoIf2() throws Exception { - instrument(TwoIf.class); - target.test(-1); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(2, 1), complexity); - } - - @Test - public void testTwoIf3() throws Exception { - instrument(TwoIf.class); - target.test(-1); - target.test(0); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(1, 2), complexity); - } - - @Test - public void testTwoIf4() throws Exception { - instrument(TwoIf.class); - target.test(-1); - target.test(+1); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(0, 3), complexity); - } - - public static class NestedIf implements Target { - public void test(int arg) { - if (arg >= 0) { - if (arg == 0) { - nop(); - } - nop(); - } - } - } - - @Test - public void testNestedIf1() throws Exception { - instrument(NestedIf.class); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(3, 0), complexity); - } - - @Test - public void testNestedIf2() throws Exception { - instrument(NestedIf.class); - target.test(-1); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(2, 1), complexity); - } - - @Test - public void testNestedIf3() throws Exception { - instrument(NestedIf.class); - target.test(-1); - target.test(0); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(1, 2), complexity); - } - - @Test - public void testNestedIf4() throws Exception { - instrument(NestedIf.class); - target.test(-1); - target.test(0); - target.test(+1); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(0, 3), complexity); - } - - public static class Switch implements Target { - public void test(int arg) { - switch (arg) { - case 1: - nop(); - break; - case 2: - nop(); - break; - } - } - } - - @Test - public void testSwitch1() throws Exception { - instrument(Switch.class); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(3, 0), complexity); - } - - @Test - public void testSwitch2() throws Exception { - instrument(Switch.class); - target.test(0); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(2, 1), complexity); - } - - @Test - public void testSwitch3() throws Exception { - instrument(Switch.class); - target.test(0); - target.test(1); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(1, 2), complexity); - } - - @Test - public void testSwitch4() throws Exception { - instrument(Switch.class); - target.test(0); - target.test(1); - target.test(2); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(0, 3), complexity); - } - - private void instrument(final Class<? extends Target> clazz) - throws Exception { - bytes = TargetLoader.getClassDataAsBytes(clazz); - final byte[] instrumented = new Instrumenter(runtime).instrument(bytes, - "TestTarget"); - final TargetLoader loader = new TargetLoader(); - target = (Target) loader.add(clazz, instrumented).newInstance(); - } - - private ICounter analyze() throws IOException { - final CoverageBuilder builder = new CoverageBuilder(); - final ExecutionDataStore store = new ExecutionDataStore(); - data.collect(store, new SessionInfoStore(), false); - final Analyzer analyzer = new Analyzer(store, builder); - analyzer.analyzeClass(bytes, "TestTarget"); - final Collection<IClassCoverage> classes = builder.getClasses(); - assertEquals(1, classes.size(), 0.0); - final IClassCoverage classCoverage = classes.iterator().next(); - for (final IMethodCoverage m : classCoverage.getMethods()) { - if (m.getName().equals("test")) { - return m.getComplexityCounter(); - } - } - throw new AssertionError("No test() method."); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java deleted file mode 100644 index fbd9e540..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.EnumImplicitMethods; -import org.junit.Test; - -/** - * Test of an implicit methods and static initializer in enums. - */ -public class EnumImplicitMethodsTest extends ValidationTestBase { - - public EnumImplicitMethodsTest() { - super(EnumImplicitMethods.class); - } - - @Test - public void testCoverageResult() { - assertMethodCount(5); - - assertLine("classdef", ICounter.FULLY_COVERED); - assertLine("customValueOfMethod", ICounter.NOT_COVERED); - assertLine("customValuesMethod", ICounter.NOT_COVERED); - - assertLine("const", ICounter.PARTLY_COVERED); - assertLine("staticblock", ICounter.FULLY_COVERED); - assertLine("super", ICounter.FULLY_COVERED); - assertLine("constructor", ICounter.FULLY_COVERED); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ExceptionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ExceptionsTest.java deleted file mode 100644 index c68bd374..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ExceptionsTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target03; -import org.junit.Test; - -/** - * Tests of exception based control flow. - */ -public class ExceptionsTest extends ValidationTestBase { - - public ExceptionsTest() { - super(Target03.class); - } - - @Test - public void testCoverageResult() { - - // 0. Implicit NullPointerException - // Currently no coverage at all, as we don't see when a block aborts - // somewhere in the middle. - assertLine("implicitNullPointerException.before", ICounter.NOT_COVERED); - assertLine("implicitNullPointerException.exception", - ICounter.NOT_COVERED); - assertLine("implicitNullPointerException.after", ICounter.NOT_COVERED); - - // 1. Implicit Exception - assertLine("implicitException.before", ICounter.FULLY_COVERED); - assertLine("implicitException.exception", ICounter.NOT_COVERED); - assertLine("implicitException.after", ICounter.NOT_COVERED); - - // 2. Explicit Exception - // Full coverage, as we recognize throw statements as block boundaries. - assertLine("explicitException.before", ICounter.FULLY_COVERED); - assertLine("explicitException.throw", ICounter.FULLY_COVERED); - - // 3. Try/Catch Block Without Exception Thrown - assertLine("noExceptionTryCatch.beforeBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionTryCatch.tryBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionTryCatch.catch", - isJDKCompiler ? ICounter.NOT_COVERED : ICounter.PARTLY_COVERED); - assertLine("noExceptionTryCatch.catchBlock", ICounter.NOT_COVERED); - assertLine("noExceptionTryCatch.catchBlockEnd", - isJDKCompiler ? ICounter.FULLY_COVERED : ICounter.EMPTY); - assertLine("noExceptionTryCatch.afterBlock", ICounter.FULLY_COVERED); - - // 4. Try/Catch Block With Exception Thrown Implicitly - assertLine("implicitExceptionTryCatch.beforeBlock", - ICounter.FULLY_COVERED); - assertLine("implicitExceptionTryCatch.before", ICounter.FULLY_COVERED); - assertLine("implicitExceptionTryCatch.exception", ICounter.NOT_COVERED); - assertLine("implicitExceptionTryCatch.after", ICounter.NOT_COVERED); - assertLine("implicitExceptionTryCatch.catch", isJDKCompiler - ? ICounter.FULLY_COVERED : ICounter.PARTLY_COVERED); - assertLine("implicitExceptionTryCatch.catchBlock", - ICounter.FULLY_COVERED); - assertLine("implicitExceptionTryCatch.catchBlockEnd", - isJDKCompiler ? ICounter.NOT_COVERED : ICounter.EMPTY); - assertLine("implicitExceptionTryCatch.afterBlock", - ICounter.FULLY_COVERED); - - // 5. Try/Catch Block With Exception Thrown Implicitly After Condition - // As the try/catch block is entered at one branch of the condition - // should be marked as executed - assertLine("implicitExceptionTryCatchAfterCondition.condition", - ICounter.FULLY_COVERED, 1, 1); - assertLine("implicitExceptionTryCatchAfterCondition.exception", - ICounter.NOT_COVERED); - assertLine("implicitExceptionTryCatchAfterCondition.catchBlock", - ICounter.FULLY_COVERED); - - // 6. Try/Catch Block With Exception Thrown Explicitly - assertLine("explicitExceptionTryCatch.beforeBlock", - ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.before", ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.throw", ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.catch", ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.catchBlock", - ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.catchBlockEnd", ICounter.EMPTY); - assertLine("explicitExceptionTryCatch.afterBlock", - ICounter.FULLY_COVERED); - - // 7. Finally Block Without Exception Thrown - assertLine("noExceptionFinally.beforeBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionFinally.tryBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionFinally.finally", - isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); - assertLine("noExceptionFinally.finallyBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionFinally.finallyBlockEnd", ICounter.EMPTY); - assertLine("noExceptionFinally.afterBlock", ICounter.FULLY_COVERED); - - // 8. Finally Block With Implicit Exception - assertLine("implicitExceptionFinally.beforeBlock", - ICounter.FULLY_COVERED); - assertLine("implicitExceptionFinally.before", ICounter.FULLY_COVERED); - assertLine("implicitExceptionFinally.exception", ICounter.NOT_COVERED); - assertLine("implicitExceptionFinally.after", ICounter.NOT_COVERED); - assertLine("implicitExceptionFinally.finally", - isJDKCompiler ? ICounter.EMPTY : ICounter.NOT_COVERED); - assertLine("implicitExceptionFinally.finallyBlock", - ICounter.FULLY_COVERED); - assertLine("implicitExceptionFinally.finallyBlockEnd", ICounter.EMPTY); - assertLine("implicitExceptionFinally.afterBlock", ICounter.NOT_COVERED); - - // 9. Finally Block With Exception Thrown Explicitly - assertLine("explicitExceptionFinally.beforeBlock", - ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.before", ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.throw", ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.finally", - isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.finallyBlock", - ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.finallyBlockEnd", - isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.afterBlock", ICounter.EMPTY); - - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ExplicitInitialFrameTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ExplicitInitialFrameTest.java deleted file mode 100644 index 1c0a02f1..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ExplicitInitialFrameTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target11; -import org.junit.Test; - -/** - * Test for a methods having a explicit initial frame. - */ -public class ExplicitInitialFrameTest extends ValidationTestBase { - - public ExplicitInitialFrameTest() { - super(Target11.class); - } - - @Test - public void testCoverageResult() { - - assertLine("dowhilebody", ICounter.FULLY_COVERED); - - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/FieldInitializationInTwoConstructorsTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/FieldInitializationInTwoConstructorsTest.java deleted file mode 100644 index 6896bf6d..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/FieldInitializationInTwoConstructorsTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target09; -import org.junit.Test; - -/** - * Test of field initialization in two constructors. - */ -public class FieldInitializationInTwoConstructorsTest extends - ValidationTestBase { - - public FieldInitializationInTwoConstructorsTest() { - super(Target09.class); - } - - @Test - public void testCoverageResult() { - - assertLine("field1", ICounter.PARTLY_COVERED); - assertLine("field2", ICounter.PARTLY_COVERED); - assertLine("constr1", ICounter.FULLY_COVERED); - assertLine("constr2", ICounter.NOT_COVERED); - - } - -} 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 deleted file mode 100644 index 9ab062b6..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/FramesTest.java +++ /dev/null @@ -1,179 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; - -import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.internal.BytecodeVersion; -import org.jacoco.core.internal.instr.InstrSupport; -import org.jacoco.core.runtime.IRuntime; -import org.jacoco.core.runtime.SystemPropertiesRuntime; -import org.jacoco.core.test.TargetLoader; -import org.jacoco.core.test.validation.targets.Target01; -import org.jacoco.core.test.validation.targets.Target02; -import org.jacoco.core.test.validation.targets.Target03; -import org.jacoco.core.test.validation.targets.Target04; -import org.jacoco.core.test.validation.targets.Target05; -import org.jacoco.core.test.validation.targets.Target06; -import org.jacoco.core.test.validation.targets.Target07; -import org.jacoco.core.test.validation.targets.Target08; -import org.jacoco.core.test.validation.targets.Target09; -import org.jacoco.core.test.validation.targets.Target10; -import org.jacoco.core.test.validation.targets.Target11; -import org.jacoco.core.test.validation.targets.Target12; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.util.TraceClassVisitor; - -/** - * Tests whether stackmap frames are correctly adjusted. - */ -public class FramesTest { - - /** - * Stack sizes calculated for instrumented classes might be sometimes bigger - * than actually needed. This is an acceptable tradeoff in favor of keeping - * track of the actual stack sizes. For test assertions we need to replace - * max stack sizes with constant value. - */ - private static class MaxStackEliminator extends ClassVisitor { - public MaxStackEliminator(ClassVisitor cv) { - super(InstrSupport.ASM_API_VERSION, cv); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, - String signature, String[] exceptions) { - final MethodVisitor mv = super.visitMethod(access, name, desc, - signature, exceptions); - return new MethodVisitor(InstrSupport.ASM_API_VERSION, mv) { - @Override - public void visitMaxs(int maxStack, int maxLocals) { - super.visitMaxs(-1, maxLocals); - } - }; - } - } - - private void testFrames(Class<?> target) throws IOException { - testFrames(TargetLoader.getClassDataAsBytes(target)); - } - - private void testFrames(byte[] source) throws IOException { - IRuntime runtime = new SystemPropertiesRuntime(); - Instrumenter instrumenter = new Instrumenter(runtime); - source = calculateFrames(source); - byte[] actual = instrumenter.instrument(source, "TestTarget"); - byte[] expected = calculateFrames(actual); - - assertEquals(dump(expected), dump(actual)); - } - - private byte[] calculateFrames(byte[] source) { - source = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(source), - source); - - ClassReader rc = new ClassReader(source); - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - - // Adjust Version to 1.6 to enable frames: - rc.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, cw) { - - @Override - public void visit(int version, int access, String name, - String signature, String superName, String[] interfaces) { - super.visit(Opcodes.V1_6, access, name, signature, superName, - interfaces); - } - }, 0); - return cw.toByteArray(); - } - - private String dump(byte[] bytes) { - final StringWriter buffer = new StringWriter(); - final PrintWriter writer = new PrintWriter(buffer); - new ClassReader(bytes).accept( - new MaxStackEliminator(new TraceClassVisitor(writer)), - ClassReader.EXPAND_FRAMES); - return buffer.toString(); - } - - @Test - public void testTarget01() throws IOException { - testFrames(Target01.class); - } - - @Test - public void testTarget02() throws IOException { - testFrames(Target02.class); - } - - @Test - public void testTarget03() throws IOException { - testFrames(Target03.class); - } - - @Test - public void testTarget04() throws IOException { - testFrames(Target04.class); - } - - @Test - public void testTarget05() throws IOException { - testFrames(Target05.class); - } - - @Test - public void testTarget06() throws IOException { - testFrames(Target06.class); - } - - @Test - public void testTarget07() throws IOException { - testFrames(Target07.class); - } - - @Test - public void testTarget08() throws IOException { - testFrames(Target08.class); - } - - @Test - public void testTarget09() throws IOException { - testFrames(Target09.class); - } - - @Test - public void testTarget10() throws IOException { - testFrames(Target10.class); - } - - @Test - public void testTarget11() throws IOException { - testFrames(Target11.class); - } - - @Test - public void testTarget12() throws IOException { - testFrames(Target12.class); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ImplicitDefaultConstructorTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ImplicitDefaultConstructorTest.java deleted file mode 100644 index 09872e8d..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ImplicitDefaultConstructorTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target06; -import org.junit.Test; - -/** - * Test of a implicit default constructor. - * - * @see PrivateEmptyDefaultConstructorTest - */ -public class ImplicitDefaultConstructorTest extends ValidationTestBase { - - public ImplicitDefaultConstructorTest() { - super(Target06.class); - } - - @Test - public void testCoverageResult() { - - assertLine("classdef", ICounter.FULLY_COVERED); - - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ImplicitFieldInitializationTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ImplicitFieldInitializationTest.java deleted file mode 100644 index 769593d7..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ImplicitFieldInitializationTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target08; -import org.junit.Test; - -/** - * Test of a implicit field initialization. - */ -public class ImplicitFieldInitializationTest extends ValidationTestBase { - - public ImplicitFieldInitializationTest() { - super(Target08.class); - } - - @Test - public void testCoverageResult() { - - assertLine("classdef", ICounter.FULLY_COVERED); - assertLine("field1", ICounter.EMPTY); - assertLine("field2", ICounter.FULLY_COVERED); - assertLine("field3", ICounter.EMPTY); - assertLine("field4", ICounter.FULLY_COVERED); - - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/InterfaceClassInitializerTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/InterfaceClassInitializerTest.java deleted file mode 100644 index 5675dbb0..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/InterfaceClassInitializerTest.java +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target04; -import org.junit.Test; - -/** - * Tests of static initializer in interfaces. - */ -public class InterfaceClassInitializerTest extends ValidationTestBase { - - public InterfaceClassInitializerTest() { - super(Target04.class); - } - - @Override - protected void run(final Class<?> targetClass) throws Exception { - // Force class initialization - targetClass.getField("CONST1").get(null); - } - - @Test - public void testCoverageResult() { - - assertLine("const1", ICounter.EMPTY); - assertLine("const2", ICounter.EMPTY); - - assertLine("const3", ICounter.FULLY_COVERED); - assertLine("const4", ICounter.FULLY_COVERED); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java deleted file mode 100644 index 1d144b7d..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target07; -import org.junit.Test; - -/** - * Test of a private empty default constructor. - * - * @see ImplicitDefaultConstructorTest - */ -public class PrivateEmptyDefaultConstructorTest extends ValidationTestBase { - - public PrivateEmptyDefaultConstructorTest() { - super(Target07.class); - } - - @Test - public void testCoverageResult() { - - assertLine("classdef", ICounter.EMPTY); - assertLine("super", ICounter.EMPTY); - assertLine("constructor", ICounter.EMPTY); - - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ProbesBeforeSuperConstructorTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ProbesBeforeSuperConstructorTest.java deleted file mode 100644 index 88b1ae54..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ProbesBeforeSuperConstructorTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target10; -import org.junit.Test; - -/** - * Test of probes before the super constructor call. - */ -public class ProbesBeforeSuperConstructorTest extends ValidationTestBase { - - public ProbesBeforeSuperConstructorTest() { - super(Target10.class); - } - - @Test - public void testCoverageResult() { - - assertLine("super", ICounter.PARTLY_COVERED, 3, 1); - - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java deleted file mode 100644 index fe6d134a..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java +++ /dev/null @@ -1,171 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.internal.BytecodeVersion; -import org.jacoco.core.internal.instr.InstrSupport; -import org.jacoco.core.runtime.IRuntime; -import org.jacoco.core.runtime.RuntimeData; -import org.jacoco.core.runtime.SystemPropertiesRuntime; -import org.jacoco.core.test.TargetLoader; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -public class ResizeInstructionsTest { - - private final IRuntime runtime = new SystemPropertiesRuntime(); - private final Instrumenter instrumenter = new Instrumenter(runtime); - - private boolean computedCommonSuperClass = false; - - @Before - public void setup() throws Exception { - runtime.startup(new RuntimeData()); - } - - @After - public void teardown() { - runtime.shutdown(); - } - - private class Inner { - } - - /** - * Test of ASM bug - * <a href="https://gitlab.ow2.org/asm/asm/issues/317792">#317792</a>. - */ - @Test - public void should_not_loose_InnerClasses_attribute() throws Exception { - byte[] source = TargetLoader.getClassDataAsBytes(Inner.class); - final int version = BytecodeVersion.get(source); - source = BytecodeVersion.downgradeIfNeeded(version, source); - - final ClassReader cr = new ClassReader(source); - final ClassWriter cw = new ClassWriter(0); - cr.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, cw) { - @Override - public void visitEnd() { - final MethodVisitor mv = cv.visitMethod(0, "m", "()V", null, - null); - mv.visitCode(); - addCauseOfResizeInstructions(mv); - mv.visitInsn(Opcodes.NOP); - mv.visitMaxs(2, 1); - mv.visitEnd(); - super.visitEnd(); - } - }, 0); - source = cw.toByteArray(); - BytecodeVersion.set(source, version); - - final byte[] bytes = instrumenter.instrument(source, ""); - - final TargetLoader targetLoader = new TargetLoader(); - final Class<?> outer = targetLoader.add(ResizeInstructionsTest.class, - TargetLoader.getClassDataAsBytes(ResizeInstructionsTest.class)); - final Class<?> inner = targetLoader.add(Inner.class, bytes); - assertSame(outer, inner.getEnclosingClass()); - assertNotNull(inner.getEnclosingClass()); - assertSame(outer, inner.getDeclaringClass()); - assertNotNull(inner.getDeclaringClass()); - } - - /** - * Test of ASM bug - * <a href= "https://gitlab.ow2.org/asm/asm/issues/317630">#317630</a> that - * caused {@code java.lang.ClassNotFoundException}. - */ - @Test - public void should_not_require_computation_of_common_superclass() - throws Exception { - final String className = "Example"; - - final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES) { - @Override - protected String getCommonSuperClass(final String type1, - final String type2) { - computedCommonSuperClass |= className.equals(type1) - || className.equals(type2); - return "java/lang/Object"; - } - }; - cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, className, null, - "java/lang/Object", null); - final MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "m", "()V", - null, null); - mv.visitCode(); - addCauseOfResizeInstructions(mv); - addCauseOfGetCommonSuperClass(mv); - mv.visitMaxs(1, 1); - mv.visitEnd(); - cw.visitEnd(); - final byte[] original = cw.toByteArray(); - assertTrue(computedCommonSuperClass); - new TargetLoader().add(className, original); - - final byte[] instrumented = instrumenter.instrument(original, - className); - new TargetLoader().add(className, instrumented); - } - - /** - * Adds code that requires - * {@link ClassWriter#getCommonSuperClass(String, String)}. - * - * <pre> - * Object o = this; - * while (true) { - * o = (Integer) null; - * } - * </pre> - */ - private static void addCauseOfGetCommonSuperClass(final MethodVisitor mv) { - mv.visitVarInsn(Opcodes.ALOAD, 0); - mv.visitVarInsn(Opcodes.ASTORE, 1); - Label label = new Label(); - mv.visitLabel(label); - mv.visitInsn(Opcodes.ACONST_NULL); - mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Integer"); - mv.visitVarInsn(Opcodes.ASTORE, 1); - mv.visitJumpInsn(Opcodes.GOTO, label); - } - - /** - * Adds code that triggers usage of - * {@link org.objectweb.asm.MethodWriter#COMPUTE_INSERTED_FRAMES} during - * instrumentation. - */ - private static void addCauseOfResizeInstructions(final MethodVisitor mv) { - mv.visitInsn(Opcodes.ICONST_0); - mv.visitInsn(Opcodes.ICONST_1); - final Label target = new Label(); - mv.visitJumpInsn(Opcodes.IFLE, target); - for (int i = 0; i < Short.MAX_VALUE; i++) { - mv.visitInsn(Opcodes.NOP); - } - mv.visitLabel(target); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StructuredLockingTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StructuredLockingTest.java deleted file mode 100644 index 823ab787..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StructuredLockingTest.java +++ /dev/null @@ -1,202 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.internal.BytecodeVersion; -import org.jacoco.core.runtime.IRuntime; -import org.jacoco.core.runtime.SystemPropertiesRuntime; -import org.jacoco.core.test.TargetLoader; -import org.jacoco.core.test.validation.targets.Target12; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; -import org.objectweb.asm.tree.TryCatchBlockNode; -import org.objectweb.asm.tree.VarInsnNode; -import org.objectweb.asm.tree.analysis.Analyzer; -import org.objectweb.asm.tree.analysis.AnalyzerException; -import org.objectweb.asm.tree.analysis.BasicInterpreter; -import org.objectweb.asm.tree.analysis.BasicValue; -import org.objectweb.asm.tree.analysis.Frame; -import org.objectweb.asm.tree.analysis.Interpreter; - -/** - * Tests that the invariants specified in <a href= - * "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-2.html#jvms-2.11.10">chapter - * 2.11.10 of the JVM Spec</a> do also hold for instrumented classes. - * - * This is important because JIT compiler in HotSpot JVM ignores methods with - * unstructured locking, so that they executed by interpreter. Android Runtime - * also doesn't optimize such methods. - * - * TODO verification implemented here is incomplete - in particular it is unable - * to catch problem described in https://github.com/jacoco/jacoco/issues/626 - */ -public class StructuredLockingTest { - - @Test - public void testTarget12() throws Exception { - testMonitorExit(Target12.class); - } - - private void testMonitorExit(Class<?> target) throws Exception { - assertStructuredLocking(TargetLoader.getClassDataAsBytes(target)); - } - - private void assertStructuredLocking(byte[] source) throws Exception { - IRuntime runtime = new SystemPropertiesRuntime(); - Instrumenter instrumenter = new Instrumenter(runtime); - byte[] instrumented = instrumenter.instrument(source, "TestTarget"); - - final int version = BytecodeVersion.get(instrumented); - instrumented = BytecodeVersion.downgradeIfNeeded(version, instrumented); - - ClassNode cn = new ClassNode(); - new ClassReader(instrumented).accept(cn, 0); - for (MethodNode mn : cn.methods) { - assertStructuredLocking(cn.name, mn); - } - } - - private void assertStructuredLocking(String owner, MethodNode mn) - throws Exception { - Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>( - new BasicInterpreter()) { - - @Override - protected Frame<BasicValue> newFrame(int nLocals, int nStack) { - return new LockFrame(nLocals, nStack); - } - - @Override - protected Frame<BasicValue> newFrame(Frame<? extends BasicValue> src) { - return new LockFrame(src); - } - }; - - Frame<BasicValue>[] frames = analyzer.analyze(owner, mn); - - // Make sure no locks are left when method exits: - for (int i = 0; i < frames.length; i++) { - AbstractInsnNode insn = mn.instructions.get(i); - switch (insn.getOpcode()) { - case Opcodes.IRETURN: - case Opcodes.LRETURN: - case Opcodes.FRETURN: - case Opcodes.DRETURN: - case Opcodes.ARETURN: - case Opcodes.RETURN: - ((LockFrame) frames[i]).assertNoLock("Exit with lock"); - break; - case Opcodes.ATHROW: - List<TryCatchBlockNode> handlers = analyzer.getHandlers(i); - if (handlers == null || handlers.isEmpty()) { - ((LockFrame) frames[i]).assertNoLock("Exit with lock"); - } - break; - } - } - - // Only instructions protected by a catch-all handler can hold locks: - for (int i = 0; i < frames.length; i++) { - AbstractInsnNode insn = mn.instructions.get(i); - if (insn.getOpcode() > 0) { - boolean catchAll = false; - List<TryCatchBlockNode> handlers = analyzer.getHandlers(i); - if (handlers != null) { - for (TryCatchBlockNode node : handlers) { - catchAll |= node.type == null; - } - } - if (!catchAll) { - ((LockFrame) frames[i]) - .assertNoLock("No handlers for insn with lock"); - } - } - } - - } - - /** - * A Frame implementation that keeps track of the locking state. It is - * assumed that the monitor objects are stored in local variables. - */ - private static class LockFrame extends Frame<BasicValue> { - - Set<Integer> locks; - - public LockFrame(final int nLocals, final int nStack) { - super(nLocals, nStack); - locks = new HashSet<Integer>(); - } - - public LockFrame(Frame<? extends BasicValue> src) { - super(src); - } - - @Override - public Frame<BasicValue> init(Frame<? extends BasicValue> src) { - locks = new HashSet<Integer>(((LockFrame) src).locks); - return super.init(src); - } - - @Override - public void execute(AbstractInsnNode insn, - Interpreter<BasicValue> interpreter) throws AnalyzerException { - super.execute(insn, interpreter); - switch (insn.getOpcode()) { - case Opcodes.MONITORENTER: - // Lock is stored in a local variable: - enter(((VarInsnNode) insn.getPrevious()).var); - break; - case Opcodes.MONITOREXIT: - // Lock is stored in a local variable: - exit(((VarInsnNode) insn.getPrevious()).var); - break; - } - } - - void enter(int lock) { - assertTrue("multiple ENTER for lock " + lock, - locks.add(Integer.valueOf(lock))); - } - - void exit(int lock) { - assertTrue("invalid EXIT for lock " + lock, - locks.remove(Integer.valueOf(lock))); - } - - @Override - public boolean merge(Frame<? extends BasicValue> frame, - Interpreter<BasicValue> interpreter) throws AnalyzerException { - this.locks.addAll(((LockFrame) frame).locks); - return super.merge(frame, interpreter); - } - - void assertNoLock(String message) { - assertEquals(message, Collections.emptySet(), locks); - - } - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java index 6ab58594..b2853842 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java @@ -51,8 +51,6 @@ public abstract class ValidationTestBase { STATUS_NAME[ICounter.PARTLY_COVERED] = "PARTLY_COVERED"; } - private final String srcFolder; - private final Class<?> target; private ISourceFileCoverage sourceCoverage; @@ -61,20 +59,15 @@ public abstract class ValidationTestBase { private InstrumentingLoader loader; - protected ValidationTestBase(final String srcFolder, final Class<?> target) { - this.srcFolder = srcFolder; - this.target = target; - } - protected ValidationTestBase(final Class<?> target) { - this("src", target); + this.target = target; } @Before public void setup() throws Exception { final ExecutionDataStore store = execute(); analyze(store); - source = Source.getSourceFor(srcFolder, target); + source = Source.getSourceFor("src", target); } private ExecutionDataStore execute() throws Exception { diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/AnnotationInitializer.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/AnnotationInitializer.java deleted file mode 100644 index f7b9e0af..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/AnnotationInitializer.java +++ /dev/null @@ -1,23 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation.targets; - -/** - * This test target is an annotation with an initializer. - */ -public @interface AnnotationInitializer { - - Object CONST = new Object(); // $line-const$ - - int value() default 0; // $line-value$ - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/BadCycleClass.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/BadCycleClass.java deleted file mode 100644 index c1826646..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/BadCycleClass.java +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation.targets; - -public class BadCycleClass { - - public static class Base { - static final Child b = new Child(); - - static { - b.someMethod(); - } - } - - public static class Child extends Base { - - static { - Stubs.logEvent("childclinit"); // $line-childclinit$ - } - - public Child() { - Stubs.logEvent("childinit"); // $line-childinit$ - } - - void someMethod() { - Stubs.logEvent("childsomeMethod"); // $line-childsomeMethod$ - } - - } - - public static void main(String[] args) { - new Child(); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java deleted file mode 100644 index afbc46fd..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation.targets; - -public enum EnumImplicitMethods { // $line-classdef$ - - CONST(Stubs.f() ? new Object() : new Object()); // $line-const$ - - static { - } // $line-staticblock$ - - /** - * Unlike in {@link Target07 regular classes}, even if enum has explicit - * constructor, {@code clinit} method in any case has a reference to the - * line of enum definition. - */ - EnumImplicitMethods(Object o) { // $line-super$ - } // $line-constructor$ - - /** - * This method should not be excluded from analysis unlike implicitly - * created {@link #valueOf(String)} method that refers to the line of enum - * definition in case of javac and to the first line in case of ECJ. - */ - public void valueOf() { - } // $line-customValueOfMethod$ - - /** - * This method should not be excluded from analysis unlike implicitly - * created {@link #values()} method that refers to the line of enum - * definition in case of javac and to the first line in case of ECJ. - */ - public void values(Object o) { - } // $line-customValuesMethod$ - - public static void main(String[] args) { - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target01.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target01.java deleted file mode 100644 index 81d00fa5..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target01.java +++ /dev/null @@ -1,293 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.i2; -import static org.jacoco.core.test.validation.targets.Stubs.nop; -import static org.jacoco.core.test.validation.targets.Stubs.t; - -import java.util.Collections; - -/** - * This target exercises a set of common Java control structures. - */ -public class Target01 { - - public static void main(String[] args) { - - unconditionalExecution(); - missedIfBlock(); - executedIfBlock(); - missedWhileBlock(); - alwaysExecutedWhileBlock(); - executedWhileBlock(); - executedDoWhileBlock(); - missedForBlock(); - executedForBlock(); - missedForEachBlock(); - executedForEachBlock(); - tableSwitchWithHit(); - continuedTableSwitchWithHit(); - tableSwitchWithoutHit(); - lookupSwitchWithHit(); - continuedLookupSwitchWithHit(); - lookupSwitchWithoutHit(); - breakStatement(); - continueStatement(); - conditionalReturn(); - implicitReturn(); - explicitReturn(); - - } - - private static void unconditionalExecution() { - - nop(); // $line-unconditional$ - - } - - private static void missedIfBlock() { - - if (f()) { // $line-iffalse$ - nop(); // $line-missedif$ - } else { - nop(); // $line-executedelse$ - } - - } - - private static void executedIfBlock() { - - if (t()) { // $line-iftrue$ - nop(); // $line-executedif$ - } else { - nop(); // $line-missedelse$ - } - - } - - private static void missedWhileBlock() { - - while (f()) { // $line-whilefalse$ - nop(); // $line-missedwhile$ - } - - } - - private static void alwaysExecutedWhileBlock() { - - while (t()) { // $line-whiletrue$ - if (t()) { - break; - } - } - - } - - private static void executedWhileBlock() { - - int i = 0; - while (i++ < 3) { // $line-whiletruefalse$ - nop(); // $line-executedwhile$ - } - - } - - private static void executedDoWhileBlock() { - - do { - nop(); // $line-executeddowhile$ - } while (f()); // $line-executeddowhilefalse$ - - } - - private static void missedForBlock() { - - for (nop(); f(); nop()) { // $line-missedforincrementer$ - nop(); // $line-missedfor$ - } - - } - - private static void executedForBlock() { - - for (int j = 0; j < 1; j++) { // $line-executedforincrementer$ - nop(); // $line-executedfor$ - } - - } - - private static void missedForEachBlock() { - - for (Object o : Collections.emptyList()) { // $line-missedforeachincrementer$ - nop(o); // $line-missedforeach$ - } - - } - - private static void executedForEachBlock() { - - for (Object o : Collections.singleton(new Object())) { // $line-executedforeachincrementer$ - nop(o); // $line-executedforeach$ - } - - } - - private static void tableSwitchWithHit() { - - switch (i2()) { // $line-tswitch1$ - case 1: - nop(); // $line-tswitch1case1$ - break; - case 2: - nop(); // $line-tswitch1case2$ - break; - case 3: - nop(); // $line-tswitch1case3$ - break; - default: - nop(); // $line-tswitch1default$ - break; - } - - } - - private static void continuedTableSwitchWithHit() { - - switch (i2()) { // $line-tswitch2$ - case 1: - nop(); // $line-tswitch2case1$ - case 2: - nop(); // $line-tswitch2case2$ - case 3: - nop(); // $line-tswitch2case3$ - default: - nop(); // $line-tswitch2default$ - } - - } - - private static void tableSwitchWithoutHit() { - - switch (i2()) { // $line-tswitch3$ - case 3: - nop(); // $line-tswitch3case1$ - break; - case 4: - nop(); // $line-tswitch3case2$ - break; - case 5: - nop(); // $line-tswitch3case3$ - break; - default: - nop(); // $line-tswitch3default$ - break; - } - - } - - private static void lookupSwitchWithHit() { - - switch (i2()) { // $line-lswitch1$ - case -123: - nop(); // $line-lswitch1case1$ - break; - case 2: - nop(); // $line-lswitch1case2$ - break; - case 456: - nop(); // $line-lswitch1case3$ - break; - default: - nop(); // $line-lswitch1default$ - break; - } - - } - - private static void continuedLookupSwitchWithHit() { - - switch (i2()) { // $line-lswitch2$ - case -123: - nop(); // $line-lswitch2case1$ - case 2: - nop(); // $line-lswitch2case2$ - case 456: - nop(); // $line-lswitch2case3$ - default: - nop(); // $line-lswitch2default$ - } - - } - - private static void lookupSwitchWithoutHit() { - - switch (i2()) { // $line-lswitch3$ - case -123: - nop(); // $line-lswitch3case1$ - break; - case 456: - nop(); // $line-lswitch3case2$ - break; - case 789: - nop(); // $line-lswitch3case3$ - break; - default: - nop(); // $line-lswitch3default$ - break; - } - - } - - private static void breakStatement() { - - while (true) { - if (t()) { - break; // $line-executedbreak$ - } - nop(); // $line-missedafterbreak$ - } - - } - - private static void continueStatement() { - - for (int j = 0; j < 1; j++) { - if (t()) { - continue; // $line-executedcontinue$ - } - nop(); // $line-missedaftercontinue$ - } - - } - - private static void conditionalReturn() { - - if (t()) { - return; // $line-conditionalreturn$ - } - nop(); // $line-afterconditionalreturn$ - - } - - private static void implicitReturn() { - - } // $line-implicitreturn$ - - private static void explicitReturn() { - - return; // $line-explicitreturn$ - - } // $line-afterexplicitreturn$ - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target02.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target02.java deleted file mode 100644 index 62e22ef9..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target02.java +++ /dev/null @@ -1,120 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.i1; -import static org.jacoco.core.test.validation.targets.Stubs.i2; -import static org.jacoco.core.test.validation.targets.Stubs.nop; -import static org.jacoco.core.test.validation.targets.Stubs.t; - -/** - * This target exercises boolean expressions. - */ -public class Target02 { - - public static void main(String[] args) { - - // 1. Boolean comparison result (one case) - nop(i2() > 3); // $line-booleancmp1$ - - // 2. Boolean comparison result (both cases) - for (int i = 0; i < 2; i++) { - nop(i < 1); // $line-booleancmp2$ - } - - // 3. And - if (f() & f()) { // $line-andFF$ - nop(); - } - if (f() & t()) { // $line-andFT$ - nop(); - } - if (t() & f()) { // $line-andTF$ - nop(); - } - if (t() & t()) { // $line-andTT$ - nop(); - } - - // 4. Conditional And - if (f() && f()) { // $line-conditionalandFF$ - nop(); - } - if (f() && t()) { // $line-conditionalandFT$ - nop(); - } - if (t() && f()) { // $line-conditionalandTF$ - nop(); - } - if (t() && t()) { // $line-conditionalandTT$ - nop(); - } - - // 5. Or - if (f() | f()) { // $line-orFF$ - nop(); - } - if (f() | t()) { // $line-orFT$ - nop(); - } - if (t() | f()) { // $line-orTF$ - nop(); - } - if (t() | t()) { // $line-orTT$ - nop(); - } - - // 6. Conditional Or - if (f() || f()) { // $line-conditionalorFF$ - nop(); - } - if (f() || t()) { // $line-conditionalorFT$ - nop(); - } - if (t() || f()) { // $line-conditionalorTF$ - nop(); - } - if (t() || t()) { // $line-conditionalorTT$ - nop(); - } - - // 7. Exclusive Or - if (f() ^ f()) { // $line-xorFF$ - nop(); - } - if (f() ^ t()) { // $line-xorFT$ - nop(); - } - if (t() ^ f()) { // $line-xorTF$ - nop(); - } - if (t() ^ t()) { // $line-xorTT$ - nop(); - } - - // 8. Conditional Operator - nop(t() ? i1() : i2()); // $line-condT$ - nop(f() ? i1() : i2()); // $line-condF$ - - // 9. Not (one case) - nop(!t()); // $line-notT$ - nop(!f()); // $line-notF$ - - // 10. Not (both cases) - for (boolean b : new boolean[] { true, false }) { - nop(!b); // $line-notTF$ - } - - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target03.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target03.java deleted file mode 100644 index b4418edd..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target03.java +++ /dev/null @@ -1,142 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.ex; -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -import org.jacoco.core.test.validation.targets.Stubs.StubException; - -/** - * This target produces exception based control flow examples. - */ -public class Target03 { - - public static void main(String[] args) { - - try { - implicitNullPointerException(null); - } catch (NullPointerException e) { - } - try { - implicitException(); - } catch (StubException e) { - } - try { - explicitException(); - } catch (StubException e) { - } - noExceptionTryCatch(); - implicitExceptionTryCatch(); - implicitExceptionTryCatchAfterCondition(); - explicitExceptionTryCatch(); - noExceptionFinally(); - try { - explicitExceptionFinally(); - } catch (StubException e) { - } - try { - implicitExceptionFinally(); - } catch (StubException e) { - } - } - - private static void implicitNullPointerException(int[] a) { - nop(); // $line-implicitNullPointerException.before$ - a[0] = 0; // $line-implicitNullPointerException.exception$ - nop(); // $line-implicitNullPointerException.after$ - } - - private static void implicitException() { - nop(); // $line-implicitException.before$ - ex(); // $line-implicitException.exception$ - nop(); // $line-implicitException.after$ - } - - private static void explicitException() { - nop(); // $line-explicitException.before$ - throw new StubException(); // $line-explicitException.throw$ - } - - private static void noExceptionTryCatch() { - nop(); // $line-noExceptionTryCatch.beforeBlock$ - try { - nop(); // $line-noExceptionTryCatch.tryBlock$ - } catch (StubException e) { // $line-noExceptionTryCatch.catch$ - nop(); // $line-noExceptionTryCatch.catchBlock$ - } // $line-noExceptionTryCatch.catchBlockEnd$ - } // $line-noExceptionTryCatch.afterBlock$ - - private static void implicitExceptionTryCatch() { - nop(); // $line-implicitExceptionTryCatch.beforeBlock$ - try { - nop(); // $line-implicitExceptionTryCatch.before$ - ex(); // $line-implicitExceptionTryCatch.exception$ - nop(); // $line-implicitExceptionTryCatch.after$ - } catch (StubException e) { // $line-implicitExceptionTryCatch.catch$ - nop(); // $line-implicitExceptionTryCatch.catchBlock$ - } // $line-implicitExceptionTryCatch.catchBlockEnd$ - } // $line-implicitExceptionTryCatch.afterBlock$ - - private static void implicitExceptionTryCatchAfterCondition() { - if (f()) { // $line-implicitExceptionTryCatchAfterCondition.condition$ - return; - } - try { - ex(); // $line-implicitExceptionTryCatchAfterCondition.exception$ - } catch (StubException e) { - nop(); // $line-implicitExceptionTryCatchAfterCondition.catchBlock$ - } - } - - private static void explicitExceptionTryCatch() { - nop(); // $line-explicitExceptionTryCatch.beforeBlock$ - try { - nop(); // $line-explicitExceptionTryCatch.before$ - throw new StubException(); // $line-explicitExceptionTryCatch.throw$ - } catch (StubException e) { // $line-explicitExceptionTryCatch.catch$ - nop(); // $line-explicitExceptionTryCatch.catchBlock$ - } // $line-explicitExceptionTryCatch.catchBlockEnd$ - } // $line-explicitExceptionTryCatch.afterBlock$ - - private static void noExceptionFinally() { - nop(); // $line-noExceptionFinally.beforeBlock$ - try { - nop(); // $line-noExceptionFinally.tryBlock$ - } finally { // $line-noExceptionFinally.finally$ - nop(); // $line-noExceptionFinally.finallyBlock$ - } // $line-noExceptionFinally.finallyBlockEnd$ - } // $line-noExceptionFinally.afterBlock$ - - private static void implicitExceptionFinally() { - nop(); // $line-implicitExceptionFinally.beforeBlock$ - try { - nop(); // $line-implicitExceptionFinally.before$ - ex(); // $line-implicitExceptionFinally.exception$ - nop(); // $line-implicitExceptionFinally.after$ - } finally { // $line-implicitExceptionFinally.finally$ - nop(); // $line-implicitExceptionFinally.finallyBlock$ - } // $line-implicitExceptionFinally.finallyBlockEnd$ - } // $line-implicitExceptionFinally.afterBlock$ - - private static void explicitExceptionFinally() { - nop(); // $line-explicitExceptionFinally.beforeBlock$ - try { - nop(); // $line-explicitExceptionFinally.before$ - throw new StubException(); // $line-explicitExceptionFinally.throw$ - } finally { // $line-explicitExceptionFinally.finally$ - nop(); // $line-explicitExceptionFinally.finallyBlock$ - } // $line-explicitExceptionFinally.finallyBlockEnd$ - } // $line-explicitExceptionFinally.afterBlock$ - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target04.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target04.java deleted file mode 100644 index 8384744b..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target04.java +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.i1; - -/** - * This test target is an interface with a class initializer. - */ -public interface Target04 { - - // No code required to initialize these fields: - - static final int CONST1 = 12345; // $line-const1$ - - static final String CONST2 = "const"; // $line-const2$ - - // These fields are initialized within <clinit> - - static final int CONST3 = i1(); // $line-const3$ - - static final Object CONST4 = new Object(); // $line-const4$ - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target05.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target05.java deleted file mode 100644 index ef5c3989..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target05.java +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.i1; - -/** - * This test target is a class with a static initializer. - */ -public class Target05 { - - // No code required to initialize these fields: - - public static final int CONST1 = 3; // $line-const1$ - - public static final String CONST2 = "Hello"; // $line-const2$ - - // These fields are initialized within <clinit> - - public static final int CONST3 = i1(); // $line-const3$ - - public static final Object CONST4 = new Object(); // $line-const4$ - - public static int field1 = 3; // $line-field1$ - - public static String field2 = "Hello"; // $line-field2$ - - public static int field3 = i1(); // $line-field3$ - - public static Object field4 = new Object(); // $line-field4$ - - static { - Stubs.nop(); // $line-staticblock$ - } - - private Target05() { - } - - public static void main(String[] args) { - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target06.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target06.java deleted file mode 100644 index f6bc75e8..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target06.java +++ /dev/null @@ -1,25 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -/** - * This test target is a class with a implicit default constructor. - * - * @see Target07 explicit constructor - */ -public class Target06 { // $line-classdef$ - - public static void main(String[] args) { - new Target06(); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target07.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target07.java deleted file mode 100644 index 18c3ba52..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target07.java +++ /dev/null @@ -1,27 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -/** - * This test target is a private empty default constructor. - * - * @see Target06 implicit constructor - */ -public class Target07 { // $line-classdef$ - - private Target07() { // $line-super$ - } // $line-constructor$ - - public static void main(String[] args) { - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target08.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target08.java deleted file mode 100644 index 1fe938aa..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target08.java +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -/** - * This test target has instance members with implicit initializers. - */ -public class Target08 { // $line-classdef$ - - Object field1; // $line-field1$ - - Object field2 = this; // $line-field2$ - - int field3; // $line-field3$ - - int field4 = 2000; // $line-field4$ - - public static void main(String[] args) { - new Target08(); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target09.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target09.java deleted file mode 100644 index a8589d1d..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target09.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -/** - * This test target has instance members with initialization in two - * constructors. - */ -public class Target09 { - - Object field1 = null; // $line-field1$ - - int field2 = 123; // $line-field2$ - - public Target09() { - } // $line-constr1$ - - public Target09(String arg) { - } // $line-constr2$ - - public static void main(String[] args) { - new Target09(); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target10.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target10.java deleted file mode 100644 index bb4496e9..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target10.java +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.t; - -import org.jacoco.core.test.validation.targets.Stubs.SuperClass; - -/** - * This test target has a constructor containing control structures before the - * superclass constructor is called. - */ -public class Target10 extends SuperClass { - - public Target10() { - super(t() || f()); // $line-super$ - } - - public static void main(String[] args) { - new Target10(); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target11.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target11.java deleted file mode 100644 index d393cb7f..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target11.java +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target needs an explicit initial frame as the first instruction - * already is a jump target. - */ -public class Target11 { - - public static void main(String[] args) { - - do { - nop(); // $line-dowhilebody$ - } while (f()); - - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target12.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target12.java deleted file mode 100644 index 5ee2e324..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/Target12.java +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This target uses synchronized blocks which compile to try/catch statements. - */ -public class Target12 { - - static void simple() { - Object lock1 = new Object(); - synchronized (lock1) { - nop(); - } - } - - static void nested() { - Object lock1 = new Object(); - synchronized (lock1) { - nop(); - Object lock2 = new Object(); - synchronized (lock2) { - nop(); - } - nop(); - } - - } - - public static void main(String[] args) { - simple(); - nested(); - } - -} diff --git a/org.jacoco.doc/docroot/doc/build.html b/org.jacoco.doc/docroot/doc/build.html index 3a125e0f..987fcc69 100644 --- a/org.jacoco.doc/docroot/doc/build.html +++ b/org.jacoco.doc/docroot/doc/build.html @@ -6,6 +6,21 @@ <link rel="stylesheet" href="resources/doc.css" charset="UTF-8" type="text/css" /> <link rel="stylesheet" href="../coverage/jacoco-resources/prettify.css" charset="UTF-8" type="text/css" /> <link rel="shortcut icon" href="resources/report.gif" type="image/gif" /> + <style> + table, th, td { + border-collapse: collapse; + padding: 3px; + } + table tbody tr td:nth-child(2) { + border-right: #b0b0b0 3px solid; + } + th { + background-color:#e0e0e0; + } + table tbody td:hover { + background: #f0f0d0; + } + </style> <script type="text/javascript" src="../coverage/jacoco-resources/prettify.js"></script> <title>JaCoCo - Build @@ -24,9 +39,9 @@ The JaCoCo build is based on Maven and can be locally executed on every machine with a proper environment setup. In particular you need at - least Maven 3.3.9 installation. - Developers are encouraged to run the build before every commit to ensure - consistency of the source tree. + least Maven 3.3.9 and JDK 8 + installations. Developers are encouraged to run the build before every commit + to ensure consistency of the source tree.

    @@ -63,92 +78,62 @@ -

    Testing with different JDKs

    +

    Compilation and testing with different JDKs

    - Target Java version for JaCoCo builds is 1.5, however for verification - purposes you can execute tests using other versions. In order to do so, first - you should create file toolchains.xml in ~/.m2/ - directory. Here is an example of such file. For more information see + By default for compilation and execution of tests will be used JDK that runs + Maven. Alternatively you can use JDK from Maven - Guide to Using Toolchains. + Toolchains by setting property jdk.version.

    -
    -<?xml version="1.0" encoding="UTF8"?>
    -<toolchains>
    -  <toolchain>
    -    <type>jdk</type>
    -    <provides>
    -      <id>java15</id>
    -      <version>1.5</version>
    -      <vendor>sun</vendor>
    -    </provides>
    -    <configuration>
    -      <jdkHome>/usr/lib/jvm/sun-jdk-1.5</jdkHome>
    -    </configuration>
    -  </toolchain>
    -  <toolchain>
    -    <type>jdk</type>
    -    <provides>
    -      <id>java16</id>
    -      <version>1.6</version>
    -      <vendor>sun</vendor>
    -    </provides>
    -    <configuration>
    -      <jdkHome>/usr/lib/jvm/sun-jdk-1.6</jdkHome>
    -    </configuration>
    -  </toolchain>
    -  <toolchain>
    -    <type>jdk</type>
    -    <provides>
    -      <id>java17</id>
    -      <version>1.7</version>
    -      <vendor>sun</vendor>
    -    </provides>
    -    <configuration>
    -      <jdkHome>/usr/lib/jvm/sun-jdk-1.7</jdkHome>
    -    </configuration>
    -  </toolchain>
    -  <toolchain>
    -    <type>jdk</type>
    -    <provides>
    -      <id>java18</id>
    -      <version>1.8</version>
    -      <vendor>sun</vendor>
    -    </provides>
    -    <configuration>
    -      <jdkHome>/usr/lib/jvm/sun-jdk-1.8</jdkHome>
    -    </configuration>
    -  </toolchain>
    -  <toolchain>
    -    <type>jdk</type>
    -    <provides>
    -      <id>java19</id>
    -      <version>1.9</version>
    -      <vendor>sun</vendor>
    -    </provides>
    -    <configuration>
    -      <jdkHome>/usr/lib/jvm/sun-jdk-1.9</jdkHome>
    -    </configuration>
    -  </toolchain>
    -</toolchains>
    -
    -

    - Now you should be able to execute maven build with specified version of JDK: + Following table shows how modules will be compiled depending on version of JDK:

    -
    -  mvn clean install -Djdk.version=version
    -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    JDK 5JDK 6JDK 7JDK 8JDK 9JDK 10
    org.jacoco.core.test.validation.java7excluded from buildcompiled into bytecode version 51 (Java 7)
    org.jacoco.core.test.validation.java8excluded from buildcompiled into bytecode version 52 (Java 8)
    all other modulescompiled into bytecode version 49 (Java 5)compiled into bytecode version 50 (Java 6)
    + +

    + Alternatively you can specify bytecode version for all modules using property + bytecode.version. +

    - Location of toolchains.xml can be set via an option: + For example to use JDK 10 from Maven Toolchains and compile all modules + into bytecode version 53 (Java 9):

    -  mvn --toolchains path clean install -Djdk.version=version
    +  mvn clean install -Djdk.version=10 -Dbytecode.version=9
     

    @@ -160,20 +145,17 @@

    - In addition JaCoCo can be compiled for higher class file versions than 1.5 - specifying the property bytecode.version. Note that in this case - the version of the JVM running Maven must be at least the version of the - specified bytecode version as this JVM is also running the tests. Combining - these options JaCoCo is regularly tested with the following setups: + Combining these options JaCoCo is regularly tested with the following setups:

      -
    • Maven with 1.5 JDK: mvn clean install -Djdk.version=1.5 -Dbytecode.version=1.5
    • -
    • Maven with 1.6 JDK: mvn clean install -Djdk.version=1.6 -Dbytecode.version=1.6
    • -
    • Maven with 1.7 JDK: mvn clean install -Djdk.version=1.7 -Dbytecode.version=1.7
    • -
    • Maven with 1.8 JDK: mvn clean install -Djdk.version=1.8 -Dbytecode.version=1.8
    • -
    • Maven with 1.8 JDK: mvn clean install -Djdk.version=1.8 -Dbytecode.version=1.8 -Decj
    • -
    • Maven with 1.9 JDK: mvn clean install -Djdk.version=1.9 -Dbytecode.version=1.9
    • +
    • mvn clean install -Djdk.version=5 -Dbytecode.version=5
    • +
    • mvn clean install -Djdk.version=6 -Dbytecode.version=6
    • +
    • mvn clean install -Djdk.version=7 -Dbytecode.version=7
    • +
    • mvn clean install -Djdk.version=8 -Dbytecode.version=8
    • +
    • mvn clean install -Djdk.version=8 -Dbytecode.version=8 -Decj
    • +
    • mvn clean install -Djdk.version=9 -Dbytecode.version=9
    • +
    • mvn clean install -Djdk.version=10 -Dbytecode.version=10
    diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 02dc8cb1..daca307e 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -49,6 +49,8 @@
  • Improved error message when already instrumented classes are used for instrumentation or analysis (GitHub #703).
  • +
  • JaCoCo build now requires at least Maven 3.3.9 and JDK 8 + (GitHub #711).

API Changes

diff --git a/org.jacoco.doc/docroot/doc/environment.html b/org.jacoco.doc/docroot/doc/environment.html index bcc59534..2a303d8a 100644 --- a/org.jacoco.doc/docroot/doc/environment.html +++ b/org.jacoco.doc/docroot/doc/environment.html @@ -66,16 +66,16 @@

JRE/JDK

- The minimum supported JRE version for JaCoCo is Java 1.5. To guarantee - compatibility JaCoCo builds should always be executed against Java 1.5 JDK. In - addition we run builds with 1.6, 1.7, 1.8 and 1.9 JDKs. + The minimum supported JRE version for JaCoCo is Java 5. To guarantee + compatibility JaCoCo release builds should always be executed using JDK 5. + In addition we run builds with 6, 7, 8, 9 and 10 JDKs.

Build

The JaCoCo build is based on Maven - and requires at least Maven 3.3.9. + and requires at least Maven 3.3.9 and JDK 8. See the build description for details.

diff --git a/org.jacoco.tests/pom.xml b/org.jacoco.tests/pom.xml index 7f071172..8e49ba70 100644 --- a/org.jacoco.tests/pom.xml +++ b/org.jacoco.tests/pom.xml @@ -27,6 +27,7 @@ ../org.jacoco.core.test + ../org.jacoco.core.test.validation ../org.jacoco.report.test ../org.jacoco.agent.rt.test ../org.jacoco.agent.test -- cgit v1.2.3 From 2961642572c82900a3133f5db086d90c7d5d525a Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Tue, 24 Jul 2018 12:56:21 +0200 Subject: Validation tests should use source filename from coverage results (#714) To support non Java source files. --- .../org/jacoco/core/test/filter/FinallyTest.java | 5 +---- .../org/jacoco/core/test/validation/Source.java | 20 ++---------------- .../jacoco/core/test/validation/SourceTest.java | 9 -------- .../core/test/validation/ValidationTestBase.java | 24 ++++++++++++++++++++-- 4 files changed, 25 insertions(+), 33 deletions(-) diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/FinallyTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/FinallyTest.java index 9c6b2af4..2aa97562 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/FinallyTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/FinallyTest.java @@ -21,7 +21,6 @@ import org.jacoco.core.analysis.ICounter; import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.test.TargetLoader; import org.jacoco.core.test.filter.targets.Finally; -import org.jacoco.core.test.validation.Source; import org.jacoco.core.test.validation.ValidationTestBase; import org.junit.Test; import org.objectweb.asm.ClassReader; @@ -180,8 +179,6 @@ public class FinallyTest extends ValidationTestBase { */ @Test public void gotos() throws IOException { - final Source source = Source.getSourceFor("src", Finally.class); - byte[] b = TargetLoader.getClassDataAsBytes(Finally.class); b = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(b), b); @@ -200,7 +197,7 @@ public class FinallyTest extends ValidationTestBase { lineNumber = ((LineNumberNode) i).line; } if (Opcodes.GOTO == i.getOpcode()) { - final String line = source.getLine(lineNumber); + final String line = getSource().getLine(lineNumber); if (line.indexOf('$') < 0) { throw new AssertionError( "No tag at line " + lineNumber); diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/Source.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/Source.java index c04841e2..6d2d7172 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/Source.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/Source.java @@ -12,8 +12,6 @@ package org.jacoco.core.test.validation; import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.util.ArrayList; @@ -31,22 +29,6 @@ import java.util.regex.Pattern; */ public class Source { - /** - * Reads the source for the given type from the given source folder relative - * to the working directory. - * - * @param srcFolder - * source folder - * @param type - * type to load the source file for - */ - public static Source getSourceFor(final String srcFolder, - final Class type) throws IOException { - File folder = new File(srcFolder); - File file = new File(folder, type.getName().replace('.', '/') + ".java"); - return new Source(new FileReader(file)); - } - private static final Pattern TAG_PATTERN = Pattern .compile("\\$line-(.*)\\$"); @@ -58,7 +40,9 @@ public class Source { * Reads a source file from the given reader. * * @param reader + * the reader to read from * @throws IOException + * if an I/O error occurs */ public Source(final Reader reader) throws IOException { final BufferedReader buffer = new BufferedReader(reader); diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/SourceTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/SourceTest.java index 6432c392..6d422c60 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/SourceTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/SourceTest.java @@ -12,7 +12,6 @@ package org.jacoco.core.test.validation; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.StringReader; @@ -76,12 +75,4 @@ public class SourceTest { new Source(new StringReader(src)); } - @Test - public void testGetSourceFor() throws IOException { - final Source s = Source.getSourceFor("src", SourceTest.class); - // Here we are. $line-testGetSourceFor$ - final String l = s.getLine(s.getLineNumber("testGetSourceFor")); - assertTrue(l, l.contains("Here we are.")); - } - } diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java index b2853842..1efff1bf 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java @@ -14,12 +14,14 @@ package org.jacoco.core.test.validation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Method; import java.util.Arrays; import org.jacoco.core.analysis.Analyzer; import org.jacoco.core.analysis.CoverageBuilder; +import org.jacoco.core.analysis.IClassCoverage; import org.jacoco.core.analysis.ICounter; import org.jacoco.core.analysis.ILine; import org.jacoco.core.analysis.ISourceFileCoverage; @@ -67,7 +69,6 @@ public abstract class ValidationTestBase { public void setup() throws Exception { final ExecutionDataStore store = execute(); analyze(store); - source = Source.getSourceFor("src", target); } private ExecutionDataStore execute() throws Exception { @@ -88,7 +89,11 @@ public abstract class ValidationTestBase { analyze(analyzer, data); } - String srcName = target.getName().replace('.', '/') + ".java"; + final String srcName = findSourceFileName(builder, + target.getName().replace('.', '/')); + + source = new Source(new FileReader("src/" + srcName)); + for (ISourceFileCoverage file : builder.getSourceFiles()) { if (srcName.equals(file.getPackageName() + "/" + file.getName())) { sourceCoverage = file; @@ -105,6 +110,21 @@ public abstract class ValidationTestBase { analyzer.analyzeClass(bytes, data.getName()); } + private static String findSourceFileName( + final CoverageBuilder coverageBuilder, final String className) { + for (IClassCoverage classCoverage : coverageBuilder.getClasses()) { + if (className.equals(classCoverage.getName())) { + return classCoverage.getPackageName() + '/' + + classCoverage.getSourceFileName(); + } + } + throw new AssertionError(); + } + + protected final Source getSource() { + return source; + } + protected void assertMethodCount(final int expectedTotal) { assertEquals(expectedTotal, sourceCoverage.getMethodCounter().getTotalCount()); -- cgit v1.2.3 From e2b21fb31653219d7ea07487d0575a0212f6fa70 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sat, 28 Jul 2018 21:23:48 +0200 Subject: Upgrade maven-compiler-plugin to 3.7.0 --- org.jacoco.build/pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index 02dc806e..8f8156e7 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -305,7 +305,7 @@ org.apache.maven.plugins maven-compiler-plugin - 2.3.2 + 3.7.0 org.apache.maven.plugins @@ -784,7 +784,6 @@ org.apache.maven.plugins maven-compiler-plugin - 3.6.0 eclipse 1.8 -- cgit v1.2.3 From 65d1aea1bd0f85f8be9bbc5076b7191515fe5f39 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 1 Aug 2018 17:02:50 +0200 Subject: Add filter for try-with-resources for javac 11 (#669) --- .../core/test/filter/TryWithResourcesTest.java | 54 +++++-- .../filter/TryWithResourcesJavac11FilterTest.java | 175 +++++++++++++++++++++ .../core/internal/analysis/filter/Filters.java | 1 + .../filter/TryWithResourcesJavac11Filter.java | 144 +++++++++++++++++ .../filter/TryWithResourcesJavacFilter.java | 3 +- org.jacoco.doc/docroot/doc/changes.html | 3 + 6 files changed, 370 insertions(+), 10 deletions(-) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11FilterTest.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/TryWithResourcesTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/TryWithResourcesTest.java index fe441164..41c61713 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/TryWithResourcesTest.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/TryWithResourcesTest.java @@ -33,7 +33,11 @@ public class TryWithResourcesTest extends ValidationTestBase { public void test() { assertLine("test.before", ICounter.FULLY_COVERED); // without filter next line covered partly: - assertLine("test.try", ICounter.FULLY_COVERED); + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("test.try", ICounter.FULLY_COVERED); + } else { + assertLine("test.try", ICounter.EMPTY); + } assertLine("test.open1", ICounter.FULLY_COVERED); assertLine("test.open2", ICounter.FULLY_COVERED); assertLine("test.open3", ICounter.FULLY_COVERED); @@ -51,7 +55,11 @@ public class TryWithResourcesTest extends ValidationTestBase { public void test2() { assertLine("test2.before", ICounter.FULLY_COVERED); // without filter next line covered partly: - assertLine("test2.try", ICounter.FULLY_COVERED); + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("test2.try", ICounter.FULLY_COVERED); + } else { + assertLine("test2.try", ICounter.EMPTY); + } assertLine("test2.open1", ICounter.FULLY_COVERED); assertLine("test2.open2", ICounter.FULLY_COVERED); assertLine("test2.open3", ICounter.FULLY_COVERED); @@ -69,7 +77,11 @@ public class TryWithResourcesTest extends ValidationTestBase { @Test public void returnInBody() { // without filter next line covered partly: - assertLine("returnInBody.try", ICounter.FULLY_COVERED); + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("returnInBody.try", ICounter.FULLY_COVERED); + } else { + assertLine("returnInBody.try", ICounter.EMPTY); + } assertLine("returnInBody.open", ICounter.FULLY_COVERED); // without filter next line has branches: @@ -94,18 +106,30 @@ public class TryWithResourcesTest extends ValidationTestBase { @Test public void nested() { // without filter next line covered partly: - assertLine("nested.try1", ICounter.FULLY_COVERED); + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("nested.try1", ICounter.FULLY_COVERED); + } else { + assertLine("nested.try1", ICounter.EMPTY); + } assertLine("nested.open1", ICounter.FULLY_COVERED); assertLine("nested.catch1", ICounter.NOT_COVERED); // without filter next line covered partly: - assertLine("nested.try2", ICounter.FULLY_COVERED); + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("nested.try2", ICounter.FULLY_COVERED); + } else { + assertLine("nested.try2", ICounter.EMPTY); + } assertLine("nested.body", ICounter.FULLY_COVERED); assertLine("nested.catch2", ICounter.NOT_COVERED); assertLine("nested.finally2", ICounter.FULLY_COVERED); // next lines not covered on exceptional path: - assertLine("nested.try3", ICounter.FULLY_COVERED, 0, 0); + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("nested.try3", ICounter.FULLY_COVERED); + } else { + assertLine("nested.try3", ICounter.EMPTY); + } assertLine("nested.open3", ICounter.FULLY_COVERED, 0, 0); assertLine("nested.body3", ICounter.FULLY_COVERED, 0, 0); assertLine("nested.catch3", ICounter.NOT_COVERED); @@ -123,7 +147,11 @@ public class TryWithResourcesTest extends ValidationTestBase { @Test public void returnInCatch() { // without filter next line covered partly: - assertLine("returnInCatch.try1", ICounter.FULLY_COVERED); + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("returnInCatch.try1", ICounter.FULLY_COVERED); + } else { + assertLine("returnInCatch.try1", ICounter.EMPTY); + } assertLine("returnInCatch.open", ICounter.FULLY_COVERED); assertLine("returnInCatch.finally1", ICounter.PARTLY_COVERED, 1, 1); // without filter next line has branches: @@ -152,7 +180,11 @@ public class TryWithResourcesTest extends ValidationTestBase { */ @Test public void empty() { - assertLine("empty.try", ICounter.FULLY_COVERED, 0, 0); + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("empty.try", ICounter.FULLY_COVERED); + } else { + assertLine("empty.try", ICounter.EMPTY); + } assertLine("empty.open", ICounter.FULLY_COVERED); // empty when EJC: if (isJDKCompiler) { @@ -172,7 +204,11 @@ public class TryWithResourcesTest extends ValidationTestBase { public void throwInBody() { // not filtered assertLine("throwInBody.try", ICounter.NOT_COVERED); - assertLine("throwInBody.close", ICounter.NOT_COVERED); + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("throwInBody.close", ICounter.NOT_COVERED); + } else { + assertLine("throwInBody.close", ICounter.EMPTY); + } } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11FilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11FilterTest.java new file mode 100644 index 00000000..f012d87b --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11FilterTest.java @@ -0,0 +1,175 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class TryWithResourcesJavac11FilterTest implements IFilterOutput { + + private final TryWithResourcesJavac11Filter filter = new TryWithResourcesJavac11Filter(); + + private final FilterContextMock context = new FilterContextMock(); + + private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "name", "()V", null, null); + + /** + *
+	 *   try (r = new ...) {
+	 *     ...
+	 *   }
+	 * 
+ */ + @Test + public void without_null_check() { + final Range range1 = new Range(); + final Range range2 = new Range(); + + final Label e = new Label(); + final Label t = new Label(); + + final Label handler = new Label(); + m.visitTryCatchBlock(handler, handler, handler, "java/lang/Throwable"); + + m.visitInsn(Opcodes.NOP); + + m.visitVarInsn(Opcodes.ALOAD, 0); + range1.fromInclusive = m.instructions.getLast(); + m.visitMethodInsn(Opcodes.INVOKEINTERFACE, "Resource", "close", + "()V", false); + m.visitJumpInsn(Opcodes.GOTO, e); + range1.toInclusive = m.instructions.getLast(); + + m.visitLabel(handler); + range2.fromInclusive = m.instructions.getLast(); + m.visitVarInsn(Opcodes.ASTORE, 1); + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitMethodInsn(Opcodes.INVOKEINTERFACE, "Resource", "close", + "()V", false); + m.visitJumpInsn(Opcodes.GOTO, t); + + m.visitVarInsn(Opcodes.ASTORE, 2); + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitVarInsn(Opcodes.ALOAD, 2); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", + "addSuppressed", "(Ljava/lang/Throwable;)V", false); + m.visitLabel(t); + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitInsn(Opcodes.ATHROW); + range2.toInclusive = m.instructions.getLast(); + + m.visitLabel(e); + + filter.filter(m, context, this); + + assertEquals(2, from.size()); + assertEquals(2, to.size()); + + assertEquals(range1.fromInclusive, from.get(0)); + assertEquals(range1.toInclusive, to.get(0)); + + assertEquals(range2.fromInclusive, from.get(1)); + assertEquals(range2.toInclusive, to.get(1)); + } + + /** + *
+	 *   try (r = open()) {
+	 *     ...
+	 *   }
+	 * 
+ */ + @Test + public void with_null_check() { + final Range range1 = new Range(); + final Range range2 = new Range(); + + final Label e = new Label(); + final Label t = new Label(); + + final Label handler = new Label(); + m.visitTryCatchBlock(handler, handler, handler, "java/lang/Throwable"); + + m.visitInsn(Opcodes.NOP); + + m.visitVarInsn(Opcodes.ALOAD, 0); + range1.fromInclusive = m.instructions.getLast(); + m.visitJumpInsn(Opcodes.IFNULL, e); + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitMethodInsn(Opcodes.INVOKEINTERFACE, "Resource", "close", + "()V", false); + m.visitJumpInsn(Opcodes.GOTO, e); + range1.toInclusive = m.instructions.getLast(); + + m.visitLabel(handler); + range2.fromInclusive = m.instructions.getLast(); + m.visitVarInsn(Opcodes.ASTORE, 1); + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitJumpInsn(Opcodes.IFNULL, t); + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitMethodInsn(Opcodes.INVOKEINTERFACE, "Resource", "close", + "()V", false); + m.visitJumpInsn(Opcodes.GOTO, t); + + m.visitVarInsn(Opcodes.ASTORE, 2); + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitVarInsn(Opcodes.ALOAD, 2); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", + "addSuppressed", "(Ljava/lang/Throwable;)V", false); + m.visitLabel(t); + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitInsn(Opcodes.ATHROW); + range2.toInclusive = m.instructions.getLast(); + + m.visitLabel(e); + + filter.filter(m, context, this); + + assertEquals(2, from.size()); + assertEquals(2, to.size()); + + assertEquals(range1.fromInclusive, from.get(0)); + assertEquals(range1.toInclusive, to.get(0)); + + assertEquals(range2.fromInclusive, from.get(1)); + assertEquals(range2.toInclusive, to.get(1)); + } + + static class Range { + AbstractInsnNode fromInclusive; + AbstractInsnNode toInclusive; + } + + private final List from = new ArrayList(); + private final List to = new ArrayList(); + + public void ignore(AbstractInsnNode from, AbstractInsnNode to) { + this.from.add(from); + this.to.add(to); + } + + public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { + fail(); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index b235e1e6..68e9b234 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -28,6 +28,7 @@ public final class Filters implements IFilter { */ public static final IFilter ALL = new Filters(new EnumFilter(), new SyntheticFilter(), new SynchronizedFilter(), + new TryWithResourcesJavac11Filter(), new TryWithResourcesJavacFilter(), new TryWithResourcesEcjFilter(), new FinallyFilter(), new PrivateEmptyNoArgConstructorFilter(), new StringSwitchJavacFilter(), new LombokGeneratedFilter(), diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java new file mode 100644 index 00000000..a7bd85ea --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java @@ -0,0 +1,144 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TryCatchBlockNode; + +/** + * Filters code which is generated for try-with-resources statement by javac + * starting from version 11. + */ +public final class TryWithResourcesJavac11Filter implements IFilter { + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + if (methodNode.tryCatchBlocks.isEmpty()) { + return; + } + final Matcher matcher = new Matcher(); + for (TryCatchBlockNode t : methodNode.tryCatchBlocks) { + if ("java/lang/Throwable".equals(t.type)) { + matcher.match(t.handler, output, true); + matcher.match(t.handler, output, false); + } + } + } + + /** + *
+	 *     r = ...;
+	 *     try {
+	 *         ...
+	 *     } body-only-finally {
+	 *         if (r != null)
+	 *             r.close();
+	 *     } catch (Throwable primaryExc) {
+	 *         if (r != null)
+	 *             try {
+	 *                 r.close();
+	 *             } catch (Throwable t) {
+	 *                 primaryExc.addSuppressed(t);
+	 *             }
+	 *         throw primaryExc;
+	 *     }
+	 * 
+ * + * null check for resource is omitted when it is initialized + * using new + */ + private class Matcher extends AbstractMatcher { + private boolean withNullCheck; + + private String expectedOwner; + + void match(final AbstractInsnNode start, final IFilterOutput output, + final boolean withNullCheck) { + this.withNullCheck = withNullCheck; + vars.clear(); + expectedOwner = null; + + cursor = start.getPrevious(); + nextIsVar(Opcodes.ASTORE, "primaryExc"); + nextIsJavacClose(); + nextIs(Opcodes.GOTO); + nextIsVar(Opcodes.ASTORE, "t"); + nextIsVar(Opcodes.ALOAD, "primaryExc"); + nextIsVar(Opcodes.ALOAD, "t"); + nextIsInvokeVirtual("java/lang/Throwable", "addSuppressed"); // primaryExc.addSuppressed(t) + nextIsVar(Opcodes.ALOAD, "primaryExc"); + nextIs(Opcodes.ATHROW); + if (cursor == null) { + return; + } + final AbstractInsnNode end = cursor; + + AbstractInsnNode s = start.getPrevious(); + cursor = start.getPrevious(); + while (!nextIsJavacClose()) { + s = s.getPrevious(); + cursor = s; + if (cursor == null) { + return; + } + } + s = s.getNext(); + + final AbstractInsnNode m = cursor; + next(); + if (cursor.getOpcode() != Opcodes.GOTO) { + cursor = m; + } + + output.ignore(s, cursor); + output.ignore(start, end); + } + + private boolean nextIsJavacClose() { + if (withNullCheck) { + nextIsVar(Opcodes.ALOAD, "r"); + nextIs(Opcodes.IFNULL); + } + nextIsClose(); + return cursor != null; + } + + private void nextIsClose() { + nextIsVar(Opcodes.ALOAD, "r"); + next(); + if (cursor == null) { + return; + } + if (cursor.getOpcode() != Opcodes.INVOKEINTERFACE + && cursor.getOpcode() != Opcodes.INVOKEVIRTUAL) { + cursor = null; + return; + } + final MethodInsnNode m = (MethodInsnNode) cursor; + if (!"close".equals(m.name) || !"()V".equals(m.desc)) { + cursor = null; + return; + } + final String actual = m.owner; + if (expectedOwner == null) { + expectedOwner = actual; + } else if (!expectedOwner.equals(actual)) { + cursor = null; + } + } + + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java index fea477f6..211a5cf6 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java @@ -18,7 +18,8 @@ import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TryCatchBlockNode; /** - * Filters code that javac generates for try-with-resources statement. + * Filters code which is generated for try-with-resources statement by javac + * versions from 7 to 10. */ public final class TryWithResourcesJavacFilter implements IFilter { diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index daca307e..eb19df86 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -22,6 +22,9 @@

New Features

    +
  • Branches and instructions generated by javac 11 for try-with-resources + statement are filtered out + (GitHub #669).
  • Synthetic classes are filtered out during generation of report (GitHub #668).
  • Methods added by the Kotlin compiler are filtered out during generation -- cgit v1.2.3 From b2c5ff73d24cc0c57f308f046de008568068b4c8 Mon Sep 17 00:00:00 2001 From: "Marc R. Hoffmann" Date: Thu, 2 Aug 2018 21:56:26 +0200 Subject: Reorganize validation test packages (#716) * Use module names as package names * Merge previously separate filter validation tests * Move non-version specific tests to org.jacoco.core.test --- .../jacoco/core/test/filter/ConstructorTest.java | 63 ----- .../core/test/filter/EnumConstructorTest.java | 62 ----- .../jacoco/core/test/filter/EnumSwitchTest.java | 40 --- .../org/jacoco/core/test/filter/FinallyTest.java | 267 ------------------- .../jacoco/core/test/filter/SynchronizedTest.java | 74 ------ .../org/jacoco/core/test/filter/SyntheticTest.java | 38 --- .../core/test/filter/targets/Constructor.java | 77 ------ .../core/test/filter/targets/EnumConstructor.java | 49 ---- .../core/test/filter/targets/EnumSwitch.java | 42 --- .../jacoco/core/test/filter/targets/Finally.java | 148 ----------- .../core/test/filter/targets/Synchronized.java | 60 ----- .../jacoco/core/test/filter/targets/Synthetic.java | 64 ----- .../test/validation/AnnotationInitializerTest.java | 47 ---- .../core/test/validation/BadCycleClassTest.java | 39 --- .../test/validation/BooleanExpressionsTest.java | 79 ------ .../test/validation/ClassFileVersionsTest.java | 195 -------------- .../core/test/validation/ClassInitializerTest.java | 44 ---- .../test/validation/ControlStructuresTest.java | 137 ---------- .../test/validation/CyclomaticComplexityTest.java | 280 -------------------- .../test/validation/EnumImplicitMethodsTest.java | 41 --- .../core/test/validation/ExceptionsTest.java | 132 ---------- .../test/validation/ExplicitInitialFrameTest.java | 34 --- .../FieldInitializationInTwoConstructorsTest.java | 38 --- .../jacoco/core/test/validation/FramesTest.java | 179 ------------- .../validation/ImplicitDefaultConstructorTest.java | 36 --- .../ImplicitFieldInitializationTest.java | 38 --- .../validation/InterfaceClassInitializerTest.java | 43 --- .../PrivateEmptyDefaultConstructorTest.java | 38 --- .../ProbesBeforeSuperConstructorTest.java | 34 --- .../test/validation/ResizeInstructionsTest.java | 171 ------------ .../test/validation/StructuredLockingTest.java | 202 -------------- .../java5/AnnotationInitializerTest.java | 48 ++++ .../test/validation/java5/BadCycleClassTest.java | 40 +++ .../validation/java5/BooleanExpressionsTest.java | 80 ++++++ .../validation/java5/ClassInitializerTest.java | 45 ++++ .../test/validation/java5/ConstructorsTest.java | 63 +++++ ...ControlStructureBeforeSuperConstructorTest.java | 35 +++ .../validation/java5/ControlStructuresTest.java | 138 ++++++++++ .../validation/java5/CyclomaticComplexityTest.java | 280 ++++++++++++++++++++ .../test/validation/java5/EnumConstructorTest.java | 63 +++++ .../validation/java5/EnumImplicitMethodsTest.java | 42 +++ .../core/test/validation/java5/EnumSwitchTest.java | 40 +++ .../core/test/validation/java5/ExceptionsTest.java | 133 ++++++++++ .../validation/java5/ExplicitInitialFrameTest.java | 35 +++ .../FieldInitializationInTwoConstructorsTest.java | 39 +++ .../core/test/validation/java5/FinallyTest.java | 267 +++++++++++++++++++ .../core/test/validation/java5/FramesTest.java | 174 ++++++++++++ .../java5/ImplicitFieldInitializationTest.java | 39 +++ .../java5/InterfaceClassInitializerTest.java | 44 ++++ .../validation/java5/StructuredLockingTest.java | 200 ++++++++++++++ .../test/validation/java5/SynchronizedTest.java | 74 ++++++ .../core/test/validation/java5/SyntheticTest.java | 38 +++ .../java5/targets/AnnotationInitializerTarget.java | 23 ++ .../java5/targets/BadCycleClassTarget.java | 46 ++++ .../java5/targets/BooleanExpressionsTarget.java | 120 +++++++++ .../java5/targets/ClassInitializerTarget.java | 53 ++++ .../java5/targets/ConstructorsTarget.java | 77 ++++++ ...ntrolStructureBeforeSuperConstructorTarget.java | 33 +++ .../java5/targets/ControlStructuresTarget.java | 293 +++++++++++++++++++++ .../java5/targets/EnumConstructorTarget.java | 49 ++++ .../java5/targets/EnumImplicitMethodsTarget.java | 50 ++++ .../validation/java5/targets/EnumSwitchTarget.java | 42 +++ .../validation/java5/targets/ExceptionsTarget.java | 142 ++++++++++ .../java5/targets/ExplicitInitialFrameTarget.java | 31 +++ ...FieldInitializationInTwoConstructorsTarget.java | 34 +++ .../validation/java5/targets/FinallyTarget.java | 148 +++++++++++ .../targets/ImplicitFieldInitializationTarget.java | 31 +++ .../targets/InterfaceClassInitializerTarget.java | 33 +++ .../java5/targets/StructuredLockingTarget.java | 46 ++++ .../java5/targets/SynchronizedTarget.java | 60 +++++ .../validation/java5/targets/SyntheticTarget.java | 64 +++++ .../validation/targets/AnnotationInitializer.java | 23 -- .../test/validation/targets/BadCycleClass.java | 44 ---- .../validation/targets/EnumImplicitMethods.java | 48 ---- .../core/test/validation/targets/Target01.java | 293 --------------------- .../core/test/validation/targets/Target02.java | 120 --------- .../core/test/validation/targets/Target03.java | 142 ---------- .../core/test/validation/targets/Target04.java | 33 --- .../core/test/validation/targets/Target05.java | 51 ---- .../core/test/validation/targets/Target06.java | 25 -- .../core/test/validation/targets/Target07.java | 27 -- .../core/test/validation/targets/Target08.java | 31 --- .../core/test/validation/targets/Target09.java | 34 --- .../core/test/validation/targets/Target10.java | 33 --- .../core/test/validation/targets/Target11.java | 31 --- .../core/test/validation/targets/Target12.java | 46 ---- .../jacoco/core/test/filter/StringSwitchTest.java | 66 ----- .../core/test/filter/TryWithResourcesTest.java | 214 --------------- .../core/test/filter/targets/StringSwitch.java | 96 ------- .../core/test/filter/targets/TryWithResources.java | 204 -------------- .../test/validation/java7/StringSwitchTest.java | 66 +++++ .../validation/java7/TryWithResourcesTest.java | 214 +++++++++++++++ .../java7/targets/StringSwitchTarget.java | 96 +++++++ .../java7/targets/TryWithResourcesTarget.java | 204 ++++++++++++++ .../validation/AnnotationOnLocalVariableTest.java | 35 --- .../test/validation/BadCycleInterfaceTest.java | 49 ---- .../validation/BootstrapMethodReferenceTest.java | 126 --------- .../validation/InterfaceDefaultMethodsTest.java | 34 --- .../InterfaceOnlyDefaultMethodsTest.java | 33 --- .../test/validation/LambdaExpressionsTest.java | 36 --- .../test/validation/LambdaInInterfaceTest.java | 40 --- .../java8/AnnotationOnLocalVariableTest.java | 36 +++ .../validation/java8/BadCycleInterfaceTest.java | 50 ++++ .../java8/BootstrapMethodReferenceTest.java | 128 +++++++++ .../java8/InterfaceDefaultMethodsTest.java | 35 +++ .../java8/InterfaceOnlyDefaultMethodsTest.java | 34 +++ .../validation/java8/LambdaExpressionsTest.java | 37 +++ .../validation/java8/LambdaInInterfaceTest.java | 41 +++ .../targets/AnnotationOnLocalVariableTarget.java | 40 +++ .../java8/targets/BadCycleInterfaceTarget.java | 50 ++++ .../targets/InterfaceDefaultMethodsTarget.java | 42 +++ .../targets/InterfaceOnlyDefaultMethodsTarget.java | 40 +++ .../java8/targets/LambdaExpressionsTarget.java | 35 +++ .../java8/targets/LambdaInInterfaceTarget.java | 25 ++ .../targets/AnnotationOnLocalVariableTarget.java | 40 --- .../test/validation/targets/BadCycleInterface.java | 48 ---- .../targets/InterfaceDefaultMethodsTarget.java | 42 --- .../targets/InterfaceOnlyDefaultMethodsTarget.java | 40 --- .../targets/LambdaExpressionsTarget.java | 35 --- .../targets/LambdaInInterfaceTarget.java | 25 -- .../jacoco/core/instr/ClassFileVersionsTest.java | 195 ++++++++++++++ .../jacoco/core/instr/ResizeInstructionsTest.java | 174 ++++++++++++ 122 files changed, 4834 insertions(+), 4935 deletions(-) delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/ConstructorTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumConstructorTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumSwitchTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/FinallyTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SynchronizedTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SyntheticTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Constructor.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumConstructor.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumSwitch.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Finally.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synchronized.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synthetic.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/AnnotationInitializerTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BadCycleClassTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BooleanExpressionsTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassInitializerTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ControlStructuresTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExceptionsTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExplicitInitialFrameTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FieldInitializationInTwoConstructorsTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FramesTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitDefaultConstructorTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitFieldInitializationTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/InterfaceClassInitializerTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ProbesBeforeSuperConstructorTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/StructuredLockingTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationInitializerTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BadCycleClassTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BooleanExpressionsTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ClassInitializerTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ConstructorsTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructureBeforeSuperConstructorTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructuresTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/CyclomaticComplexityTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumConstructorTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumSwitchTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExceptionsTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExplicitInitialFrameTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FieldInitializationInTwoConstructorsTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FramesTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ImplicitFieldInitializationTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/InterfaceClassInitializerTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/StructuredLockingTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SynchronizedTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SyntheticTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/AnnotationInitializerTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BadCycleClassTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BooleanExpressionsTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ClassInitializerTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ConstructorsTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructureBeforeSuperConstructorTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructuresTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumConstructorTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumImplicitMethodsTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumSwitchTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExceptionsTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExplicitInitialFrameTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FieldInitializationInTwoConstructorsTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FinallyTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ImplicitFieldInitializationTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/InterfaceClassInitializerTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/StructuredLockingTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SynchronizedTarget.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SyntheticTarget.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/AnnotationInitializer.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/BadCycleClass.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target01.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target02.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target03.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target04.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target05.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target06.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target07.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target08.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target09.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target10.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target11.java delete mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target12.java delete mode 100644 org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/StringSwitchTest.java delete mode 100644 org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/TryWithResourcesTest.java delete mode 100644 org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/StringSwitch.java delete mode 100644 org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/TryWithResources.java create mode 100644 org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java create mode 100644 org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java create mode 100644 org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java create mode 100644 org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/TryWithResourcesTarget.java delete mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java delete mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BadCycleInterfaceTest.java delete mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java delete mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java delete mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java delete mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaExpressionsTest.java delete mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaInInterfaceTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/AnnotationOnLocalVariableTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/BadCycleInterfaceTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/BootstrapMethodReferenceTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceDefaultMethodsTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceOnlyDefaultMethodsTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaInInterfaceTest.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/AnnotationOnLocalVariableTarget.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/BadCycleInterfaceTarget.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceDefaultMethodsTarget.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceOnlyDefaultMethodsTarget.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaExpressionsTarget.java create mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaInInterfaceTarget.java delete mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java delete mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/BadCycleInterface.java delete mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java delete mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java delete mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaExpressionsTarget.java delete mode 100644 org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaInInterfaceTarget.java create mode 100644 org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java create mode 100644 org.jacoco.core.test/src/org/jacoco/core/instr/ResizeInstructionsTest.java diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/ConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/ConstructorTest.java deleted file mode 100644 index 1dffc684..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/ConstructorTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.Constructor; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of a bytecode that is generated for a private empty - * constructors that do not have no arguments. - */ -public class ConstructorTest extends ValidationTestBase { - - public ConstructorTest() { - super(Constructor.class); - } - - @Test - public void testCoverageResult() { - // not filtered because not private: - assertLine("packageLocal", ICounter.FULLY_COVERED); - - // not filtered because has argument: - assertLine("arg", ICounter.FULLY_COVERED); - - // not filtered because not empty - prepares arguments for super - // constructor: - assertLine("super", ICounter.FULLY_COVERED); - - // not filtered because contains initialization of a field to hold - // reference to an instance of outer class that is passed as an - // argument: - assertLine("inner", ICounter.FULLY_COVERED); - - // not filtered because not empty - contains initialization of - // a field: - assertLine("innerStatic", ICounter.FULLY_COVERED); - - // not filtered because default constructor for not private inner - // classes is not private: - assertLine("publicDefault", ICounter.FULLY_COVERED); - assertLine("packageLocalDefault", ICounter.FULLY_COVERED); - - assertLine("privateDefault", ICounter.EMPTY); - - assertLine("privateNonEmptyNoArg", ICounter.FULLY_COVERED); - - assertLine("privateEmptyNoArg", ICounter.EMPTY); - assertLine("return", ICounter.EMPTY); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumConstructorTest.java deleted file mode 100644 index fd88787b..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumConstructorTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.EnumConstructor; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of enum constructors. - */ -public class EnumConstructorTest extends ValidationTestBase { - - public EnumConstructorTest() { - super(EnumConstructor.class); - } - - /** - * {@link EnumConstructor.ImplicitConstructor} - */ - @Test - public void implicit_constructor_should_be_filtered() { - // without filter next line is partly covered: - assertLine("implicitConstructor", ICounter.FULLY_COVERED); - } - - /** - * {@link EnumConstructor.ExplicitNonEmptyConstructor#ExplicitNonEmptyConstructor()} - */ - @Test - public void explicit_non_empty_constructor_should_not_be_filtered() { - assertLine("explicitNonEmptyConstructor", ICounter.NOT_COVERED); - } - - /** - * {@link EnumConstructor.ExplicitEmptyConstructor#ExplicitEmptyConstructor()} - */ - @Test - public void explicit_empty_constructor_should_be_filtered() { - // without filter next line is not covered: - assertLine("explicitEmptyConstructor", ICounter.EMPTY); - } - - /** - * {@link EnumConstructor.ExplicitEmptyConstructor#ExplicitEmptyConstructor(Object)} - */ - @Test - public void explicit_empty_constructor_with_parameters_should_not_be_filtered() { - assertLine("explicitEmptyConstructorWithParameter", ICounter.NOT_COVERED); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumSwitchTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumSwitchTest.java deleted file mode 100644 index 3708899a..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/EnumSwitchTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.EnumSwitch; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of a synthetic class that is generated by javac for a enum - * in switch statement. - */ -public class EnumSwitchTest extends ValidationTestBase { - - public EnumSwitchTest() { - super(EnumSwitch.class); - } - - @Test - public void testCoverageResult() { - if (isJDKCompiler && JAVA_VERSION.isBefore("1.6")) { - // class that holds "switch map" is not marked as synthetic when - // compiling with javac 1.5 - assertLine("switch", ICounter.PARTLY_COVERED, 0, 2); - } else { - assertLine("switch", ICounter.FULLY_COVERED, 0, 2); - } - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/FinallyTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/FinallyTest.java deleted file mode 100644 index 2aa97562..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/FinallyTest.java +++ /dev/null @@ -1,267 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.internal.BytecodeVersion; -import org.jacoco.core.test.TargetLoader; -import org.jacoco.core.test.filter.targets.Finally; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.LineNumberNode; -import org.objectweb.asm.tree.MethodNode; - -/** - * Test of filtering of duplicated bytecode that is generated for finally block. - */ -public class FinallyTest extends ValidationTestBase { - - public FinallyTest() { - super(Finally.class); - } - - /** - * {@link Finally#example(boolean)} - */ - @Test - public void example() { - if (isJDKCompiler) { - assertLine("example.0", ICounter.EMPTY); - } else { - assertLine("example.0", ICounter.FULLY_COVERED); - } - assertLine("example.1", ICounter.FULLY_COVERED, 0, 2); - assertLine("example.2", ICounter.FULLY_COVERED); - assertLine("example.3", ICounter.EMPTY); - assertLine("example.4", ICounter.EMPTY); - } - - /** - * GOTO instructions at the end of duplicates of finally block might have - * line number of a last instruction of finally block and hence lead to - * unexpected coverage results, like for example in case of ECJ for - * {@link Finally#catchNotExecuted()}, {@link Finally#emptyCatch()}. So we - * decided to ignore them, even if they can correspond to a real break - * statement. - *

    - * See also JDK-8180141 and - * JDK-7008643. - *

    - * {@link Finally#breakStatement()} - */ - @Test - public void breakStatement() { - assertLine("breakStatement", ICounter.EMPTY); - - assertLine("breakStatement.1", ICounter.FULLY_COVERED); - assertLine("breakStatement.2", ICounter.EMPTY); - } - - /** - * {@link Finally#catchNotExecuted()} - */ - @Test - public void catchNotExecuted() { - assertLine("catchNotExecuted.catch", ICounter.NOT_COVERED); - assertLine("catchNotExecuted.0", ICounter.EMPTY); - assertLine("catchNotExecuted.1", ICounter.FULLY_COVERED); - assertLine("catchNotExecuted.2", ICounter.EMPTY); - } - - /** - * {@link Finally#emptyCatch()} - */ - @Test - public void emptyCatch() { - assertLine("emptyCatch.0", ICounter.EMPTY); - assertLine("emptyCatch.1", ICounter.FULLY_COVERED); - assertLine("emptyCatch.2", ICounter.EMPTY); - } - - /** - * {@link Finally#twoRegions()} - */ - @Test - public void twoRegions() { - assertLine("twoRegions.0", ICounter.EMPTY); - if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { - // https://bugs.openjdk.java.net/browse/JDK-7008643 - assertLine("twoRegions.1", ICounter.PARTLY_COVERED); - assertLine("twoRegions.return.1", ICounter.EMPTY); - assertLine("twoRegions.return.2", ICounter.EMPTY); - } else { - assertLine("twoRegions.1", ICounter.FULLY_COVERED); - assertLine("twoRegions.return.1", ICounter.FULLY_COVERED); - assertLine("twoRegions.return.2", ICounter.NOT_COVERED); - } - assertLine("twoRegions.2", ICounter.EMPTY); - - assertLine("twoRegions.if", ICounter.FULLY_COVERED); - assertLine("twoRegions.region.1", ICounter.FULLY_COVERED); - assertLine("twoRegions.region.2", ICounter.NOT_COVERED); - } - - /** - * {@link Finally#nested()} - */ - @Test - public void nested() { - if (isJDKCompiler) { - assertLine("nested.0", ICounter.EMPTY); - } else { - assertLine("nested.0", ICounter.FULLY_COVERED); - } - assertLine("nested.1", ICounter.EMPTY); - assertLine("nested.2", ICounter.FULLY_COVERED); - if (isJDKCompiler) { - assertLine("nested.3", ICounter.EMPTY); - } else { - assertLine("nested.3", ICounter.FULLY_COVERED); - } - assertLine("nested.4", ICounter.FULLY_COVERED); - } - - /** - * {@link Finally#emptyTry()} - */ - @Test - public void emptyTry() { - assertLine("emptyTry.0", ICounter.EMPTY); - if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { - // compiler bug fixed in javac >= 1.8: - assertLine("emptyTry.1", ICounter.PARTLY_COVERED); - assertLine("emptyTry.2", ICounter.FULLY_COVERED); - } else { - assertLine("emptyTry.1", ICounter.FULLY_COVERED); - assertLine("emptyTry.2", ICounter.EMPTY); - } - } - - /** - * {@link Finally#alwaysCompletesAbruptly()} - */ - @Test - public void alwaysCompletesAbruptly() { - if (isJDKCompiler) { - // uncovered case: - assertLine("alwaysCompletesAbruptly.0", ICounter.EMPTY); - assertLine("alwaysCompletesAbruptly.1", ICounter.PARTLY_COVERED); - } else { - assertLine("alwaysCompletesAbruptly.0", ICounter.PARTLY_COVERED); - assertLine("alwaysCompletesAbruptly.1", ICounter.FULLY_COVERED); - } - assertLine("alwaysCompletesAbruptly.2", ICounter.EMPTY); - } - - /** - * This test studies placement of GOTO instructions. - */ - @Test - public void gotos() throws IOException { - byte[] b = TargetLoader.getClassDataAsBytes(Finally.class); - b = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(b), b); - - final ClassNode classNode = new ClassNode(); - new ClassReader(b).accept(classNode, 0); - final Set tags = new HashSet(); - for (final MethodNode m : classNode.methods) { - if ("main".equals(m.name)) { - // skip it - continue; - } - int lineNumber = -1; - for (AbstractInsnNode i = m.instructions - .getFirst(); i != null; i = i.getNext()) { - if (AbstractInsnNode.LINE == i.getType()) { - lineNumber = ((LineNumberNode) i).line; - } - if (Opcodes.GOTO == i.getOpcode()) { - final String line = getSource().getLine(lineNumber); - if (line.indexOf('$') < 0) { - throw new AssertionError( - "No tag at line " + lineNumber); - } - final String tag = line.substring( - line.indexOf('$') + "$line-".length(), - line.lastIndexOf('$')); - tags.add(tag); - } - } - } - - final Set expected = new HashSet(); - - if (isJDKCompiler) { - expected.add("example.2"); - } else { - expected.add("example.0"); - } - - expected.add("breakStatement.for"); - if (isJDKCompiler) { - if (JAVA_VERSION.isBefore("10")) { - // https://bugs.openjdk.java.net/browse/JDK-8180141 - expected.add("breakStatement.1"); - } else { - expected.add("breakStatement"); - } - expected.add("breakStatement.2"); - } else { - expected.add("breakStatement"); - } - - if (isJDKCompiler) { - expected.add("emptyCatch.2"); - } else { - expected.add("emptyCatch"); - expected.add("emptyCatch.1"); - } - - if (isJDKCompiler) { - expected.add("catchNotExecuted.2"); - } else { - expected.add("catchNotExecuted"); - expected.add("catchNotExecuted.1"); - } - - if (isJDKCompiler) { - expected.add("nested.5"); - expected.add("nested.6"); - } else { - expected.add("nested.0"); - expected.add("nested.3"); - } - - if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { - expected.add("emptyTry.2"); - } - - if (!isJDKCompiler) { - expected.add("alwaysCompletesAbruptly.0"); - } - - assertEquals(expected, tags); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SynchronizedTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SynchronizedTest.java deleted file mode 100644 index 2d0fa973..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SynchronizedTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.Synchronized; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of a bytecode that is generated for a synchronized - * statement. - */ -public class SynchronizedTest extends ValidationTestBase { - - public SynchronizedTest() { - super(Synchronized.class); - } - - /** - * {@link Synchronized#normal()} - */ - @Test - public void normal() { - assertLine("before", ICounter.FULLY_COVERED); - // when compiled with ECJ next line covered partly without filter: - assertLine("monitorEnter", ICounter.FULLY_COVERED); - assertLine("body", ICounter.FULLY_COVERED); - if (isJDKCompiler) { - // without filter next line covered partly: - assertLine("monitorExit", ICounter.FULLY_COVERED); - } else { - assertLine("monitorExit", ICounter.EMPTY); - } - assertLine("after", ICounter.FULLY_COVERED); - } - - /** - * {@link Synchronized#explicitException()} - */ - @Test - public void explicitException() { - assertLine("explicitException.monitorEnter", ICounter.FULLY_COVERED); - assertLine("explicitException.exception", ICounter.FULLY_COVERED); - // when compiled with javac next line covered fully without filter: - assertLine("explicitException.monitorExit", ICounter.EMPTY); - } - - /** - * {@link Synchronized#implicitException()} - */ - @Test - public void implicitException() { - assertLine("implicitException.monitorEnter", isJDKCompiler - ? ICounter.FULLY_COVERED : ICounter.PARTLY_COVERED); - assertLine("implicitException.exception", ICounter.NOT_COVERED); - if (isJDKCompiler) { - // without filter next line covered partly: - assertLine("implicitException.monitorExit", ICounter.NOT_COVERED); - } else { - assertLine("implicitException.monitorExit", ICounter.EMPTY); - } - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SyntheticTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SyntheticTest.java deleted file mode 100644 index f439736b..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/SyntheticTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.Synthetic; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of synthetic methods. - */ -public class SyntheticTest extends ValidationTestBase { - - public SyntheticTest() { - super(Synthetic.class); - } - - @Test - public void testCoverageResult() { - assertMethodCount(5); - - assertLine("classdef", ICounter.EMPTY); - assertLine("field", ICounter.EMPTY); - - assertLine("inner.classdef", ICounter.EMPTY); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Constructor.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Constructor.java deleted file mode 100644 index 8a3e394a..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Constructor.java +++ /dev/null @@ -1,77 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target is a constructors. - */ -public class Constructor { - - Constructor() { // $line-packageLocal$ - } - - private Constructor(Object arg) { // $line-arg$ - } - - private static class Super extends Constructor { - private Super() { - super(null); // $line-super$ - } - } - - private class Inner { - private Inner() { // $line-inner$ - } - } - - private static class InnerStatic { - @SuppressWarnings("unused") - private final Object field = this; - - private InnerStatic() { // $line-innerStatic$ - } - } - - public static class PublicDefault { // $line-publicDefault$ - } - - static class PackageLocalDefault { // $line-packageLocalDefault$ - } - - private static class PrivateDefault { // $line-privateDefault$ - } - - private static class PrivateNonEmptyNoArg { - private PrivateNonEmptyNoArg() { - nop(); // $line-privateNonEmptyNoArg$ - } - } - - private static class PrivateEmptyNoArg { - private PrivateEmptyNoArg() { // $line-privateEmptyNoArg$ - } // $line-return$ - } - - public static void main(String[] args) { - new Super(); - new Constructor().new Inner(); - new InnerStatic(); - new PublicDefault(); - new PackageLocalDefault(); - new PrivateDefault(); - new PrivateNonEmptyNoArg(); - new PrivateEmptyNoArg(); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumConstructor.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumConstructor.java deleted file mode 100644 index c6eb1c53..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumConstructor.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target is an enum constructor. - */ -public class EnumConstructor { - - private enum ImplicitConstructor { // $line-implicitConstructor$ - } - - private enum ExplicitNonEmptyConstructor { - ; - - ExplicitNonEmptyConstructor() { - nop(); // $line-explicitNonEmptyConstructor$ - } - } - - @SuppressWarnings("unused") - private enum ExplicitEmptyConstructor { - ; - - ExplicitEmptyConstructor() { - } // $line-explicitEmptyConstructor$ - - ExplicitEmptyConstructor(Object p) { - } // $line-explicitEmptyConstructorWithParameter$ - } - - public static void main(String[] args) { - ImplicitConstructor.values(); - ExplicitEmptyConstructor.values(); - ExplicitNonEmptyConstructor.values(); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumSwitch.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumSwitch.java deleted file mode 100644 index 850ef295..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/EnumSwitch.java +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target is a switch statement with a enum. - */ -public class EnumSwitch { - - private enum E { - V1, V2 - } - - private static void example(E e) { - switch (e) { // $line-switch$ - case V1: - nop("V1"); - break; - case V2: - default: - nop("V2"); - break; - } - } - - public static void main(String[] args) { - example(E.V1); - example(E.V2); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Finally.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Finally.java deleted file mode 100644 index 6471a809..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Finally.java +++ /dev/null @@ -1,148 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.ex; -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.nop; -import static org.jacoco.core.test.validation.targets.Stubs.t; - -public class Finally { - - /** - *

    -	 *   InputStream in = null;
    -	 *   try {
    -	 *     in = ...;
    -	 *     ...
    -	 *   } finally {
    -	 *     if (in != null) {
    -	 *       in.close();
    -	 *     }
    -	 *   }
    -	 * 
    - */ - private static void example(boolean t) { - Object in = null; - try { - in = open(t); - } finally { // $line-example.0$ - if (in != null) { // $line-example.1$ - nop(); // $line-example.2$ - } // $line-example.3$ - } // $line-example.4$ - } - - private static Object open(boolean t) { - ex(t); - return new Object(); - } - - private static void breakStatement() { - for (int i = 0; i < 1; i++) { // $line-breakStatement.for$ - try { - if (f()) { - break; // $line-breakStatement$ - } - } finally { - nop("finally"); // $line-breakStatement.1$ - } // $line-breakStatement.2$ - } - } - - private static void catchNotExecuted() { - try { - nop("try"); - } catch (Exception e) { // $line-catchNotExecuted$ - nop("catch"); // $line-catchNotExecuted.catch$ - } finally { // $line-catchNotExecuted.0$ - nop("finally"); // $line-catchNotExecuted.1$ - } // $line-catchNotExecuted.2$ - } - - private static void emptyCatch() { - try { - nop("try"); - } catch (Exception e) { // $line-emptyCatch$ - // empty - } finally { // $line-emptyCatch.0$ - nop("finally"); // $line-emptyCatch.1$ - } // $line-emptyCatch.2$ - } - - private static void twoRegions() { - try { - // jump to another region associated with same handler: - if (t()) { // $line-twoRegions.if$ - nop(); // $line-twoRegions.region.1$ - return; // $line-twoRegions.return.1$ - } else { - nop(); // $line-twoRegions.region.2$ - return; // $line-twoRegions.return.2$ - } - } finally { // $line-twoRegions.0$ - nop(); // $line-twoRegions.1$ - } // $line-twoRegions.2$ - } - - private static void nested() { - try { - nop(); - } finally { // $line-nested.0$ - try { // $line-nested.1$ - nop(); // $line-nested.2$ - } finally { // $line-nested.3$ - nop(); // $line-nested.4$ - } // $line-nested.5$ - } // $line-nested.6$ - } - - private static void emptyTry() { - try { - // empty - } finally { // $line-emptyTry.0$ - nop(); // $line-emptyTry.1$ - } // $line-emptyTry.2$ - } - - @SuppressWarnings("finally") - private static void alwaysCompletesAbruptly() { - try { - nop(); - } finally { // $line-alwaysCompletesAbruptly.0$ - return; // $line-alwaysCompletesAbruptly.1$ - } // $line-alwaysCompletesAbruptly.2$ - } - - public static void main(String[] args) { - example(false); - try { - example(true); - } catch (Exception ignore) { - } - - breakStatement(); - - catchNotExecuted(); - - emptyCatch(); - - twoRegions(); - - nested(); - - emptyTry(); - - alwaysCompletesAbruptly(); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synchronized.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synchronized.java deleted file mode 100644 index b2d503f8..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synchronized.java +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.ex; -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -import org.jacoco.core.test.validation.targets.Stubs.StubException; - -/** - * This test target is a synchronized statement. - */ -public class Synchronized { - - private static final Object lock = new Object(); - - private static void normal() { - nop(); // $line-before$ - synchronized (lock) { // $line-monitorEnter$ - nop(); // $line-body$ - } // $line-monitorExit$ - nop(); // $line-after$ - } - - private static void explicitException() { - synchronized (lock) { // $line-explicitException.monitorEnter$ - throw new StubException(); // $line-explicitException.exception$ - } // $line-explicitException.monitorExit$ - } - - private static void implicitException() { - synchronized (lock) { // $line-implicitException.monitorEnter$ - ex(); // $line-implicitException.exception$ - } // $line-implicitException.monitorExit$ - } - - public static void main(String[] args) { - normal(); - - try { - explicitException(); - } catch (StubException e) { - } - - try { - implicitException(); - } catch (StubException e) { - } - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synthetic.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synthetic.java deleted file mode 100644 index 6e2f6266..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/filter/targets/Synthetic.java +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -/** - * This test target is synthetic methods. - */ -public class Synthetic { // $line-classdef$ - - private static int counter; // $line-field$ - - /** - * {@link org.jacoco.core.test.validation.targets.Target06 Default - * constructor will refer to a line of class definition}, so that we define - * constructor explicitly in order to verify that we filter all other - * constructions here that might refer to line of class definition. - */ - private Synthetic() { - } - - static class Inner extends Synthetic { // $line-inner.classdef$ - - Inner() { - } - - /** - * Access to private field of outer class causes creation of synthetic - * methods in it. In case of javac those methods refer to the line of - * outer class definition, in case of ECJ - to the line of field. - */ - private static void inc() { - counter = counter + 2; - } - - /** - * Difference of return type with overridden method causes creation of - * synthetic bridge method in this class. In case of javac this method - * refers to the line of inner class definition, in case of EJC - to the - * first line of file. - */ - @Override - public String get() { - return null; - } - } - - public Object get() { - return null; - } - - public static void main(String[] args) { - Inner.inc(); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/AnnotationInitializerTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/AnnotationInitializerTest.java deleted file mode 100644 index 60a38339..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/AnnotationInitializerTest.java +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.AnnotationInitializer; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * Test of initializer in annotations. - */ -public class AnnotationInitializerTest extends ValidationTestBase { - - public AnnotationInitializerTest() { - super(AnnotationInitializer.class); - } - - @Override - protected void run(Class targetClass) throws Exception { - // Instrumentation should not add members, - // otherwise sun.reflect.annotation.AnnotationInvocationHandler - // can throw java.lang.annotation.AnnotationFormatError - assertEquals(1, targetClass.getDeclaredFields().length); - assertEquals(1, targetClass.getDeclaredMethods().length); - - // Force initialization - targetClass.getField("CONST").get(null); - } - - @Test - public void testCoverageResult() { - assertLine("const", ICounter.FULLY_COVERED); - assertLine("value", ICounter.EMPTY); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BadCycleClassTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BadCycleClassTest.java deleted file mode 100644 index aa646ddf..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BadCycleClassTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.BadCycleClass; -import org.junit.Test; - -/** - * Test of "bad cycles" with classes. - */ -public class BadCycleClassTest extends ValidationTestBase { - - public BadCycleClassTest() throws Exception { - super(BadCycleClass.class); - } - - @Test - public void test() throws Exception { - assertLine("childinit", ICounter.FULLY_COVERED); - assertLine("childsomeMethod", ICounter.FULLY_COVERED); - assertLine("childclinit", ICounter.FULLY_COVERED); - - // The cycle causes a constructor and instance method to be called - // before the static initializer of a class: - assertLogEvents("childinit", "childsomeMethod", "childclinit", - "childinit"); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BooleanExpressionsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BooleanExpressionsTest.java deleted file mode 100644 index 64dee474..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/BooleanExpressionsTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target02; -import org.junit.Test; - -/** - * Tests of basic Java boolean expressions. - */ -public class BooleanExpressionsTest extends ValidationTestBase { - - public BooleanExpressionsTest() { - super(Target02.class); - } - - @Test - public void testCoverageResult() { - - // 1. Boolean comparison result (one case) - assertLine("booleancmp1", ICounter.PARTLY_COVERED, 1, 1); - - // 2. Boolean comparison result (both cases) - assertLine("booleancmp2", ICounter.FULLY_COVERED, 0, 2); - - // 3. And - assertLine("andFF", ICounter.FULLY_COVERED, 1, 1); - assertLine("andFT", ICounter.FULLY_COVERED, 1, 1); - assertLine("andTF", ICounter.FULLY_COVERED, 1, 1); - assertLine("andTT", ICounter.FULLY_COVERED, 1, 1); - - // 4. Conditional And - assertLine("conditionalandFF", ICounter.PARTLY_COVERED, 3, 1); - assertLine("conditionalandFT", ICounter.PARTLY_COVERED, 3, 1); - assertLine("conditionalandTF", ICounter.FULLY_COVERED, 2, 2); - assertLine("conditionalandTT", ICounter.FULLY_COVERED, 2, 2); - - // 5. Or - assertLine("orFF", ICounter.FULLY_COVERED, 1, 1); - assertLine("orFT", ICounter.FULLY_COVERED, 1, 1); - assertLine("orTF", ICounter.FULLY_COVERED, 1, 1); - assertLine("orTT", ICounter.FULLY_COVERED, 1, 1); - - // 6. Conditional Or - assertLine("conditionalorFF", ICounter.FULLY_COVERED, 2, 2); - assertLine("conditionalorFT", ICounter.FULLY_COVERED, 2, 2); - assertLine("conditionalorTF", ICounter.PARTLY_COVERED, 3, 1); - assertLine("conditionalorTT", ICounter.PARTLY_COVERED, 3, 1); - - // 7. Exclusive Or - assertLine("xorFF", ICounter.FULLY_COVERED, 1, 1); - assertLine("xorFT", ICounter.FULLY_COVERED, 1, 1); - assertLine("xorTF", ICounter.FULLY_COVERED, 1, 1); - assertLine("xorTT", ICounter.FULLY_COVERED, 1, 1); - - // 8. Conditional Operator - assertLine("condT", ICounter.PARTLY_COVERED, 1, 1); - assertLine("condF", ICounter.PARTLY_COVERED, 1, 1); - - // 9. Not (one case) - assertLine("notT", ICounter.PARTLY_COVERED, 1, 1); - assertLine("notF", ICounter.PARTLY_COVERED, 1, 1); - - // 10. Not (both cases) - assertLine("notTF", ICounter.FULLY_COVERED, 0, 2); - - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java deleted file mode 100644 index 87d78a21..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassFileVersionsTest.java +++ /dev/null @@ -1,195 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import static org.junit.Assert.assertEquals; -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import static org.objectweb.asm.Opcodes.ACC_SUPER; -import static org.objectweb.asm.Opcodes.ALOAD; -import static org.objectweb.asm.Opcodes.F_NEW; -import static org.objectweb.asm.Opcodes.IFEQ; -import static org.objectweb.asm.Opcodes.ILOAD; -import static org.objectweb.asm.Opcodes.INVOKESPECIAL; -import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; -import static org.objectweb.asm.Opcodes.POP; -import static org.objectweb.asm.Opcodes.RETURN; -import static org.objectweb.asm.Opcodes.V1_1; -import static org.objectweb.asm.Opcodes.V1_2; -import static org.objectweb.asm.Opcodes.V1_3; -import static org.objectweb.asm.Opcodes.V1_4; -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 static org.objectweb.asm.Opcodes.V1_8; -import static org.objectweb.asm.Opcodes.V9; - -import java.io.IOException; - -import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.internal.BytecodeVersion; -import org.jacoco.core.internal.instr.InstrSupport; -import org.jacoco.core.runtime.IRuntime; -import org.jacoco.core.runtime.SystemPropertiesRuntime; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -/** - * Test class inserted stackmap frames for different class file versions. - */ -public class ClassFileVersionsTest { - - @Test - public void test_1_1() throws IOException { - testVersion(V1_1, false); - } - - @Test - public void test_1_2() throws IOException { - testVersion(V1_2, false); - } - - @Test - public void test_1_3() throws IOException { - testVersion(V1_3, false); - } - - @Test - public void test_1_4() throws IOException { - testVersion(V1_4, false); - } - - @Test - public void test_1_5() throws IOException { - testVersion(V1_5, false); - } - - @Test - public void test_1_6() throws IOException { - testVersion(V1_6, true); - } - - @Test - public void test_1_7() throws IOException { - testVersion(V1_7, true); - } - - @Test - public void test_1_8() throws IOException { - testVersion(V1_8, true); - } - - @Test - public void test_9() throws IOException { - testVersion(V9, true); - } - - @Test - public void test_10() throws IOException { - testVersion(BytecodeVersion.V10, true); - } - - private void testVersion(int version, boolean frames) throws IOException { - final byte[] original = createClass(version, frames); - - IRuntime runtime = new SystemPropertiesRuntime(); - Instrumenter instrumenter = new Instrumenter(runtime); - byte[] instrumented = instrumenter.instrument(original, "TestTarget"); - - assertFrames(instrumented, frames); - } - - private void assertFrames(byte[] source, final boolean expected) { - int version = BytecodeVersion.get(source); - source = BytecodeVersion.downgradeIfNeeded(version, source); - new ClassReader(source) - .accept(new ClassVisitor(InstrSupport.ASM_API_VERSION) { - - @Override - public MethodVisitor visitMethod(int access, String name, - String desc, String signature, - String[] exceptions) { - return new MethodVisitor(InstrSupport.ASM_API_VERSION) { - boolean frames = false; - - @Override - public void visitFrame(int type, int nLocal, - Object[] local, int nStack, - Object[] stack) { - frames = true; - } - - @Override - public void visitEnd() { - assertEquals(Boolean.valueOf(expected), - Boolean.valueOf(frames)); - } - }; - } - }, 0); - } - - /** - * Creates a class that requires a frame before the return statement. Also - * for this class instrumentation should insert another frame. - * - *
    -	 * public class Sample {
    -	 *   public Sample(boolean b){
    -	 *     if(b){
    -	 *       toString();
    -	 *     }
    -	 *     return;
    -	 *   }
    -	 * }
    -	 * 
    - */ - private byte[] createClass(int version, boolean frames) { - - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - - cw.visit(version, ACC_PUBLIC + ACC_SUPER, "org/jacoco/test/Sample", - null, "java/lang/Object", null); - - mv = cw.visitMethod(ACC_PUBLIC, "", "(Z)V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", - false); - mv.visitVarInsn(ILOAD, 1); - Label l1 = new Label(); - mv.visitJumpInsn(IFEQ, l1); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", - "()Ljava/lang/String;", false); - mv.visitInsn(POP); - mv.visitLabel(l1); - if (frames) { - mv.visitFrame(F_NEW, 2, - new Object[] { "org/jacoco/test/Sample", Opcodes.INTEGER }, - 0, new Object[] {}); - } - mv.visitInsn(RETURN); - mv.visitMaxs(1, 2); - mv.visitEnd(); - - cw.visitEnd(); - - return cw.toByteArray(); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassInitializerTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassInitializerTest.java deleted file mode 100644 index f87e705c..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ClassInitializerTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target05; -import org.junit.Test; - -/** - * Tests of static initializer in classes. - */ -public class ClassInitializerTest extends ValidationTestBase { - - public ClassInitializerTest() { - super(Target05.class); - } - - @Test - public void testCoverageResult() { - - assertLine("const1", ICounter.EMPTY); - assertLine("const2", ICounter.EMPTY); - - assertLine("const3", ICounter.FULLY_COVERED); - assertLine("const4", ICounter.FULLY_COVERED); - - assertLine("field1", ICounter.FULLY_COVERED); - assertLine("field2", ICounter.FULLY_COVERED); - assertLine("field3", ICounter.FULLY_COVERED); - assertLine("field4", ICounter.FULLY_COVERED); - - assertLine("staticblock", ICounter.FULLY_COVERED); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ControlStructuresTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ControlStructuresTest.java deleted file mode 100644 index 37db4c14..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ControlStructuresTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target01; -import org.junit.Test; - -/** - * Tests of basic Java control structures. - */ -public class ControlStructuresTest extends ValidationTestBase { - - public ControlStructuresTest() { - super(Target01.class); - } - - @Test - public void testCoverageResult() { - - // 1. Direct unconditional execution - assertLine("unconditional", ICounter.FULLY_COVERED); - - // 2. Missed if block - assertLine("iffalse", ICounter.FULLY_COVERED, 1, 1); - assertLine("missedif", ICounter.NOT_COVERED); - assertLine("executedelse", ICounter.FULLY_COVERED); - - // 3. Executed if block - assertLine("iftrue", ICounter.FULLY_COVERED, 1, 1); - assertLine("executedif", ICounter.FULLY_COVERED); - assertLine("missedelse", ICounter.NOT_COVERED); - - // 4. Missed while block - assertLine("whilefalse", ICounter.FULLY_COVERED, 1, 1); - assertLine("missedwhile", ICounter.NOT_COVERED); - - // 5. Always true while block - assertLine("whiletrue", ICounter.FULLY_COVERED, 1, 1); - - // 6. Executed while block - assertLine("whiletruefalse", ICounter.FULLY_COVERED, 0, 2); - assertLine("executedwhile", ICounter.FULLY_COVERED); - - // 7. Executed do while block - assertLine("executeddowhile", ICounter.FULLY_COVERED); - assertLine("executeddowhilefalse", ICounter.FULLY_COVERED, 1, 1); - - // 8. Missed for block - assertLine("missedforincrementer", ICounter.PARTLY_COVERED, 1, 1); - assertLine("missedfor", ICounter.NOT_COVERED); - - // 9. Executed for block - assertLine("executedforincrementer", ICounter.FULLY_COVERED, 0, 2); - assertLine("executedfor", ICounter.FULLY_COVERED); - - // 10. Missed for each block - assertLine("missedforeachincrementer", ICounter.PARTLY_COVERED, 1, 1); - assertLine("missedforeach", ICounter.NOT_COVERED); - - // 11. Executed for each block - assertLine("executedforeachincrementer", ICounter.FULLY_COVERED, 0, 2); - assertLine("executedforeach", ICounter.FULLY_COVERED); - - // 12. Table switch with hit - assertLine("tswitch1", ICounter.FULLY_COVERED, 3, 1); - assertLine("tswitch1case1", ICounter.NOT_COVERED); - assertLine("tswitch1case2", ICounter.FULLY_COVERED); - assertLine("tswitch1case3", ICounter.NOT_COVERED); - assertLine("tswitch1default", ICounter.NOT_COVERED); - - // 13. Continued table switch with hit - assertLine("tswitch2", ICounter.FULLY_COVERED, 3, 1); - assertLine("tswitch2case1", ICounter.NOT_COVERED); - assertLine("tswitch2case2", ICounter.FULLY_COVERED); - assertLine("tswitch2case3", ICounter.FULLY_COVERED); - assertLine("tswitch2default", ICounter.FULLY_COVERED); - - // 14. Table switch without hit - assertLine("tswitch2", ICounter.FULLY_COVERED, 3, 1); - assertLine("tswitch3case1", ICounter.NOT_COVERED); - assertLine("tswitch3case2", ICounter.NOT_COVERED); - assertLine("tswitch3case3", ICounter.NOT_COVERED); - assertLine("tswitch3default", ICounter.FULLY_COVERED); - - // 15. Lookup switch with hit - assertLine("lswitch1", ICounter.FULLY_COVERED, 3, 1); - assertLine("lswitch1case1", ICounter.NOT_COVERED); - assertLine("lswitch1case2", ICounter.FULLY_COVERED); - assertLine("lswitch1case3", ICounter.NOT_COVERED); - assertLine("lswitch1default", ICounter.NOT_COVERED); - - // 16. Continued lookup switch with hit - assertLine("lswitch2", ICounter.FULLY_COVERED, 3, 1); - assertLine("lswitch2case1", ICounter.NOT_COVERED); - assertLine("lswitch2case2", ICounter.FULLY_COVERED); - assertLine("lswitch2case3", ICounter.FULLY_COVERED); - assertLine("lswitch2default", ICounter.FULLY_COVERED); - - // 17. Lookup switch without hit - assertLine("lswitch3", ICounter.FULLY_COVERED, 3, 1); - assertLine("lswitch3case1", ICounter.NOT_COVERED); - assertLine("lswitch3case2", ICounter.NOT_COVERED); - assertLine("lswitch3case3", ICounter.NOT_COVERED); - assertLine("lswitch3default", ICounter.FULLY_COVERED); - - // 18. Break statement - assertLine("executedbreak", ICounter.FULLY_COVERED); - assertLine("missedafterbreak", ICounter.NOT_COVERED); - - // 19. Continue statement - assertLine("executedcontinue", ICounter.FULLY_COVERED); - assertLine("missedaftercontinue", ICounter.NOT_COVERED); - - // 20. Conditional return statement - assertLine("conditionalreturn", ICounter.FULLY_COVERED); - assertLine("afterconditionalreturn", ICounter.NOT_COVERED); - - // 21. Implicit return - assertLine("implicitreturn", ICounter.FULLY_COVERED); - - // 22. Explicit return - assertLine("explicitreturn", ICounter.FULLY_COVERED); - assertLine("afterexplicitreturn", ICounter.EMPTY); - - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java deleted file mode 100644 index 122612ce..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/CyclomaticComplexityTest.java +++ /dev/null @@ -1,280 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; -import static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.util.Collection; - -import org.jacoco.core.analysis.Analyzer; -import org.jacoco.core.analysis.CoverageBuilder; -import org.jacoco.core.analysis.IClassCoverage; -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.analysis.IMethodCoverage; -import org.jacoco.core.data.ExecutionDataStore; -import org.jacoco.core.data.SessionInfoStore; -import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.internal.analysis.CounterImpl; -import org.jacoco.core.runtime.IRuntime; -import org.jacoco.core.runtime.RuntimeData; -import org.jacoco.core.runtime.SystemPropertiesRuntime; -import org.jacoco.core.test.TargetLoader; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Various tests for cyclomatic complexity of methods. - */ -public class CyclomaticComplexityTest { - - public interface Target { - public void test(int arg); - } - - private RuntimeData data; - private IRuntime runtime; - private byte[] bytes; - private Target target; - - @Before - public void setup() throws Exception { - data = new RuntimeData(); - runtime = new SystemPropertiesRuntime(); - runtime.startup(data); - } - - @After - public void teardown() { - runtime.shutdown(); - } - - public static class Simple implements Target { - public void test(int arg) { - nop(); - nop(); - nop(); - } - } - - @Test - public void testSimple1() throws Exception { - instrument(Simple.class); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(1, 0), complexity); - } - - @Test - public void testSimple2() throws Exception { - instrument(Simple.class); - target.test(0); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(0, 1), complexity); - } - - public static class If implements Target { - public void test(int arg) { - if (arg == 0) { - nop(); - } - } - } - - @Test - public void testIf1() throws Exception { - instrument(If.class); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(2, 0), complexity); - } - - @Test - public void testIf2() throws Exception { - instrument(If.class); - target.test(0); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(1, 1), complexity); - } - - @Test - public void testIf3() throws Exception { - instrument(If.class); - target.test(0); - target.test(1); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(0, 2), complexity); - } - - public static class TwoIf implements Target { - public void test(int arg) { - if (arg < 0) { - nop(); - } - if (arg > 0) { - nop(); - } - } - } - - @Test - public void testTwoIf1() throws Exception { - instrument(TwoIf.class); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(3, 0), complexity); - } - - @Test - public void testTwoIf2() throws Exception { - instrument(TwoIf.class); - target.test(-1); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(2, 1), complexity); - } - - @Test - public void testTwoIf3() throws Exception { - instrument(TwoIf.class); - target.test(-1); - target.test(0); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(1, 2), complexity); - } - - @Test - public void testTwoIf4() throws Exception { - instrument(TwoIf.class); - target.test(-1); - target.test(+1); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(0, 3), complexity); - } - - public static class NestedIf implements Target { - public void test(int arg) { - if (arg >= 0) { - if (arg == 0) { - nop(); - } - nop(); - } - } - } - - @Test - public void testNestedIf1() throws Exception { - instrument(NestedIf.class); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(3, 0), complexity); - } - - @Test - public void testNestedIf2() throws Exception { - instrument(NestedIf.class); - target.test(-1); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(2, 1), complexity); - } - - @Test - public void testNestedIf3() throws Exception { - instrument(NestedIf.class); - target.test(-1); - target.test(0); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(1, 2), complexity); - } - - @Test - public void testNestedIf4() throws Exception { - instrument(NestedIf.class); - target.test(-1); - target.test(0); - target.test(+1); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(0, 3), complexity); - } - - public static class Switch implements Target { - public void test(int arg) { - switch (arg) { - case 1: - nop(); - break; - case 2: - nop(); - break; - } - } - } - - @Test - public void testSwitch1() throws Exception { - instrument(Switch.class); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(3, 0), complexity); - } - - @Test - public void testSwitch2() throws Exception { - instrument(Switch.class); - target.test(0); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(2, 1), complexity); - } - - @Test - public void testSwitch3() throws Exception { - instrument(Switch.class); - target.test(0); - target.test(1); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(1, 2), complexity); - } - - @Test - public void testSwitch4() throws Exception { - instrument(Switch.class); - target.test(0); - target.test(1); - target.test(2); - final ICounter complexity = analyze(); - assertEquals(CounterImpl.getInstance(0, 3), complexity); - } - - private void instrument(final Class clazz) - throws Exception { - bytes = TargetLoader.getClassDataAsBytes(clazz); - final byte[] instrumented = new Instrumenter(runtime).instrument(bytes, - "TestTarget"); - final TargetLoader loader = new TargetLoader(); - target = (Target) loader.add(clazz, instrumented).newInstance(); - } - - private ICounter analyze() throws IOException { - final CoverageBuilder builder = new CoverageBuilder(); - final ExecutionDataStore store = new ExecutionDataStore(); - data.collect(store, new SessionInfoStore(), false); - final Analyzer analyzer = new Analyzer(store, builder); - analyzer.analyzeClass(bytes, "TestTarget"); - final Collection classes = builder.getClasses(); - assertEquals(1, classes.size(), 0.0); - final IClassCoverage classCoverage = classes.iterator().next(); - for (final IMethodCoverage m : classCoverage.getMethods()) { - if (m.getName().equals("test")) { - return m.getComplexityCounter(); - } - } - throw new AssertionError("No test() method."); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java deleted file mode 100644 index fbd9e540..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/EnumImplicitMethodsTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.EnumImplicitMethods; -import org.junit.Test; - -/** - * Test of an implicit methods and static initializer in enums. - */ -public class EnumImplicitMethodsTest extends ValidationTestBase { - - public EnumImplicitMethodsTest() { - super(EnumImplicitMethods.class); - } - - @Test - public void testCoverageResult() { - assertMethodCount(5); - - assertLine("classdef", ICounter.FULLY_COVERED); - assertLine("customValueOfMethod", ICounter.NOT_COVERED); - assertLine("customValuesMethod", ICounter.NOT_COVERED); - - assertLine("const", ICounter.PARTLY_COVERED); - assertLine("staticblock", ICounter.FULLY_COVERED); - assertLine("super", ICounter.FULLY_COVERED); - assertLine("constructor", ICounter.FULLY_COVERED); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExceptionsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExceptionsTest.java deleted file mode 100644 index c68bd374..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExceptionsTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target03; -import org.junit.Test; - -/** - * Tests of exception based control flow. - */ -public class ExceptionsTest extends ValidationTestBase { - - public ExceptionsTest() { - super(Target03.class); - } - - @Test - public void testCoverageResult() { - - // 0. Implicit NullPointerException - // Currently no coverage at all, as we don't see when a block aborts - // somewhere in the middle. - assertLine("implicitNullPointerException.before", ICounter.NOT_COVERED); - assertLine("implicitNullPointerException.exception", - ICounter.NOT_COVERED); - assertLine("implicitNullPointerException.after", ICounter.NOT_COVERED); - - // 1. Implicit Exception - assertLine("implicitException.before", ICounter.FULLY_COVERED); - assertLine("implicitException.exception", ICounter.NOT_COVERED); - assertLine("implicitException.after", ICounter.NOT_COVERED); - - // 2. Explicit Exception - // Full coverage, as we recognize throw statements as block boundaries. - assertLine("explicitException.before", ICounter.FULLY_COVERED); - assertLine("explicitException.throw", ICounter.FULLY_COVERED); - - // 3. Try/Catch Block Without Exception Thrown - assertLine("noExceptionTryCatch.beforeBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionTryCatch.tryBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionTryCatch.catch", - isJDKCompiler ? ICounter.NOT_COVERED : ICounter.PARTLY_COVERED); - assertLine("noExceptionTryCatch.catchBlock", ICounter.NOT_COVERED); - assertLine("noExceptionTryCatch.catchBlockEnd", - isJDKCompiler ? ICounter.FULLY_COVERED : ICounter.EMPTY); - assertLine("noExceptionTryCatch.afterBlock", ICounter.FULLY_COVERED); - - // 4. Try/Catch Block With Exception Thrown Implicitly - assertLine("implicitExceptionTryCatch.beforeBlock", - ICounter.FULLY_COVERED); - assertLine("implicitExceptionTryCatch.before", ICounter.FULLY_COVERED); - assertLine("implicitExceptionTryCatch.exception", ICounter.NOT_COVERED); - assertLine("implicitExceptionTryCatch.after", ICounter.NOT_COVERED); - assertLine("implicitExceptionTryCatch.catch", isJDKCompiler - ? ICounter.FULLY_COVERED : ICounter.PARTLY_COVERED); - assertLine("implicitExceptionTryCatch.catchBlock", - ICounter.FULLY_COVERED); - assertLine("implicitExceptionTryCatch.catchBlockEnd", - isJDKCompiler ? ICounter.NOT_COVERED : ICounter.EMPTY); - assertLine("implicitExceptionTryCatch.afterBlock", - ICounter.FULLY_COVERED); - - // 5. Try/Catch Block With Exception Thrown Implicitly After Condition - // As the try/catch block is entered at one branch of the condition - // should be marked as executed - assertLine("implicitExceptionTryCatchAfterCondition.condition", - ICounter.FULLY_COVERED, 1, 1); - assertLine("implicitExceptionTryCatchAfterCondition.exception", - ICounter.NOT_COVERED); - assertLine("implicitExceptionTryCatchAfterCondition.catchBlock", - ICounter.FULLY_COVERED); - - // 6. Try/Catch Block With Exception Thrown Explicitly - assertLine("explicitExceptionTryCatch.beforeBlock", - ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.before", ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.throw", ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.catch", ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.catchBlock", - ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.catchBlockEnd", ICounter.EMPTY); - assertLine("explicitExceptionTryCatch.afterBlock", - ICounter.FULLY_COVERED); - - // 7. Finally Block Without Exception Thrown - assertLine("noExceptionFinally.beforeBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionFinally.tryBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionFinally.finally", - isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); - assertLine("noExceptionFinally.finallyBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionFinally.finallyBlockEnd", ICounter.EMPTY); - assertLine("noExceptionFinally.afterBlock", ICounter.FULLY_COVERED); - - // 8. Finally Block With Implicit Exception - assertLine("implicitExceptionFinally.beforeBlock", - ICounter.FULLY_COVERED); - assertLine("implicitExceptionFinally.before", ICounter.FULLY_COVERED); - assertLine("implicitExceptionFinally.exception", ICounter.NOT_COVERED); - assertLine("implicitExceptionFinally.after", ICounter.NOT_COVERED); - assertLine("implicitExceptionFinally.finally", - isJDKCompiler ? ICounter.EMPTY : ICounter.NOT_COVERED); - assertLine("implicitExceptionFinally.finallyBlock", - ICounter.FULLY_COVERED); - assertLine("implicitExceptionFinally.finallyBlockEnd", ICounter.EMPTY); - assertLine("implicitExceptionFinally.afterBlock", ICounter.NOT_COVERED); - - // 9. Finally Block With Exception Thrown Explicitly - assertLine("explicitExceptionFinally.beforeBlock", - ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.before", ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.throw", ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.finally", - isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.finallyBlock", - ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.finallyBlockEnd", - isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.afterBlock", ICounter.EMPTY); - - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExplicitInitialFrameTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExplicitInitialFrameTest.java deleted file mode 100644 index 1c0a02f1..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ExplicitInitialFrameTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target11; -import org.junit.Test; - -/** - * Test for a methods having a explicit initial frame. - */ -public class ExplicitInitialFrameTest extends ValidationTestBase { - - public ExplicitInitialFrameTest() { - super(Target11.class); - } - - @Test - public void testCoverageResult() { - - assertLine("dowhilebody", ICounter.FULLY_COVERED); - - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FieldInitializationInTwoConstructorsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FieldInitializationInTwoConstructorsTest.java deleted file mode 100644 index 6896bf6d..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FieldInitializationInTwoConstructorsTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target09; -import org.junit.Test; - -/** - * Test of field initialization in two constructors. - */ -public class FieldInitializationInTwoConstructorsTest extends - ValidationTestBase { - - public FieldInitializationInTwoConstructorsTest() { - super(Target09.class); - } - - @Test - public void testCoverageResult() { - - assertLine("field1", ICounter.PARTLY_COVERED); - assertLine("field2", ICounter.PARTLY_COVERED); - assertLine("constr1", ICounter.FULLY_COVERED); - assertLine("constr2", ICounter.NOT_COVERED); - - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FramesTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FramesTest.java deleted file mode 100644 index 9ab062b6..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/FramesTest.java +++ /dev/null @@ -1,179 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import static org.junit.Assert.assertEquals; - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; - -import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.internal.BytecodeVersion; -import org.jacoco.core.internal.instr.InstrSupport; -import org.jacoco.core.runtime.IRuntime; -import org.jacoco.core.runtime.SystemPropertiesRuntime; -import org.jacoco.core.test.TargetLoader; -import org.jacoco.core.test.validation.targets.Target01; -import org.jacoco.core.test.validation.targets.Target02; -import org.jacoco.core.test.validation.targets.Target03; -import org.jacoco.core.test.validation.targets.Target04; -import org.jacoco.core.test.validation.targets.Target05; -import org.jacoco.core.test.validation.targets.Target06; -import org.jacoco.core.test.validation.targets.Target07; -import org.jacoco.core.test.validation.targets.Target08; -import org.jacoco.core.test.validation.targets.Target09; -import org.jacoco.core.test.validation.targets.Target10; -import org.jacoco.core.test.validation.targets.Target11; -import org.jacoco.core.test.validation.targets.Target12; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.util.TraceClassVisitor; - -/** - * Tests whether stackmap frames are correctly adjusted. - */ -public class FramesTest { - - /** - * Stack sizes calculated for instrumented classes might be sometimes bigger - * than actually needed. This is an acceptable tradeoff in favor of keeping - * track of the actual stack sizes. For test assertions we need to replace - * max stack sizes with constant value. - */ - private static class MaxStackEliminator extends ClassVisitor { - public MaxStackEliminator(ClassVisitor cv) { - super(InstrSupport.ASM_API_VERSION, cv); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, - String signature, String[] exceptions) { - final MethodVisitor mv = super.visitMethod(access, name, desc, - signature, exceptions); - return new MethodVisitor(InstrSupport.ASM_API_VERSION, mv) { - @Override - public void visitMaxs(int maxStack, int maxLocals) { - super.visitMaxs(-1, maxLocals); - } - }; - } - } - - private void testFrames(Class target) throws IOException { - testFrames(TargetLoader.getClassDataAsBytes(target)); - } - - private void testFrames(byte[] source) throws IOException { - IRuntime runtime = new SystemPropertiesRuntime(); - Instrumenter instrumenter = new Instrumenter(runtime); - source = calculateFrames(source); - byte[] actual = instrumenter.instrument(source, "TestTarget"); - byte[] expected = calculateFrames(actual); - - assertEquals(dump(expected), dump(actual)); - } - - private byte[] calculateFrames(byte[] source) { - source = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(source), - source); - - ClassReader rc = new ClassReader(source); - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - - // Adjust Version to 1.6 to enable frames: - rc.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, cw) { - - @Override - public void visit(int version, int access, String name, - String signature, String superName, String[] interfaces) { - super.visit(Opcodes.V1_6, access, name, signature, superName, - interfaces); - } - }, 0); - return cw.toByteArray(); - } - - private String dump(byte[] bytes) { - final StringWriter buffer = new StringWriter(); - final PrintWriter writer = new PrintWriter(buffer); - new ClassReader(bytes).accept( - new MaxStackEliminator(new TraceClassVisitor(writer)), - ClassReader.EXPAND_FRAMES); - return buffer.toString(); - } - - @Test - public void testTarget01() throws IOException { - testFrames(Target01.class); - } - - @Test - public void testTarget02() throws IOException { - testFrames(Target02.class); - } - - @Test - public void testTarget03() throws IOException { - testFrames(Target03.class); - } - - @Test - public void testTarget04() throws IOException { - testFrames(Target04.class); - } - - @Test - public void testTarget05() throws IOException { - testFrames(Target05.class); - } - - @Test - public void testTarget06() throws IOException { - testFrames(Target06.class); - } - - @Test - public void testTarget07() throws IOException { - testFrames(Target07.class); - } - - @Test - public void testTarget08() throws IOException { - testFrames(Target08.class); - } - - @Test - public void testTarget09() throws IOException { - testFrames(Target09.class); - } - - @Test - public void testTarget10() throws IOException { - testFrames(Target10.class); - } - - @Test - public void testTarget11() throws IOException { - testFrames(Target11.class); - } - - @Test - public void testTarget12() throws IOException { - testFrames(Target12.class); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitDefaultConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitDefaultConstructorTest.java deleted file mode 100644 index 09872e8d..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitDefaultConstructorTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target06; -import org.junit.Test; - -/** - * Test of a implicit default constructor. - * - * @see PrivateEmptyDefaultConstructorTest - */ -public class ImplicitDefaultConstructorTest extends ValidationTestBase { - - public ImplicitDefaultConstructorTest() { - super(Target06.class); - } - - @Test - public void testCoverageResult() { - - assertLine("classdef", ICounter.FULLY_COVERED); - - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitFieldInitializationTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitFieldInitializationTest.java deleted file mode 100644 index 769593d7..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ImplicitFieldInitializationTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target08; -import org.junit.Test; - -/** - * Test of a implicit field initialization. - */ -public class ImplicitFieldInitializationTest extends ValidationTestBase { - - public ImplicitFieldInitializationTest() { - super(Target08.class); - } - - @Test - public void testCoverageResult() { - - assertLine("classdef", ICounter.FULLY_COVERED); - assertLine("field1", ICounter.EMPTY); - assertLine("field2", ICounter.FULLY_COVERED); - assertLine("field3", ICounter.EMPTY); - assertLine("field4", ICounter.FULLY_COVERED); - - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/InterfaceClassInitializerTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/InterfaceClassInitializerTest.java deleted file mode 100644 index 5675dbb0..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/InterfaceClassInitializerTest.java +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target04; -import org.junit.Test; - -/** - * Tests of static initializer in interfaces. - */ -public class InterfaceClassInitializerTest extends ValidationTestBase { - - public InterfaceClassInitializerTest() { - super(Target04.class); - } - - @Override - protected void run(final Class targetClass) throws Exception { - // Force class initialization - targetClass.getField("CONST1").get(null); - } - - @Test - public void testCoverageResult() { - - assertLine("const1", ICounter.EMPTY); - assertLine("const2", ICounter.EMPTY); - - assertLine("const3", ICounter.FULLY_COVERED); - assertLine("const4", ICounter.FULLY_COVERED); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java deleted file mode 100644 index 1d144b7d..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/PrivateEmptyDefaultConstructorTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target07; -import org.junit.Test; - -/** - * Test of a private empty default constructor. - * - * @see ImplicitDefaultConstructorTest - */ -public class PrivateEmptyDefaultConstructorTest extends ValidationTestBase { - - public PrivateEmptyDefaultConstructorTest() { - super(Target07.class); - } - - @Test - public void testCoverageResult() { - - assertLine("classdef", ICounter.EMPTY); - assertLine("super", ICounter.EMPTY); - assertLine("constructor", ICounter.EMPTY); - - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ProbesBeforeSuperConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ProbesBeforeSuperConstructorTest.java deleted file mode 100644 index 88b1ae54..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ProbesBeforeSuperConstructorTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.Target10; -import org.junit.Test; - -/** - * Test of probes before the super constructor call. - */ -public class ProbesBeforeSuperConstructorTest extends ValidationTestBase { - - public ProbesBeforeSuperConstructorTest() { - super(Target10.class); - } - - @Test - public void testCoverageResult() { - - assertLine("super", ICounter.PARTLY_COVERED, 3, 1); - - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java deleted file mode 100644 index fe6d134a..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/ResizeInstructionsTest.java +++ /dev/null @@ -1,171 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.internal.BytecodeVersion; -import org.jacoco.core.internal.instr.InstrSupport; -import org.jacoco.core.runtime.IRuntime; -import org.jacoco.core.runtime.RuntimeData; -import org.jacoco.core.runtime.SystemPropertiesRuntime; -import org.jacoco.core.test.TargetLoader; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -public class ResizeInstructionsTest { - - private final IRuntime runtime = new SystemPropertiesRuntime(); - private final Instrumenter instrumenter = new Instrumenter(runtime); - - private boolean computedCommonSuperClass = false; - - @Before - public void setup() throws Exception { - runtime.startup(new RuntimeData()); - } - - @After - public void teardown() { - runtime.shutdown(); - } - - private class Inner { - } - - /** - * Test of ASM bug - * #317792. - */ - @Test - public void should_not_loose_InnerClasses_attribute() throws Exception { - byte[] source = TargetLoader.getClassDataAsBytes(Inner.class); - final int version = BytecodeVersion.get(source); - source = BytecodeVersion.downgradeIfNeeded(version, source); - - final ClassReader cr = new ClassReader(source); - final ClassWriter cw = new ClassWriter(0); - cr.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, cw) { - @Override - public void visitEnd() { - final MethodVisitor mv = cv.visitMethod(0, "m", "()V", null, - null); - mv.visitCode(); - addCauseOfResizeInstructions(mv); - mv.visitInsn(Opcodes.NOP); - mv.visitMaxs(2, 1); - mv.visitEnd(); - super.visitEnd(); - } - }, 0); - source = cw.toByteArray(); - BytecodeVersion.set(source, version); - - final byte[] bytes = instrumenter.instrument(source, ""); - - final TargetLoader targetLoader = new TargetLoader(); - final Class outer = targetLoader.add(ResizeInstructionsTest.class, - TargetLoader.getClassDataAsBytes(ResizeInstructionsTest.class)); - final Class inner = targetLoader.add(Inner.class, bytes); - assertSame(outer, inner.getEnclosingClass()); - assertNotNull(inner.getEnclosingClass()); - assertSame(outer, inner.getDeclaringClass()); - assertNotNull(inner.getDeclaringClass()); - } - - /** - * Test of ASM bug - * #317630 that - * caused {@code java.lang.ClassNotFoundException}. - */ - @Test - public void should_not_require_computation_of_common_superclass() - throws Exception { - final String className = "Example"; - - final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES) { - @Override - protected String getCommonSuperClass(final String type1, - final String type2) { - computedCommonSuperClass |= className.equals(type1) - || className.equals(type2); - return "java/lang/Object"; - } - }; - cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, className, null, - "java/lang/Object", null); - final MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "m", "()V", - null, null); - mv.visitCode(); - addCauseOfResizeInstructions(mv); - addCauseOfGetCommonSuperClass(mv); - mv.visitMaxs(1, 1); - mv.visitEnd(); - cw.visitEnd(); - final byte[] original = cw.toByteArray(); - assertTrue(computedCommonSuperClass); - new TargetLoader().add(className, original); - - final byte[] instrumented = instrumenter.instrument(original, - className); - new TargetLoader().add(className, instrumented); - } - - /** - * Adds code that requires - * {@link ClassWriter#getCommonSuperClass(String, String)}. - * - *
    -	 * Object o = this;
    -	 * while (true) {
    -	 * 	o = (Integer) null;
    -	 * }
    -	 * 
    - */ - private static void addCauseOfGetCommonSuperClass(final MethodVisitor mv) { - mv.visitVarInsn(Opcodes.ALOAD, 0); - mv.visitVarInsn(Opcodes.ASTORE, 1); - Label label = new Label(); - mv.visitLabel(label); - mv.visitInsn(Opcodes.ACONST_NULL); - mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Integer"); - mv.visitVarInsn(Opcodes.ASTORE, 1); - mv.visitJumpInsn(Opcodes.GOTO, label); - } - - /** - * Adds code that triggers usage of - * {@link org.objectweb.asm.MethodWriter#COMPUTE_INSERTED_FRAMES} during - * instrumentation. - */ - private static void addCauseOfResizeInstructions(final MethodVisitor mv) { - mv.visitInsn(Opcodes.ICONST_0); - mv.visitInsn(Opcodes.ICONST_1); - final Label target = new Label(); - mv.visitJumpInsn(Opcodes.IFLE, target); - for (int i = 0; i < Short.MAX_VALUE; i++) { - mv.visitInsn(Opcodes.NOP); - } - mv.visitLabel(target); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/StructuredLockingTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/StructuredLockingTest.java deleted file mode 100644 index 823ab787..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/StructuredLockingTest.java +++ /dev/null @@ -1,202 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.internal.BytecodeVersion; -import org.jacoco.core.runtime.IRuntime; -import org.jacoco.core.runtime.SystemPropertiesRuntime; -import org.jacoco.core.test.TargetLoader; -import org.jacoco.core.test.validation.targets.Target12; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; -import org.objectweb.asm.tree.TryCatchBlockNode; -import org.objectweb.asm.tree.VarInsnNode; -import org.objectweb.asm.tree.analysis.Analyzer; -import org.objectweb.asm.tree.analysis.AnalyzerException; -import org.objectweb.asm.tree.analysis.BasicInterpreter; -import org.objectweb.asm.tree.analysis.BasicValue; -import org.objectweb.asm.tree.analysis.Frame; -import org.objectweb.asm.tree.analysis.Interpreter; - -/** - * Tests that the invariants specified in chapter - * 2.11.10 of the JVM Spec do also hold for instrumented classes. - * - * This is important because JIT compiler in HotSpot JVM ignores methods with - * unstructured locking, so that they executed by interpreter. Android Runtime - * also doesn't optimize such methods. - * - * TODO verification implemented here is incomplete - in particular it is unable - * to catch problem described in https://github.com/jacoco/jacoco/issues/626 - */ -public class StructuredLockingTest { - - @Test - public void testTarget12() throws Exception { - testMonitorExit(Target12.class); - } - - private void testMonitorExit(Class target) throws Exception { - assertStructuredLocking(TargetLoader.getClassDataAsBytes(target)); - } - - private void assertStructuredLocking(byte[] source) throws Exception { - IRuntime runtime = new SystemPropertiesRuntime(); - Instrumenter instrumenter = new Instrumenter(runtime); - byte[] instrumented = instrumenter.instrument(source, "TestTarget"); - - final int version = BytecodeVersion.get(instrumented); - instrumented = BytecodeVersion.downgradeIfNeeded(version, instrumented); - - ClassNode cn = new ClassNode(); - new ClassReader(instrumented).accept(cn, 0); - for (MethodNode mn : cn.methods) { - assertStructuredLocking(cn.name, mn); - } - } - - private void assertStructuredLocking(String owner, MethodNode mn) - throws Exception { - Analyzer analyzer = new Analyzer( - new BasicInterpreter()) { - - @Override - protected Frame newFrame(int nLocals, int nStack) { - return new LockFrame(nLocals, nStack); - } - - @Override - protected Frame newFrame(Frame src) { - return new LockFrame(src); - } - }; - - Frame[] frames = analyzer.analyze(owner, mn); - - // Make sure no locks are left when method exits: - for (int i = 0; i < frames.length; i++) { - AbstractInsnNode insn = mn.instructions.get(i); - switch (insn.getOpcode()) { - case Opcodes.IRETURN: - case Opcodes.LRETURN: - case Opcodes.FRETURN: - case Opcodes.DRETURN: - case Opcodes.ARETURN: - case Opcodes.RETURN: - ((LockFrame) frames[i]).assertNoLock("Exit with lock"); - break; - case Opcodes.ATHROW: - List handlers = analyzer.getHandlers(i); - if (handlers == null || handlers.isEmpty()) { - ((LockFrame) frames[i]).assertNoLock("Exit with lock"); - } - break; - } - } - - // Only instructions protected by a catch-all handler can hold locks: - for (int i = 0; i < frames.length; i++) { - AbstractInsnNode insn = mn.instructions.get(i); - if (insn.getOpcode() > 0) { - boolean catchAll = false; - List handlers = analyzer.getHandlers(i); - if (handlers != null) { - for (TryCatchBlockNode node : handlers) { - catchAll |= node.type == null; - } - } - if (!catchAll) { - ((LockFrame) frames[i]) - .assertNoLock("No handlers for insn with lock"); - } - } - } - - } - - /** - * A Frame implementation that keeps track of the locking state. It is - * assumed that the monitor objects are stored in local variables. - */ - private static class LockFrame extends Frame { - - Set locks; - - public LockFrame(final int nLocals, final int nStack) { - super(nLocals, nStack); - locks = new HashSet(); - } - - public LockFrame(Frame src) { - super(src); - } - - @Override - public Frame init(Frame src) { - locks = new HashSet(((LockFrame) src).locks); - return super.init(src); - } - - @Override - public void execute(AbstractInsnNode insn, - Interpreter interpreter) throws AnalyzerException { - super.execute(insn, interpreter); - switch (insn.getOpcode()) { - case Opcodes.MONITORENTER: - // Lock is stored in a local variable: - enter(((VarInsnNode) insn.getPrevious()).var); - break; - case Opcodes.MONITOREXIT: - // Lock is stored in a local variable: - exit(((VarInsnNode) insn.getPrevious()).var); - break; - } - } - - void enter(int lock) { - assertTrue("multiple ENTER for lock " + lock, - locks.add(Integer.valueOf(lock))); - } - - void exit(int lock) { - assertTrue("invalid EXIT for lock " + lock, - locks.remove(Integer.valueOf(lock))); - } - - @Override - public boolean merge(Frame frame, - Interpreter interpreter) throws AnalyzerException { - this.locks.addAll(((LockFrame) frame).locks); - return super.merge(frame, interpreter); - } - - void assertNoLock(String message) { - assertEquals(message, Collections.emptySet(), locks); - - } - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationInitializerTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationInitializerTest.java new file mode 100644 index 00000000..7286cd13 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationInitializerTest.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.AnnotationInitializerTarget; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Test of initializer in annotations. + */ +public class AnnotationInitializerTest extends ValidationTestBase { + + public AnnotationInitializerTest() { + super(AnnotationInitializerTarget.class); + } + + @Override + protected void run(Class targetClass) throws Exception { + // Instrumentation should not add members, + // otherwise sun.reflect.annotation.AnnotationInvocationHandler + // can throw java.lang.annotation.AnnotationFormatError + assertEquals(1, targetClass.getDeclaredFields().length); + assertEquals(1, targetClass.getDeclaredMethods().length); + + // Force initialization + targetClass.getField("CONST").get(null); + } + + @Test + public void testCoverageResult() { + assertLine("const", ICounter.FULLY_COVERED); + assertLine("value", ICounter.EMPTY); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BadCycleClassTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BadCycleClassTest.java new file mode 100644 index 00000000..da53f5a0 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BadCycleClassTest.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.BadCycleClassTarget; +import org.junit.Test; + +/** + * Test of "bad cycles" with classes. + */ +public class BadCycleClassTest extends ValidationTestBase { + + public BadCycleClassTest() throws Exception { + super(BadCycleClassTarget.class); + } + + @Test + public void test() throws Exception { + assertLine("childinit", ICounter.FULLY_COVERED); + assertLine("childsomeMethod", ICounter.FULLY_COVERED); + assertLine("childclinit", ICounter.FULLY_COVERED); + + // The cycle causes a constructor and instance method to be called + // before the static initializer of a class: + assertLogEvents("childinit", "childsomeMethod", "childclinit", + "childinit"); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BooleanExpressionsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BooleanExpressionsTest.java new file mode 100644 index 00000000..f91e1c10 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BooleanExpressionsTest.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.BooleanExpressionsTarget; +import org.junit.Test; + +/** + * Tests of basic Java boolean expressions. + */ +public class BooleanExpressionsTest extends ValidationTestBase { + + public BooleanExpressionsTest() { + super(BooleanExpressionsTarget.class); + } + + @Test + public void testCoverageResult() { + + // 1. Boolean comparison result (one case) + assertLine("booleancmp1", ICounter.PARTLY_COVERED, 1, 1); + + // 2. Boolean comparison result (both cases) + assertLine("booleancmp2", ICounter.FULLY_COVERED, 0, 2); + + // 3. And + assertLine("andFF", ICounter.FULLY_COVERED, 1, 1); + assertLine("andFT", ICounter.FULLY_COVERED, 1, 1); + assertLine("andTF", ICounter.FULLY_COVERED, 1, 1); + assertLine("andTT", ICounter.FULLY_COVERED, 1, 1); + + // 4. Conditional And + assertLine("conditionalandFF", ICounter.PARTLY_COVERED, 3, 1); + assertLine("conditionalandFT", ICounter.PARTLY_COVERED, 3, 1); + assertLine("conditionalandTF", ICounter.FULLY_COVERED, 2, 2); + assertLine("conditionalandTT", ICounter.FULLY_COVERED, 2, 2); + + // 5. Or + assertLine("orFF", ICounter.FULLY_COVERED, 1, 1); + assertLine("orFT", ICounter.FULLY_COVERED, 1, 1); + assertLine("orTF", ICounter.FULLY_COVERED, 1, 1); + assertLine("orTT", ICounter.FULLY_COVERED, 1, 1); + + // 6. Conditional Or + assertLine("conditionalorFF", ICounter.FULLY_COVERED, 2, 2); + assertLine("conditionalorFT", ICounter.FULLY_COVERED, 2, 2); + assertLine("conditionalorTF", ICounter.PARTLY_COVERED, 3, 1); + assertLine("conditionalorTT", ICounter.PARTLY_COVERED, 3, 1); + + // 7. Exclusive Or + assertLine("xorFF", ICounter.FULLY_COVERED, 1, 1); + assertLine("xorFT", ICounter.FULLY_COVERED, 1, 1); + assertLine("xorTF", ICounter.FULLY_COVERED, 1, 1); + assertLine("xorTT", ICounter.FULLY_COVERED, 1, 1); + + // 8. Conditional Operator + assertLine("condT", ICounter.PARTLY_COVERED, 1, 1); + assertLine("condF", ICounter.PARTLY_COVERED, 1, 1); + + // 9. Not (one case) + assertLine("notT", ICounter.PARTLY_COVERED, 1, 1); + assertLine("notF", ICounter.PARTLY_COVERED, 1, 1); + + // 10. Not (both cases) + assertLine("notTF", ICounter.FULLY_COVERED, 0, 2); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ClassInitializerTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ClassInitializerTest.java new file mode 100644 index 00000000..8df6e8d8 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ClassInitializerTest.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.ClassInitializerTarget; +import org.junit.Test; + +/** + * Tests of static initializer in classes. + */ +public class ClassInitializerTest extends ValidationTestBase { + + public ClassInitializerTest() { + super(ClassInitializerTarget.class); + } + + @Test + public void testCoverageResult() { + + assertLine("const1", ICounter.EMPTY); + assertLine("const2", ICounter.EMPTY); + + assertLine("const3", ICounter.FULLY_COVERED); + assertLine("const4", ICounter.FULLY_COVERED); + + assertLine("field1", ICounter.FULLY_COVERED); + assertLine("field2", ICounter.FULLY_COVERED); + assertLine("field3", ICounter.FULLY_COVERED); + assertLine("field4", ICounter.FULLY_COVERED); + + assertLine("staticblock", ICounter.FULLY_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ConstructorsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ConstructorsTest.java new file mode 100644 index 00000000..4c3ed6ac --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ConstructorsTest.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.ConstructorsTarget; +import org.junit.Test; + +/** + * Tests for different constructors. Private empty constructors without + * arguments are filtered. + */ +public class ConstructorsTest extends ValidationTestBase { + + public ConstructorsTest() { + super(ConstructorsTarget.class); + } + + @Test + public void testCoverageResult() { + // not filtered because not private: + assertLine("packageLocal", ICounter.FULLY_COVERED); + + // not filtered because has argument: + assertLine("arg", ICounter.FULLY_COVERED); + + // not filtered because not empty - prepares arguments for super + // constructor: + assertLine("super", ICounter.FULLY_COVERED); + + // not filtered because contains initialization of a field to hold + // reference to an instance of outer class that is passed as an + // argument: + assertLine("inner", ICounter.FULLY_COVERED); + + // not filtered because not empty - contains initialization of + // a field: + assertLine("innerStatic", ICounter.FULLY_COVERED); + + // not filtered because default constructor for not private inner + // classes is not private: + assertLine("publicDefault", ICounter.FULLY_COVERED); + assertLine("packageLocalDefault", ICounter.FULLY_COVERED); + + assertLine("privateDefault", ICounter.EMPTY); + + assertLine("privateNonEmptyNoArg", ICounter.FULLY_COVERED); + + assertLine("privateEmptyNoArg", ICounter.EMPTY); + assertLine("return", ICounter.EMPTY); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructureBeforeSuperConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructureBeforeSuperConstructorTest.java new file mode 100644 index 00000000..d381887a --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructureBeforeSuperConstructorTest.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.ControlStructureBeforeSuperConstructorTarget; +import org.junit.Test; + +/** + * Test of probes before the super constructor call. + */ +public class ControlStructureBeforeSuperConstructorTest extends ValidationTestBase { + + public ControlStructureBeforeSuperConstructorTest() { + super(ControlStructureBeforeSuperConstructorTarget.class); + } + + @Test + public void testCoverageResult() { + + assertLine("super", ICounter.PARTLY_COVERED, 3, 1); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructuresTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructuresTest.java new file mode 100644 index 00000000..768312fc --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructuresTest.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.ControlStructuresTarget; +import org.junit.Test; + +/** + * Tests of basic Java control structures. + */ +public class ControlStructuresTest extends ValidationTestBase { + + public ControlStructuresTest() { + super(ControlStructuresTarget.class); + } + + @Test + public void testCoverageResult() { + + // 1. Direct unconditional execution + assertLine("unconditional", ICounter.FULLY_COVERED); + + // 2. Missed if block + assertLine("iffalse", ICounter.FULLY_COVERED, 1, 1); + assertLine("missedif", ICounter.NOT_COVERED); + assertLine("executedelse", ICounter.FULLY_COVERED); + + // 3. Executed if block + assertLine("iftrue", ICounter.FULLY_COVERED, 1, 1); + assertLine("executedif", ICounter.FULLY_COVERED); + assertLine("missedelse", ICounter.NOT_COVERED); + + // 4. Missed while block + assertLine("whilefalse", ICounter.FULLY_COVERED, 1, 1); + assertLine("missedwhile", ICounter.NOT_COVERED); + + // 5. Always true while block + assertLine("whiletrue", ICounter.FULLY_COVERED, 1, 1); + + // 6. Executed while block + assertLine("whiletruefalse", ICounter.FULLY_COVERED, 0, 2); + assertLine("executedwhile", ICounter.FULLY_COVERED); + + // 7. Executed do while block + assertLine("executeddowhile", ICounter.FULLY_COVERED); + assertLine("executeddowhilefalse", ICounter.FULLY_COVERED, 1, 1); + + // 8. Missed for block + assertLine("missedforincrementer", ICounter.PARTLY_COVERED, 1, 1); + assertLine("missedfor", ICounter.NOT_COVERED); + + // 9. Executed for block + assertLine("executedforincrementer", ICounter.FULLY_COVERED, 0, 2); + assertLine("executedfor", ICounter.FULLY_COVERED); + + // 10. Missed for each block + assertLine("missedforeachincrementer", ICounter.PARTLY_COVERED, 1, 1); + assertLine("missedforeach", ICounter.NOT_COVERED); + + // 11. Executed for each block + assertLine("executedforeachincrementer", ICounter.FULLY_COVERED, 0, 2); + assertLine("executedforeach", ICounter.FULLY_COVERED); + + // 12. Table switch with hit + assertLine("tswitch1", ICounter.FULLY_COVERED, 3, 1); + assertLine("tswitch1case1", ICounter.NOT_COVERED); + assertLine("tswitch1case2", ICounter.FULLY_COVERED); + assertLine("tswitch1case3", ICounter.NOT_COVERED); + assertLine("tswitch1default", ICounter.NOT_COVERED); + + // 13. Continued table switch with hit + assertLine("tswitch2", ICounter.FULLY_COVERED, 3, 1); + assertLine("tswitch2case1", ICounter.NOT_COVERED); + assertLine("tswitch2case2", ICounter.FULLY_COVERED); + assertLine("tswitch2case3", ICounter.FULLY_COVERED); + assertLine("tswitch2default", ICounter.FULLY_COVERED); + + // 14. Table switch without hit + assertLine("tswitch2", ICounter.FULLY_COVERED, 3, 1); + assertLine("tswitch3case1", ICounter.NOT_COVERED); + assertLine("tswitch3case2", ICounter.NOT_COVERED); + assertLine("tswitch3case3", ICounter.NOT_COVERED); + assertLine("tswitch3default", ICounter.FULLY_COVERED); + + // 15. Lookup switch with hit + assertLine("lswitch1", ICounter.FULLY_COVERED, 3, 1); + assertLine("lswitch1case1", ICounter.NOT_COVERED); + assertLine("lswitch1case2", ICounter.FULLY_COVERED); + assertLine("lswitch1case3", ICounter.NOT_COVERED); + assertLine("lswitch1default", ICounter.NOT_COVERED); + + // 16. Continued lookup switch with hit + assertLine("lswitch2", ICounter.FULLY_COVERED, 3, 1); + assertLine("lswitch2case1", ICounter.NOT_COVERED); + assertLine("lswitch2case2", ICounter.FULLY_COVERED); + assertLine("lswitch2case3", ICounter.FULLY_COVERED); + assertLine("lswitch2default", ICounter.FULLY_COVERED); + + // 17. Lookup switch without hit + assertLine("lswitch3", ICounter.FULLY_COVERED, 3, 1); + assertLine("lswitch3case1", ICounter.NOT_COVERED); + assertLine("lswitch3case2", ICounter.NOT_COVERED); + assertLine("lswitch3case3", ICounter.NOT_COVERED); + assertLine("lswitch3default", ICounter.FULLY_COVERED); + + // 18. Break statement + assertLine("executedbreak", ICounter.FULLY_COVERED); + assertLine("missedafterbreak", ICounter.NOT_COVERED); + + // 19. Continue statement + assertLine("executedcontinue", ICounter.FULLY_COVERED); + assertLine("missedaftercontinue", ICounter.NOT_COVERED); + + // 20. Conditional return statement + assertLine("conditionalreturn", ICounter.FULLY_COVERED); + assertLine("afterconditionalreturn", ICounter.NOT_COVERED); + + // 21. Implicit return + assertLine("implicitreturn", ICounter.FULLY_COVERED); + + // 22. Explicit return + assertLine("explicitreturn", ICounter.FULLY_COVERED); + assertLine("afterexplicitreturn", ICounter.EMPTY); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/CyclomaticComplexityTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/CyclomaticComplexityTest.java new file mode 100644 index 00000000..b7b11286 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/CyclomaticComplexityTest.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.Collection; + +import org.jacoco.core.analysis.Analyzer; +import org.jacoco.core.analysis.CoverageBuilder; +import org.jacoco.core.analysis.IClassCoverage; +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.analysis.IMethodCoverage; +import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.data.SessionInfoStore; +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.analysis.CounterImpl; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.RuntimeData; +import org.jacoco.core.runtime.SystemPropertiesRuntime; +import org.jacoco.core.test.TargetLoader; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Various tests for cyclomatic complexity of methods. + */ +public class CyclomaticComplexityTest { + + public interface Target { + public void test(int arg); + } + + private RuntimeData data; + private IRuntime runtime; + private byte[] bytes; + private Target target; + + @Before + public void setup() throws Exception { + data = new RuntimeData(); + runtime = new SystemPropertiesRuntime(); + runtime.startup(data); + } + + @After + public void teardown() { + runtime.shutdown(); + } + + public static class Simple implements Target { + public void test(int arg) { + nop(); + nop(); + nop(); + } + } + + @Test + public void testSimple1() throws Exception { + instrument(Simple.class); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(1, 0), complexity); + } + + @Test + public void testSimple2() throws Exception { + instrument(Simple.class); + target.test(0); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(0, 1), complexity); + } + + public static class If implements Target { + public void test(int arg) { + if (arg == 0) { + nop(); + } + } + } + + @Test + public void testIf1() throws Exception { + instrument(If.class); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(2, 0), complexity); + } + + @Test + public void testIf2() throws Exception { + instrument(If.class); + target.test(0); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(1, 1), complexity); + } + + @Test + public void testIf3() throws Exception { + instrument(If.class); + target.test(0); + target.test(1); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(0, 2), complexity); + } + + public static class TwoIf implements Target { + public void test(int arg) { + if (arg < 0) { + nop(); + } + if (arg > 0) { + nop(); + } + } + } + + @Test + public void testTwoIf1() throws Exception { + instrument(TwoIf.class); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(3, 0), complexity); + } + + @Test + public void testTwoIf2() throws Exception { + instrument(TwoIf.class); + target.test(-1); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(2, 1), complexity); + } + + @Test + public void testTwoIf3() throws Exception { + instrument(TwoIf.class); + target.test(-1); + target.test(0); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(1, 2), complexity); + } + + @Test + public void testTwoIf4() throws Exception { + instrument(TwoIf.class); + target.test(-1); + target.test(+1); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(0, 3), complexity); + } + + public static class NestedIf implements Target { + public void test(int arg) { + if (arg >= 0) { + if (arg == 0) { + nop(); + } + nop(); + } + } + } + + @Test + public void testNestedIf1() throws Exception { + instrument(NestedIf.class); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(3, 0), complexity); + } + + @Test + public void testNestedIf2() throws Exception { + instrument(NestedIf.class); + target.test(-1); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(2, 1), complexity); + } + + @Test + public void testNestedIf3() throws Exception { + instrument(NestedIf.class); + target.test(-1); + target.test(0); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(1, 2), complexity); + } + + @Test + public void testNestedIf4() throws Exception { + instrument(NestedIf.class); + target.test(-1); + target.test(0); + target.test(+1); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(0, 3), complexity); + } + + public static class Switch implements Target { + public void test(int arg) { + switch (arg) { + case 1: + nop(); + break; + case 2: + nop(); + break; + } + } + } + + @Test + public void testSwitch1() throws Exception { + instrument(Switch.class); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(3, 0), complexity); + } + + @Test + public void testSwitch2() throws Exception { + instrument(Switch.class); + target.test(0); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(2, 1), complexity); + } + + @Test + public void testSwitch3() throws Exception { + instrument(Switch.class); + target.test(0); + target.test(1); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(1, 2), complexity); + } + + @Test + public void testSwitch4() throws Exception { + instrument(Switch.class); + target.test(0); + target.test(1); + target.test(2); + final ICounter complexity = analyze(); + assertEquals(CounterImpl.getInstance(0, 3), complexity); + } + + private void instrument(final Class clazz) + throws Exception { + bytes = TargetLoader.getClassDataAsBytes(clazz); + final byte[] instrumented = new Instrumenter(runtime).instrument(bytes, + "TestTarget"); + final TargetLoader loader = new TargetLoader(); + target = (Target) loader.add(clazz, instrumented).newInstance(); + } + + private ICounter analyze() throws IOException { + final CoverageBuilder builder = new CoverageBuilder(); + final ExecutionDataStore store = new ExecutionDataStore(); + data.collect(store, new SessionInfoStore(), false); + final Analyzer analyzer = new Analyzer(store, builder); + analyzer.analyzeClass(bytes, "TestTarget"); + final Collection classes = builder.getClasses(); + assertEquals(1, classes.size(), 0.0); + final IClassCoverage classCoverage = classes.iterator().next(); + for (final IMethodCoverage m : classCoverage.getMethods()) { + if (m.getName().equals("test")) { + return m.getComplexityCounter(); + } + } + throw new AssertionError("No test() method."); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumConstructorTest.java new file mode 100644 index 00000000..28652700 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumConstructorTest.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.EnumConstructorTarget; +import org.junit.Test; + +/** + * Test of filtering of enum constructors. + */ +public class EnumConstructorTest extends ValidationTestBase { + + public EnumConstructorTest() { + super(EnumConstructorTarget.class); + } + + /** + * {@link EnumConstructorTarget.ImplicitConstructor} + */ + @Test + public void implicit_constructor_should_be_filtered() { + // without filter next line is partly covered: + assertLine("implicitConstructor", ICounter.FULLY_COVERED); + } + + /** + * {@link EnumConstructorTarget.ExplicitNonEmptyConstructor#ExplicitNonEmptyConstructor()} + */ + @Test + public void explicit_non_empty_constructor_should_not_be_filtered() { + assertLine("explicitNonEmptyConstructor", ICounter.NOT_COVERED); + } + + /** + * {@link EnumConstructorTarget.ExplicitEmptyConstructor#ExplicitEmptyConstructor()} + */ + @Test + public void explicit_empty_constructor_should_be_filtered() { + // without filter next line is not covered: + assertLine("explicitEmptyConstructor", ICounter.EMPTY); + } + + /** + * {@link EnumConstructorTarget.ExplicitEmptyConstructor#ExplicitEmptyConstructor(Object)} + */ + @Test + public void explicit_empty_constructor_with_parameters_should_not_be_filtered() { + assertLine("explicitEmptyConstructorWithParameter", + ICounter.NOT_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java new file mode 100644 index 00000000..0f6a8660 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.EnumImplicitMethodsTarget; +import org.junit.Test; + +/** + * Test of an implicit methods and static initializer in enums. + */ +public class EnumImplicitMethodsTest extends ValidationTestBase { + + public EnumImplicitMethodsTest() { + super(EnumImplicitMethodsTarget.class); + } + + @Test + public void testCoverageResult() { + assertMethodCount(5); + + assertLine("classdef", ICounter.FULLY_COVERED); + assertLine("customValueOfMethod", ICounter.NOT_COVERED); + assertLine("customValuesMethod", ICounter.NOT_COVERED); + + assertLine("const", ICounter.PARTLY_COVERED); + assertLine("staticblock", ICounter.FULLY_COVERED); + assertLine("super", ICounter.FULLY_COVERED); + assertLine("constructor", ICounter.FULLY_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumSwitchTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumSwitchTest.java new file mode 100644 index 00000000..fa3c44ca --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumSwitchTest.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.EnumSwitchTarget; +import org.junit.Test; + +/** + * Test of filtering of a synthetic class that is generated by javac for a enum + * in switch statement. + */ +public class EnumSwitchTest extends ValidationTestBase { + + public EnumSwitchTest() { + super(EnumSwitchTarget.class); + } + + @Test + public void testCoverageResult() { + if (isJDKCompiler && JAVA_VERSION.isBefore("1.6")) { + // class that holds "switch map" is not marked as synthetic when + // compiling with javac 1.5 + assertLine("switch", ICounter.PARTLY_COVERED, 0, 2); + } else { + assertLine("switch", ICounter.FULLY_COVERED, 0, 2); + } + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExceptionsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExceptionsTest.java new file mode 100644 index 00000000..15e47167 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExceptionsTest.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.ExceptionsTarget; +import org.junit.Test; + +/** + * Tests of exception based control flow. + */ +public class ExceptionsTest extends ValidationTestBase { + + public ExceptionsTest() { + super(ExceptionsTarget.class); + } + + @Test + public void testCoverageResult() { + + // 0. Implicit NullPointerException + // Currently no coverage at all, as we don't see when a block aborts + // somewhere in the middle. + assertLine("implicitNullPointerException.before", ICounter.NOT_COVERED); + assertLine("implicitNullPointerException.exception", + ICounter.NOT_COVERED); + assertLine("implicitNullPointerException.after", ICounter.NOT_COVERED); + + // 1. Implicit Exception + assertLine("implicitException.before", ICounter.FULLY_COVERED); + assertLine("implicitException.exception", ICounter.NOT_COVERED); + assertLine("implicitException.after", ICounter.NOT_COVERED); + + // 2. Explicit Exception + // Full coverage, as we recognize throw statements as block boundaries. + assertLine("explicitException.before", ICounter.FULLY_COVERED); + assertLine("explicitException.throw", ICounter.FULLY_COVERED); + + // 3. Try/Catch Block Without Exception Thrown + assertLine("noExceptionTryCatch.beforeBlock", ICounter.FULLY_COVERED); + assertLine("noExceptionTryCatch.tryBlock", ICounter.FULLY_COVERED); + assertLine("noExceptionTryCatch.catch", + isJDKCompiler ? ICounter.NOT_COVERED : ICounter.PARTLY_COVERED); + assertLine("noExceptionTryCatch.catchBlock", ICounter.NOT_COVERED); + assertLine("noExceptionTryCatch.catchBlockEnd", + isJDKCompiler ? ICounter.FULLY_COVERED : ICounter.EMPTY); + assertLine("noExceptionTryCatch.afterBlock", ICounter.FULLY_COVERED); + + // 4. Try/Catch Block With Exception Thrown Implicitly + assertLine("implicitExceptionTryCatch.beforeBlock", + ICounter.FULLY_COVERED); + assertLine("implicitExceptionTryCatch.before", ICounter.FULLY_COVERED); + assertLine("implicitExceptionTryCatch.exception", ICounter.NOT_COVERED); + assertLine("implicitExceptionTryCatch.after", ICounter.NOT_COVERED); + assertLine("implicitExceptionTryCatch.catch", isJDKCompiler + ? ICounter.FULLY_COVERED : ICounter.PARTLY_COVERED); + assertLine("implicitExceptionTryCatch.catchBlock", + ICounter.FULLY_COVERED); + assertLine("implicitExceptionTryCatch.catchBlockEnd", + isJDKCompiler ? ICounter.NOT_COVERED : ICounter.EMPTY); + assertLine("implicitExceptionTryCatch.afterBlock", + ICounter.FULLY_COVERED); + + // 5. Try/Catch Block With Exception Thrown Implicitly After Condition + // As the try/catch block is entered at one branch of the condition + // should be marked as executed + assertLine("implicitExceptionTryCatchAfterCondition.condition", + ICounter.FULLY_COVERED, 1, 1); + assertLine("implicitExceptionTryCatchAfterCondition.exception", + ICounter.NOT_COVERED); + assertLine("implicitExceptionTryCatchAfterCondition.catchBlock", + ICounter.FULLY_COVERED); + + // 6. Try/Catch Block With Exception Thrown Explicitly + assertLine("explicitExceptionTryCatch.beforeBlock", + ICounter.FULLY_COVERED); + assertLine("explicitExceptionTryCatch.before", ICounter.FULLY_COVERED); + assertLine("explicitExceptionTryCatch.throw", ICounter.FULLY_COVERED); + assertLine("explicitExceptionTryCatch.catch", ICounter.FULLY_COVERED); + assertLine("explicitExceptionTryCatch.catchBlock", + ICounter.FULLY_COVERED); + assertLine("explicitExceptionTryCatch.catchBlockEnd", ICounter.EMPTY); + assertLine("explicitExceptionTryCatch.afterBlock", + ICounter.FULLY_COVERED); + + // 7. Finally Block Without Exception Thrown + assertLine("noExceptionFinally.beforeBlock", ICounter.FULLY_COVERED); + assertLine("noExceptionFinally.tryBlock", ICounter.FULLY_COVERED); + assertLine("noExceptionFinally.finally", + isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); + assertLine("noExceptionFinally.finallyBlock", ICounter.FULLY_COVERED); + assertLine("noExceptionFinally.finallyBlockEnd", ICounter.EMPTY); + assertLine("noExceptionFinally.afterBlock", ICounter.FULLY_COVERED); + + // 8. Finally Block With Implicit Exception + assertLine("implicitExceptionFinally.beforeBlock", + ICounter.FULLY_COVERED); + assertLine("implicitExceptionFinally.before", ICounter.FULLY_COVERED); + assertLine("implicitExceptionFinally.exception", ICounter.NOT_COVERED); + assertLine("implicitExceptionFinally.after", ICounter.NOT_COVERED); + assertLine("implicitExceptionFinally.finally", + isJDKCompiler ? ICounter.EMPTY : ICounter.NOT_COVERED); + assertLine("implicitExceptionFinally.finallyBlock", + ICounter.FULLY_COVERED); + assertLine("implicitExceptionFinally.finallyBlockEnd", ICounter.EMPTY); + assertLine("implicitExceptionFinally.afterBlock", ICounter.NOT_COVERED); + + // 9. Finally Block With Exception Thrown Explicitly + assertLine("explicitExceptionFinally.beforeBlock", + ICounter.FULLY_COVERED); + assertLine("explicitExceptionFinally.before", ICounter.FULLY_COVERED); + assertLine("explicitExceptionFinally.throw", ICounter.FULLY_COVERED); + assertLine("explicitExceptionFinally.finally", + isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); + assertLine("explicitExceptionFinally.finallyBlock", + ICounter.FULLY_COVERED); + assertLine("explicitExceptionFinally.finallyBlockEnd", + isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); + assertLine("explicitExceptionFinally.afterBlock", ICounter.EMPTY); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExplicitInitialFrameTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExplicitInitialFrameTest.java new file mode 100644 index 00000000..b04c1a6b --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExplicitInitialFrameTest.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.ExplicitInitialFrameTarget; +import org.junit.Test; + +/** + * Test for a methods having a explicit initial frame. + */ +public class ExplicitInitialFrameTest extends ValidationTestBase { + + public ExplicitInitialFrameTest() { + super(ExplicitInitialFrameTarget.class); + } + + @Test + public void testCoverageResult() { + + assertLine("dowhilebody", ICounter.FULLY_COVERED); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FieldInitializationInTwoConstructorsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FieldInitializationInTwoConstructorsTest.java new file mode 100644 index 00000000..6be37f4d --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FieldInitializationInTwoConstructorsTest.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.FieldInitializationInTwoConstructorsTarget; +import org.junit.Test; + +/** + * Test of field initialization in two constructors. + */ +public class FieldInitializationInTwoConstructorsTest extends + ValidationTestBase { + + public FieldInitializationInTwoConstructorsTest() { + super(FieldInitializationInTwoConstructorsTarget.class); + } + + @Test + public void testCoverageResult() { + + assertLine("field1", ICounter.PARTLY_COVERED); + assertLine("field2", ICounter.PARTLY_COVERED); + assertLine("constr1", ICounter.FULLY_COVERED); + assertLine("constr2", ICounter.NOT_COVERED); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java new file mode 100644 index 00000000..8531a501 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java @@ -0,0 +1,267 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.internal.BytecodeVersion; +import org.jacoco.core.test.TargetLoader; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.FinallyTarget; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.LineNumberNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Test of filtering of duplicated bytecode that is generated for finally block. + */ +public class FinallyTest extends ValidationTestBase { + + public FinallyTest() { + super(FinallyTarget.class); + } + + /** + * {@link FinallyTarget#example(boolean)} + */ + @Test + public void example() { + if (isJDKCompiler) { + assertLine("example.0", ICounter.EMPTY); + } else { + assertLine("example.0", ICounter.FULLY_COVERED); + } + assertLine("example.1", ICounter.FULLY_COVERED, 0, 2); + assertLine("example.2", ICounter.FULLY_COVERED); + assertLine("example.3", ICounter.EMPTY); + assertLine("example.4", ICounter.EMPTY); + } + + /** + * GOTO instructions at the end of duplicates of finally block might have + * line number of a last instruction of finally block and hence lead to + * unexpected coverage results, like for example in case of ECJ for + * {@link FinallyTarget#catchNotExecuted()}, + * {@link FinallyTarget#emptyCatch()}. So we decided to ignore them, even if + * they can correspond to a real break statement. + *

    + * See also JDK-8180141 and + * JDK-7008643. + *

    + * {@link FinallyTarget#breakStatement()} + */ + @Test + public void breakStatement() { + assertLine("breakStatement", ICounter.EMPTY); + + assertLine("breakStatement.1", ICounter.FULLY_COVERED); + assertLine("breakStatement.2", ICounter.EMPTY); + } + + /** + * {@link FinallyTarget#catchNotExecuted()} + */ + @Test + public void catchNotExecuted() { + assertLine("catchNotExecuted.catch", ICounter.NOT_COVERED); + assertLine("catchNotExecuted.0", ICounter.EMPTY); + assertLine("catchNotExecuted.1", ICounter.FULLY_COVERED); + assertLine("catchNotExecuted.2", ICounter.EMPTY); + } + + /** + * {@link FinallyTarget#emptyCatch()} + */ + @Test + public void emptyCatch() { + assertLine("emptyCatch.0", ICounter.EMPTY); + assertLine("emptyCatch.1", ICounter.FULLY_COVERED); + assertLine("emptyCatch.2", ICounter.EMPTY); + } + + /** + * {@link FinallyTarget#twoRegions()} + */ + @Test + public void twoRegions() { + assertLine("twoRegions.0", ICounter.EMPTY); + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { + // https://bugs.openjdk.java.net/browse/JDK-7008643 + assertLine("twoRegions.1", ICounter.PARTLY_COVERED); + assertLine("twoRegions.return.1", ICounter.EMPTY); + assertLine("twoRegions.return.2", ICounter.EMPTY); + } else { + assertLine("twoRegions.1", ICounter.FULLY_COVERED); + assertLine("twoRegions.return.1", ICounter.FULLY_COVERED); + assertLine("twoRegions.return.2", ICounter.NOT_COVERED); + } + assertLine("twoRegions.2", ICounter.EMPTY); + + assertLine("twoRegions.if", ICounter.FULLY_COVERED); + assertLine("twoRegions.region.1", ICounter.FULLY_COVERED); + assertLine("twoRegions.region.2", ICounter.NOT_COVERED); + } + + /** + * {@link FinallyTarget#nested()} + */ + @Test + public void nested() { + if (isJDKCompiler) { + assertLine("nested.0", ICounter.EMPTY); + } else { + assertLine("nested.0", ICounter.FULLY_COVERED); + } + assertLine("nested.1", ICounter.EMPTY); + assertLine("nested.2", ICounter.FULLY_COVERED); + if (isJDKCompiler) { + assertLine("nested.3", ICounter.EMPTY); + } else { + assertLine("nested.3", ICounter.FULLY_COVERED); + } + assertLine("nested.4", ICounter.FULLY_COVERED); + } + + /** + * {@link FinallyTarget#emptyTry()} + */ + @Test + public void emptyTry() { + assertLine("emptyTry.0", ICounter.EMPTY); + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { + // compiler bug fixed in javac >= 1.8: + assertLine("emptyTry.1", ICounter.PARTLY_COVERED); + assertLine("emptyTry.2", ICounter.FULLY_COVERED); + } else { + assertLine("emptyTry.1", ICounter.FULLY_COVERED); + assertLine("emptyTry.2", ICounter.EMPTY); + } + } + + /** + * {@link FinallyTarget#alwaysCompletesAbruptly()} + */ + @Test + public void alwaysCompletesAbruptly() { + if (isJDKCompiler) { + // uncovered case: + assertLine("alwaysCompletesAbruptly.0", ICounter.EMPTY); + assertLine("alwaysCompletesAbruptly.1", ICounter.PARTLY_COVERED); + } else { + assertLine("alwaysCompletesAbruptly.0", ICounter.PARTLY_COVERED); + assertLine("alwaysCompletesAbruptly.1", ICounter.FULLY_COVERED); + } + assertLine("alwaysCompletesAbruptly.2", ICounter.EMPTY); + } + + /** + * This test studies placement of GOTO instructions. + */ + @Test + public void gotos() throws IOException { + byte[] b = TargetLoader.getClassDataAsBytes(FinallyTarget.class); + b = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(b), b); + + final ClassNode classNode = new ClassNode(); + new ClassReader(b).accept(classNode, 0); + final Set tags = new HashSet(); + for (final MethodNode m : classNode.methods) { + if ("main".equals(m.name)) { + // skip it + continue; + } + int lineNumber = -1; + for (AbstractInsnNode i = m.instructions + .getFirst(); i != null; i = i.getNext()) { + if (AbstractInsnNode.LINE == i.getType()) { + lineNumber = ((LineNumberNode) i).line; + } + if (Opcodes.GOTO == i.getOpcode()) { + final String line = getSource().getLine(lineNumber); + if (line.indexOf('$') < 0) { + throw new AssertionError( + "No tag at line " + lineNumber); + } + final String tag = line.substring( + line.indexOf('$') + "$line-".length(), + line.lastIndexOf('$')); + tags.add(tag); + } + } + } + + final Set expected = new HashSet(); + + if (isJDKCompiler) { + expected.add("example.2"); + } else { + expected.add("example.0"); + } + + expected.add("breakStatement.for"); + if (isJDKCompiler) { + if (JAVA_VERSION.isBefore("10")) { + // https://bugs.openjdk.java.net/browse/JDK-8180141 + expected.add("breakStatement.1"); + } else { + expected.add("breakStatement"); + } + expected.add("breakStatement.2"); + } else { + expected.add("breakStatement"); + } + + if (isJDKCompiler) { + expected.add("emptyCatch.2"); + } else { + expected.add("emptyCatch"); + expected.add("emptyCatch.1"); + } + + if (isJDKCompiler) { + expected.add("catchNotExecuted.2"); + } else { + expected.add("catchNotExecuted"); + expected.add("catchNotExecuted.1"); + } + + if (isJDKCompiler) { + expected.add("nested.5"); + expected.add("nested.6"); + } else { + expected.add("nested.0"); + expected.add("nested.3"); + } + + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { + expected.add("emptyTry.2"); + } + + if (!isJDKCompiler) { + expected.add("alwaysCompletesAbruptly.0"); + } + + assertEquals(expected, tags); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FramesTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FramesTest.java new file mode 100644 index 00000000..2d502c31 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FramesTest.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.BytecodeVersion; +import org.jacoco.core.internal.instr.InstrSupport; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.SystemPropertiesRuntime; +import org.jacoco.core.test.TargetLoader; +import org.jacoco.core.test.validation.java5.targets.BooleanExpressionsTarget; +import org.jacoco.core.test.validation.java5.targets.ClassInitializerTarget; +import org.jacoco.core.test.validation.java5.targets.ConstructorsTarget; +import org.jacoco.core.test.validation.java5.targets.ControlStructureBeforeSuperConstructorTarget; +import org.jacoco.core.test.validation.java5.targets.ControlStructuresTarget; +import org.jacoco.core.test.validation.java5.targets.ExceptionsTarget; +import org.jacoco.core.test.validation.java5.targets.ExplicitInitialFrameTarget; +import org.jacoco.core.test.validation.java5.targets.FieldInitializationInTwoConstructorsTarget; +import org.jacoco.core.test.validation.java5.targets.ImplicitFieldInitializationTarget; +import org.jacoco.core.test.validation.java5.targets.InterfaceClassInitializerTarget; +import org.jacoco.core.test.validation.java5.targets.StructuredLockingTarget; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.util.TraceClassVisitor; + +/** + * Tests whether stackmap frames are correctly adjusted. + */ +public class FramesTest { + + /** + * Stack sizes calculated for instrumented classes might be sometimes bigger + * than actually needed. This is an acceptable tradeoff in favor of keeping + * track of the actual stack sizes. For test assertions we need to replace + * max stack sizes with constant value. + */ + private static class MaxStackEliminator extends ClassVisitor { + public MaxStackEliminator(ClassVisitor cv) { + super(InstrSupport.ASM_API_VERSION, cv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { + final MethodVisitor mv = super.visitMethod(access, name, desc, + signature, exceptions); + return new MethodVisitor(InstrSupport.ASM_API_VERSION, mv) { + @Override + public void visitMaxs(int maxStack, int maxLocals) { + super.visitMaxs(-1, maxLocals); + } + }; + } + } + + private void testFrames(Class target) throws IOException { + testFrames(TargetLoader.getClassDataAsBytes(target)); + } + + private void testFrames(byte[] source) throws IOException { + IRuntime runtime = new SystemPropertiesRuntime(); + Instrumenter instrumenter = new Instrumenter(runtime); + source = calculateFrames(source); + byte[] actual = instrumenter.instrument(source, "TestTarget"); + byte[] expected = calculateFrames(actual); + + assertEquals(dump(expected), dump(actual)); + } + + private byte[] calculateFrames(byte[] source) { + source = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(source), + source); + + ClassReader rc = new ClassReader(source); + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + + // Adjust Version to 1.6 to enable frames: + rc.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, cw) { + + @Override + public void visit(int version, int access, String name, + String signature, String superName, String[] interfaces) { + super.visit(Opcodes.V1_6, access, name, signature, superName, + interfaces); + } + }, 0); + return cw.toByteArray(); + } + + private String dump(byte[] bytes) { + final StringWriter buffer = new StringWriter(); + final PrintWriter writer = new PrintWriter(buffer); + new ClassReader(bytes).accept( + new MaxStackEliminator(new TraceClassVisitor(writer)), + ClassReader.EXPAND_FRAMES); + return buffer.toString(); + } + + @Test + public void boolean_expressions() throws IOException { + testFrames(BooleanExpressionsTarget.class); + } + + @Test + public void class_initializer() throws IOException { + testFrames(ClassInitializerTarget.class); + } + + @Test + public void constructors() throws IOException { + testFrames(ConstructorsTarget.class); + } + + @Test + public void control_structures() throws IOException { + testFrames(ControlStructuresTarget.class); + } + + @Test + public void control_structure_before_super_constructor() + throws IOException { + testFrames(ControlStructureBeforeSuperConstructorTarget.class); + } + + @Test + public void exceptions() throws IOException { + testFrames(ExceptionsTarget.class); + } + + @Test + public void explicit_initial_frame() throws IOException { + testFrames(ExplicitInitialFrameTarget.class); + } + + @Test + public void field_initialization_in_two_constructors() throws IOException { + testFrames(FieldInitializationInTwoConstructorsTarget.class); + } + + @Test + public void implicit_field_initialization() throws IOException { + testFrames(ImplicitFieldInitializationTarget.class); + } + + @Test + public void interface_class_initializer() throws IOException { + testFrames(InterfaceClassInitializerTarget.class); + } + + @Test + public void structured_locking() throws IOException { + testFrames(StructuredLockingTarget.class); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ImplicitFieldInitializationTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ImplicitFieldInitializationTest.java new file mode 100644 index 00000000..d87d039b --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ImplicitFieldInitializationTest.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.ImplicitFieldInitializationTarget; +import org.junit.Test; + +/** + * Test of a implicit field initialization. + */ +public class ImplicitFieldInitializationTest extends ValidationTestBase { + + public ImplicitFieldInitializationTest() { + super(ImplicitFieldInitializationTarget.class); + } + + @Test + public void testCoverageResult() { + + assertLine("classdef", ICounter.FULLY_COVERED); + assertLine("field1", ICounter.EMPTY); + assertLine("field2", ICounter.FULLY_COVERED); + assertLine("field3", ICounter.EMPTY); + assertLine("field4", ICounter.FULLY_COVERED); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/InterfaceClassInitializerTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/InterfaceClassInitializerTest.java new file mode 100644 index 00000000..9e13debb --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/InterfaceClassInitializerTest.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.InterfaceClassInitializerTarget; +import org.junit.Test; + +/** + * Tests of static initializer in interfaces. + */ +public class InterfaceClassInitializerTest extends ValidationTestBase { + + public InterfaceClassInitializerTest() { + super(InterfaceClassInitializerTarget.class); + } + + @Override + protected void run(final Class targetClass) throws Exception { + // Force class initialization + targetClass.getField("CONST1").get(null); + } + + @Test + public void testCoverageResult() { + + assertLine("const1", ICounter.EMPTY); + assertLine("const2", ICounter.EMPTY); + + assertLine("const3", ICounter.FULLY_COVERED); + assertLine("const4", ICounter.FULLY_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/StructuredLockingTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/StructuredLockingTest.java new file mode 100644 index 00000000..8243c4bc --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/StructuredLockingTest.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.BytecodeVersion; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.SystemPropertiesRuntime; +import org.jacoco.core.test.TargetLoader; +import org.jacoco.core.test.validation.java5.targets.StructuredLockingTarget; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TryCatchBlockNode; +import org.objectweb.asm.tree.VarInsnNode; +import org.objectweb.asm.tree.analysis.Analyzer; +import org.objectweb.asm.tree.analysis.AnalyzerException; +import org.objectweb.asm.tree.analysis.BasicInterpreter; +import org.objectweb.asm.tree.analysis.BasicValue; +import org.objectweb.asm.tree.analysis.Frame; +import org.objectweb.asm.tree.analysis.Interpreter; + +/** + * Tests that the invariants specified in chapter + * 2.11.10 of the JVM Spec do also hold for instrumented classes. + * + * This is important because JIT compiler in HotSpot JVM ignores methods with + * unstructured locking, so that they executed by interpreter. Android Runtime + * also doesn't optimize such methods. + * + * TODO verification implemented here is incomplete - in particular it is unable + * to catch problem described in https://github.com/jacoco/jacoco/issues/626 + */ +public class StructuredLockingTest { + + @Test + public void testMonitorExit() throws Exception { + assertStructuredLocking(TargetLoader + .getClassDataAsBytes(StructuredLockingTarget.class)); + } + + private void assertStructuredLocking(byte[] source) throws Exception { + IRuntime runtime = new SystemPropertiesRuntime(); + Instrumenter instrumenter = new Instrumenter(runtime); + byte[] instrumented = instrumenter.instrument(source, "TestTarget"); + + final int version = BytecodeVersion.get(instrumented); + instrumented = BytecodeVersion.downgradeIfNeeded(version, instrumented); + + ClassNode cn = new ClassNode(); + new ClassReader(instrumented).accept(cn, 0); + for (MethodNode mn : cn.methods) { + assertStructuredLocking(cn.name, mn); + } + } + + private void assertStructuredLocking(String owner, MethodNode mn) + throws Exception { + Analyzer analyzer = new Analyzer( + new BasicInterpreter()) { + + @Override + protected Frame newFrame(int nLocals, int nStack) { + return new LockFrame(nLocals, nStack); + } + + @Override + protected Frame newFrame( + Frame src) { + return new LockFrame(src); + } + }; + + Frame[] frames = analyzer.analyze(owner, mn); + + // Make sure no locks are left when method exits: + for (int i = 0; i < frames.length; i++) { + AbstractInsnNode insn = mn.instructions.get(i); + switch (insn.getOpcode()) { + case Opcodes.IRETURN: + case Opcodes.LRETURN: + case Opcodes.FRETURN: + case Opcodes.DRETURN: + case Opcodes.ARETURN: + case Opcodes.RETURN: + ((LockFrame) frames[i]).assertNoLock("Exit with lock"); + break; + case Opcodes.ATHROW: + List handlers = analyzer.getHandlers(i); + if (handlers == null || handlers.isEmpty()) { + ((LockFrame) frames[i]).assertNoLock("Exit with lock"); + } + break; + } + } + + // Only instructions protected by a catch-all handler can hold locks: + for (int i = 0; i < frames.length; i++) { + AbstractInsnNode insn = mn.instructions.get(i); + if (insn.getOpcode() > 0) { + boolean catchAll = false; + List handlers = analyzer.getHandlers(i); + if (handlers != null) { + for (TryCatchBlockNode node : handlers) { + catchAll |= node.type == null; + } + } + if (!catchAll) { + ((LockFrame) frames[i]) + .assertNoLock("No handlers for insn with lock"); + } + } + } + + } + + /** + * A Frame implementation that keeps track of the locking state. It is + * assumed that the monitor objects are stored in local variables. + */ + private static class LockFrame extends Frame { + + Set locks; + + public LockFrame(final int nLocals, final int nStack) { + super(nLocals, nStack); + locks = new HashSet(); + } + + public LockFrame(Frame src) { + super(src); + } + + @Override + public Frame init(Frame src) { + locks = new HashSet(((LockFrame) src).locks); + return super.init(src); + } + + @Override + public void execute(AbstractInsnNode insn, + Interpreter interpreter) throws AnalyzerException { + super.execute(insn, interpreter); + switch (insn.getOpcode()) { + case Opcodes.MONITORENTER: + // Lock is stored in a local variable: + enter(((VarInsnNode) insn.getPrevious()).var); + break; + case Opcodes.MONITOREXIT: + // Lock is stored in a local variable: + exit(((VarInsnNode) insn.getPrevious()).var); + break; + } + } + + void enter(int lock) { + assertTrue("multiple ENTER for lock " + lock, + locks.add(Integer.valueOf(lock))); + } + + void exit(int lock) { + assertTrue("invalid EXIT for lock " + lock, + locks.remove(Integer.valueOf(lock))); + } + + @Override + public boolean merge(Frame frame, + Interpreter interpreter) throws AnalyzerException { + this.locks.addAll(((LockFrame) frame).locks); + return super.merge(frame, interpreter); + } + + void assertNoLock(String message) { + assertEquals(message, Collections.emptySet(), locks); + + } + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SynchronizedTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SynchronizedTest.java new file mode 100644 index 00000000..c1498be1 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SynchronizedTest.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.SynchronizedTarget; +import org.junit.Test; + +/** + * Test of filtering of a bytecode that is generated for a synchronized + * statement. + */ +public class SynchronizedTest extends ValidationTestBase { + + public SynchronizedTest() { + super(SynchronizedTarget.class); + } + + /** + * {@link SynchronizedTarget#normal()} + */ + @Test + public void normal() { + assertLine("before", ICounter.FULLY_COVERED); + // when compiled with ECJ next line covered partly without filter: + assertLine("monitorEnter", ICounter.FULLY_COVERED); + assertLine("body", ICounter.FULLY_COVERED); + if (isJDKCompiler) { + // without filter next line covered partly: + assertLine("monitorExit", ICounter.FULLY_COVERED); + } else { + assertLine("monitorExit", ICounter.EMPTY); + } + assertLine("after", ICounter.FULLY_COVERED); + } + + /** + * {@link SynchronizedTarget#explicitException()} + */ + @Test + public void explicitException() { + assertLine("explicitException.monitorEnter", ICounter.FULLY_COVERED); + assertLine("explicitException.exception", ICounter.FULLY_COVERED); + // when compiled with javac next line covered fully without filter: + assertLine("explicitException.monitorExit", ICounter.EMPTY); + } + + /** + * {@link SynchronizedTarget#implicitException()} + */ + @Test + public void implicitException() { + assertLine("implicitException.monitorEnter", isJDKCompiler + ? ICounter.FULLY_COVERED : ICounter.PARTLY_COVERED); + assertLine("implicitException.exception", ICounter.NOT_COVERED); + if (isJDKCompiler) { + // without filter next line covered partly: + assertLine("implicitException.monitorExit", ICounter.NOT_COVERED); + } else { + assertLine("implicitException.monitorExit", ICounter.EMPTY); + } + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SyntheticTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SyntheticTest.java new file mode 100644 index 00000000..f1f8372e --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SyntheticTest.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.SyntheticTarget; +import org.junit.Test; + +/** + * Test of filtering of synthetic methods. + */ +public class SyntheticTest extends ValidationTestBase { + + public SyntheticTest() { + super(SyntheticTarget.class); + } + + @Test + public void testCoverageResult() { + assertMethodCount(5); + + assertLine("classdef", ICounter.EMPTY); + assertLine("field", ICounter.EMPTY); + + assertLine("inner.classdef", ICounter.EMPTY); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/AnnotationInitializerTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/AnnotationInitializerTarget.java new file mode 100644 index 00000000..95171b3b --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/AnnotationInitializerTarget.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5.targets; + +/** + * This test target is an annotation with an initializer. + */ +public @interface AnnotationInitializerTarget { + + Object CONST = new Object(); // $line-const$ + + int value() default 0; // $line-value$ + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BadCycleClassTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BadCycleClassTarget.java new file mode 100644 index 00000000..27b48dcc --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BadCycleClassTarget.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5.targets; + +import org.jacoco.core.test.validation.targets.Stubs; + +public class BadCycleClassTarget { + + public static class Base { + static final Child b = new Child(); + + static { + b.someMethod(); + } + } + + public static class Child extends Base { + + static { + Stubs.logEvent("childclinit"); // $line-childclinit$ + } + + public Child() { + Stubs.logEvent("childinit"); // $line-childinit$ + } + + void someMethod() { + Stubs.logEvent("childsomeMethod"); // $line-childsomeMethod$ + } + + } + + public static void main(String[] args) { + new Child(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BooleanExpressionsTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BooleanExpressionsTarget.java new file mode 100644 index 00000000..a0b4ff50 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BooleanExpressionsTarget.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.i1; +import static org.jacoco.core.test.validation.targets.Stubs.i2; +import static org.jacoco.core.test.validation.targets.Stubs.nop; +import static org.jacoco.core.test.validation.targets.Stubs.t; + +/** + * This target exercises boolean expressions. + */ +public class BooleanExpressionsTarget { + + public static void main(String[] args) { + + // 1. Boolean comparison result (one case) + nop(i2() > 3); // $line-booleancmp1$ + + // 2. Boolean comparison result (both cases) + for (int i = 0; i < 2; i++) { + nop(i < 1); // $line-booleancmp2$ + } + + // 3. And + if (f() & f()) { // $line-andFF$ + nop(); + } + if (f() & t()) { // $line-andFT$ + nop(); + } + if (t() & f()) { // $line-andTF$ + nop(); + } + if (t() & t()) { // $line-andTT$ + nop(); + } + + // 4. Conditional And + if (f() && f()) { // $line-conditionalandFF$ + nop(); + } + if (f() && t()) { // $line-conditionalandFT$ + nop(); + } + if (t() && f()) { // $line-conditionalandTF$ + nop(); + } + if (t() && t()) { // $line-conditionalandTT$ + nop(); + } + + // 5. Or + if (f() | f()) { // $line-orFF$ + nop(); + } + if (f() | t()) { // $line-orFT$ + nop(); + } + if (t() | f()) { // $line-orTF$ + nop(); + } + if (t() | t()) { // $line-orTT$ + nop(); + } + + // 6. Conditional Or + if (f() || f()) { // $line-conditionalorFF$ + nop(); + } + if (f() || t()) { // $line-conditionalorFT$ + nop(); + } + if (t() || f()) { // $line-conditionalorTF$ + nop(); + } + if (t() || t()) { // $line-conditionalorTT$ + nop(); + } + + // 7. Exclusive Or + if (f() ^ f()) { // $line-xorFF$ + nop(); + } + if (f() ^ t()) { // $line-xorFT$ + nop(); + } + if (t() ^ f()) { // $line-xorTF$ + nop(); + } + if (t() ^ t()) { // $line-xorTT$ + nop(); + } + + // 8. Conditional Operator + nop(t() ? i1() : i2()); // $line-condT$ + nop(f() ? i1() : i2()); // $line-condF$ + + // 9. Not (one case) + nop(!t()); // $line-notT$ + nop(!f()); // $line-notF$ + + // 10. Not (both cases) + for (boolean b : new boolean[] { true, false }) { + nop(!b); // $line-notTF$ + } + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ClassInitializerTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ClassInitializerTarget.java new file mode 100644 index 00000000..a8978362 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ClassInitializerTarget.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.i1; + +import org.jacoco.core.test.validation.targets.Stubs; + +/** + * This test target is a class with a static initializer. + */ +public class ClassInitializerTarget { + + // No code required to initialize these fields: + + public static final int CONST1 = 3; // $line-const1$ + + public static final String CONST2 = "Hello"; // $line-const2$ + + // These fields are initialized within + + public static final int CONST3 = i1(); // $line-const3$ + + public static final Object CONST4 = new Object(); // $line-const4$ + + public static int field1 = 3; // $line-field1$ + + public static String field2 = "Hello"; // $line-field2$ + + public static int field3 = i1(); // $line-field3$ + + public static Object field4 = new Object(); // $line-field4$ + + static { + Stubs.nop(); // $line-staticblock$ + } + + private ClassInitializerTarget() { + } + + public static void main(String[] args) { + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ConstructorsTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ConstructorsTarget.java new file mode 100644 index 00000000..99ff020d --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ConstructorsTarget.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target calls different constructors. + */ +public class ConstructorsTarget { + + ConstructorsTarget() { // $line-packageLocal$ + } + + private ConstructorsTarget(Object arg) { // $line-arg$ + } + + private static class Super extends ConstructorsTarget { + private Super() { + super(null); // $line-super$ + } + } + + private class Inner { + private Inner() { // $line-inner$ + } + } + + private static class InnerStatic { + @SuppressWarnings("unused") + private final Object field = this; + + private InnerStatic() { // $line-innerStatic$ + } + } + + public static class PublicDefault { // $line-publicDefault$ + } + + static class PackageLocalDefault { // $line-packageLocalDefault$ + } + + private static class PrivateDefault { // $line-privateDefault$ + } + + private static class PrivateNonEmptyNoArg { + private PrivateNonEmptyNoArg() { + nop(); // $line-privateNonEmptyNoArg$ + } + } + + private static class PrivateEmptyNoArg { + private PrivateEmptyNoArg() { // $line-privateEmptyNoArg$ + } // $line-return$ + } + + public static void main(String[] args) { + new Super(); + new ConstructorsTarget().new Inner(); + new InnerStatic(); + new PublicDefault(); + new PackageLocalDefault(); + new PrivateDefault(); + new PrivateNonEmptyNoArg(); + new PrivateEmptyNoArg(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructureBeforeSuperConstructorTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructureBeforeSuperConstructorTarget.java new file mode 100644 index 00000000..ffc1d5f7 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructureBeforeSuperConstructorTarget.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.t; + +import org.jacoco.core.test.validation.targets.Stubs.SuperClass; + +/** + * This test target has a constructor containing control structures before the + * superclass constructor is called. + */ +public class ControlStructureBeforeSuperConstructorTarget extends SuperClass { + + public ControlStructureBeforeSuperConstructorTarget() { + super(t() || f()); // $line-super$ + } + + public static void main(String[] args) { + new ControlStructureBeforeSuperConstructorTarget(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructuresTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructuresTarget.java new file mode 100644 index 00000000..3152a8b1 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructuresTarget.java @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.i2; +import static org.jacoco.core.test.validation.targets.Stubs.nop; +import static org.jacoco.core.test.validation.targets.Stubs.t; + +import java.util.Collections; + +/** + * This target exercises a set of common Java control structures. + */ +public class ControlStructuresTarget { + + public static void main(String[] args) { + + unconditionalExecution(); + missedIfBlock(); + executedIfBlock(); + missedWhileBlock(); + alwaysExecutedWhileBlock(); + executedWhileBlock(); + executedDoWhileBlock(); + missedForBlock(); + executedForBlock(); + missedForEachBlock(); + executedForEachBlock(); + tableSwitchWithHit(); + continuedTableSwitchWithHit(); + tableSwitchWithoutHit(); + lookupSwitchWithHit(); + continuedLookupSwitchWithHit(); + lookupSwitchWithoutHit(); + breakStatement(); + continueStatement(); + conditionalReturn(); + implicitReturn(); + explicitReturn(); + + } + + private static void unconditionalExecution() { + + nop(); // $line-unconditional$ + + } + + private static void missedIfBlock() { + + if (f()) { // $line-iffalse$ + nop(); // $line-missedif$ + } else { + nop(); // $line-executedelse$ + } + + } + + private static void executedIfBlock() { + + if (t()) { // $line-iftrue$ + nop(); // $line-executedif$ + } else { + nop(); // $line-missedelse$ + } + + } + + private static void missedWhileBlock() { + + while (f()) { // $line-whilefalse$ + nop(); // $line-missedwhile$ + } + + } + + private static void alwaysExecutedWhileBlock() { + + while (t()) { // $line-whiletrue$ + if (t()) { + break; + } + } + + } + + private static void executedWhileBlock() { + + int i = 0; + while (i++ < 3) { // $line-whiletruefalse$ + nop(); // $line-executedwhile$ + } + + } + + private static void executedDoWhileBlock() { + + do { + nop(); // $line-executeddowhile$ + } while (f()); // $line-executeddowhilefalse$ + + } + + private static void missedForBlock() { + + for (nop(); f(); nop()) { // $line-missedforincrementer$ + nop(); // $line-missedfor$ + } + + } + + private static void executedForBlock() { + + for (int j = 0; j < 1; j++) { // $line-executedforincrementer$ + nop(); // $line-executedfor$ + } + + } + + private static void missedForEachBlock() { + + for (Object o : Collections.emptyList()) { // $line-missedforeachincrementer$ + nop(o); // $line-missedforeach$ + } + + } + + private static void executedForEachBlock() { + + for (Object o : Collections.singleton(new Object())) { // $line-executedforeachincrementer$ + nop(o); // $line-executedforeach$ + } + + } + + private static void tableSwitchWithHit() { + + switch (i2()) { // $line-tswitch1$ + case 1: + nop(); // $line-tswitch1case1$ + break; + case 2: + nop(); // $line-tswitch1case2$ + break; + case 3: + nop(); // $line-tswitch1case3$ + break; + default: + nop(); // $line-tswitch1default$ + break; + } + + } + + private static void continuedTableSwitchWithHit() { + + switch (i2()) { // $line-tswitch2$ + case 1: + nop(); // $line-tswitch2case1$ + case 2: + nop(); // $line-tswitch2case2$ + case 3: + nop(); // $line-tswitch2case3$ + default: + nop(); // $line-tswitch2default$ + } + + } + + private static void tableSwitchWithoutHit() { + + switch (i2()) { // $line-tswitch3$ + case 3: + nop(); // $line-tswitch3case1$ + break; + case 4: + nop(); // $line-tswitch3case2$ + break; + case 5: + nop(); // $line-tswitch3case3$ + break; + default: + nop(); // $line-tswitch3default$ + break; + } + + } + + private static void lookupSwitchWithHit() { + + switch (i2()) { // $line-lswitch1$ + case -123: + nop(); // $line-lswitch1case1$ + break; + case 2: + nop(); // $line-lswitch1case2$ + break; + case 456: + nop(); // $line-lswitch1case3$ + break; + default: + nop(); // $line-lswitch1default$ + break; + } + + } + + private static void continuedLookupSwitchWithHit() { + + switch (i2()) { // $line-lswitch2$ + case -123: + nop(); // $line-lswitch2case1$ + case 2: + nop(); // $line-lswitch2case2$ + case 456: + nop(); // $line-lswitch2case3$ + default: + nop(); // $line-lswitch2default$ + } + + } + + private static void lookupSwitchWithoutHit() { + + switch (i2()) { // $line-lswitch3$ + case -123: + nop(); // $line-lswitch3case1$ + break; + case 456: + nop(); // $line-lswitch3case2$ + break; + case 789: + nop(); // $line-lswitch3case3$ + break; + default: + nop(); // $line-lswitch3default$ + break; + } + + } + + private static void breakStatement() { + + while (true) { + if (t()) { + break; // $line-executedbreak$ + } + nop(); // $line-missedafterbreak$ + } + + } + + private static void continueStatement() { + + for (int j = 0; j < 1; j++) { + if (t()) { + continue; // $line-executedcontinue$ + } + nop(); // $line-missedaftercontinue$ + } + + } + + private static void conditionalReturn() { + + if (t()) { + return; // $line-conditionalreturn$ + } + nop(); // $line-afterconditionalreturn$ + + } + + private static void implicitReturn() { + + } // $line-implicitreturn$ + + private static void explicitReturn() { + + return; // $line-explicitreturn$ + + } // $line-afterexplicitreturn$ + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumConstructorTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumConstructorTarget.java new file mode 100644 index 00000000..7d232bd7 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumConstructorTarget.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target is an enum constructor. + */ +public class EnumConstructorTarget { + + private enum ImplicitConstructor { // $line-implicitConstructor$ + } + + private enum ExplicitNonEmptyConstructor { + ; + + ExplicitNonEmptyConstructor() { + nop(); // $line-explicitNonEmptyConstructor$ + } + } + + @SuppressWarnings("unused") + private enum ExplicitEmptyConstructor { + ; + + ExplicitEmptyConstructor() { + } // $line-explicitEmptyConstructor$ + + ExplicitEmptyConstructor(Object p) { + } // $line-explicitEmptyConstructorWithParameter$ + } + + public static void main(String[] args) { + ImplicitConstructor.values(); + ExplicitEmptyConstructor.values(); + ExplicitNonEmptyConstructor.values(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumImplicitMethodsTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumImplicitMethodsTarget.java new file mode 100644 index 00000000..ff589f78 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumImplicitMethodsTarget.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5.targets; + +import org.jacoco.core.test.validation.targets.Stubs; + +public enum EnumImplicitMethodsTarget { // $line-classdef$ + + CONST(Stubs.f() ? new Object() : new Object()); // $line-const$ + + static { + } // $line-staticblock$ + + /** + * Unlike in {@link ConstructorsTarget regular classes}, even if enum has explicit + * constructor, {@code clinit} method in any case has a reference to the + * line of enum definition. + */ + EnumImplicitMethodsTarget(Object o) { // $line-super$ + } // $line-constructor$ + + /** + * This method should not be excluded from analysis unlike implicitly + * created {@link #valueOf(String)} method that refers to the line of enum + * definition in case of javac and to the first line in case of ECJ. + */ + public void valueOf() { + } // $line-customValueOfMethod$ + + /** + * This method should not be excluded from analysis unlike implicitly + * created {@link #values()} method that refers to the line of enum + * definition in case of javac and to the first line in case of ECJ. + */ + public void values(Object o) { + } // $line-customValuesMethod$ + + public static void main(String[] args) { + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumSwitchTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumSwitchTarget.java new file mode 100644 index 00000000..47447e5a --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumSwitchTarget.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target is a switch statement with a enum. + */ +public class EnumSwitchTarget { + + private enum E { + V1, V2 + } + + private static void example(E e) { + switch (e) { // $line-switch$ + case V1: + nop("V1"); + break; + case V2: + default: + nop("V2"); + break; + } + } + + public static void main(String[] args) { + example(E.V1); + example(E.V2); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExceptionsTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExceptionsTarget.java new file mode 100644 index 00000000..1896e64d --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExceptionsTarget.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.ex; +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +import org.jacoco.core.test.validation.targets.Stubs.StubException; + +/** + * This target produces exception based control flow examples. + */ +public class ExceptionsTarget { + + public static void main(String[] args) { + + try { + implicitNullPointerException(null); + } catch (NullPointerException e) { + } + try { + implicitException(); + } catch (StubException e) { + } + try { + explicitException(); + } catch (StubException e) { + } + noExceptionTryCatch(); + implicitExceptionTryCatch(); + implicitExceptionTryCatchAfterCondition(); + explicitExceptionTryCatch(); + noExceptionFinally(); + try { + explicitExceptionFinally(); + } catch (StubException e) { + } + try { + implicitExceptionFinally(); + } catch (StubException e) { + } + } + + private static void implicitNullPointerException(int[] a) { + nop(); // $line-implicitNullPointerException.before$ + a[0] = 0; // $line-implicitNullPointerException.exception$ + nop(); // $line-implicitNullPointerException.after$ + } + + private static void implicitException() { + nop(); // $line-implicitException.before$ + ex(); // $line-implicitException.exception$ + nop(); // $line-implicitException.after$ + } + + private static void explicitException() { + nop(); // $line-explicitException.before$ + throw new StubException(); // $line-explicitException.throw$ + } + + private static void noExceptionTryCatch() { + nop(); // $line-noExceptionTryCatch.beforeBlock$ + try { + nop(); // $line-noExceptionTryCatch.tryBlock$ + } catch (StubException e) { // $line-noExceptionTryCatch.catch$ + nop(); // $line-noExceptionTryCatch.catchBlock$ + } // $line-noExceptionTryCatch.catchBlockEnd$ + } // $line-noExceptionTryCatch.afterBlock$ + + private static void implicitExceptionTryCatch() { + nop(); // $line-implicitExceptionTryCatch.beforeBlock$ + try { + nop(); // $line-implicitExceptionTryCatch.before$ + ex(); // $line-implicitExceptionTryCatch.exception$ + nop(); // $line-implicitExceptionTryCatch.after$ + } catch (StubException e) { // $line-implicitExceptionTryCatch.catch$ + nop(); // $line-implicitExceptionTryCatch.catchBlock$ + } // $line-implicitExceptionTryCatch.catchBlockEnd$ + } // $line-implicitExceptionTryCatch.afterBlock$ + + private static void implicitExceptionTryCatchAfterCondition() { + if (f()) { // $line-implicitExceptionTryCatchAfterCondition.condition$ + return; + } + try { + ex(); // $line-implicitExceptionTryCatchAfterCondition.exception$ + } catch (StubException e) { + nop(); // $line-implicitExceptionTryCatchAfterCondition.catchBlock$ + } + } + + private static void explicitExceptionTryCatch() { + nop(); // $line-explicitExceptionTryCatch.beforeBlock$ + try { + nop(); // $line-explicitExceptionTryCatch.before$ + throw new StubException(); // $line-explicitExceptionTryCatch.throw$ + } catch (StubException e) { // $line-explicitExceptionTryCatch.catch$ + nop(); // $line-explicitExceptionTryCatch.catchBlock$ + } // $line-explicitExceptionTryCatch.catchBlockEnd$ + } // $line-explicitExceptionTryCatch.afterBlock$ + + private static void noExceptionFinally() { + nop(); // $line-noExceptionFinally.beforeBlock$ + try { + nop(); // $line-noExceptionFinally.tryBlock$ + } finally { // $line-noExceptionFinally.finally$ + nop(); // $line-noExceptionFinally.finallyBlock$ + } // $line-noExceptionFinally.finallyBlockEnd$ + } // $line-noExceptionFinally.afterBlock$ + + private static void implicitExceptionFinally() { + nop(); // $line-implicitExceptionFinally.beforeBlock$ + try { + nop(); // $line-implicitExceptionFinally.before$ + ex(); // $line-implicitExceptionFinally.exception$ + nop(); // $line-implicitExceptionFinally.after$ + } finally { // $line-implicitExceptionFinally.finally$ + nop(); // $line-implicitExceptionFinally.finallyBlock$ + } // $line-implicitExceptionFinally.finallyBlockEnd$ + } // $line-implicitExceptionFinally.afterBlock$ + + private static void explicitExceptionFinally() { + nop(); // $line-explicitExceptionFinally.beforeBlock$ + try { + nop(); // $line-explicitExceptionFinally.before$ + throw new StubException(); // $line-explicitExceptionFinally.throw$ + } finally { // $line-explicitExceptionFinally.finally$ + nop(); // $line-explicitExceptionFinally.finallyBlock$ + } // $line-explicitExceptionFinally.finallyBlockEnd$ + } // $line-explicitExceptionFinally.afterBlock$ + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExplicitInitialFrameTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExplicitInitialFrameTarget.java new file mode 100644 index 00000000..bc089fc7 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExplicitInitialFrameTarget.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target needs an explicit initial frame as the first instruction + * already is a jump target. + */ +public class ExplicitInitialFrameTarget { + + public static void main(String[] args) { + + do { + nop(); // $line-dowhilebody$ + } while (f()); + + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FieldInitializationInTwoConstructorsTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FieldInitializationInTwoConstructorsTarget.java new file mode 100644 index 00000000..58bf6890 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FieldInitializationInTwoConstructorsTarget.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5.targets; + +/** + * This test target has instance members with initialization in two + * constructors. + */ +public class FieldInitializationInTwoConstructorsTarget { + + Object field1 = null; // $line-field1$ + + int field2 = 123; // $line-field2$ + + public FieldInitializationInTwoConstructorsTarget() { + } // $line-constr1$ + + public FieldInitializationInTwoConstructorsTarget(String arg) { + } // $line-constr2$ + + public static void main(String[] args) { + new FieldInitializationInTwoConstructorsTarget(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FinallyTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FinallyTarget.java new file mode 100644 index 00000000..2c317e95 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FinallyTarget.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.ex; +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.nop; +import static org.jacoco.core.test.validation.targets.Stubs.t; + +public class FinallyTarget { + + /** + *

    +	 *   InputStream in = null;
    +	 *   try {
    +	 *     in = ...;
    +	 *     ...
    +	 *   } finally {
    +	 *     if (in != null) {
    +	 *       in.close();
    +	 *     }
    +	 *   }
    +	 * 
    + */ + private static void example(boolean t) { + Object in = null; + try { + in = open(t); + } finally { // $line-example.0$ + if (in != null) { // $line-example.1$ + nop(); // $line-example.2$ + } // $line-example.3$ + } // $line-example.4$ + } + + private static Object open(boolean t) { + ex(t); + return new Object(); + } + + private static void breakStatement() { + for (int i = 0; i < 1; i++) { // $line-breakStatement.for$ + try { + if (f()) { + break; // $line-breakStatement$ + } + } finally { + nop("finally"); // $line-breakStatement.1$ + } // $line-breakStatement.2$ + } + } + + private static void catchNotExecuted() { + try { + nop("try"); + } catch (Exception e) { // $line-catchNotExecuted$ + nop("catch"); // $line-catchNotExecuted.catch$ + } finally { // $line-catchNotExecuted.0$ + nop("finally"); // $line-catchNotExecuted.1$ + } // $line-catchNotExecuted.2$ + } + + private static void emptyCatch() { + try { + nop("try"); + } catch (Exception e) { // $line-emptyCatch$ + // empty + } finally { // $line-emptyCatch.0$ + nop("finally"); // $line-emptyCatch.1$ + } // $line-emptyCatch.2$ + } + + private static void twoRegions() { + try { + // jump to another region associated with same handler: + if (t()) { // $line-twoRegions.if$ + nop(); // $line-twoRegions.region.1$ + return; // $line-twoRegions.return.1$ + } else { + nop(); // $line-twoRegions.region.2$ + return; // $line-twoRegions.return.2$ + } + } finally { // $line-twoRegions.0$ + nop(); // $line-twoRegions.1$ + } // $line-twoRegions.2$ + } + + private static void nested() { + try { + nop(); + } finally { // $line-nested.0$ + try { // $line-nested.1$ + nop(); // $line-nested.2$ + } finally { // $line-nested.3$ + nop(); // $line-nested.4$ + } // $line-nested.5$ + } // $line-nested.6$ + } + + private static void emptyTry() { + try { + // empty + } finally { // $line-emptyTry.0$ + nop(); // $line-emptyTry.1$ + } // $line-emptyTry.2$ + } + + @SuppressWarnings("finally") + private static void alwaysCompletesAbruptly() { + try { + nop(); + } finally { // $line-alwaysCompletesAbruptly.0$ + return; // $line-alwaysCompletesAbruptly.1$ + } // $line-alwaysCompletesAbruptly.2$ + } + + public static void main(String[] args) { + example(false); + try { + example(true); + } catch (Exception ignore) { + } + + breakStatement(); + + catchNotExecuted(); + + emptyCatch(); + + twoRegions(); + + nested(); + + emptyTry(); + + alwaysCompletesAbruptly(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ImplicitFieldInitializationTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ImplicitFieldInitializationTarget.java new file mode 100644 index 00000000..6ddf8cbd --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ImplicitFieldInitializationTarget.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5.targets; + +/** + * This test target has instance members with implicit initializers. + */ +public class ImplicitFieldInitializationTarget { // $line-classdef$ + + Object field1; // $line-field1$ + + Object field2 = this; // $line-field2$ + + int field3; // $line-field3$ + + int field4 = 2000; // $line-field4$ + + public static void main(String[] args) { + new ImplicitFieldInitializationTarget(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/InterfaceClassInitializerTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/InterfaceClassInitializerTarget.java new file mode 100644 index 00000000..2debf6bd --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/InterfaceClassInitializerTarget.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.i1; + +/** + * This test target is an interface with a class initializer. + */ +public interface InterfaceClassInitializerTarget { + + // No code required to initialize these fields: + + static final int CONST1 = 12345; // $line-const1$ + + static final String CONST2 = "const"; // $line-const2$ + + // These fields are initialized within + + static final int CONST3 = i1(); // $line-const3$ + + static final Object CONST4 = new Object(); // $line-const4$ + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/StructuredLockingTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/StructuredLockingTarget.java new file mode 100644 index 00000000..1e561ae1 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/StructuredLockingTarget.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This target uses synchronized blocks which compile to try/catch statements. + */ +public class StructuredLockingTarget { + + static void simple() { + Object lock1 = new Object(); + synchronized (lock1) { + nop(); + } + } + + static void nested() { + Object lock1 = new Object(); + synchronized (lock1) { + nop(); + Object lock2 = new Object(); + synchronized (lock2) { + nop(); + } + nop(); + } + + } + + public static void main(String[] args) { + simple(); + nested(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SynchronizedTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SynchronizedTarget.java new file mode 100644 index 00000000..5bea5758 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SynchronizedTarget.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.ex; +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +import org.jacoco.core.test.validation.targets.Stubs.StubException; + +/** + * This test target is a synchronized statement. + */ +public class SynchronizedTarget { + + private static final Object lock = new Object(); + + private static void normal() { + nop(); // $line-before$ + synchronized (lock) { // $line-monitorEnter$ + nop(); // $line-body$ + } // $line-monitorExit$ + nop(); // $line-after$ + } + + private static void explicitException() { + synchronized (lock) { // $line-explicitException.monitorEnter$ + throw new StubException(); // $line-explicitException.exception$ + } // $line-explicitException.monitorExit$ + } + + private static void implicitException() { + synchronized (lock) { // $line-implicitException.monitorEnter$ + ex(); // $line-implicitException.exception$ + } // $line-implicitException.monitorExit$ + } + + public static void main(String[] args) { + normal(); + + try { + explicitException(); + } catch (StubException e) { + } + + try { + implicitException(); + } catch (StubException e) { + } + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SyntheticTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SyntheticTarget.java new file mode 100644 index 00000000..c5cc3fee --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SyntheticTarget.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5.targets; + +/** + * This test target results in synthetic methods. + */ +public class SyntheticTarget { // $line-classdef$ + + private static int counter; // $line-field$ + + /** + * {@link org.jacoco.core.test.validation.java5.targets.ImplicitDefaultConstructorTarget + * Default constructor will refer to a line of class definition}, so that we + * define constructor explicitly in order to verify that we filter all other + * constructions here that might refer to line of class definition. + */ + private SyntheticTarget() { + } + + static class Inner extends SyntheticTarget { // $line-inner.classdef$ + + Inner() { + } + + /** + * Access to private field of outer class causes creation of synthetic + * methods in it. In case of javac those methods refer to the line of + * outer class definition, in case of ECJ - to the line of field. + */ + private static void inc() { + counter = counter + 2; + } + + /** + * Difference of return type with overridden method causes creation of + * synthetic bridge method in this class. In case of javac this method + * refers to the line of inner class definition, in case of EJC - to the + * first line of file. + */ + @Override + public String get() { + return null; + } + } + + public Object get() { + return null; + } + + public static void main(String[] args) { + Inner.inc(); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/AnnotationInitializer.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/AnnotationInitializer.java deleted file mode 100644 index f7b9e0af..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/AnnotationInitializer.java +++ /dev/null @@ -1,23 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation.targets; - -/** - * This test target is an annotation with an initializer. - */ -public @interface AnnotationInitializer { - - Object CONST = new Object(); // $line-const$ - - int value() default 0; // $line-value$ - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/BadCycleClass.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/BadCycleClass.java deleted file mode 100644 index c1826646..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/BadCycleClass.java +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation.targets; - -public class BadCycleClass { - - public static class Base { - static final Child b = new Child(); - - static { - b.someMethod(); - } - } - - public static class Child extends Base { - - static { - Stubs.logEvent("childclinit"); // $line-childclinit$ - } - - public Child() { - Stubs.logEvent("childinit"); // $line-childinit$ - } - - void someMethod() { - Stubs.logEvent("childsomeMethod"); // $line-childsomeMethod$ - } - - } - - public static void main(String[] args) { - new Child(); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java deleted file mode 100644 index afbc46fd..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/EnumImplicitMethods.java +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation.targets; - -public enum EnumImplicitMethods { // $line-classdef$ - - CONST(Stubs.f() ? new Object() : new Object()); // $line-const$ - - static { - } // $line-staticblock$ - - /** - * Unlike in {@link Target07 regular classes}, even if enum has explicit - * constructor, {@code clinit} method in any case has a reference to the - * line of enum definition. - */ - EnumImplicitMethods(Object o) { // $line-super$ - } // $line-constructor$ - - /** - * This method should not be excluded from analysis unlike implicitly - * created {@link #valueOf(String)} method that refers to the line of enum - * definition in case of javac and to the first line in case of ECJ. - */ - public void valueOf() { - } // $line-customValueOfMethod$ - - /** - * This method should not be excluded from analysis unlike implicitly - * created {@link #values()} method that refers to the line of enum - * definition in case of javac and to the first line in case of ECJ. - */ - public void values(Object o) { - } // $line-customValuesMethod$ - - public static void main(String[] args) { - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target01.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target01.java deleted file mode 100644 index 81d00fa5..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target01.java +++ /dev/null @@ -1,293 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.i2; -import static org.jacoco.core.test.validation.targets.Stubs.nop; -import static org.jacoco.core.test.validation.targets.Stubs.t; - -import java.util.Collections; - -/** - * This target exercises a set of common Java control structures. - */ -public class Target01 { - - public static void main(String[] args) { - - unconditionalExecution(); - missedIfBlock(); - executedIfBlock(); - missedWhileBlock(); - alwaysExecutedWhileBlock(); - executedWhileBlock(); - executedDoWhileBlock(); - missedForBlock(); - executedForBlock(); - missedForEachBlock(); - executedForEachBlock(); - tableSwitchWithHit(); - continuedTableSwitchWithHit(); - tableSwitchWithoutHit(); - lookupSwitchWithHit(); - continuedLookupSwitchWithHit(); - lookupSwitchWithoutHit(); - breakStatement(); - continueStatement(); - conditionalReturn(); - implicitReturn(); - explicitReturn(); - - } - - private static void unconditionalExecution() { - - nop(); // $line-unconditional$ - - } - - private static void missedIfBlock() { - - if (f()) { // $line-iffalse$ - nop(); // $line-missedif$ - } else { - nop(); // $line-executedelse$ - } - - } - - private static void executedIfBlock() { - - if (t()) { // $line-iftrue$ - nop(); // $line-executedif$ - } else { - nop(); // $line-missedelse$ - } - - } - - private static void missedWhileBlock() { - - while (f()) { // $line-whilefalse$ - nop(); // $line-missedwhile$ - } - - } - - private static void alwaysExecutedWhileBlock() { - - while (t()) { // $line-whiletrue$ - if (t()) { - break; - } - } - - } - - private static void executedWhileBlock() { - - int i = 0; - while (i++ < 3) { // $line-whiletruefalse$ - nop(); // $line-executedwhile$ - } - - } - - private static void executedDoWhileBlock() { - - do { - nop(); // $line-executeddowhile$ - } while (f()); // $line-executeddowhilefalse$ - - } - - private static void missedForBlock() { - - for (nop(); f(); nop()) { // $line-missedforincrementer$ - nop(); // $line-missedfor$ - } - - } - - private static void executedForBlock() { - - for (int j = 0; j < 1; j++) { // $line-executedforincrementer$ - nop(); // $line-executedfor$ - } - - } - - private static void missedForEachBlock() { - - for (Object o : Collections.emptyList()) { // $line-missedforeachincrementer$ - nop(o); // $line-missedforeach$ - } - - } - - private static void executedForEachBlock() { - - for (Object o : Collections.singleton(new Object())) { // $line-executedforeachincrementer$ - nop(o); // $line-executedforeach$ - } - - } - - private static void tableSwitchWithHit() { - - switch (i2()) { // $line-tswitch1$ - case 1: - nop(); // $line-tswitch1case1$ - break; - case 2: - nop(); // $line-tswitch1case2$ - break; - case 3: - nop(); // $line-tswitch1case3$ - break; - default: - nop(); // $line-tswitch1default$ - break; - } - - } - - private static void continuedTableSwitchWithHit() { - - switch (i2()) { // $line-tswitch2$ - case 1: - nop(); // $line-tswitch2case1$ - case 2: - nop(); // $line-tswitch2case2$ - case 3: - nop(); // $line-tswitch2case3$ - default: - nop(); // $line-tswitch2default$ - } - - } - - private static void tableSwitchWithoutHit() { - - switch (i2()) { // $line-tswitch3$ - case 3: - nop(); // $line-tswitch3case1$ - break; - case 4: - nop(); // $line-tswitch3case2$ - break; - case 5: - nop(); // $line-tswitch3case3$ - break; - default: - nop(); // $line-tswitch3default$ - break; - } - - } - - private static void lookupSwitchWithHit() { - - switch (i2()) { // $line-lswitch1$ - case -123: - nop(); // $line-lswitch1case1$ - break; - case 2: - nop(); // $line-lswitch1case2$ - break; - case 456: - nop(); // $line-lswitch1case3$ - break; - default: - nop(); // $line-lswitch1default$ - break; - } - - } - - private static void continuedLookupSwitchWithHit() { - - switch (i2()) { // $line-lswitch2$ - case -123: - nop(); // $line-lswitch2case1$ - case 2: - nop(); // $line-lswitch2case2$ - case 456: - nop(); // $line-lswitch2case3$ - default: - nop(); // $line-lswitch2default$ - } - - } - - private static void lookupSwitchWithoutHit() { - - switch (i2()) { // $line-lswitch3$ - case -123: - nop(); // $line-lswitch3case1$ - break; - case 456: - nop(); // $line-lswitch3case2$ - break; - case 789: - nop(); // $line-lswitch3case3$ - break; - default: - nop(); // $line-lswitch3default$ - break; - } - - } - - private static void breakStatement() { - - while (true) { - if (t()) { - break; // $line-executedbreak$ - } - nop(); // $line-missedafterbreak$ - } - - } - - private static void continueStatement() { - - for (int j = 0; j < 1; j++) { - if (t()) { - continue; // $line-executedcontinue$ - } - nop(); // $line-missedaftercontinue$ - } - - } - - private static void conditionalReturn() { - - if (t()) { - return; // $line-conditionalreturn$ - } - nop(); // $line-afterconditionalreturn$ - - } - - private static void implicitReturn() { - - } // $line-implicitreturn$ - - private static void explicitReturn() { - - return; // $line-explicitreturn$ - - } // $line-afterexplicitreturn$ - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target02.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target02.java deleted file mode 100644 index 62e22ef9..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target02.java +++ /dev/null @@ -1,120 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.i1; -import static org.jacoco.core.test.validation.targets.Stubs.i2; -import static org.jacoco.core.test.validation.targets.Stubs.nop; -import static org.jacoco.core.test.validation.targets.Stubs.t; - -/** - * This target exercises boolean expressions. - */ -public class Target02 { - - public static void main(String[] args) { - - // 1. Boolean comparison result (one case) - nop(i2() > 3); // $line-booleancmp1$ - - // 2. Boolean comparison result (both cases) - for (int i = 0; i < 2; i++) { - nop(i < 1); // $line-booleancmp2$ - } - - // 3. And - if (f() & f()) { // $line-andFF$ - nop(); - } - if (f() & t()) { // $line-andFT$ - nop(); - } - if (t() & f()) { // $line-andTF$ - nop(); - } - if (t() & t()) { // $line-andTT$ - nop(); - } - - // 4. Conditional And - if (f() && f()) { // $line-conditionalandFF$ - nop(); - } - if (f() && t()) { // $line-conditionalandFT$ - nop(); - } - if (t() && f()) { // $line-conditionalandTF$ - nop(); - } - if (t() && t()) { // $line-conditionalandTT$ - nop(); - } - - // 5. Or - if (f() | f()) { // $line-orFF$ - nop(); - } - if (f() | t()) { // $line-orFT$ - nop(); - } - if (t() | f()) { // $line-orTF$ - nop(); - } - if (t() | t()) { // $line-orTT$ - nop(); - } - - // 6. Conditional Or - if (f() || f()) { // $line-conditionalorFF$ - nop(); - } - if (f() || t()) { // $line-conditionalorFT$ - nop(); - } - if (t() || f()) { // $line-conditionalorTF$ - nop(); - } - if (t() || t()) { // $line-conditionalorTT$ - nop(); - } - - // 7. Exclusive Or - if (f() ^ f()) { // $line-xorFF$ - nop(); - } - if (f() ^ t()) { // $line-xorFT$ - nop(); - } - if (t() ^ f()) { // $line-xorTF$ - nop(); - } - if (t() ^ t()) { // $line-xorTT$ - nop(); - } - - // 8. Conditional Operator - nop(t() ? i1() : i2()); // $line-condT$ - nop(f() ? i1() : i2()); // $line-condF$ - - // 9. Not (one case) - nop(!t()); // $line-notT$ - nop(!f()); // $line-notF$ - - // 10. Not (both cases) - for (boolean b : new boolean[] { true, false }) { - nop(!b); // $line-notTF$ - } - - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target03.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target03.java deleted file mode 100644 index b4418edd..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target03.java +++ /dev/null @@ -1,142 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.ex; -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -import org.jacoco.core.test.validation.targets.Stubs.StubException; - -/** - * This target produces exception based control flow examples. - */ -public class Target03 { - - public static void main(String[] args) { - - try { - implicitNullPointerException(null); - } catch (NullPointerException e) { - } - try { - implicitException(); - } catch (StubException e) { - } - try { - explicitException(); - } catch (StubException e) { - } - noExceptionTryCatch(); - implicitExceptionTryCatch(); - implicitExceptionTryCatchAfterCondition(); - explicitExceptionTryCatch(); - noExceptionFinally(); - try { - explicitExceptionFinally(); - } catch (StubException e) { - } - try { - implicitExceptionFinally(); - } catch (StubException e) { - } - } - - private static void implicitNullPointerException(int[] a) { - nop(); // $line-implicitNullPointerException.before$ - a[0] = 0; // $line-implicitNullPointerException.exception$ - nop(); // $line-implicitNullPointerException.after$ - } - - private static void implicitException() { - nop(); // $line-implicitException.before$ - ex(); // $line-implicitException.exception$ - nop(); // $line-implicitException.after$ - } - - private static void explicitException() { - nop(); // $line-explicitException.before$ - throw new StubException(); // $line-explicitException.throw$ - } - - private static void noExceptionTryCatch() { - nop(); // $line-noExceptionTryCatch.beforeBlock$ - try { - nop(); // $line-noExceptionTryCatch.tryBlock$ - } catch (StubException e) { // $line-noExceptionTryCatch.catch$ - nop(); // $line-noExceptionTryCatch.catchBlock$ - } // $line-noExceptionTryCatch.catchBlockEnd$ - } // $line-noExceptionTryCatch.afterBlock$ - - private static void implicitExceptionTryCatch() { - nop(); // $line-implicitExceptionTryCatch.beforeBlock$ - try { - nop(); // $line-implicitExceptionTryCatch.before$ - ex(); // $line-implicitExceptionTryCatch.exception$ - nop(); // $line-implicitExceptionTryCatch.after$ - } catch (StubException e) { // $line-implicitExceptionTryCatch.catch$ - nop(); // $line-implicitExceptionTryCatch.catchBlock$ - } // $line-implicitExceptionTryCatch.catchBlockEnd$ - } // $line-implicitExceptionTryCatch.afterBlock$ - - private static void implicitExceptionTryCatchAfterCondition() { - if (f()) { // $line-implicitExceptionTryCatchAfterCondition.condition$ - return; - } - try { - ex(); // $line-implicitExceptionTryCatchAfterCondition.exception$ - } catch (StubException e) { - nop(); // $line-implicitExceptionTryCatchAfterCondition.catchBlock$ - } - } - - private static void explicitExceptionTryCatch() { - nop(); // $line-explicitExceptionTryCatch.beforeBlock$ - try { - nop(); // $line-explicitExceptionTryCatch.before$ - throw new StubException(); // $line-explicitExceptionTryCatch.throw$ - } catch (StubException e) { // $line-explicitExceptionTryCatch.catch$ - nop(); // $line-explicitExceptionTryCatch.catchBlock$ - } // $line-explicitExceptionTryCatch.catchBlockEnd$ - } // $line-explicitExceptionTryCatch.afterBlock$ - - private static void noExceptionFinally() { - nop(); // $line-noExceptionFinally.beforeBlock$ - try { - nop(); // $line-noExceptionFinally.tryBlock$ - } finally { // $line-noExceptionFinally.finally$ - nop(); // $line-noExceptionFinally.finallyBlock$ - } // $line-noExceptionFinally.finallyBlockEnd$ - } // $line-noExceptionFinally.afterBlock$ - - private static void implicitExceptionFinally() { - nop(); // $line-implicitExceptionFinally.beforeBlock$ - try { - nop(); // $line-implicitExceptionFinally.before$ - ex(); // $line-implicitExceptionFinally.exception$ - nop(); // $line-implicitExceptionFinally.after$ - } finally { // $line-implicitExceptionFinally.finally$ - nop(); // $line-implicitExceptionFinally.finallyBlock$ - } // $line-implicitExceptionFinally.finallyBlockEnd$ - } // $line-implicitExceptionFinally.afterBlock$ - - private static void explicitExceptionFinally() { - nop(); // $line-explicitExceptionFinally.beforeBlock$ - try { - nop(); // $line-explicitExceptionFinally.before$ - throw new StubException(); // $line-explicitExceptionFinally.throw$ - } finally { // $line-explicitExceptionFinally.finally$ - nop(); // $line-explicitExceptionFinally.finallyBlock$ - } // $line-explicitExceptionFinally.finallyBlockEnd$ - } // $line-explicitExceptionFinally.afterBlock$ - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target04.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target04.java deleted file mode 100644 index 8384744b..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target04.java +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.i1; - -/** - * This test target is an interface with a class initializer. - */ -public interface Target04 { - - // No code required to initialize these fields: - - static final int CONST1 = 12345; // $line-const1$ - - static final String CONST2 = "const"; // $line-const2$ - - // These fields are initialized within - - static final int CONST3 = i1(); // $line-const3$ - - static final Object CONST4 = new Object(); // $line-const4$ - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target05.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target05.java deleted file mode 100644 index ef5c3989..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target05.java +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.i1; - -/** - * This test target is a class with a static initializer. - */ -public class Target05 { - - // No code required to initialize these fields: - - public static final int CONST1 = 3; // $line-const1$ - - public static final String CONST2 = "Hello"; // $line-const2$ - - // These fields are initialized within - - public static final int CONST3 = i1(); // $line-const3$ - - public static final Object CONST4 = new Object(); // $line-const4$ - - public static int field1 = 3; // $line-field1$ - - public static String field2 = "Hello"; // $line-field2$ - - public static int field3 = i1(); // $line-field3$ - - public static Object field4 = new Object(); // $line-field4$ - - static { - Stubs.nop(); // $line-staticblock$ - } - - private Target05() { - } - - public static void main(String[] args) { - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target06.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target06.java deleted file mode 100644 index f6bc75e8..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target06.java +++ /dev/null @@ -1,25 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -/** - * This test target is a class with a implicit default constructor. - * - * @see Target07 explicit constructor - */ -public class Target06 { // $line-classdef$ - - public static void main(String[] args) { - new Target06(); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target07.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target07.java deleted file mode 100644 index 18c3ba52..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target07.java +++ /dev/null @@ -1,27 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -/** - * This test target is a private empty default constructor. - * - * @see Target06 implicit constructor - */ -public class Target07 { // $line-classdef$ - - private Target07() { // $line-super$ - } // $line-constructor$ - - public static void main(String[] args) { - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target08.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target08.java deleted file mode 100644 index 1fe938aa..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target08.java +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -/** - * This test target has instance members with implicit initializers. - */ -public class Target08 { // $line-classdef$ - - Object field1; // $line-field1$ - - Object field2 = this; // $line-field2$ - - int field3; // $line-field3$ - - int field4 = 2000; // $line-field4$ - - public static void main(String[] args) { - new Target08(); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target09.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target09.java deleted file mode 100644 index a8589d1d..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target09.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -/** - * This test target has instance members with initialization in two - * constructors. - */ -public class Target09 { - - Object field1 = null; // $line-field1$ - - int field2 = 123; // $line-field2$ - - public Target09() { - } // $line-constr1$ - - public Target09(String arg) { - } // $line-constr2$ - - public static void main(String[] args) { - new Target09(); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target10.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target10.java deleted file mode 100644 index bb4496e9..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target10.java +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.t; - -import org.jacoco.core.test.validation.targets.Stubs.SuperClass; - -/** - * This test target has a constructor containing control structures before the - * superclass constructor is called. - */ -public class Target10 extends SuperClass { - - public Target10() { - super(t() || f()); // $line-super$ - } - - public static void main(String[] args) { - new Target10(); - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target11.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target11.java deleted file mode 100644 index d393cb7f..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target11.java +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target needs an explicit initial frame as the first instruction - * already is a jump target. - */ -public class Target11 { - - public static void main(String[] args) { - - do { - nop(); // $line-dowhilebody$ - } while (f()); - - } - -} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target12.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target12.java deleted file mode 100644 index 5ee2e324..00000000 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/targets/Target12.java +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This target uses synchronized blocks which compile to try/catch statements. - */ -public class Target12 { - - static void simple() { - Object lock1 = new Object(); - synchronized (lock1) { - nop(); - } - } - - static void nested() { - Object lock1 = new Object(); - synchronized (lock1) { - nop(); - Object lock2 = new Object(); - synchronized (lock2) { - nop(); - } - nop(); - } - - } - - public static void main(String[] args) { - simple(); - nested(); - } - -} diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/StringSwitchTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/StringSwitchTest.java deleted file mode 100644 index 15181359..00000000 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/StringSwitchTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.StringSwitch; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of a bytecode that is generated for a String in switch - * statement. - */ -public class StringSwitchTest extends ValidationTestBase { - - public StringSwitchTest() { - super(StringSwitch.class); - } - - /** - * {@link StringSwitch#covered(String)} - */ - @Test - public void covered() { - if (isJDKCompiler) { - assertLine("covered.switch", ICounter.FULLY_COVERED, 0, 4); - } else { - assertLine("covered.switch", ICounter.PARTLY_COVERED, 2, 7); - } - assertLine("covered.case1", ICounter.FULLY_COVERED, 0, 0); - assertLine("covered.case2", ICounter.FULLY_COVERED, 0, 0); - assertLine("covered.case3", ICounter.FULLY_COVERED, 0, 0); - assertLine("covered.default", ICounter.FULLY_COVERED, 0, 0); - } - - /** - * {@link StringSwitch#notCovered(String)} - */ - @Test - public void notCovered() { - assertLine("notCovered", ICounter.NOT_COVERED, isJDKCompiler ? 4 : 9, - 0); - } - - /** - * {@link StringSwitch#handwritten(String)} - */ - @Test - public void handwritten() { - assertLine("handwritten.firstSwitch", ICounter.FULLY_COVERED, 2, 1); - assertLine("handwritten.ignored", ICounter.FULLY_COVERED); - assertLine("handwritten.secondSwitch", ICounter.FULLY_COVERED, 3, 1); - assertLine("handwritten.case1", ICounter.FULLY_COVERED); - assertLine("handwritten.case2", ICounter.NOT_COVERED); - } - -} diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/TryWithResourcesTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/TryWithResourcesTest.java deleted file mode 100644 index 41c61713..00000000 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/TryWithResourcesTest.java +++ /dev/null @@ -1,214 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.filter.targets.TryWithResources; -import org.jacoco.core.test.validation.ValidationTestBase; -import org.junit.Test; - -/** - * Test of filtering of a bytecode that is generated for a try-with-resources - * statement. - */ -public class TryWithResourcesTest extends ValidationTestBase { - - public TryWithResourcesTest() { - super(TryWithResources.class); - } - - /** - * {@link TryWithResources#test()} - */ - @Test - public void test() { - assertLine("test.before", ICounter.FULLY_COVERED); - // without filter next line covered partly: - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("test.try", ICounter.FULLY_COVERED); - } else { - assertLine("test.try", ICounter.EMPTY); - } - assertLine("test.open1", ICounter.FULLY_COVERED); - assertLine("test.open2", ICounter.FULLY_COVERED); - assertLine("test.open3", ICounter.FULLY_COVERED); - assertLine("test.body", ICounter.FULLY_COVERED); - // without filter next line has branches: - assertLine("test.close", ICounter.EMPTY); - assertLine("test.catch", ICounter.NOT_COVERED); - assertLine("test.finally", ICounter.FULLY_COVERED); - } - - /** - * {@link TryWithResources#test2()} - */ - @Test - public void test2() { - assertLine("test2.before", ICounter.FULLY_COVERED); - // without filter next line covered partly: - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("test2.try", ICounter.FULLY_COVERED); - } else { - assertLine("test2.try", ICounter.EMPTY); - } - assertLine("test2.open1", ICounter.FULLY_COVERED); - assertLine("test2.open2", ICounter.FULLY_COVERED); - assertLine("test2.open3", ICounter.FULLY_COVERED); - assertLine("test2.body", ICounter.FULLY_COVERED); - // without filter next line has branches: - assertLine("test2.close", ICounter.EMPTY); - assertLine("test2.catch", ICounter.NOT_COVERED); - assertLine("test2.finally", ICounter.FULLY_COVERED); - assertLine("test2.after", ICounter.FULLY_COVERED); - } - - /** - * {@link TryWithResources#returnInBody()} - */ - @Test - public void returnInBody() { - // without filter next line covered partly: - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("returnInBody.try", ICounter.FULLY_COVERED); - } else { - assertLine("returnInBody.try", ICounter.EMPTY); - } - assertLine("returnInBody.open", ICounter.FULLY_COVERED); - - // without filter next line has branches: - if (isJDKCompiler) { - // https://bugs.openjdk.java.net/browse/JDK-8134759 - // javac 7 and 8 up to 8u92 are affected - if (JAVA_VERSION.isBefore("1.8.0_92")) { - assertLine("returnInBody.close", ICounter.FULLY_COVERED, 0, 0); - } else { - assertLine("returnInBody.close", ICounter.EMPTY); - } - } else { - assertLine("returnInBody.close", ICounter.EMPTY); - } - - assertLine("returnInBody.return", ICounter.FULLY_COVERED); - } - - /** - * {@link TryWithResources#nested()} - */ - @Test - public void nested() { - // without filter next line covered partly: - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("nested.try1", ICounter.FULLY_COVERED); - } else { - assertLine("nested.try1", ICounter.EMPTY); - } - assertLine("nested.open1", ICounter.FULLY_COVERED); - assertLine("nested.catch1", ICounter.NOT_COVERED); - - // without filter next line covered partly: - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("nested.try2", ICounter.FULLY_COVERED); - } else { - assertLine("nested.try2", ICounter.EMPTY); - } - assertLine("nested.body", ICounter.FULLY_COVERED); - assertLine("nested.catch2", ICounter.NOT_COVERED); - assertLine("nested.finally2", ICounter.FULLY_COVERED); - - // next lines not covered on exceptional path: - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("nested.try3", ICounter.FULLY_COVERED); - } else { - assertLine("nested.try3", ICounter.EMPTY); - } - assertLine("nested.open3", ICounter.FULLY_COVERED, 0, 0); - assertLine("nested.body3", ICounter.FULLY_COVERED, 0, 0); - assertLine("nested.catch3", ICounter.NOT_COVERED); - assertLine("nested.finally3", ICounter.FULLY_COVERED, 0, 0); - - // without filter next lines have branches: - assertLine("nested.close3", ICounter.EMPTY); - assertLine("nested.close2", ICounter.EMPTY); - assertLine("nested.close1", ICounter.EMPTY); - } - - /** - * {@link TryWithResources#returnInCatch()} - */ - @Test - public void returnInCatch() { - // without filter next line covered partly: - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("returnInCatch.try1", ICounter.FULLY_COVERED); - } else { - assertLine("returnInCatch.try1", ICounter.EMPTY); - } - assertLine("returnInCatch.open", ICounter.FULLY_COVERED); - assertLine("returnInCatch.finally1", ICounter.PARTLY_COVERED, 1, 1); - // without filter next line has branches: - assertLine("returnInCatch.close", ICounter.EMPTY); - - assertLine("returnInCatch.try2", ICounter.EMPTY); - assertLine("returnInCatch.finally2", ICounter.PARTLY_COVERED, 1, 1); - } - - /* - * Corner cases - */ - - /** - * {@link TryWithResources#handwritten()} - */ - @Test - public void handwritten() { - if (isJDKCompiler) { - assertLine("handwritten", /* partly when ECJ: */ICounter.EMPTY); - } - } - - /** - * {@link TryWithResources#empty()} - */ - @Test - public void empty() { - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("empty.try", ICounter.FULLY_COVERED); - } else { - assertLine("empty.try", ICounter.EMPTY); - } - assertLine("empty.open", ICounter.FULLY_COVERED); - // empty when EJC: - if (isJDKCompiler) { - if (JAVA_VERSION.isBefore("9")) { - // branches with javac 7 and 8 - assertLine("empty.close", ICounter.PARTLY_COVERED); - } else { - assertLine("empty.close", ICounter.FULLY_COVERED, 0, 0); - } - } - } - - /** - * {@link TryWithResources#throwInBody()} - */ - @Test - public void throwInBody() { - // not filtered - assertLine("throwInBody.try", ICounter.NOT_COVERED); - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("throwInBody.close", ICounter.NOT_COVERED); - } else { - assertLine("throwInBody.close", ICounter.EMPTY); - } - } - -} diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/StringSwitch.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/StringSwitch.java deleted file mode 100644 index c8b9a232..00000000 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/StringSwitch.java +++ /dev/null @@ -1,96 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target is a switch statement with a String. - */ -public class StringSwitch { - - private static void covered(Object s) { - switch (String.valueOf(s)) { // $line-covered.switch$ - case "a": - nop("case a"); // $line-covered.case1$ - break; - case "b": - nop("case b"); // $line-covered.case2$ - break; - case "\0a": - nop("case \0a"); // $line-covered.case3$ - break; - default: - nop("case default"); // $line-covered.default$ - break; - } - } - - private static void notCovered(Object s) { - switch (String.valueOf(s)) { // $line-notCovered$ - case "a": - nop("case a"); - break; - case "b": - nop("case b"); - break; - case "\0a": - nop("case \0a"); - break; - default: - nop("default"); - break; - } - } - - private static void handwritten(String s) { - int c = -1; - switch (s.hashCode()) { // $line-handwritten.firstSwitch$ - case 97: - if ("a".equals(s)) { // $line-handwritten.ignored$ - c = 0; - } else if ("\0a".equals(s)) { - c = 1; - } - break; - case 98: - if ("b".equals(s)) { - c = 2; - } - break; - } - switch (c) { // $line-handwritten.secondSwitch$ - case 0: - nop("case a"); // $line-handwritten.case1$ - break; - case 1: - nop("case \0a"); // $line-handwritten.case2$ - break; - case 2: - nop("case b"); - break; - default: - nop("default"); - break; - } - } - - public static void main(String[] args) { - covered(""); - covered("a"); - covered("b"); - covered("\0a"); - - handwritten("a"); - } - -} diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/TryWithResources.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/TryWithResources.java deleted file mode 100644 index 3d3a30db..00000000 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/filter/targets/TryWithResources.java +++ /dev/null @@ -1,204 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.filter.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.f; -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -import java.io.Closeable; -import java.io.IOException; - -/** - * This test target is a try-with-resources statement. - */ -public class TryWithResources { - - private static class Resource implements Closeable { - @Override - public void close() { - } - } - - /** - * Closing performed using {@link org.objectweb.asm.Opcodes#INVOKEVIRTUAL} - * or {@link org.objectweb.asm.Opcodes#INVOKEINTERFACE} depending on a class - * of resource. - */ - private static Object test() throws Exception { - nop(); // $line-test.before$ - try ( // $line-test.try$ - Resource r1 = new Resource(); // $line-test.open1$ - Closeable r2 = new Resource(); // $line-test.open2$ - AutoCloseable r3 = new Resource() // $line-test.open3$ - ) { - return read(r1, r2, r3); // $line-test.body$ - } // $line-test.close$ - catch (Exception e) { - nop(); // $line-test.catch$ - throw e; - } finally { - nop(); // $line-test.finally$ - } - } - - private static void test2() throws Exception { - nop(); // $line-test2.before$ - try ( // $line-test2.try$ - Resource r1 = new Resource(); // $line-test2.open1$ - Closeable r2 = new Resource(); // $line-test2.open2$ - AutoCloseable r3 = new Resource() // $line-test2.open3$ - ) { - read(r1, r2, r3); // $line-test2.body$ - } // $line-test2.close$ - catch (Exception e) { - nop(); // $line-test2.catch$ - } finally { - nop(); // $line-test2.finally$ - } - nop(); // $line-test2.after$ - } - - private static Object returnInBody() throws IOException { - try ( // $line-returnInBody.try$ - Closeable r = new Resource() // $line-returnInBody.open$ - ) { - return read(r); // $line-returnInBody.return$ - } // $line-returnInBody.close$ - } - - private static void nested() { - try ( // $line-nested.try1$ - Resource r1 = new Resource() // $line-nested.open1$ - ) { - - try ( // $line-nested.try2$ - Resource r2 = new Resource() // $line-nested.open2$ - ) { - nop(r1.toString() + r2.toString()); // $line-nested.body$ - } // $line-nested.close2$ - catch (Exception e) { - nop(); // $line-nested.catch2$ - } finally { - nop(); // $line-nested.finally2$ - } - - } // $line-nested.close1$ - catch (Exception e) { - nop(); // $line-nested.catch1$ - } finally { - - try ( // $line-nested.try3$ - Resource r2 = new Resource() // $line-nested.open3$ - ) { - nop(r2); // $line-nested.body3$ - } // $line-nested.close3$ - catch (Exception e) { - nop(); // $line-nested.catch3$ - } finally { - nop(); // $line-nested.finally3$ - } - - } - } - - /** - * In this case bytecode will contain 3 copies of finally - * block, each containing 2 branches, resulting in 6 branches in total. One - * could think that this is artifact of try-with-resources, but the same - * happens without it. - */ - private static Object returnInCatch() { - try ( // $line-returnInCatch.try1$ - Resource r = new Resource() // $line-returnInCatch.open$ - ) { - read(r); - } // $line-returnInCatch.close$ - catch (Exception e) { - return null; - } finally { - nop(!f()); // $line-returnInCatch.finally1$ - } - - try { // $line-returnInCatch.try2$ - read(new Resource()); - } catch (Exception e) { - return null; - } finally { - nop(!f()); // $line-returnInCatch.finally2$ - } - - return null; - } - - private static Object read(Object r1, Object r2, Object r3) { - return r1.toString() + r2.toString() + r3.toString(); - } - - private static Object read(Object r1) { - return r1.toString(); - } - - public static void main(String[] args) throws Exception { - test(); - test2(); - returnInBody(); - nested(); - - returnInCatch(); - - empty(); - handwritten(); - } - - /* - * Corner cases - */ - - private static void empty() throws Exception { - try ( // $line-empty.try$ - Closeable r = new Resource() // $line-empty.open$ - ) { - } // $line-empty.close$ - } - - private static void handwritten() throws IOException { - Closeable r = new Resource(); - Throwable primaryExc = null; - try { - nop(r); - } catch (Throwable t) { - primaryExc = t; - throw t; - } finally { - if (r != null) { // $line-handwritten$ - if (primaryExc != null) { - try { - r.close(); - } catch (Throwable suppressedExc) { - primaryExc.addSuppressed(suppressedExc); - } - } else { - r.close(); - } - } - } - } - - private static void throwInBody() throws IOException { - try ( // $line-throwInBody.try$ - Closeable r = new Resource()) { - nop(r); - throw new RuntimeException(); - } // $line-throwInBody.close$ - } - -} diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java new file mode 100644 index 00000000..778097e0 --- /dev/null +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java7; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java7.targets.StringSwitchTarget; +import org.junit.Test; + +/** + * Test of filtering of a bytecode that is generated for a String in switch + * statement. + */ +public class StringSwitchTest extends ValidationTestBase { + + public StringSwitchTest() { + super(StringSwitchTarget.class); + } + + /** + * {@link StringSwitchTarget#covered(String)} + */ + @Test + public void covered() { + if (isJDKCompiler) { + assertLine("covered.switch", ICounter.FULLY_COVERED, 0, 4); + } else { + assertLine("covered.switch", ICounter.PARTLY_COVERED, 2, 7); + } + assertLine("covered.case1", ICounter.FULLY_COVERED, 0, 0); + assertLine("covered.case2", ICounter.FULLY_COVERED, 0, 0); + assertLine("covered.case3", ICounter.FULLY_COVERED, 0, 0); + assertLine("covered.default", ICounter.FULLY_COVERED, 0, 0); + } + + /** + * {@link StringSwitchTarget#notCovered(String)} + */ + @Test + public void notCovered() { + assertLine("notCovered", ICounter.NOT_COVERED, isJDKCompiler ? 4 : 9, + 0); + } + + /** + * {@link StringSwitchTarget#handwritten(String)} + */ + @Test + public void handwritten() { + assertLine("handwritten.firstSwitch", ICounter.FULLY_COVERED, 2, 1); + assertLine("handwritten.ignored", ICounter.FULLY_COVERED); + assertLine("handwritten.secondSwitch", ICounter.FULLY_COVERED, 3, 1); + assertLine("handwritten.case1", ICounter.FULLY_COVERED); + assertLine("handwritten.case2", ICounter.NOT_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java new file mode 100644 index 00000000..0056a34a --- /dev/null +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java @@ -0,0 +1,214 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java7; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java7.targets.TryWithResourcesTarget; +import org.junit.Test; + +/** + * Test of filtering of a bytecode that is generated for a try-with-resources + * statement. + */ +public class TryWithResourcesTest extends ValidationTestBase { + + public TryWithResourcesTest() { + super(TryWithResourcesTarget.class); + } + + /** + * {@link TryWithResourcesFilterTarget#test()} + */ + @Test + public void test() { + assertLine("test.before", ICounter.FULLY_COVERED); + // without filter next line covered partly: + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("test.try", ICounter.FULLY_COVERED); + } else { + assertLine("test.try", ICounter.EMPTY); + } + assertLine("test.open1", ICounter.FULLY_COVERED); + assertLine("test.open2", ICounter.FULLY_COVERED); + assertLine("test.open3", ICounter.FULLY_COVERED); + assertLine("test.body", ICounter.FULLY_COVERED); + // without filter next line has branches: + assertLine("test.close", ICounter.EMPTY); + assertLine("test.catch", ICounter.NOT_COVERED); + assertLine("test.finally", ICounter.FULLY_COVERED); + } + + /** + * {@link TryWithResourcesFilterTarget#test2()} + */ + @Test + public void test2() { + assertLine("test2.before", ICounter.FULLY_COVERED); + // without filter next line covered partly: + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("test2.try", ICounter.FULLY_COVERED); + } else { + assertLine("test2.try", ICounter.EMPTY); + } + assertLine("test2.open1", ICounter.FULLY_COVERED); + assertLine("test2.open2", ICounter.FULLY_COVERED); + assertLine("test2.open3", ICounter.FULLY_COVERED); + assertLine("test2.body", ICounter.FULLY_COVERED); + // without filter next line has branches: + assertLine("test2.close", ICounter.EMPTY); + assertLine("test2.catch", ICounter.NOT_COVERED); + assertLine("test2.finally", ICounter.FULLY_COVERED); + assertLine("test2.after", ICounter.FULLY_COVERED); + } + + /** + * {@link TryWithResourcesFilterTarget#returnInBody()} + */ + @Test + public void returnInBody() { + // without filter next line covered partly: + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("returnInBody.try", ICounter.FULLY_COVERED); + } else { + assertLine("returnInBody.try", ICounter.EMPTY); + } + assertLine("returnInBody.open", ICounter.FULLY_COVERED); + + // without filter next line has branches: + if (isJDKCompiler) { + // https://bugs.openjdk.java.net/browse/JDK-8134759 + // javac 7 and 8 up to 8u92 are affected + if (JAVA_VERSION.isBefore("1.8.0_92")) { + assertLine("returnInBody.close", ICounter.FULLY_COVERED, 0, 0); + } else { + assertLine("returnInBody.close", ICounter.EMPTY); + } + } else { + assertLine("returnInBody.close", ICounter.EMPTY); + } + + assertLine("returnInBody.return", ICounter.FULLY_COVERED); + } + + /** + * {@link TryWithResourcesFilterTarget#nested()} + */ + @Test + public void nested() { + // without filter next line covered partly: + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("nested.try1", ICounter.FULLY_COVERED); + } else { + assertLine("nested.try1", ICounter.EMPTY); + } + assertLine("nested.open1", ICounter.FULLY_COVERED); + assertLine("nested.catch1", ICounter.NOT_COVERED); + + // without filter next line covered partly: + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("nested.try2", ICounter.FULLY_COVERED); + } else { + assertLine("nested.try2", ICounter.EMPTY); + } + assertLine("nested.body", ICounter.FULLY_COVERED); + assertLine("nested.catch2", ICounter.NOT_COVERED); + assertLine("nested.finally2", ICounter.FULLY_COVERED); + + // next lines not covered on exceptional path: + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("nested.try3", ICounter.FULLY_COVERED); + } else { + assertLine("nested.try3", ICounter.EMPTY); + } + assertLine("nested.open3", ICounter.FULLY_COVERED, 0, 0); + assertLine("nested.body3", ICounter.FULLY_COVERED, 0, 0); + assertLine("nested.catch3", ICounter.NOT_COVERED); + assertLine("nested.finally3", ICounter.FULLY_COVERED, 0, 0); + + // without filter next lines have branches: + assertLine("nested.close3", ICounter.EMPTY); + assertLine("nested.close2", ICounter.EMPTY); + assertLine("nested.close1", ICounter.EMPTY); + } + + /** + * {@link TryWithResourcesFilterTarget#returnInCatch()} + */ + @Test + public void returnInCatch() { + // without filter next line covered partly: + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("returnInCatch.try1", ICounter.FULLY_COVERED); + } else { + assertLine("returnInCatch.try1", ICounter.EMPTY); + } + assertLine("returnInCatch.open", ICounter.FULLY_COVERED); + assertLine("returnInCatch.finally1", ICounter.PARTLY_COVERED, 1, 1); + // without filter next line has branches: + assertLine("returnInCatch.close", ICounter.EMPTY); + + assertLine("returnInCatch.try2", ICounter.EMPTY); + assertLine("returnInCatch.finally2", ICounter.PARTLY_COVERED, 1, 1); + } + + /* + * Corner cases + */ + + /** + * {@link TryWithResourcesFilterTarget#handwritten()} + */ + @Test + public void handwritten() { + if (isJDKCompiler) { + assertLine("handwritten", /* partly when ECJ: */ICounter.EMPTY); + } + } + + /** + * {@link TryWithResourcesFilterTarget#empty()} + */ + @Test + public void empty() { + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("empty.try", ICounter.FULLY_COVERED); + } else { + assertLine("empty.try", ICounter.EMPTY); + } + assertLine("empty.open", ICounter.FULLY_COVERED); + // empty when EJC: + if (isJDKCompiler) { + if (JAVA_VERSION.isBefore("9")) { + // branches with javac 7 and 8 + assertLine("empty.close", ICounter.PARTLY_COVERED); + } else { + assertLine("empty.close", ICounter.FULLY_COVERED, 0, 0); + } + } + } + + /** + * {@link TryWithResourcesFilterTarget#throwInBody()} + */ + @Test + public void throwInBody() { + // not filtered + assertLine("throwInBody.try", ICounter.NOT_COVERED); + if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + assertLine("throwInBody.close", ICounter.NOT_COVERED); + } else { + assertLine("throwInBody.close", ICounter.EMPTY); + } + } + +} diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java new file mode 100644 index 00000000..8e182a4f --- /dev/null +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java7.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target is a switch statement with a String. + */ +public class StringSwitchTarget { + + private static void covered(Object s) { + switch (String.valueOf(s)) { // $line-covered.switch$ + case "a": + nop("case a"); // $line-covered.case1$ + break; + case "b": + nop("case b"); // $line-covered.case2$ + break; + case "\0a": + nop("case \0a"); // $line-covered.case3$ + break; + default: + nop("case default"); // $line-covered.default$ + break; + } + } + + private static void notCovered(Object s) { + switch (String.valueOf(s)) { // $line-notCovered$ + case "a": + nop("case a"); + break; + case "b": + nop("case b"); + break; + case "\0a": + nop("case \0a"); + break; + default: + nop("default"); + break; + } + } + + private static void handwritten(String s) { + int c = -1; + switch (s.hashCode()) { // $line-handwritten.firstSwitch$ + case 97: + if ("a".equals(s)) { // $line-handwritten.ignored$ + c = 0; + } else if ("\0a".equals(s)) { + c = 1; + } + break; + case 98: + if ("b".equals(s)) { + c = 2; + } + break; + } + switch (c) { // $line-handwritten.secondSwitch$ + case 0: + nop("case a"); // $line-handwritten.case1$ + break; + case 1: + nop("case \0a"); // $line-handwritten.case2$ + break; + case 2: + nop("case b"); + break; + default: + nop("default"); + break; + } + } + + public static void main(String[] args) { + covered(""); + covered("a"); + covered("b"); + covered("\0a"); + + handwritten("a"); + } + +} diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/TryWithResourcesTarget.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/TryWithResourcesTarget.java new file mode 100644 index 00000000..08d9cdab --- /dev/null +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/TryWithResourcesTarget.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java7.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.f; +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +import java.io.Closeable; +import java.io.IOException; + +/** + * This test target is a try-with-resources statement. + */ +public class TryWithResourcesTarget { + + private static class Resource implements Closeable { + @Override + public void close() { + } + } + + /** + * Closing performed using {@link org.objectweb.asm.Opcodes#INVOKEVIRTUAL} + * or {@link org.objectweb.asm.Opcodes#INVOKEINTERFACE} depending on a class + * of resource. + */ + private static Object test() throws Exception { + nop(); // $line-test.before$ + try ( // $line-test.try$ + Resource r1 = new Resource(); // $line-test.open1$ + Closeable r2 = new Resource(); // $line-test.open2$ + AutoCloseable r3 = new Resource() // $line-test.open3$ + ) { + return read(r1, r2, r3); // $line-test.body$ + } // $line-test.close$ + catch (Exception e) { + nop(); // $line-test.catch$ + throw e; + } finally { + nop(); // $line-test.finally$ + } + } + + private static void test2() throws Exception { + nop(); // $line-test2.before$ + try ( // $line-test2.try$ + Resource r1 = new Resource(); // $line-test2.open1$ + Closeable r2 = new Resource(); // $line-test2.open2$ + AutoCloseable r3 = new Resource() // $line-test2.open3$ + ) { + read(r1, r2, r3); // $line-test2.body$ + } // $line-test2.close$ + catch (Exception e) { + nop(); // $line-test2.catch$ + } finally { + nop(); // $line-test2.finally$ + } + nop(); // $line-test2.after$ + } + + private static Object returnInBody() throws IOException { + try ( // $line-returnInBody.try$ + Closeable r = new Resource() // $line-returnInBody.open$ + ) { + return read(r); // $line-returnInBody.return$ + } // $line-returnInBody.close$ + } + + private static void nested() { + try ( // $line-nested.try1$ + Resource r1 = new Resource() // $line-nested.open1$ + ) { + + try ( // $line-nested.try2$ + Resource r2 = new Resource() // $line-nested.open2$ + ) { + nop(r1.toString() + r2.toString()); // $line-nested.body$ + } // $line-nested.close2$ + catch (Exception e) { + nop(); // $line-nested.catch2$ + } finally { + nop(); // $line-nested.finally2$ + } + + } // $line-nested.close1$ + catch (Exception e) { + nop(); // $line-nested.catch1$ + } finally { + + try ( // $line-nested.try3$ + Resource r2 = new Resource() // $line-nested.open3$ + ) { + nop(r2); // $line-nested.body3$ + } // $line-nested.close3$ + catch (Exception e) { + nop(); // $line-nested.catch3$ + } finally { + nop(); // $line-nested.finally3$ + } + + } + } + + /** + * In this case bytecode will contain 3 copies of finally + * block, each containing 2 branches, resulting in 6 branches in total. One + * could think that this is artifact of try-with-resources, but the same + * happens without it. + */ + private static Object returnInCatch() { + try ( // $line-returnInCatch.try1$ + Resource r = new Resource() // $line-returnInCatch.open$ + ) { + read(r); + } // $line-returnInCatch.close$ + catch (Exception e) { + return null; + } finally { + nop(!f()); // $line-returnInCatch.finally1$ + } + + try { // $line-returnInCatch.try2$ + read(new Resource()); + } catch (Exception e) { + return null; + } finally { + nop(!f()); // $line-returnInCatch.finally2$ + } + + return null; + } + + private static Object read(Object r1, Object r2, Object r3) { + return r1.toString() + r2.toString() + r3.toString(); + } + + private static Object read(Object r1) { + return r1.toString(); + } + + public static void main(String[] args) throws Exception { + test(); + test2(); + returnInBody(); + nested(); + + returnInCatch(); + + empty(); + handwritten(); + } + + /* + * Corner cases + */ + + private static void empty() throws Exception { + try ( // $line-empty.try$ + Closeable r = new Resource() // $line-empty.open$ + ) { + } // $line-empty.close$ + } + + private static void handwritten() throws IOException { + Closeable r = new Resource(); + Throwable primaryExc = null; + try { + nop(r); + } catch (Throwable t) { + primaryExc = t; + throw t; + } finally { + if (r != null) { // $line-handwritten$ + if (primaryExc != null) { + try { + r.close(); + } catch (Throwable suppressedExc) { + primaryExc.addSuppressed(suppressedExc); + } + } else { + r.close(); + } + } + } + } + + private static void throwInBody() throws IOException { + try ( // $line-throwInBody.try$ + Closeable r = new Resource()) { + nop(r); + throw new RuntimeException(); + } // $line-throwInBody.close$ + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java deleted file mode 100644 index 64e8fafa..00000000 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/AnnotationOnLocalVariableTest.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.AnnotationOnLocalVariableTarget; -import org.junit.Test; - -/** - * Test of ASM bug - * #317815 - */ -public class AnnotationOnLocalVariableTest extends ValidationTestBase { - - public AnnotationOnLocalVariableTest() { - super(AnnotationOnLocalVariableTarget.class); - } - - @Test - public void testCoverageResult() { - - assertLine("var", ICounter.FULLY_COVERED); - - } - -} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BadCycleInterfaceTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BadCycleInterfaceTest.java deleted file mode 100644 index a8ab6727..00000000 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BadCycleInterfaceTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.BadCycleInterface; -import org.junit.Test; - -/** - * Test of "bad cycles" with interfaces. - */ -public class BadCycleInterfaceTest extends ValidationTestBase { - - public BadCycleInterfaceTest() throws Exception { - super(BadCycleInterface.class); - } - - @Test - public void test() throws Exception { - if (JAVA_VERSION.isBefore("1.8.0_152")) { - // Incorrect interpetation of JVMS 5.5 in JDK 8 causes a default - // method to be called before the static initializer of an interface - // (see JDK-8098557 and JDK-8164302): - assertLine("baseclinit", ICounter.FULLY_COVERED); - assertLine("childdefault", ICounter.FULLY_COVERED); - - assertLogEvents("baseclinit", "childdefaultmethod", "childclinit", - "childstaticmethod"); - } else { - // This shouldn't happen with JDK 9 (see also JDK-8043275) - // and starting with JDK 8u152 (see JDK-8167607): - assertLine("baseclinit", ICounter.EMPTY); - assertLine("childdefault", ICounter.NOT_COVERED); - assertLogEvents("childclinit", "childstaticmethod"); - } - assertLine("childclinit", ICounter.FULLY_COVERED); - assertLine("childstatic", ICounter.FULLY_COVERED); - } - -} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java deleted file mode 100644 index dc20f0af..00000000 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java +++ /dev/null @@ -1,126 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import static org.junit.Assert.assertEquals; - -import java.lang.invoke.CallSite; -import java.lang.invoke.ConstantCallSite; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.InvocationTargetException; - -import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.runtime.IRuntime; -import org.jacoco.core.runtime.RuntimeData; -import org.jacoco.core.runtime.SystemPropertiesRuntime; -import org.jacoco.core.test.TargetLoader; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -/** - * Test of ASM bug - * #317748 that - * caused - * {@code java.lang.ClassFormatError: Short length on BootstrapMethods in class file} - * during instrumentation. - */ -public class BootstrapMethodReferenceTest { - - private final IRuntime runtime = new SystemPropertiesRuntime(); - private final Instrumenter instrumenter = new Instrumenter(runtime); - - @Before - public void setup() throws Exception { - runtime.startup(new RuntimeData()); - } - - @After - public void teardown() { - runtime.shutdown(); - } - - @Test - public void test() throws Exception { - final String className = "Example"; - - final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, className, null, - "java/lang/Object", null); - - final MethodVisitor mv = cw.visitMethod( - Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "run", "()I", null, - null); - mv.visitCode(); - addCauseOfResizeInstructions(mv); - final MethodType methodType = MethodType.methodType(CallSite.class, - MethodHandles.Lookup.class, String.class, MethodType.class); - final Handle handle = new Handle(Opcodes.H_INVOKESTATIC, - this.getClass().getCanonicalName().replace('.', '/'), - "bootstrap", methodType.toMethodDescriptorString(), false); - mv.visitInvokeDynamicInsn("invoke", "()I", handle); - mv.visitInsn(Opcodes.IRETURN); - mv.visitMaxs(1, 0); - mv.visitEnd(); - - cw.visitEnd(); - - final byte[] original = cw.toByteArray(); - assertEquals(42, run(className, original)); - - final byte[] instrumented = instrumenter.instrument(original, - className); - assertEquals(42, run(className, instrumented)); - } - - private static int run(final String className, final byte[] bytes) - throws ClassNotFoundException, NoSuchMethodException, - InvocationTargetException, IllegalAccessException { - return (Integer) new TargetLoader().add(className, bytes) - .getMethod("run").invoke(null); - } - - /** - * Adds code that triggers usage of - * {@link org.objectweb.asm.MethodWriter#COMPUTE_INSERTED_FRAMES} during - * instrumentation. - */ - private static void addCauseOfResizeInstructions(final MethodVisitor mv) { - mv.visitInsn(Opcodes.ICONST_0); - mv.visitInsn(Opcodes.ICONST_1); - final Label target = new Label(); - mv.visitJumpInsn(Opcodes.IFLE, target); - for (int i = 0; i < Short.MAX_VALUE; i++) { - mv.visitInsn(Opcodes.NOP); - } - mv.visitLabel(target); - } - - @SuppressWarnings("unused") - public static CallSite bootstrap(final MethodHandles.Lookup caller, - final String name, final MethodType type) throws Exception { - return new ConstantCallSite(caller.findStatic(BootstrapMethodReferenceTest.class, - "callTarget", MethodType.methodType(int.class))); - } - - @SuppressWarnings("unused") - public static int callTarget() { - return 42; - } - -} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java deleted file mode 100644 index 4611d782..00000000 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.InterfaceDefaultMethodsTarget; -import org.junit.Test; - -/** - * Tests of static initializer and default methods in interfaces. - */ -public class InterfaceDefaultMethodsTest extends ValidationTestBase { - - public InterfaceDefaultMethodsTest() { - super(InterfaceDefaultMethodsTarget.class); - } - - @Test - public void testCoverageResult() { - assertLine("clinit", ICounter.FULLY_COVERED); - assertLine("m1", ICounter.FULLY_COVERED); - assertLine("m2", ICounter.NOT_COVERED); - } - -} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java deleted file mode 100644 index bbb7f0ed..00000000 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.InterfaceOnlyDefaultMethodsTarget; -import org.junit.Test; - -/** - * Tests of default methods in interfaces. - */ -public class InterfaceOnlyDefaultMethodsTest extends ValidationTestBase { - - public InterfaceOnlyDefaultMethodsTest() { - super(InterfaceOnlyDefaultMethodsTarget.class); - } - - @Test - public void testCoverageResult() { - assertLine("m1", ICounter.FULLY_COVERED); - assertLine("m2", ICounter.NOT_COVERED); - } - -} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaExpressionsTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaExpressionsTest.java deleted file mode 100644 index f1344991..00000000 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaExpressionsTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.LambdaExpressionsTarget; -import org.junit.Test; - -/** - * Tests for different lambda expressions. - */ -public class LambdaExpressionsTest extends ValidationTestBase { - - public LambdaExpressionsTest() { - super(LambdaExpressionsTarget.class); - } - - @Test - public void testCoverageResult() { - - // Coverage of lambda bodies - assertLine("executedlambdabody", ICounter.FULLY_COVERED); - assertLine("notexecutedlambdabody", ICounter.NOT_COVERED); - - } - -} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaInInterfaceTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaInInterfaceTest.java deleted file mode 100644 index 759a78fc..00000000 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/LambdaInInterfaceTest.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation; - -import org.jacoco.core.analysis.ICounter; -import org.jacoco.core.test.validation.targets.LambdaInInterfaceTarget; -import org.junit.Test; - -/** - * Tests a constant with a lambda value in an interface. - */ -public class LambdaInInterfaceTest extends ValidationTestBase { - - public LambdaInInterfaceTest() { - super(LambdaInInterfaceTarget.class); - } - - @Override - protected void run(final Class targetClass) throws Exception { - ((Runnable) targetClass.getField("RUN").get(null)).run(); - } - - @Test - public void testCoverageResult() { - - // Coverage of lambda body - assertLine("lambdabody", ICounter.FULLY_COVERED); - - } - -} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/AnnotationOnLocalVariableTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/AnnotationOnLocalVariableTest.java new file mode 100644 index 00000000..0b9a3c1d --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/AnnotationOnLocalVariableTest.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java8; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java8.targets.AnnotationOnLocalVariableTarget; +import org.junit.Test; + +/** + * Test of ASM bug + * #317815 + */ +public class AnnotationOnLocalVariableTest extends ValidationTestBase { + + public AnnotationOnLocalVariableTest() { + super(AnnotationOnLocalVariableTarget.class); + } + + @Test + public void testCoverageResult() { + + assertLine("var", ICounter.FULLY_COVERED); + + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/BadCycleInterfaceTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/BadCycleInterfaceTest.java new file mode 100644 index 00000000..b9f0a469 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/BadCycleInterfaceTest.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java8; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java8.targets.BadCycleInterfaceTarget; +import org.junit.Test; + +/** + * Test of "bad cycles" with interfaces. + */ +public class BadCycleInterfaceTest extends ValidationTestBase { + + public BadCycleInterfaceTest() throws Exception { + super(BadCycleInterfaceTarget.class); + } + + @Test + public void test() throws Exception { + if (JAVA_VERSION.isBefore("1.8.0_152")) { + // Incorrect interpetation of JVMS 5.5 in JDK 8 causes a default + // method to be called before the static initializer of an interface + // (see JDK-8098557 and JDK-8164302): + assertLine("baseclinit", ICounter.FULLY_COVERED); + assertLine("childdefault", ICounter.FULLY_COVERED); + + assertLogEvents("baseclinit", "childdefaultmethod", "childclinit", + "childstaticmethod"); + } else { + // This shouldn't happen with JDK 9 (see also JDK-8043275) + // and starting with JDK 8u152 (see JDK-8167607): + assertLine("baseclinit", ICounter.EMPTY); + assertLine("childdefault", ICounter.NOT_COVERED); + assertLogEvents("childclinit", "childstaticmethod"); + } + assertLine("childclinit", ICounter.FULLY_COVERED); + assertLine("childstatic", ICounter.FULLY_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/BootstrapMethodReferenceTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/BootstrapMethodReferenceTest.java new file mode 100644 index 00000000..69348001 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/BootstrapMethodReferenceTest.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java8; + +import static org.junit.Assert.assertEquals; + +import java.lang.invoke.CallSite; +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.InvocationTargetException; + +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.RuntimeData; +import org.jacoco.core.runtime.SystemPropertiesRuntime; +import org.jacoco.core.test.TargetLoader; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Test of ASM bug + * #317748 that + * caused + * {@code java.lang.ClassFormatError: Short length on BootstrapMethods in class file} + * during instrumentation. + */ +public class BootstrapMethodReferenceTest { + + private IRuntime runtime; + private Instrumenter instrumenter; + + @Before + public void setup() throws Exception { + runtime = new SystemPropertiesRuntime(); + instrumenter = new Instrumenter(runtime); + runtime.startup(new RuntimeData()); + } + + @After + public void teardown() { + runtime.shutdown(); + } + + @Test + public void test() throws Exception { + final String className = "Example"; + + final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + cw.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, className, null, + "java/lang/Object", null); + + final MethodVisitor mv = cw.visitMethod( + Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "run", "()I", null, + null); + mv.visitCode(); + addCauseOfResizeInstructions(mv); + final MethodType methodType = MethodType.methodType(CallSite.class, + MethodHandles.Lookup.class, String.class, MethodType.class); + final Handle handle = new Handle(Opcodes.H_INVOKESTATIC, + this.getClass().getCanonicalName().replace('.', '/'), + "bootstrap", methodType.toMethodDescriptorString(), false); + mv.visitInvokeDynamicInsn("invoke", "()I", handle); + mv.visitInsn(Opcodes.IRETURN); + mv.visitMaxs(1, 0); + mv.visitEnd(); + + cw.visitEnd(); + + final byte[] original = cw.toByteArray(); + assertEquals(42, run(className, original)); + + final byte[] instrumented = instrumenter.instrument(original, + className); + assertEquals(42, run(className, instrumented)); + } + + private static int run(final String className, final byte[] bytes) + throws ClassNotFoundException, NoSuchMethodException, + InvocationTargetException, IllegalAccessException { + final Integer result = (Integer) new TargetLoader() + .add(className, bytes).getMethod("run").invoke(null); + return result.intValue(); + } + + /** + * Adds code that triggers usage of + * {@link org.objectweb.asm.MethodWriter#COMPUTE_INSERTED_FRAMES} during + * instrumentation. + */ + private static void addCauseOfResizeInstructions(final MethodVisitor mv) { + mv.visitInsn(Opcodes.ICONST_0); + mv.visitInsn(Opcodes.ICONST_1); + final Label target = new Label(); + mv.visitJumpInsn(Opcodes.IFLE, target); + for (int i = 0; i < Short.MAX_VALUE; i++) { + mv.visitInsn(Opcodes.NOP); + } + mv.visitLabel(target); + } + + public static CallSite bootstrap(final MethodHandles.Lookup caller, + final String name, final MethodType type) throws Exception { + return new ConstantCallSite( + caller.findStatic(BootstrapMethodReferenceTest.class, + "callTarget", MethodType.methodType(int.class))); + } + + public static int callTarget() { + return 42; + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceDefaultMethodsTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceDefaultMethodsTest.java new file mode 100644 index 00000000..4701e27f --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceDefaultMethodsTest.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java8; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java8.targets.InterfaceDefaultMethodsTarget; +import org.junit.Test; + +/** + * Tests of static initializer and default methods in interfaces. + */ +public class InterfaceDefaultMethodsTest extends ValidationTestBase { + + public InterfaceDefaultMethodsTest() { + super(InterfaceDefaultMethodsTarget.class); + } + + @Test + public void testCoverageResult() { + assertLine("clinit", ICounter.FULLY_COVERED); + assertLine("m1", ICounter.FULLY_COVERED); + assertLine("m2", ICounter.NOT_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceOnlyDefaultMethodsTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceOnlyDefaultMethodsTest.java new file mode 100644 index 00000000..e0ffc723 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceOnlyDefaultMethodsTest.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java8; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java8.targets.InterfaceOnlyDefaultMethodsTarget; +import org.junit.Test; + +/** + * Tests of default methods in interfaces. + */ +public class InterfaceOnlyDefaultMethodsTest extends ValidationTestBase { + + public InterfaceOnlyDefaultMethodsTest() { + super(InterfaceOnlyDefaultMethodsTarget.class); + } + + @Test + public void testCoverageResult() { + assertLine("m1", ICounter.FULLY_COVERED); + assertLine("m2", ICounter.NOT_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTest.java new file mode 100644 index 00000000..1d97a3dc --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTest.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java8; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java8.targets.LambdaExpressionsTarget; +import org.junit.Test; + +/** + * Tests for different lambda expressions. + */ +public class LambdaExpressionsTest extends ValidationTestBase { + + public LambdaExpressionsTest() { + super(LambdaExpressionsTarget.class); + } + + @Test + public void testCoverageResult() { + + // Coverage of lambda bodies + assertLine("executedlambdabody", ICounter.FULLY_COVERED); + assertLine("notexecutedlambdabody", ICounter.NOT_COVERED); + + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaInInterfaceTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaInInterfaceTest.java new file mode 100644 index 00000000..4d4d184f --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaInInterfaceTest.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java8; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java8.targets.LambdaInInterfaceTarget; +import org.junit.Test; + +/** + * Tests a constant with a lambda value in an interface. + */ +public class LambdaInInterfaceTest extends ValidationTestBase { + + public LambdaInInterfaceTest() { + super(LambdaInInterfaceTarget.class); + } + + @Override + protected void run(final Class targetClass) throws Exception { + ((Runnable) targetClass.getField("RUN").get(null)).run(); + } + + @Test + public void testCoverageResult() { + + // Coverage of lambda body + assertLine("lambdabody", ICounter.FULLY_COVERED); + + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/AnnotationOnLocalVariableTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/AnnotationOnLocalVariableTarget.java new file mode 100644 index 00000000..b2d6acbf --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/AnnotationOnLocalVariableTarget.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java8.targets; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This test target contains annotation on local variable. + */ +public class AnnotationOnLocalVariableTarget { + + @Documented + @Retention(RetentionPolicy.CLASS) + @Target(ElementType.TYPE_USE) + @interface NonNull { + } + + private static Object legacy() { + return new Object(); + } + + public static void main(String[] args) { + @NonNull + Object o = legacy(); // $line-var$ + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/BadCycleInterfaceTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/BadCycleInterfaceTarget.java new file mode 100644 index 00000000..bac69f81 --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/BadCycleInterfaceTarget.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java8.targets; + +import org.jacoco.core.test.validation.targets.Stubs; + +public class BadCycleInterfaceTarget { + + public interface Base { + static final Object BASE_CONST = new Child() { + { + Stubs.logEvent("baseclinit"); // $line-baseclinit$ + } + }.childDefaultMethod(); + + default void baseDefaultMethod() { + } + } + + public interface Child extends Base { + static final Object CHILD_CONST = new Object() { + { + Stubs.logEvent("childclinit"); // $line-childclinit$ + } + }; + + default Object childDefaultMethod() { + Stubs.logEvent("childdefaultmethod"); // $line-childdefault$ + return null; + } + + static void childStaticMethod() { + Stubs.logEvent("childstaticmethod"); // $line-childstatic$ + } + } + + public static void main(String[] args) { + Child.childStaticMethod(); + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceDefaultMethodsTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceDefaultMethodsTarget.java new file mode 100644 index 00000000..2c8a13db --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceDefaultMethodsTarget.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java8.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.i1; + +/** + * This test target is an interface with a class initializer and default methods. + */ +public interface InterfaceDefaultMethodsTarget { + + public static final int CONST = i1(); // $line-clinit$ + + default void m1() { + return; // $line-m1$ + } + + default void m2() { + return; // $line-m2$ + } + + public class Impl implements InterfaceDefaultMethodsTarget { + + public Impl() { + m1(); + } + } + + public static void main(String[] args) { + new Impl(); + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceOnlyDefaultMethodsTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceOnlyDefaultMethodsTarget.java new file mode 100644 index 00000000..dd96e0ad --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceOnlyDefaultMethodsTarget.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java8.targets; + +/** + * This test target is an interface with only default methods. + */ +public interface InterfaceOnlyDefaultMethodsTarget { + + // no , only default methods: + + default void m1() { + return; // $line-m1$ + } + + default void m2() { + return; // $line-m2$ + } + + public class Impl implements InterfaceOnlyDefaultMethodsTarget { + + public Impl() { + m1(); + } + } + + public static void main(String[] args) { + new Impl(); + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaExpressionsTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaExpressionsTarget.java new file mode 100644 index 00000000..a8c7bd8b --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaExpressionsTarget.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java8.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.exec; +import static org.jacoco.core.test.validation.targets.Stubs.noexec; +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target contains different lambda expressions. + */ +public class LambdaExpressionsTarget { + + public static void main(String[] args) { + + exec(() -> { + nop(); // $line-executedlambdabody$ + }); + + noexec(() -> { + nop(); // $line-notexecutedlambdabody$ + }); + + } + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaInInterfaceTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaInInterfaceTarget.java new file mode 100644 index 00000000..4a9db74b --- /dev/null +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaInInterfaceTarget.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation.java8.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target builds a constant with a lambda value in an interface. + */ +public interface LambdaInInterfaceTarget { + + public static final Runnable RUN = () -> { + nop(); // $line-lambdabody$ + }; + +} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java deleted file mode 100644 index 3417c098..00000000 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/AnnotationOnLocalVariableTarget.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation.targets; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This test target contains annotation on local variable. - */ -public class AnnotationOnLocalVariableTarget { - - @Documented - @Retention(RetentionPolicy.CLASS) - @Target(ElementType.TYPE_USE) - @interface NonNull { - } - - private static Object legacy() { - return new Object(); - } - - public static void main(String[] args) { - @NonNull - Object o = legacy(); // $line-var$ - } - -} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/BadCycleInterface.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/BadCycleInterface.java deleted file mode 100644 index d7e7a746..00000000 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/BadCycleInterface.java +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation.targets; - -public class BadCycleInterface { - - public interface Base { - static final Object BASE_CONST = new Child() { - { - Stubs.logEvent("baseclinit"); // $line-baseclinit$ - } - }.childDefaultMethod(); - - default void baseDefaultMethod() { - } - } - - public interface Child extends Base { - static final Object CHILD_CONST = new Object() { - { - Stubs.logEvent("childclinit"); // $line-childclinit$ - } - }; - - default Object childDefaultMethod() { - Stubs.logEvent("childdefaultmethod"); // $line-childdefault$ - return null; - } - - static void childStaticMethod() { - Stubs.logEvent("childstaticmethod"); // $line-childstatic$ - } - } - - public static void main(String[] args) { - Child.childStaticMethod(); - } - -} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java deleted file mode 100644 index 2e952995..00000000 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.i1; - -/** - * This test target is an interface with a class initializer and default methods. - */ -public interface InterfaceDefaultMethodsTarget { - - public static final int CONST = i1(); // $line-clinit$ - - default void m1() { - return; // $line-m1$ - } - - default void m2() { - return; // $line-m2$ - } - - public class Impl implements InterfaceDefaultMethodsTarget { - - public Impl() { - m1(); - } - } - - public static void main(String[] args) { - new Impl(); - } - -} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java deleted file mode 100644 index 5fa48fb8..00000000 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.test.validation.targets; - -/** - * This test target is an interface with only default methods. - */ -public interface InterfaceOnlyDefaultMethodsTarget { - - // no , only default methods: - - default void m1() { - return; // $line-m1$ - } - - default void m2() { - return; // $line-m2$ - } - - public class Impl implements InterfaceOnlyDefaultMethodsTarget { - - public Impl() { - m1(); - } - } - - public static void main(String[] args) { - new Impl(); - } - -} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaExpressionsTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaExpressionsTarget.java deleted file mode 100644 index bcb65b60..00000000 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaExpressionsTarget.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.exec; -import static org.jacoco.core.test.validation.targets.Stubs.noexec; -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target contains different lambda expressions. - */ -public class LambdaExpressionsTarget { - - public static void main(String[] args) { - - exec(() -> { - nop(); // $line-executedlambdabody$ - }); - - noexec(() -> { - nop(); // $line-notexecutedlambdabody$ - }); - - } - -} diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaInInterfaceTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaInInterfaceTarget.java deleted file mode 100644 index 23edc6dd..00000000 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/targets/LambdaInInterfaceTarget.java +++ /dev/null @@ -1,25 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.test.validation.targets; - -import static org.jacoco.core.test.validation.targets.Stubs.nop; - -/** - * This test target builds a constant with a lambda value in an interface. - */ -public interface LambdaInInterfaceTarget { - - public static final Runnable RUN = () -> { - nop(); // $line-lambdabody$ - }; - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java new file mode 100644 index 00000000..9df4e30d --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java @@ -0,0 +1,195 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.instr; + +import static org.junit.Assert.assertEquals; +import static org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static org.objectweb.asm.Opcodes.ACC_SUPER; +import static org.objectweb.asm.Opcodes.ALOAD; +import static org.objectweb.asm.Opcodes.F_NEW; +import static org.objectweb.asm.Opcodes.IFEQ; +import static org.objectweb.asm.Opcodes.ILOAD; +import static org.objectweb.asm.Opcodes.INVOKESPECIAL; +import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; +import static org.objectweb.asm.Opcodes.POP; +import static org.objectweb.asm.Opcodes.RETURN; +import static org.objectweb.asm.Opcodes.V1_1; +import static org.objectweb.asm.Opcodes.V1_2; +import static org.objectweb.asm.Opcodes.V1_3; +import static org.objectweb.asm.Opcodes.V1_4; +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 static org.objectweb.asm.Opcodes.V1_8; +import static org.objectweb.asm.Opcodes.V9; + +import java.io.IOException; + +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.BytecodeVersion; +import org.jacoco.core.internal.instr.InstrSupport; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.SystemPropertiesRuntime; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Test class inserted stackmap frames for different class file versions. + */ +public class ClassFileVersionsTest { + + @Test + public void test_1_1() throws IOException { + testVersion(V1_1, false); + } + + @Test + public void test_1_2() throws IOException { + testVersion(V1_2, false); + } + + @Test + public void test_1_3() throws IOException { + testVersion(V1_3, false); + } + + @Test + public void test_1_4() throws IOException { + testVersion(V1_4, false); + } + + @Test + public void test_1_5() throws IOException { + testVersion(V1_5, false); + } + + @Test + public void test_1_6() throws IOException { + testVersion(V1_6, true); + } + + @Test + public void test_1_7() throws IOException { + testVersion(V1_7, true); + } + + @Test + public void test_1_8() throws IOException { + testVersion(V1_8, true); + } + + @Test + public void test_9() throws IOException { + testVersion(V9, true); + } + + @Test + public void test_10() throws IOException { + testVersion(BytecodeVersion.V10, true); + } + + private void testVersion(int version, boolean frames) throws IOException { + final byte[] original = createClass(version, frames); + + IRuntime runtime = new SystemPropertiesRuntime(); + Instrumenter instrumenter = new Instrumenter(runtime); + byte[] instrumented = instrumenter.instrument(original, "TestTarget"); + + assertFrames(instrumented, frames); + } + + private void assertFrames(byte[] source, final boolean expected) { + int version = BytecodeVersion.get(source); + source = BytecodeVersion.downgradeIfNeeded(version, source); + new ClassReader(source) + .accept(new ClassVisitor(InstrSupport.ASM_API_VERSION) { + + @Override + public MethodVisitor visitMethod(int access, String name, + String desc, String signature, + String[] exceptions) { + return new MethodVisitor(InstrSupport.ASM_API_VERSION) { + boolean frames = false; + + @Override + public void visitFrame(int type, int nLocal, + Object[] local, int nStack, + Object[] stack) { + frames = true; + } + + @Override + public void visitEnd() { + assertEquals(Boolean.valueOf(expected), + Boolean.valueOf(frames)); + } + }; + } + }, 0); + } + + /** + * Creates a class that requires a frame before the return statement. Also + * for this class instrumentation should insert another frame. + * + *
    +	 * public class Sample {
    +	 *   public Sample(boolean b){
    +	 *     if(b){
    +	 *       toString();
    +	 *     }
    +	 *     return;
    +	 *   }
    +	 * }
    +	 * 
    + */ + private byte[] createClass(int version, boolean frames) { + + ClassWriter cw = new ClassWriter(0); + MethodVisitor mv; + + cw.visit(version, ACC_PUBLIC + ACC_SUPER, "org/jacoco/test/Sample", + null, "java/lang/Object", null); + + mv = cw.visitMethod(ACC_PUBLIC, "", "(Z)V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", + false); + mv.visitVarInsn(ILOAD, 1); + Label l1 = new Label(); + mv.visitJumpInsn(IFEQ, l1); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", + "()Ljava/lang/String;", false); + mv.visitInsn(POP); + mv.visitLabel(l1); + if (frames) { + mv.visitFrame(F_NEW, 2, + new Object[] { "org/jacoco/test/Sample", Opcodes.INTEGER }, + 0, new Object[] {}); + } + mv.visitInsn(RETURN); + mv.visitMaxs(1, 2); + mv.visitEnd(); + + cw.visitEnd(); + + return cw.toByteArray(); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/instr/ResizeInstructionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/instr/ResizeInstructionsTest.java new file mode 100644 index 00000000..fb639ca3 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/instr/ResizeInstructionsTest.java @@ -0,0 +1,174 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.instr; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.internal.BytecodeVersion; +import org.jacoco.core.internal.instr.InstrSupport; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.RuntimeData; +import org.jacoco.core.runtime.SystemPropertiesRuntime; +import org.jacoco.core.test.TargetLoader; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class ResizeInstructionsTest { + + private IRuntime runtime; + private Instrumenter instrumenter; + + private boolean computedCommonSuperClass; + + @Before + public void setup() throws Exception { + runtime = new SystemPropertiesRuntime(); + instrumenter = new Instrumenter(runtime); + runtime.startup(new RuntimeData()); + computedCommonSuperClass = false; + } + + @After + public void teardown() { + runtime.shutdown(); + } + + private class Inner { + } + + /** + * Test of ASM bug + * #317792. + */ + @Test + public void should_not_loose_InnerClasses_attribute() throws Exception { + byte[] source = TargetLoader.getClassDataAsBytes(Inner.class); + final int version = BytecodeVersion.get(source); + source = BytecodeVersion.downgradeIfNeeded(version, source); + + final ClassReader cr = new ClassReader(source); + final ClassWriter cw = new ClassWriter(0); + cr.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, cw) { + @Override + public void visitEnd() { + final MethodVisitor mv = cv.visitMethod(0, "m", "()V", null, + null); + mv.visitCode(); + addCauseOfResizeInstructions(mv); + mv.visitInsn(Opcodes.NOP); + mv.visitMaxs(2, 1); + mv.visitEnd(); + super.visitEnd(); + } + }, 0); + source = cw.toByteArray(); + BytecodeVersion.set(source, version); + + final byte[] bytes = instrumenter.instrument(source, ""); + + final TargetLoader targetLoader = new TargetLoader(); + final Class outer = targetLoader.add(ResizeInstructionsTest.class, + TargetLoader.getClassDataAsBytes(ResizeInstructionsTest.class)); + final Class inner = targetLoader.add(Inner.class, bytes); + assertSame(outer, inner.getEnclosingClass()); + assertNotNull(inner.getEnclosingClass()); + assertSame(outer, inner.getDeclaringClass()); + assertNotNull(inner.getDeclaringClass()); + } + + /** + * Test of ASM bug + * #317630 that + * caused {@code java.lang.ClassNotFoundException}. + */ + @Test + public void should_not_require_computation_of_common_superclass() + throws Exception { + final String className = "Example"; + + final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES) { + @Override + protected String getCommonSuperClass(final String type1, + final String type2) { + computedCommonSuperClass |= className.equals(type1) + || className.equals(type2); + return "java/lang/Object"; + } + }; + cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, className, null, + "java/lang/Object", null); + final MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "m", "()V", + null, null); + mv.visitCode(); + addCauseOfResizeInstructions(mv); + addCauseOfGetCommonSuperClass(mv); + mv.visitMaxs(1, 1); + mv.visitEnd(); + cw.visitEnd(); + final byte[] original = cw.toByteArray(); + assertTrue(computedCommonSuperClass); + new TargetLoader().add(className, original); + + final byte[] instrumented = instrumenter.instrument(original, + className); + new TargetLoader().add(className, instrumented); + } + + /** + * Adds code that requires + * {@link ClassWriter#getCommonSuperClass(String, String)}. + * + *
    +	 * Object o = this;
    +	 * while (true) {
    +	 * 	o = (Integer) null;
    +	 * }
    +	 * 
    + */ + private static void addCauseOfGetCommonSuperClass(final MethodVisitor mv) { + mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitVarInsn(Opcodes.ASTORE, 1); + Label label = new Label(); + mv.visitLabel(label); + mv.visitInsn(Opcodes.ACONST_NULL); + mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Integer"); + mv.visitVarInsn(Opcodes.ASTORE, 1); + mv.visitJumpInsn(Opcodes.GOTO, label); + } + + /** + * Adds code that triggers usage of + * {@link org.objectweb.asm.MethodWriter#COMPUTE_INSERTED_FRAMES} during + * instrumentation. + */ + private static void addCauseOfResizeInstructions(final MethodVisitor mv) { + mv.visitInsn(Opcodes.ICONST_0); + mv.visitInsn(Opcodes.ICONST_1); + final Label target = new Label(); + mv.visitJumpInsn(Opcodes.IFLE, target); + for (int i = 0; i < Short.MAX_VALUE; i++) { + mv.visitInsn(Opcodes.NOP); + } + mv.visitLabel(target); + } + +} -- cgit v1.2.3 From bbcb18a5cd1f06c3e636847581623b9bd5e2c928 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Thu, 2 Aug 2018 22:39:58 +0200 Subject: Build with JDK 11 EA in Travis (#717) --- .travis.sh | 5 +++++ .travis.yml | 6 +----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.sh b/.travis.sh index ffeff4ce..76652d37 100755 --- a/.travis.sh +++ b/.travis.sh @@ -60,6 +60,9 @@ case "$JDK" in 10) install_jdk $JDK10_URL ;; +11-ea) + install_jdk $JDK11_EA_URL + ;; esac # Do not use "~/.mavenrc" set by Travis (https://github.com/travis-ci/travis-ci/issues/3893), @@ -86,6 +89,8 @@ case "$JDK" in mvn -V -B -e verify -Djdk.version=${JDK} -Dbytecode.version=${JDK} -Decj=${ECJ:-} --toolchains=./.travis/travis-toolchains.xml ;; 10) + ;& +11-ea) mvn -V -B -e verify -Dbytecode.version=10 ;; *) diff --git a/.travis.yml b/.travis.yml index 772382ec..17782084 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,12 +23,8 @@ env: - JDK=8 - JDK=8 ECJ=true - - JDK=8-ea - JDK=9 - JDK=10 - -matrix: - allow_failures: - - env: JDK=8-ea + - JDK=11-ea script: ./.travis.sh -- cgit v1.2.3 From 811cf32772ce5d36947235d11d3b5af6ee3f1d8b Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sun, 5 Aug 2018 22:48:02 +0200 Subject: Add module for Kotlin validation tests (#720) --- org.jacoco.build/pom.xml | 2 + org.jacoco.core.test.validation.kotlin/.classpath | 20 +++++++ org.jacoco.core.test.validation.kotlin/.project | 30 +++++++++++ org.jacoco.core.test.validation.kotlin/pom.xml | 62 ++++++++++++++++++++++ .../kotlin/KotlinTopLevelFunctionTest.java | 33 ++++++++++++ .../kotlin/targets/KotlinTopLevelFunctionTarget.kt | 18 +++++++ org.jacoco.core.test.validation/pom.xml | 18 +++++++ org.jacoco.doc/docroot/doc/build.html | 5 ++ 8 files changed, 188 insertions(+) create mode 100644 org.jacoco.core.test.validation.kotlin/.classpath create mode 100644 org.jacoco.core.test.validation.kotlin/.project create mode 100644 org.jacoco.core.test.validation.kotlin/pom.xml create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinTopLevelFunctionTest.java create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinTopLevelFunctionTarget.kt diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index 8f8156e7..092eb85d 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -265,6 +265,7 @@ false **/*.java + **/*.kt **/*.properties @@ -554,6 +555,7 @@ + diff --git a/org.jacoco.core.test.validation.kotlin/.classpath b/org.jacoco.core.test.validation.kotlin/.classpath new file mode 100644 index 00000000..80ba0e5a --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/.classpath @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/org.jacoco.core.test.validation.kotlin/.project b/org.jacoco.core.test.validation.kotlin/.project new file mode 100644 index 00000000..1454c19b --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/.project @@ -0,0 +1,30 @@ + + + org.jacoco.core.test.validation.kotlin + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + org.eclipse.jdt.core.javanature + + + + .settings + 2 + PARENT-1-PROJECT_LOC/org.jacoco.core.test/.settings + + + diff --git a/org.jacoco.core.test.validation.kotlin/pom.xml b/org.jacoco.core.test.validation.kotlin/pom.xml new file mode 100644 index 00000000..d9e76806 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/pom.xml @@ -0,0 +1,62 @@ + + + + 4.0.0 + + + org.jacoco + org.jacoco.core.test.validation + 0.8.2-SNAPSHOT + ../org.jacoco.core.test.validation + + + org.jacoco.core.test.validation.kotlin + + JaCoCo :: Test :: Core :: Validation Kotlin + + + 6 + 1.2.60 + + + + + ${project.groupId} + org.jacoco.core.test + ${project.version} + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + process-sources + + compile + + + + + + + diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinTopLevelFunctionTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinTopLevelFunctionTest.java new file mode 100644 index 00000000..a647be4a --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinTopLevelFunctionTest.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.kotlin.targets.KotlinTopLevelFunctionTargetKt; +import org.junit.Test; + +/** + * Test of top level function. + */ +public class KotlinTopLevelFunctionTest extends ValidationTestBase { + + public KotlinTopLevelFunctionTest() { + super(KotlinTopLevelFunctionTargetKt.class); + } + + @Test + public void test() { + assertLine("fun", ICounter.FULLY_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinTopLevelFunctionTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinTopLevelFunctionTarget.kt new file mode 100644 index 00000000..424e58c0 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinTopLevelFunctionTarget.kt @@ -0,0 +1,18 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin.targets + +/** + * This test target is top level function. + */ +fun main(args: Array) { +} // $line-fun$ diff --git a/org.jacoco.core.test.validation/pom.xml b/org.jacoco.core.test.validation/pom.xml index 691de9ac..ae677de8 100644 --- a/org.jacoco.core.test.validation/pom.xml +++ b/org.jacoco.core.test.validation/pom.xml @@ -62,6 +62,9 @@ 6 + + ../org.jacoco.core.test.validation.kotlin + @@ -72,6 +75,9 @@ 6 + + ../org.jacoco.core.test.validation.kotlin + @@ -83,6 +89,7 @@ + ../org.jacoco.core.test.validation.kotlin ../org.jacoco.core.test.validation.java7 @@ -96,6 +103,7 @@ + ../org.jacoco.core.test.validation.kotlin ../org.jacoco.core.test.validation.java7 @@ -109,7 +117,11 @@ 8 + + 1.8 + + ../org.jacoco.core.test.validation.kotlin ../org.jacoco.core.test.validation.java7 ../org.jacoco.core.test.validation.java8 @@ -124,11 +136,13 @@ + 1.8 10 10 + ../org.jacoco.core.test.validation.kotlin ../org.jacoco.core.test.validation.java7 ../org.jacoco.core.test.validation.java8 @@ -143,11 +157,13 @@ + 1.8 11 11 + ../org.jacoco.core.test.validation.kotlin ../org.jacoco.core.test.validation.java7 ../org.jacoco.core.test.validation.java8 @@ -162,11 +178,13 @@ + 1.8 12 12 + ../org.jacoco.core.test.validation.kotlin ../org.jacoco.core.test.validation.java7 ../org.jacoco.core.test.validation.java8 diff --git a/org.jacoco.doc/docroot/doc/build.html b/org.jacoco.doc/docroot/doc/build.html index 987fcc69..c3e2abab 100644 --- a/org.jacoco.doc/docroot/doc/build.html +++ b/org.jacoco.doc/docroot/doc/build.html @@ -104,6 +104,11 @@ + + org.jacoco.core.test.validation.kotlin + excluded from build + compiled into bytecode version 50 (Java 6) + org.jacoco.core.test.validation.java7 excluded from build -- cgit v1.2.3 From 250e176ecb295a2f36c2debbe72b7136823de296 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 6 Aug 2018 09:00:52 +0200 Subject: Add experimental support for Java 11 class files (#719) --- .travis.sh | 5 +++-- .../src/org/jacoco/core/instr/ClassFileVersionsTest.java | 7 ++++++- .../src/org/jacoco/core/internal/ContentTypeDetectorTest.java | 7 +++++++ .../src/org/jacoco/core/internal/instr/InstrSupportTest.java | 1 + .../src/org/jacoco/core/internal/ContentTypeDetector.java | 1 + .../src/org/jacoco/core/internal/instr/InstrSupport.java | 2 +- org.jacoco.doc/docroot/doc/changes.html | 2 ++ 7 files changed, 21 insertions(+), 4 deletions(-) diff --git a/.travis.sh b/.travis.sh index 76652d37..62fd54e5 100755 --- a/.travis.sh +++ b/.travis.sh @@ -89,10 +89,11 @@ case "$JDK" in mvn -V -B -e verify -Djdk.version=${JDK} -Dbytecode.version=${JDK} -Decj=${ECJ:-} --toolchains=./.travis/travis-toolchains.xml ;; 10) - ;& -11-ea) mvn -V -B -e verify -Dbytecode.version=10 ;; +11-ea) + mvn -V -B -e verify -Dbytecode.version=11 + ;; *) echo "Incorrect JDK [$JDK]" exit 1; diff --git a/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java index 9df4e30d..1c9afee0 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java @@ -22,6 +22,7 @@ import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; import static org.objectweb.asm.Opcodes.POP; import static org.objectweb.asm.Opcodes.RETURN; +import static org.objectweb.asm.Opcodes.V11; import static org.objectweb.asm.Opcodes.V1_1; import static org.objectweb.asm.Opcodes.V1_2; import static org.objectweb.asm.Opcodes.V1_3; @@ -34,7 +35,6 @@ import static org.objectweb.asm.Opcodes.V9; import java.io.IOException; -import org.jacoco.core.instr.Instrumenter; import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.instr.InstrSupport; import org.jacoco.core.runtime.IRuntime; @@ -102,6 +102,11 @@ public class ClassFileVersionsTest { testVersion(BytecodeVersion.V10, true); } + @Test + public void test_11() throws IOException { + testVersion(V11, true); + } + private void testVersion(int version, boolean frames) throws IOException { final byte[] original = createClass(version, frames); 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 f3dde668..4d95dd47 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 @@ -121,6 +121,13 @@ public class ContentTypeDetectorTest { assertContent(); } + @Test + public void should_detect_java_11() throws IOException { + initData(0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x37); + assertEquals(ContentTypeDetector.CLASSFILE, detector.getType()); + assertContent(); + } + @Test public void testMachObjectFile() throws IOException { initData(0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x02); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java index b8a89cbc..95bd0437 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java @@ -58,6 +58,7 @@ public class InstrSupportTest { assertTrue(InstrSupport.needsFrames(Opcodes.V1_8)); assertTrue(InstrSupport.needsFrames(Opcodes.V9)); assertTrue(InstrSupport.needsFrames(BytecodeVersion.V10)); + assertTrue(InstrSupport.needsFrames(Opcodes.V11)); } @Test diff --git a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java index b30f6366..0df14607 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java @@ -84,6 +84,7 @@ public class ContentTypeDetector { case Opcodes.V1_8: case Opcodes.V9: case BytecodeVersion.V10: + case Opcodes.V11: return CLASSFILE; } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java index ed52bd37..1d4cf2a3 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java @@ -25,7 +25,7 @@ public final class InstrSupport { } /** ASM API version */ - public static final int ASM_API_VERSION = Opcodes.ASM6; + public static final int ASM_API_VERSION = Opcodes.ASM7_EXPERIMENTAL; // === Data Field === diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index eb19df86..70656793 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -22,6 +22,8 @@

    New Features

      +
    • Experimental support for Java 11 class files + (GitHub #719).
    • Branches and instructions generated by javac 11 for try-with-resources statement are filtered out (GitHub #669).
    • -- cgit v1.2.3 From 3f5baf93594b46bd7a3d70984578ed36f776c1c2 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 6 Aug 2018 22:08:20 +0200 Subject: Fix links in Javadocs of tests This was forgotten in aca2da1d7479d6b536e027e8fa7db74428d781e6. --- .../src/org/jacoco/core/test/validation/java7/StringSwitchTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java index 778097e0..ddf0c061 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java @@ -27,7 +27,7 @@ public class StringSwitchTest extends ValidationTestBase { } /** - * {@link StringSwitchTarget#covered(String)} + * {@link StringSwitchTarget#covered(Object)} */ @Test public void covered() { @@ -43,7 +43,7 @@ public class StringSwitchTest extends ValidationTestBase { } /** - * {@link StringSwitchTarget#notCovered(String)} + * {@link StringSwitchTarget#notCovered(Object)} */ @Test public void notCovered() { -- cgit v1.2.3 From bbee0397a1ff4e39bab42c731531d02cc404fc2b Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 6 Aug 2018 23:03:51 +0200 Subject: Fix links in Javadocs of tests This was forgotten in b2c5ff73d24cc0c57f308f046de008568068b4c8. --- .../test/validation/java5/targets/SyntheticTarget.java | 2 +- .../core/test/validation/java7/TryWithResourcesTest.java | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SyntheticTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SyntheticTarget.java index c5cc3fee..79f41b10 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SyntheticTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SyntheticTarget.java @@ -19,7 +19,7 @@ public class SyntheticTarget { // $line-classdef$ private static int counter; // $line-field$ /** - * {@link org.jacoco.core.test.validation.java5.targets.ImplicitDefaultConstructorTarget + * {@link org.jacoco.core.test.validation.java5.targets.ConstructorsTarget * Default constructor will refer to a line of class definition}, so that we * define constructor explicitly in order to verify that we filter all other * constructions here that might refer to line of class definition. diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java index 0056a34a..5d0360ce 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java @@ -27,7 +27,7 @@ public class TryWithResourcesTest extends ValidationTestBase { } /** - * {@link TryWithResourcesFilterTarget#test()} + * {@link TryWithResourcesTarget#test()} */ @Test public void test() { @@ -49,7 +49,7 @@ public class TryWithResourcesTest extends ValidationTestBase { } /** - * {@link TryWithResourcesFilterTarget#test2()} + * {@link TryWithResourcesTarget#test2()} */ @Test public void test2() { @@ -72,7 +72,7 @@ public class TryWithResourcesTest extends ValidationTestBase { } /** - * {@link TryWithResourcesFilterTarget#returnInBody()} + * {@link TryWithResourcesTarget#returnInBody()} */ @Test public void returnInBody() { @@ -101,7 +101,7 @@ public class TryWithResourcesTest extends ValidationTestBase { } /** - * {@link TryWithResourcesFilterTarget#nested()} + * {@link TryWithResourcesTarget#nested()} */ @Test public void nested() { @@ -142,7 +142,7 @@ public class TryWithResourcesTest extends ValidationTestBase { } /** - * {@link TryWithResourcesFilterTarget#returnInCatch()} + * {@link TryWithResourcesTarget#returnInCatch()} */ @Test public void returnInCatch() { @@ -166,7 +166,7 @@ public class TryWithResourcesTest extends ValidationTestBase { */ /** - * {@link TryWithResourcesFilterTarget#handwritten()} + * {@link TryWithResourcesTarget#handwritten()} */ @Test public void handwritten() { @@ -176,7 +176,7 @@ public class TryWithResourcesTest extends ValidationTestBase { } /** - * {@link TryWithResourcesFilterTarget#empty()} + * {@link TryWithResourcesTarget#empty()} */ @Test public void empty() { @@ -198,7 +198,7 @@ public class TryWithResourcesTest extends ValidationTestBase { } /** - * {@link TryWithResourcesFilterTarget#throwInBody()} + * {@link TryWithResourcesTarget#throwInBody()} */ @Test public void throwInBody() { -- cgit v1.2.3 From a364dcc69503baa790e84691e4b34fc76a2e47a2 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Tue, 7 Aug 2018 09:09:54 +0200 Subject: `assertLine(String, int)` should imply zero number of branches (#722) --- .../validation/java5/EnumImplicitMethodsTest.java | 2 +- .../core/test/validation/java5/FinallyTest.java | 2 +- .../test/validation/java7/StringSwitchTest.java | 10 ++++---- .../validation/java7/TryWithResourcesTest.java | 30 ++++++++++++---------- .../core/test/validation/ValidationTestBase.java | 26 +++++++++++-------- 5 files changed, 40 insertions(+), 30 deletions(-) diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java index 0f6a8660..ced66609 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java @@ -33,7 +33,7 @@ public class EnumImplicitMethodsTest extends ValidationTestBase { assertLine("customValueOfMethod", ICounter.NOT_COVERED); assertLine("customValuesMethod", ICounter.NOT_COVERED); - assertLine("const", ICounter.PARTLY_COVERED); + assertLine("const", ICounter.PARTLY_COVERED, 1, 1); assertLine("staticblock", ICounter.FULLY_COVERED); assertLine("super", ICounter.FULLY_COVERED); assertLine("constructor", ICounter.FULLY_COVERED); diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java index 8531a501..69cf4295 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java @@ -117,7 +117,7 @@ public class FinallyTest extends ValidationTestBase { } assertLine("twoRegions.2", ICounter.EMPTY); - assertLine("twoRegions.if", ICounter.FULLY_COVERED); + assertLine("twoRegions.if", ICounter.FULLY_COVERED, 1, 1); assertLine("twoRegions.region.1", ICounter.FULLY_COVERED); assertLine("twoRegions.region.2", ICounter.NOT_COVERED); } diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java index ddf0c061..04fe6f5d 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java @@ -36,10 +36,10 @@ public class StringSwitchTest extends ValidationTestBase { } else { assertLine("covered.switch", ICounter.PARTLY_COVERED, 2, 7); } - assertLine("covered.case1", ICounter.FULLY_COVERED, 0, 0); - assertLine("covered.case2", ICounter.FULLY_COVERED, 0, 0); - assertLine("covered.case3", ICounter.FULLY_COVERED, 0, 0); - assertLine("covered.default", ICounter.FULLY_COVERED, 0, 0); + assertLine("covered.case1", ICounter.FULLY_COVERED); + assertLine("covered.case2", ICounter.FULLY_COVERED); + assertLine("covered.case3", ICounter.FULLY_COVERED); + assertLine("covered.default", ICounter.FULLY_COVERED); } /** @@ -57,7 +57,7 @@ public class StringSwitchTest extends ValidationTestBase { @Test public void handwritten() { assertLine("handwritten.firstSwitch", ICounter.FULLY_COVERED, 2, 1); - assertLine("handwritten.ignored", ICounter.FULLY_COVERED); + assertLine("handwritten.ignored", ICounter.FULLY_COVERED, 1, 1); assertLine("handwritten.secondSwitch", ICounter.FULLY_COVERED, 3, 1); assertLine("handwritten.case1", ICounter.FULLY_COVERED); assertLine("handwritten.case2", ICounter.NOT_COVERED); diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java index 5d0360ce..9eb02571 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java @@ -89,7 +89,7 @@ public class TryWithResourcesTest extends ValidationTestBase { // https://bugs.openjdk.java.net/browse/JDK-8134759 // javac 7 and 8 up to 8u92 are affected if (JAVA_VERSION.isBefore("1.8.0_92")) { - assertLine("returnInBody.close", ICounter.FULLY_COVERED, 0, 0); + assertLine("returnInBody.close", ICounter.FULLY_COVERED); } else { assertLine("returnInBody.close", ICounter.EMPTY); } @@ -130,10 +130,10 @@ public class TryWithResourcesTest extends ValidationTestBase { } else { assertLine("nested.try3", ICounter.EMPTY); } - assertLine("nested.open3", ICounter.FULLY_COVERED, 0, 0); - assertLine("nested.body3", ICounter.FULLY_COVERED, 0, 0); + assertLine("nested.open3", ICounter.FULLY_COVERED); + assertLine("nested.body3", ICounter.FULLY_COVERED); assertLine("nested.catch3", ICounter.NOT_COVERED); - assertLine("nested.finally3", ICounter.FULLY_COVERED, 0, 0); + assertLine("nested.finally3", ICounter.FULLY_COVERED); // without filter next lines have branches: assertLine("nested.close3", ICounter.EMPTY); @@ -186,14 +186,14 @@ public class TryWithResourcesTest extends ValidationTestBase { assertLine("empty.try", ICounter.EMPTY); } assertLine("empty.open", ICounter.FULLY_COVERED); - // empty when EJC: - if (isJDKCompiler) { - if (JAVA_VERSION.isBefore("9")) { - // branches with javac 7 and 8 - assertLine("empty.close", ICounter.PARTLY_COVERED); - } else { - assertLine("empty.close", ICounter.FULLY_COVERED, 0, 0); - } + if (!isJDKCompiler) { + assertLine("empty.close", ICounter.PARTLY_COVERED, 7, 1); + } else if (JAVA_VERSION.isBefore("8")) { + assertLine("empty.close", ICounter.PARTLY_COVERED, 6, 2); + } else if (JAVA_VERSION.isBefore("9")) { + assertLine("empty.close", ICounter.PARTLY_COVERED, 2, 2); + } else { + assertLine("empty.close", ICounter.FULLY_COVERED); } } @@ -204,7 +204,11 @@ public class TryWithResourcesTest extends ValidationTestBase { public void throwInBody() { // not filtered assertLine("throwInBody.try", ICounter.NOT_COVERED); - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { + if (!isJDKCompiler){ + assertLine("throwInBody.close", ICounter.NOT_COVERED, 6, 0); + } else if (JAVA_VERSION.isBefore("9")) { + assertLine("throwInBody.close", ICounter.NOT_COVERED, 4, 0); + } else if (JAVA_VERSION.isBefore("11")) { assertLine("throwInBody.close", ICounter.NOT_COVERED); } else { assertLine("throwInBody.close", ICounter.EMPTY); diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java index 1efff1bf..bd92cecc 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java @@ -131,22 +131,28 @@ public abstract class ValidationTestBase { } protected void assertLine(final String tag, final int status) { - final int nr = source.getLineNumber(tag); - final ILine line = sourceCoverage.getLine(nr); - final String msg = String.format("Status in line %s: %s", - Integer.valueOf(nr), source.getLine(nr)); - final int insnStatus = line.getInstructionCounter().getStatus(); - assertEquals(msg, STATUS_NAME[status], STATUS_NAME[insnStatus]); + privateAssertLine(tag, status, 0, 0); } protected void assertLine(final String tag, final int status, final int missedBranches, final int coveredBranches) { - assertLine(tag, status); + if (missedBranches == 0 && coveredBranches == 0) { + throw new IllegalArgumentException( + "Omit redundant specification of zero number of branches"); + } + privateAssertLine(tag, status, missedBranches, coveredBranches); + } + + private void privateAssertLine(final String tag, final int status, + final int missedBranches, final int coveredBranches) { final int nr = source.getLineNumber(tag); final ILine line = sourceCoverage.getLine(nr); - final String msg = String.format("Branches in line %s: %s", - Integer.valueOf(nr), source.getLine(nr)); - assertEquals(msg + " branches", + final String lineMsg = String.format("line %s: %s", Integer.valueOf(nr), + source.getLine(nr)); + final int insnStatus = line.getInstructionCounter().getStatus(); + assertEquals("Instructions in " + lineMsg, STATUS_NAME[status], + STATUS_NAME[insnStatus]); + assertEquals("Branches in " + lineMsg, CounterImpl.getInstance(missedBranches, coveredBranches), line.getBranchCounter()); } -- cgit v1.2.3 From 82087743dfec23b585e31b8c8c1f9adff5b8288f Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Tue, 7 Aug 2018 12:23:47 +0200 Subject: Add filter for Kotlin when-expressions that list all cases of sealed class (#721) --- .../kotlin/KotlinWhenExpressionTest.java | 88 ++++++++++++++++ .../kotlin/targets/KotlinWhenExpressionTarget.kt | 79 +++++++++++++++ .../filter/KotlinWhenSealedFilterTest.java | 111 +++++++++++++++++++++ .../internal/analysis/filter/AbstractMatcher.java | 17 ++++ .../core/internal/analysis/filter/Filters.java | 3 +- .../analysis/filter/KotlinWhenSealedFilter.java | 62 ++++++++++++ org.jacoco.doc/docroot/doc/changes.html | 4 + 7 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinWhenExpressionTest.java create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilterTest.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilter.java diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinWhenExpressionTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinWhenExpressionTest.java new file mode 100644 index 00000000..22e920a0 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinWhenExpressionTest.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.kotlin.targets.KotlinWhenExpressionTarget; +import org.junit.Test; + +/** + * Test of when expressions. + */ +public class KotlinWhenExpressionTest extends ValidationTestBase { + + public KotlinWhenExpressionTest() { + super(KotlinWhenExpressionTarget.class); + } + + /** + * {@link KotlinWhenExpressionTarget#whenSealed(KotlinWhenExpressionTarget.Sealed)} + */ + @Test + public void whenSealed() { + assertLine("whenSealed.when", ICounter.FULLY_COVERED); + assertLine("whenSealed.case1", ICounter.FULLY_COVERED, 0, 2); + // without filter next line covered partly and has one uncovered branch: + assertLine("whenSealed.case2", ICounter.FULLY_COVERED); + assertLine("whenSealed.return", ICounter.FULLY_COVERED); + } + + /** + * {@link KotlinWhenExpressionTarget#whenSealedRedundantElse(KotlinWhenExpressionTarget.Sealed)} + */ + @Test + public void whenSealedRedundantElse() { + assertLine("whenSealedRedundantElse.when", ICounter.FULLY_COVERED); + assertLine("whenSealedRedundantElse.case1", ICounter.FULLY_COVERED, 0, 2); + assertLine("whenSealedRedundantElse.case2", ICounter.FULLY_COVERED, 1, 1); + assertLine("whenSealedRedundantElse.else", ICounter.NOT_COVERED); + assertLine("whenSealedRedundantElse.return", ICounter.FULLY_COVERED); + } + + /** + * {@link KotlinWhenExpressionTarget#whenEnum(KotlinWhenExpressionTarget.Enum)} + */ + @Test + public void whenEnum() { + assertLine("whenEnum.when", ICounter.FULLY_COVERED, 1, 2); + assertLine("whenEnum.case1", ICounter.FULLY_COVERED); + assertLine("whenEnum.case2", ICounter.PARTLY_COVERED); + assertLine("whenEnum.return", ICounter.FULLY_COVERED); + } + + /** + * {@link KotlinWhenExpressionTarget#whenEnumRedundantElse(KotlinWhenExpressionTarget.Enum)} + */ + @Test + public void whenEnumRedundantElse() { + assertLine("whenEnumRedundantElse.when", ICounter.FULLY_COVERED, 1, 2); + assertLine("whenEnumRedundantElse.case1", ICounter.FULLY_COVERED); + assertLine("whenEnumRedundantElse.case2", ICounter.FULLY_COVERED); + assertLine("whenEnumRedundantElse.else", ICounter.NOT_COVERED); + assertLine("whenEnumRedundantElse.return", ICounter.FULLY_COVERED); + } + + /** + * {@link KotlinWhenExpressionTarget#whenString(String)} + */ + @Test + public void whenString() { + assertLine("whenString.when", ICounter.FULLY_COVERED, 2, 7); + assertLine("whenString.case1", ICounter.FULLY_COVERED); + assertLine("whenString.case2", ICounter.FULLY_COVERED); + assertLine("whenString.case2", ICounter.FULLY_COVERED); + assertLine("whenString.else", ICounter.FULLY_COVERED); + assertLine("whenString.return", ICounter.FULLY_COVERED); + } + +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt new file mode 100644 index 00000000..73e3dae4 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin.targets + +/** + * This test target is `when` expression. + */ +object KotlinWhenExpressionTarget { + + private sealed class Sealed { + object Sealed1 : Sealed() + object Sealed2 : Sealed() + } + + private fun whenSealed(p: Sealed): Int = when (p) { // $line-whenSealed.when$ + is Sealed.Sealed1 -> 1 // $line-whenSealed.case1$ + is Sealed.Sealed2 -> 2 // $line-whenSealed.case2$ + } // $line-whenSealed.return$ + + @Suppress("REDUNDANT_ELSE_IN_WHEN") + private fun whenSealedRedundantElse(p: Sealed): Int = when (p) { // $line-whenSealedRedundantElse.when$ + is Sealed.Sealed1 -> 1 // $line-whenSealedRedundantElse.case1$ + is Sealed.Sealed2 -> 2 // $line-whenSealedRedundantElse.case2$ + else -> throw NoWhenBranchMatchedException() // $line-whenSealedRedundantElse.else$ + } // $line-whenSealedRedundantElse.return$ + + private enum class Enum { + A, B + } + + private fun whenEnum(p: Enum): Int = when (p) { // $line-whenEnum.when$ + Enum.A -> 1 // $line-whenEnum.case1$ + Enum.B -> 2 // $line-whenEnum.case2$ + } // $line-whenEnum.return$ + + @Suppress("REDUNDANT_ELSE_IN_WHEN") + private fun whenEnumRedundantElse(p: Enum): Int = when (p) { // $line-whenEnumRedundantElse.when$ + Enum.A -> 1 // $line-whenEnumRedundantElse.case1$ + Enum.B -> 2 // $line-whenEnumRedundantElse.case2$ + else -> throw NoWhenBranchMatchedException() // $line-whenEnumRedundantElse.else$ + } // $line-whenEnumRedundantElse.return$ + + private fun whenString(p: String): Int = when (p) { // $line-whenString.when$ + "a" -> 1 // $line-whenString.case1$ + "b" -> 2 // $line-whenString.case2$ + "\u0000a" -> 3 // $line-whenString.case3$ + else -> 4 // $line-whenString.else$ + } // $line-whenString.return$ + + @JvmStatic + fun main(args: Array) { + whenSealed(Sealed.Sealed1) + whenSealed(Sealed.Sealed2) + + whenSealedRedundantElse(Sealed.Sealed1) + whenSealedRedundantElse(Sealed.Sealed2) + + whenEnum(Enum.A) + whenEnum(Enum.B) + + whenEnumRedundantElse(Enum.A) + whenEnumRedundantElse(Enum.B) + + whenString("") + whenString("a") + whenString("b") + whenString("\u0000a") + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilterTest.java new file mode 100644 index 00000000..92b0de33 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilterTest.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class KotlinWhenSealedFilterTest implements IFilterOutput { + + private final KotlinWhenSealedFilter filter = new KotlinWhenSealedFilter(); + + private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "name", "()V", null, null); + + @Test + public void should_filter_implicit_else() { + final Label label = new Label(); + + final Range range1 = new Range(); + + m.visitInsn(Opcodes.NOP); + + m.visitJumpInsn(Opcodes.IFEQ, label); + range1.fromInclusive = m.instructions.getLast(); + range1.toInclusive = m.instructions.getLast(); + + m.visitInsn(Opcodes.NOP); + + final Range range2 = new Range(); + m.visitLabel(label); + range2.fromInclusive = m.instructions.getLast(); + m.visitTypeInsn(Opcodes.NEW, "kotlin/NoWhenBranchMatchedException"); + m.visitInsn(Opcodes.DUP); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, + "kotlin/NoWhenBranchMatchedException", "", "()V", false); + m.visitInsn(Opcodes.ATHROW); + range2.toInclusive = m.instructions.getLast(); + + filter.filter(m, new FilterContextMock(), this); + + assertEquals(2, ignoredRanges.size()); + + assertEquals(range1.fromInclusive, ignoredRanges.get(0).fromInclusive); + assertEquals(range1.toInclusive, ignoredRanges.get(0).toInclusive); + + assertEquals(range2.fromInclusive, ignoredRanges.get(1).fromInclusive); + assertEquals(range2.toInclusive, ignoredRanges.get(1).toInclusive); + } + + @Test + public void should_not_filter_explicit_else() { + final Label label = new Label(); + + m.visitInsn(Opcodes.NOP); + + m.visitJumpInsn(Opcodes.IFEQ, label); + + m.visitInsn(Opcodes.NOP); + + m.visitLabel(label); + m.visitTypeInsn(Opcodes.NEW, "kotlin/NoWhenBranchMatchedException"); + m.visitInsn(Opcodes.DUP); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, + "kotlin/NoWhenBranchMatchedException", "", "()V", false); + m.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Throwable"); + m.visitInsn(Opcodes.ATHROW); + + filter.filter(m, new FilterContextMock(), this); + + assertEquals(0, ignoredRanges.size()); + } + + static class Range { + AbstractInsnNode fromInclusive; + AbstractInsnNode toInclusive; + } + + private final List ignoredRanges = new ArrayList(); + + public void ignore(final AbstractInsnNode fromInclusive, + final AbstractInsnNode toInclusive) { + final Range range = new Range(); + range.fromInclusive = fromInclusive; + range.toInclusive = toInclusive; + this.ignoredRanges.add(range); + } + + public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { + fail(); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java index d4b421ef..9e07153b 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java @@ -18,6 +18,7 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TypeInsnNode; import org.objectweb.asm.tree.VarInsnNode; abstract class AbstractMatcher { @@ -40,6 +41,22 @@ abstract class AbstractMatcher { cursor = null; } + /** + * Moves {@link #cursor} to next instruction if it is NEW with + * given operand, otherwise sets it to null. + */ + final void nextIsNew(final String desc) { + nextIs(Opcodes.NEW); + if (cursor == null) { + return; + } + final TypeInsnNode i = (TypeInsnNode) cursor; + if (desc.equals(i.desc)) { + return; + } + cursor = null; + } + /** * Moves {@link #cursor} to next instruction if it is * INVOKESPECIAL <init> with given owner and descriptor, diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index 68e9b234..2e719221 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -33,7 +33,8 @@ public final class Filters implements IFilter { new FinallyFilter(), new PrivateEmptyNoArgConstructorFilter(), new StringSwitchJavacFilter(), new LombokGeneratedFilter(), new GroovyGeneratedFilter(), new EnumEmptyConstructorFilter(), - new KotlinGeneratedFilter(), new KotlinLateinitFilter()); + new KotlinGeneratedFilter(), new KotlinLateinitFilter(), + new KotlinWhenSealedFilter()); private final IFilter[] filters; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilter.java new file mode 100644 index 00000000..ae0d8455 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilter.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Filters bytecode that Kotlin compiler generates for when + * expressions which list all cases of sealed class, i.e. which + * don't require explicit else. + */ +public final class KotlinWhenSealedFilter implements IFilter { + + private static final String EXCEPTION = "kotlin/NoWhenBranchMatchedException"; + + private final Matcher matcher = new Matcher(); + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + for (AbstractInsnNode i = methodNode.instructions + .getFirst(); i != null; i = i.getNext()) { + matcher.match(i, output); + } + } + + private static class Matcher extends AbstractMatcher { + void match(final AbstractInsnNode start, final IFilterOutput output) { + if (start.getType() != InsnNode.LABEL) { + return; + } + cursor = start; + + nextIsNew(EXCEPTION); + nextIs(Opcodes.DUP); + nextIsInvokeSuper(EXCEPTION, "()V"); + nextIs(Opcodes.ATHROW); + + for (AbstractInsnNode i = cursor; i != null; i = i.getPrevious()) { + if (i.getOpcode() == Opcodes.IFEQ + && ((JumpInsnNode) i).label == start) { + output.ignore(i, i); + output.ignore(start, cursor); + return; + } + } + } + } + +} diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 70656793..f956d531 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -36,6 +36,10 @@ property is filtered out during generation of report. Implementation by Fabian Mastenbroek (GitHub #707). +
    • Bytecode generated by Kotlin compiler for implicit else of + when expressions that list all cases of sealed class + is filtered out during generation of report + (GitHub #721).

    Fixed Bugs

    -- cgit v1.2.3 From 7bc6a0c924af94a3d95d14e4a4c85b10fb6692d5 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Thu, 9 Aug 2018 08:10:58 +0200 Subject: Upgrade ASM to 6.2.1 (#725) --- org.jacoco.build/pom.xml | 2 +- org.jacoco.doc/docroot/doc/changes.html | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index 092eb85d..f23b9b09 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -138,7 +138,7 @@ ${jvm.args} - 6.2 + 6.2.1 1.7.1 2.0.28 4.8.2 diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index f956d531..2a7f1039 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -53,8 +53,9 @@

    Non-functional Changes

      -
    • JaCoCo now depends on ASM 6.2 - (GitHub #706).
    • +
    • JaCoCo now depends on ASM 6.2.1 + (GitHub #706, + #725).
    • Improved error message when already instrumented classes are used for instrumentation or analysis (GitHub #703).
    • -- cgit v1.2.3 From 592533c898da5c11d99c9fa09177d92ad50a0455 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Thu, 9 Aug 2018 10:35:43 +0200 Subject: Add JDK 11 into documentation about build (#726) --- org.jacoco.doc/docroot/doc/build.html | 10 ++++++---- org.jacoco.doc/docroot/doc/environment.html | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/org.jacoco.doc/docroot/doc/build.html b/org.jacoco.doc/docroot/doc/build.html index c3e2abab..dd922580 100644 --- a/org.jacoco.doc/docroot/doc/build.html +++ b/org.jacoco.doc/docroot/doc/build.html @@ -101,28 +101,29 @@ JDK 8 JDK 9 JDK 10 + JDK 11 org.jacoco.core.test.validation.kotlin excluded from build - compiled into bytecode version 50 (Java 6) + compiled into bytecode version 50 (Java 6) org.jacoco.core.test.validation.java7 excluded from build - compiled into bytecode version 51 (Java 7) + compiled into bytecode version 51 (Java 7) org.jacoco.core.test.validation.java8 excluded from build - compiled into bytecode version 52 (Java 8) + compiled into bytecode version 52 (Java 8) all other modules compiled into bytecode version 49 (Java 5) - compiled into bytecode version 50 (Java 6) + compiled into bytecode version 50 (Java 6) @@ -161,6 +162,7 @@
    • mvn clean install -Djdk.version=8 -Dbytecode.version=8 -Decj
    • mvn clean install -Djdk.version=9 -Dbytecode.version=9
    • mvn clean install -Djdk.version=10 -Dbytecode.version=10
    • +
    • mvn clean install -Djdk.version=11 -Dbytecode.version=11
    diff --git a/org.jacoco.doc/docroot/doc/environment.html b/org.jacoco.doc/docroot/doc/environment.html index 2a303d8a..0cca8520 100644 --- a/org.jacoco.doc/docroot/doc/environment.html +++ b/org.jacoco.doc/docroot/doc/environment.html @@ -68,7 +68,7 @@

    The minimum supported JRE version for JaCoCo is Java 5. To guarantee compatibility JaCoCo release builds should always be executed using JDK 5. - In addition we run builds with 6, 7, 8, 9 and 10 JDKs. + In addition we run builds with 6, 7, 8, 9, 10 and 11 JDKs.

    Build

    -- cgit v1.2.3 From 1001adda9a37f262c6162c1fec99487a5a79e7fa Mon Sep 17 00:00:00 2001 From: "Marc R. Hoffmann" Date: Thu, 9 Aug 2018 19:46:04 +0200 Subject: Simplify validation test setup (#718) --- .../java5/AnnotationInitializerTest.java | 12 +- .../test/validation/java5/BadCycleClassTest.java | 7 +- .../validation/java5/BooleanExpressionsTest.java | 54 ----- .../validation/java5/ClassInitializerTest.java | 19 -- .../test/validation/java5/ConstructorsTest.java | 36 --- ...ControlStructureBeforeSuperConstructorTest.java | 12 +- .../validation/java5/ControlStructuresTest.java | 112 ---------- .../test/validation/java5/EnumConstructorTest.java | 37 ---- .../validation/java5/EnumImplicitMethodsTest.java | 24 +- .../core/test/validation/java5/EnumSwitchTest.java | 10 +- .../core/test/validation/java5/ExceptionsTest.java | 148 +++++-------- .../validation/java5/ExplicitInitialFrameTest.java | 9 - .../FieldInitializationInTwoConstructorsTest.java | 16 +- .../core/test/validation/java5/FinallyTest.java | 241 +++++++++------------ .../java5/ImplicitFieldInitializationTest.java | 13 -- .../java5/InterfaceClassInitializerTest.java | 12 - .../test/validation/java5/SynchronizedTest.java | 48 ++-- .../core/test/validation/java5/SyntheticTest.java | 10 +- .../java5/targets/AnnotationInitializerTarget.java | 4 +- .../java5/targets/BadCycleClassTarget.java | 6 +- .../java5/targets/BooleanExpressionsTarget.java | 74 +++---- .../java5/targets/ClassInitializerTarget.java | 22 +- .../java5/targets/ConstructorsTarget.java | 40 +++- ...ntrolStructureBeforeSuperConstructorTarget.java | 2 +- .../java5/targets/ControlStructuresTarget.java | 122 +++++------ .../java5/targets/EnumConstructorTarget.java | 16 +- .../java5/targets/EnumImplicitMethodsTarget.java | 20 +- .../validation/java5/targets/EnumSwitchTarget.java | 2 +- .../validation/java5/targets/ExceptionsTarget.java | 120 +++++----- .../java5/targets/ExplicitInitialFrameTarget.java | 2 +- ...FieldInitializationInTwoConstructorsTarget.java | 8 +- .../validation/java5/targets/FinallyTarget.java | 97 +++++---- .../targets/ImplicitFieldInitializationTarget.java | 10 +- .../targets/InterfaceClassInitializerTarget.java | 12 +- .../java5/targets/SynchronizedTarget.java | 23 +- .../validation/java5/targets/SyntheticTarget.java | 6 +- .../test/validation/java7/StringSwitchTest.java | 44 +--- .../validation/java7/TryWithResourcesTest.java | 181 ++-------------- .../java7/targets/StringSwitchTarget.java | 22 +- .../java7/targets/TryWithResourcesTarget.java | 129 +++++------ .../java8/AnnotationOnLocalVariableTest.java | 9 - .../validation/java8/BadCycleInterfaceTest.java | 38 +++- .../java8/InterfaceDefaultMethodsTest.java | 9 - .../java8/InterfaceOnlyDefaultMethodsTest.java | 8 - .../validation/java8/LambdaExpressionsTest.java | 11 - .../validation/java8/LambdaInInterfaceTest.java | 10 - .../targets/AnnotationOnLocalVariableTarget.java | 2 +- .../java8/targets/BadCycleInterfaceTarget.java | 8 +- .../targets/InterfaceDefaultMethodsTarget.java | 11 +- .../targets/InterfaceOnlyDefaultMethodsTarget.java | 6 +- .../java8/targets/LambdaExpressionsTarget.java | 6 +- .../java8/targets/LambdaInInterfaceTarget.java | 2 +- .../kotlin/KotlinTopLevelFunctionTest.java | 7 - .../kotlin/KotlinWhenExpressionTest.java | 62 ------ .../kotlin/targets/KotlinTopLevelFunctionTarget.kt | 2 +- .../kotlin/targets/KotlinWhenExpressionTarget.kt | 48 ++-- .../org/jacoco/core/test/validation/Source.java | 153 +++++++++---- .../jacoco/core/test/validation/SourceTest.java | 124 ++++++++--- .../core/test/validation/StatementExecutor.java | 65 ++++++ .../test/validation/StatementExecutorTest.java | 106 +++++++++ .../core/test/validation/StatementParser.java | 132 +++++++++++ .../core/test/validation/StatementParserTest.java | 140 ++++++++++++ .../core/test/validation/ValidationTestBase.java | 127 ++++++----- 63 files changed, 1400 insertions(+), 1468 deletions(-) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutor.java create mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutorTest.java create mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParser.java create mode 100644 org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParserTest.java diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationInitializerTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationInitializerTest.java index 7286cd13..c04826a1 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationInitializerTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationInitializerTest.java @@ -11,12 +11,10 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; +import static org.junit.Assert.assertEquals; + import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.AnnotationInitializerTarget; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; /** * Test of initializer in annotations. @@ -39,10 +37,4 @@ public class AnnotationInitializerTest extends ValidationTestBase { targetClass.getField("CONST").get(null); } - @Test - public void testCoverageResult() { - assertLine("const", ICounter.FULLY_COVERED); - assertLine("value", ICounter.EMPTY); - } - } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BadCycleClassTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BadCycleClassTest.java index da53f5a0..4ae12f09 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BadCycleClassTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BadCycleClassTest.java @@ -11,7 +11,6 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.BadCycleClassTarget; import org.junit.Test; @@ -26,11 +25,7 @@ public class BadCycleClassTest extends ValidationTestBase { } @Test - public void test() throws Exception { - assertLine("childinit", ICounter.FULLY_COVERED); - assertLine("childsomeMethod", ICounter.FULLY_COVERED); - assertLine("childclinit", ICounter.FULLY_COVERED); - + public void method_execution_sequence() throws Exception { // The cycle causes a constructor and instance method to be called // before the static initializer of a class: assertLogEvents("childinit", "childsomeMethod", "childclinit", diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BooleanExpressionsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BooleanExpressionsTest.java index f91e1c10..5335ca89 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BooleanExpressionsTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BooleanExpressionsTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.BooleanExpressionsTarget; -import org.junit.Test; /** * Tests of basic Java boolean expressions. @@ -25,56 +23,4 @@ public class BooleanExpressionsTest extends ValidationTestBase { super(BooleanExpressionsTarget.class); } - @Test - public void testCoverageResult() { - - // 1. Boolean comparison result (one case) - assertLine("booleancmp1", ICounter.PARTLY_COVERED, 1, 1); - - // 2. Boolean comparison result (both cases) - assertLine("booleancmp2", ICounter.FULLY_COVERED, 0, 2); - - // 3. And - assertLine("andFF", ICounter.FULLY_COVERED, 1, 1); - assertLine("andFT", ICounter.FULLY_COVERED, 1, 1); - assertLine("andTF", ICounter.FULLY_COVERED, 1, 1); - assertLine("andTT", ICounter.FULLY_COVERED, 1, 1); - - // 4. Conditional And - assertLine("conditionalandFF", ICounter.PARTLY_COVERED, 3, 1); - assertLine("conditionalandFT", ICounter.PARTLY_COVERED, 3, 1); - assertLine("conditionalandTF", ICounter.FULLY_COVERED, 2, 2); - assertLine("conditionalandTT", ICounter.FULLY_COVERED, 2, 2); - - // 5. Or - assertLine("orFF", ICounter.FULLY_COVERED, 1, 1); - assertLine("orFT", ICounter.FULLY_COVERED, 1, 1); - assertLine("orTF", ICounter.FULLY_COVERED, 1, 1); - assertLine("orTT", ICounter.FULLY_COVERED, 1, 1); - - // 6. Conditional Or - assertLine("conditionalorFF", ICounter.FULLY_COVERED, 2, 2); - assertLine("conditionalorFT", ICounter.FULLY_COVERED, 2, 2); - assertLine("conditionalorTF", ICounter.PARTLY_COVERED, 3, 1); - assertLine("conditionalorTT", ICounter.PARTLY_COVERED, 3, 1); - - // 7. Exclusive Or - assertLine("xorFF", ICounter.FULLY_COVERED, 1, 1); - assertLine("xorFT", ICounter.FULLY_COVERED, 1, 1); - assertLine("xorTF", ICounter.FULLY_COVERED, 1, 1); - assertLine("xorTT", ICounter.FULLY_COVERED, 1, 1); - - // 8. Conditional Operator - assertLine("condT", ICounter.PARTLY_COVERED, 1, 1); - assertLine("condF", ICounter.PARTLY_COVERED, 1, 1); - - // 9. Not (one case) - assertLine("notT", ICounter.PARTLY_COVERED, 1, 1); - assertLine("notF", ICounter.PARTLY_COVERED, 1, 1); - - // 10. Not (both cases) - assertLine("notTF", ICounter.FULLY_COVERED, 0, 2); - - } - } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ClassInitializerTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ClassInitializerTest.java index 8df6e8d8..7b1959de 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ClassInitializerTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ClassInitializerTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.ClassInitializerTarget; -import org.junit.Test; /** * Tests of static initializer in classes. @@ -25,21 +23,4 @@ public class ClassInitializerTest extends ValidationTestBase { super(ClassInitializerTarget.class); } - @Test - public void testCoverageResult() { - - assertLine("const1", ICounter.EMPTY); - assertLine("const2", ICounter.EMPTY); - - assertLine("const3", ICounter.FULLY_COVERED); - assertLine("const4", ICounter.FULLY_COVERED); - - assertLine("field1", ICounter.FULLY_COVERED); - assertLine("field2", ICounter.FULLY_COVERED); - assertLine("field3", ICounter.FULLY_COVERED); - assertLine("field4", ICounter.FULLY_COVERED); - - assertLine("staticblock", ICounter.FULLY_COVERED); - } - } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ConstructorsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ConstructorsTest.java index 4c3ed6ac..a9980116 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ConstructorsTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ConstructorsTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.ConstructorsTarget; -import org.junit.Test; /** * Tests for different constructors. Private empty constructors without @@ -26,38 +24,4 @@ public class ConstructorsTest extends ValidationTestBase { super(ConstructorsTarget.class); } - @Test - public void testCoverageResult() { - // not filtered because not private: - assertLine("packageLocal", ICounter.FULLY_COVERED); - - // not filtered because has argument: - assertLine("arg", ICounter.FULLY_COVERED); - - // not filtered because not empty - prepares arguments for super - // constructor: - assertLine("super", ICounter.FULLY_COVERED); - - // not filtered because contains initialization of a field to hold - // reference to an instance of outer class that is passed as an - // argument: - assertLine("inner", ICounter.FULLY_COVERED); - - // not filtered because not empty - contains initialization of - // a field: - assertLine("innerStatic", ICounter.FULLY_COVERED); - - // not filtered because default constructor for not private inner - // classes is not private: - assertLine("publicDefault", ICounter.FULLY_COVERED); - assertLine("packageLocalDefault", ICounter.FULLY_COVERED); - - assertLine("privateDefault", ICounter.EMPTY); - - assertLine("privateNonEmptyNoArg", ICounter.FULLY_COVERED); - - assertLine("privateEmptyNoArg", ICounter.EMPTY); - assertLine("return", ICounter.EMPTY); - } - } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructureBeforeSuperConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructureBeforeSuperConstructorTest.java index d381887a..4d14d241 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructureBeforeSuperConstructorTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructureBeforeSuperConstructorTest.java @@ -11,25 +11,17 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.ControlStructureBeforeSuperConstructorTarget; -import org.junit.Test; /** * Test of probes before the super constructor call. */ -public class ControlStructureBeforeSuperConstructorTest extends ValidationTestBase { +public class ControlStructureBeforeSuperConstructorTest + extends ValidationTestBase { public ControlStructureBeforeSuperConstructorTest() { super(ControlStructureBeforeSuperConstructorTarget.class); } - @Test - public void testCoverageResult() { - - assertLine("super", ICounter.PARTLY_COVERED, 3, 1); - - } - } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructuresTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructuresTest.java index 768312fc..b62ab738 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructuresTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructuresTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.ControlStructuresTarget; -import org.junit.Test; /** * Tests of basic Java control structures. @@ -25,114 +23,4 @@ public class ControlStructuresTest extends ValidationTestBase { super(ControlStructuresTarget.class); } - @Test - public void testCoverageResult() { - - // 1. Direct unconditional execution - assertLine("unconditional", ICounter.FULLY_COVERED); - - // 2. Missed if block - assertLine("iffalse", ICounter.FULLY_COVERED, 1, 1); - assertLine("missedif", ICounter.NOT_COVERED); - assertLine("executedelse", ICounter.FULLY_COVERED); - - // 3. Executed if block - assertLine("iftrue", ICounter.FULLY_COVERED, 1, 1); - assertLine("executedif", ICounter.FULLY_COVERED); - assertLine("missedelse", ICounter.NOT_COVERED); - - // 4. Missed while block - assertLine("whilefalse", ICounter.FULLY_COVERED, 1, 1); - assertLine("missedwhile", ICounter.NOT_COVERED); - - // 5. Always true while block - assertLine("whiletrue", ICounter.FULLY_COVERED, 1, 1); - - // 6. Executed while block - assertLine("whiletruefalse", ICounter.FULLY_COVERED, 0, 2); - assertLine("executedwhile", ICounter.FULLY_COVERED); - - // 7. Executed do while block - assertLine("executeddowhile", ICounter.FULLY_COVERED); - assertLine("executeddowhilefalse", ICounter.FULLY_COVERED, 1, 1); - - // 8. Missed for block - assertLine("missedforincrementer", ICounter.PARTLY_COVERED, 1, 1); - assertLine("missedfor", ICounter.NOT_COVERED); - - // 9. Executed for block - assertLine("executedforincrementer", ICounter.FULLY_COVERED, 0, 2); - assertLine("executedfor", ICounter.FULLY_COVERED); - - // 10. Missed for each block - assertLine("missedforeachincrementer", ICounter.PARTLY_COVERED, 1, 1); - assertLine("missedforeach", ICounter.NOT_COVERED); - - // 11. Executed for each block - assertLine("executedforeachincrementer", ICounter.FULLY_COVERED, 0, 2); - assertLine("executedforeach", ICounter.FULLY_COVERED); - - // 12. Table switch with hit - assertLine("tswitch1", ICounter.FULLY_COVERED, 3, 1); - assertLine("tswitch1case1", ICounter.NOT_COVERED); - assertLine("tswitch1case2", ICounter.FULLY_COVERED); - assertLine("tswitch1case3", ICounter.NOT_COVERED); - assertLine("tswitch1default", ICounter.NOT_COVERED); - - // 13. Continued table switch with hit - assertLine("tswitch2", ICounter.FULLY_COVERED, 3, 1); - assertLine("tswitch2case1", ICounter.NOT_COVERED); - assertLine("tswitch2case2", ICounter.FULLY_COVERED); - assertLine("tswitch2case3", ICounter.FULLY_COVERED); - assertLine("tswitch2default", ICounter.FULLY_COVERED); - - // 14. Table switch without hit - assertLine("tswitch2", ICounter.FULLY_COVERED, 3, 1); - assertLine("tswitch3case1", ICounter.NOT_COVERED); - assertLine("tswitch3case2", ICounter.NOT_COVERED); - assertLine("tswitch3case3", ICounter.NOT_COVERED); - assertLine("tswitch3default", ICounter.FULLY_COVERED); - - // 15. Lookup switch with hit - assertLine("lswitch1", ICounter.FULLY_COVERED, 3, 1); - assertLine("lswitch1case1", ICounter.NOT_COVERED); - assertLine("lswitch1case2", ICounter.FULLY_COVERED); - assertLine("lswitch1case3", ICounter.NOT_COVERED); - assertLine("lswitch1default", ICounter.NOT_COVERED); - - // 16. Continued lookup switch with hit - assertLine("lswitch2", ICounter.FULLY_COVERED, 3, 1); - assertLine("lswitch2case1", ICounter.NOT_COVERED); - assertLine("lswitch2case2", ICounter.FULLY_COVERED); - assertLine("lswitch2case3", ICounter.FULLY_COVERED); - assertLine("lswitch2default", ICounter.FULLY_COVERED); - - // 17. Lookup switch without hit - assertLine("lswitch3", ICounter.FULLY_COVERED, 3, 1); - assertLine("lswitch3case1", ICounter.NOT_COVERED); - assertLine("lswitch3case2", ICounter.NOT_COVERED); - assertLine("lswitch3case3", ICounter.NOT_COVERED); - assertLine("lswitch3default", ICounter.FULLY_COVERED); - - // 18. Break statement - assertLine("executedbreak", ICounter.FULLY_COVERED); - assertLine("missedafterbreak", ICounter.NOT_COVERED); - - // 19. Continue statement - assertLine("executedcontinue", ICounter.FULLY_COVERED); - assertLine("missedaftercontinue", ICounter.NOT_COVERED); - - // 20. Conditional return statement - assertLine("conditionalreturn", ICounter.FULLY_COVERED); - assertLine("afterconditionalreturn", ICounter.NOT_COVERED); - - // 21. Implicit return - assertLine("implicitreturn", ICounter.FULLY_COVERED); - - // 22. Explicit return - assertLine("explicitreturn", ICounter.FULLY_COVERED); - assertLine("afterexplicitreturn", ICounter.EMPTY); - - } - } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumConstructorTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumConstructorTest.java index 28652700..ae96745f 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumConstructorTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumConstructorTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.EnumConstructorTarget; -import org.junit.Test; /** * Test of filtering of enum constructors. @@ -25,39 +23,4 @@ public class EnumConstructorTest extends ValidationTestBase { super(EnumConstructorTarget.class); } - /** - * {@link EnumConstructorTarget.ImplicitConstructor} - */ - @Test - public void implicit_constructor_should_be_filtered() { - // without filter next line is partly covered: - assertLine("implicitConstructor", ICounter.FULLY_COVERED); - } - - /** - * {@link EnumConstructorTarget.ExplicitNonEmptyConstructor#ExplicitNonEmptyConstructor()} - */ - @Test - public void explicit_non_empty_constructor_should_not_be_filtered() { - assertLine("explicitNonEmptyConstructor", ICounter.NOT_COVERED); - } - - /** - * {@link EnumConstructorTarget.ExplicitEmptyConstructor#ExplicitEmptyConstructor()} - */ - @Test - public void explicit_empty_constructor_should_be_filtered() { - // without filter next line is not covered: - assertLine("explicitEmptyConstructor", ICounter.EMPTY); - } - - /** - * {@link EnumConstructorTarget.ExplicitEmptyConstructor#ExplicitEmptyConstructor(Object)} - */ - @Test - public void explicit_empty_constructor_with_parameters_should_not_be_filtered() { - assertLine("explicitEmptyConstructorWithParameter", - ICounter.NOT_COVERED); - } - } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java index ced66609..397e2d21 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java @@ -11,7 +11,6 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.EnumImplicitMethodsTarget; import org.junit.Test; @@ -21,22 +20,13 @@ import org.junit.Test; */ public class EnumImplicitMethodsTest extends ValidationTestBase { - public EnumImplicitMethodsTest() { - super(EnumImplicitMethodsTarget.class); - } + public EnumImplicitMethodsTest() { + super(EnumImplicitMethodsTarget.class); + } - @Test - public void testCoverageResult() { - assertMethodCount(5); - - assertLine("classdef", ICounter.FULLY_COVERED); - assertLine("customValueOfMethod", ICounter.NOT_COVERED); - assertLine("customValuesMethod", ICounter.NOT_COVERED); - - assertLine("const", ICounter.PARTLY_COVERED, 1, 1); - assertLine("staticblock", ICounter.FULLY_COVERED); - assertLine("super", ICounter.FULLY_COVERED); - assertLine("constructor", ICounter.FULLY_COVERED); - } + @Test + public void test_method_count() { + assertMethodCount(5); + } } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumSwitchTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumSwitchTest.java index fa3c44ca..24578386 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumSwitchTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumSwitchTest.java @@ -11,10 +11,9 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.Source.Line; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.EnumSwitchTarget; -import org.junit.Test; /** * Test of filtering of a synthetic class that is generated by javac for a enum @@ -26,14 +25,13 @@ public class EnumSwitchTest extends ValidationTestBase { super(EnumSwitchTarget.class); } - @Test - public void testCoverageResult() { + public void assertSwitch(final Line line) { if (isJDKCompiler && JAVA_VERSION.isBefore("1.6")) { // class that holds "switch map" is not marked as synthetic when // compiling with javac 1.5 - assertLine("switch", ICounter.PARTLY_COVERED, 0, 2); + assertPartlyCovered(line, 0, 2); } else { - assertLine("switch", ICounter.FULLY_COVERED, 0, 2); + assertFullyCovered(line, 0, 2); } } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExceptionsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExceptionsTest.java index 15e47167..86350fd1 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExceptionsTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExceptionsTest.java @@ -11,10 +11,9 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.Source.Line; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.ExceptionsTarget; -import org.junit.Test; /** * Tests of exception based control flow. @@ -25,109 +24,60 @@ public class ExceptionsTest extends ValidationTestBase { super(ExceptionsTarget.class); } - @Test - public void testCoverageResult() { - - // 0. Implicit NullPointerException - // Currently no coverage at all, as we don't see when a block aborts - // somewhere in the middle. - assertLine("implicitNullPointerException.before", ICounter.NOT_COVERED); - assertLine("implicitNullPointerException.exception", - ICounter.NOT_COVERED); - assertLine("implicitNullPointerException.after", ICounter.NOT_COVERED); - - // 1. Implicit Exception - assertLine("implicitException.before", ICounter.FULLY_COVERED); - assertLine("implicitException.exception", ICounter.NOT_COVERED); - assertLine("implicitException.after", ICounter.NOT_COVERED); - - // 2. Explicit Exception - // Full coverage, as we recognize throw statements as block boundaries. - assertLine("explicitException.before", ICounter.FULLY_COVERED); - assertLine("explicitException.throw", ICounter.FULLY_COVERED); - - // 3. Try/Catch Block Without Exception Thrown - assertLine("noExceptionTryCatch.beforeBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionTryCatch.tryBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionTryCatch.catch", - isJDKCompiler ? ICounter.NOT_COVERED : ICounter.PARTLY_COVERED); - assertLine("noExceptionTryCatch.catchBlock", ICounter.NOT_COVERED); - assertLine("noExceptionTryCatch.catchBlockEnd", - isJDKCompiler ? ICounter.FULLY_COVERED : ICounter.EMPTY); - assertLine("noExceptionTryCatch.afterBlock", ICounter.FULLY_COVERED); - - // 4. Try/Catch Block With Exception Thrown Implicitly - assertLine("implicitExceptionTryCatch.beforeBlock", - ICounter.FULLY_COVERED); - assertLine("implicitExceptionTryCatch.before", ICounter.FULLY_COVERED); - assertLine("implicitExceptionTryCatch.exception", ICounter.NOT_COVERED); - assertLine("implicitExceptionTryCatch.after", ICounter.NOT_COVERED); - assertLine("implicitExceptionTryCatch.catch", isJDKCompiler - ? ICounter.FULLY_COVERED : ICounter.PARTLY_COVERED); - assertLine("implicitExceptionTryCatch.catchBlock", - ICounter.FULLY_COVERED); - assertLine("implicitExceptionTryCatch.catchBlockEnd", - isJDKCompiler ? ICounter.NOT_COVERED : ICounter.EMPTY); - assertLine("implicitExceptionTryCatch.afterBlock", - ICounter.FULLY_COVERED); + public void assertCatchNoException(final Line line) { + if (isJDKCompiler) { + assertNotCovered(line); + } else { + assertPartlyCovered(line); + } + } - // 5. Try/Catch Block With Exception Thrown Implicitly After Condition - // As the try/catch block is entered at one branch of the condition - // should be marked as executed - assertLine("implicitExceptionTryCatchAfterCondition.condition", - ICounter.FULLY_COVERED, 1, 1); - assertLine("implicitExceptionTryCatchAfterCondition.exception", - ICounter.NOT_COVERED); - assertLine("implicitExceptionTryCatchAfterCondition.catchBlock", - ICounter.FULLY_COVERED); + public void assertCatchBlockEndNoException(final Line line) { + if (isJDKCompiler) { + assertFullyCovered(line); + } else { + assertEmpty(line); + } + } - // 6. Try/Catch Block With Exception Thrown Explicitly - assertLine("explicitExceptionTryCatch.beforeBlock", - ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.before", ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.throw", ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.catch", ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.catchBlock", - ICounter.FULLY_COVERED); - assertLine("explicitExceptionTryCatch.catchBlockEnd", ICounter.EMPTY); - assertLine("explicitExceptionTryCatch.afterBlock", - ICounter.FULLY_COVERED); + public void assertCatchImplicitException(final Line line) { + if (isJDKCompiler) { + assertFullyCovered(line); + } else { + assertPartlyCovered(line); + } + } - // 7. Finally Block Without Exception Thrown - assertLine("noExceptionFinally.beforeBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionFinally.tryBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionFinally.finally", - isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); - assertLine("noExceptionFinally.finallyBlock", ICounter.FULLY_COVERED); - assertLine("noExceptionFinally.finallyBlockEnd", ICounter.EMPTY); - assertLine("noExceptionFinally.afterBlock", ICounter.FULLY_COVERED); + public void assertCatchBlockEndImplicitException(final Line line) { + if (isJDKCompiler) { + assertNotCovered(line); + } else { + assertEmpty(line); + } + } - // 8. Finally Block With Implicit Exception - assertLine("implicitExceptionFinally.beforeBlock", - ICounter.FULLY_COVERED); - assertLine("implicitExceptionFinally.before", ICounter.FULLY_COVERED); - assertLine("implicitExceptionFinally.exception", ICounter.NOT_COVERED); - assertLine("implicitExceptionFinally.after", ICounter.NOT_COVERED); - assertLine("implicitExceptionFinally.finally", - isJDKCompiler ? ICounter.EMPTY : ICounter.NOT_COVERED); - assertLine("implicitExceptionFinally.finallyBlock", - ICounter.FULLY_COVERED); - assertLine("implicitExceptionFinally.finallyBlockEnd", ICounter.EMPTY); - assertLine("implicitExceptionFinally.afterBlock", ICounter.NOT_COVERED); + public void assertFinally(final Line line) { + if (isJDKCompiler) { + assertEmpty(line); + } else { + assertFullyCovered(line); + } + } - // 9. Finally Block With Exception Thrown Explicitly - assertLine("explicitExceptionFinally.beforeBlock", - ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.before", ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.throw", ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.finally", - isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.finallyBlock", - ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.finallyBlockEnd", - isJDKCompiler ? ICounter.EMPTY : ICounter.FULLY_COVERED); - assertLine("explicitExceptionFinally.afterBlock", ICounter.EMPTY); + public void assertFinallyImplicitException(final Line line) { + if (isJDKCompiler) { + assertEmpty(line); + } else { + assertNotCovered(line); + } + } + public void assertBlockEndImplicitException(final Line line) { + if (isJDKCompiler) { + assertEmpty(line); + } else { + assertFullyCovered(line); + } } } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExplicitInitialFrameTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExplicitInitialFrameTest.java index b04c1a6b..2aa064b9 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExplicitInitialFrameTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExplicitInitialFrameTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.ExplicitInitialFrameTarget; -import org.junit.Test; /** * Test for a methods having a explicit initial frame. @@ -25,11 +23,4 @@ public class ExplicitInitialFrameTest extends ValidationTestBase { super(ExplicitInitialFrameTarget.class); } - @Test - public void testCoverageResult() { - - assertLine("dowhilebody", ICounter.FULLY_COVERED); - - } - } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FieldInitializationInTwoConstructorsTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FieldInitializationInTwoConstructorsTest.java index 6be37f4d..ec83ad54 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FieldInitializationInTwoConstructorsTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FieldInitializationInTwoConstructorsTest.java @@ -11,29 +11,17 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.FieldInitializationInTwoConstructorsTarget; -import org.junit.Test; /** * Test of field initialization in two constructors. */ -public class FieldInitializationInTwoConstructorsTest extends - ValidationTestBase { +public class FieldInitializationInTwoConstructorsTest + extends ValidationTestBase { public FieldInitializationInTwoConstructorsTest() { super(FieldInitializationInTwoConstructorsTarget.class); } - @Test - public void testCoverageResult() { - - assertLine("field1", ICounter.PARTLY_COVERED); - assertLine("field2", ICounter.PARTLY_COVERED); - assertLine("constr1", ICounter.FULLY_COVERED); - assertLine("constr2", ICounter.NOT_COVERED); - - } - } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java index 69cf4295..82fb08cc 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java @@ -12,16 +12,21 @@ package org.jacoco.core.test.validation.java5; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import java.io.IOException; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.test.TargetLoader; +import org.jacoco.core.test.validation.Source.Line; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.FinallyTarget; +import org.junit.Before; import org.junit.Test; import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; @@ -35,180 +40,101 @@ import org.objectweb.asm.tree.MethodNode; */ public class FinallyTest extends ValidationTestBase { + private Map tags; + public FinallyTest() { super(FinallyTarget.class); } - /** - * {@link FinallyTarget#example(boolean)} - */ - @Test - public void example() { + @Before + @Override + public void setup() throws Exception { + super.setup(); + tags = new HashMap(); + } + + public void assertFinally(final Line line) { if (isJDKCompiler) { - assertLine("example.0", ICounter.EMPTY); + assertEmpty(line); } else { - assertLine("example.0", ICounter.FULLY_COVERED); + assertFullyCovered(line); } - assertLine("example.1", ICounter.FULLY_COVERED, 0, 2); - assertLine("example.2", ICounter.FULLY_COVERED); - assertLine("example.3", ICounter.EMPTY); - assertLine("example.4", ICounter.EMPTY); - } - - /** - * GOTO instructions at the end of duplicates of finally block might have - * line number of a last instruction of finally block and hence lead to - * unexpected coverage results, like for example in case of ECJ for - * {@link FinallyTarget#catchNotExecuted()}, - * {@link FinallyTarget#emptyCatch()}. So we decided to ignore them, even if - * they can correspond to a real break statement. - *

    - * See also JDK-8180141 and - * JDK-7008643. - *

    - * {@link FinallyTarget#breakStatement()} - */ - @Test - public void breakStatement() { - assertLine("breakStatement", ICounter.EMPTY); - - assertLine("breakStatement.1", ICounter.FULLY_COVERED); - assertLine("breakStatement.2", ICounter.EMPTY); } - /** - * {@link FinallyTarget#catchNotExecuted()} - */ - @Test - public void catchNotExecuted() { - assertLine("catchNotExecuted.catch", ICounter.NOT_COVERED); - assertLine("catchNotExecuted.0", ICounter.EMPTY); - assertLine("catchNotExecuted.1", ICounter.FULLY_COVERED); - assertLine("catchNotExecuted.2", ICounter.EMPTY); - } - - /** - * {@link FinallyTarget#emptyCatch()} - */ - @Test - public void emptyCatch() { - assertLine("emptyCatch.0", ICounter.EMPTY); - assertLine("emptyCatch.1", ICounter.FULLY_COVERED); - assertLine("emptyCatch.2", ICounter.EMPTY); + public void assertTwoRegions1(final Line line) { + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { + // https://bugs.openjdk.java.net/browse/JDK-7008643 + assertPartlyCovered(line); + } else { + assertFullyCovered(line); + } } - /** - * {@link FinallyTarget#twoRegions()} - */ - @Test - public void twoRegions() { - assertLine("twoRegions.0", ICounter.EMPTY); + public void assertTwoRegionsReturn1(final Line line) { if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { // https://bugs.openjdk.java.net/browse/JDK-7008643 - assertLine("twoRegions.1", ICounter.PARTLY_COVERED); - assertLine("twoRegions.return.1", ICounter.EMPTY); - assertLine("twoRegions.return.2", ICounter.EMPTY); + assertEmpty(line); } else { - assertLine("twoRegions.1", ICounter.FULLY_COVERED); - assertLine("twoRegions.return.1", ICounter.FULLY_COVERED); - assertLine("twoRegions.return.2", ICounter.NOT_COVERED); + assertFullyCovered(line); } - assertLine("twoRegions.2", ICounter.EMPTY); - - assertLine("twoRegions.if", ICounter.FULLY_COVERED, 1, 1); - assertLine("twoRegions.region.1", ICounter.FULLY_COVERED); - assertLine("twoRegions.region.2", ICounter.NOT_COVERED); } - /** - * {@link FinallyTarget#nested()} - */ - @Test - public void nested() { - if (isJDKCompiler) { - assertLine("nested.0", ICounter.EMPTY); + public void assertTwoRegionsReturn2(final Line line) { + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { + // https://bugs.openjdk.java.net/browse/JDK-7008643 + assertEmpty(line); } else { - assertLine("nested.0", ICounter.FULLY_COVERED); + assertNotCovered(line); } - assertLine("nested.1", ICounter.EMPTY); - assertLine("nested.2", ICounter.FULLY_COVERED); - if (isJDKCompiler) { - assertLine("nested.3", ICounter.EMPTY); + } + + public void assertEmptyTry1(final Line line) { + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { + // compiler bug fixed in javac >= 1.8: + assertPartlyCovered(line); } else { - assertLine("nested.3", ICounter.FULLY_COVERED); + assertFullyCovered(line); } - assertLine("nested.4", ICounter.FULLY_COVERED); } - /** - * {@link FinallyTarget#emptyTry()} - */ - @Test - public void emptyTry() { - assertLine("emptyTry.0", ICounter.EMPTY); + public void assertEmptyTry2(final Line line) { if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { // compiler bug fixed in javac >= 1.8: - assertLine("emptyTry.1", ICounter.PARTLY_COVERED); - assertLine("emptyTry.2", ICounter.FULLY_COVERED); + assertFullyCovered(line); } else { - assertLine("emptyTry.1", ICounter.FULLY_COVERED); - assertLine("emptyTry.2", ICounter.EMPTY); + assertEmpty(line); } } - /** - * {@link FinallyTarget#alwaysCompletesAbruptly()} - */ - @Test - public void alwaysCompletesAbruptly() { + public void assertAlwaysCompletesAbruptly0(final Line line) { if (isJDKCompiler) { // uncovered case: - assertLine("alwaysCompletesAbruptly.0", ICounter.EMPTY); - assertLine("alwaysCompletesAbruptly.1", ICounter.PARTLY_COVERED); + assertEmpty(line); } else { - assertLine("alwaysCompletesAbruptly.0", ICounter.PARTLY_COVERED); - assertLine("alwaysCompletesAbruptly.1", ICounter.FULLY_COVERED); + assertPartlyCovered(line); } - assertLine("alwaysCompletesAbruptly.2", ICounter.EMPTY); + } + + public void assertAlwaysCompletesAbruptly1(final Line line) { + if (isJDKCompiler) { + // uncovered case: + assertPartlyCovered(line); + } else { + assertFullyCovered(line); + } + } + + @Test + @Override + public void execute_assertions_in_comments() throws IOException { + super.execute_assertions_in_comments(); + gotos(); } /** * This test studies placement of GOTO instructions. */ - @Test - public void gotos() throws IOException { - byte[] b = TargetLoader.getClassDataAsBytes(FinallyTarget.class); - b = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(b), b); - - final ClassNode classNode = new ClassNode(); - new ClassReader(b).accept(classNode, 0); - final Set tags = new HashSet(); - for (final MethodNode m : classNode.methods) { - if ("main".equals(m.name)) { - // skip it - continue; - } - int lineNumber = -1; - for (AbstractInsnNode i = m.instructions - .getFirst(); i != null; i = i.getNext()) { - if (AbstractInsnNode.LINE == i.getType()) { - lineNumber = ((LineNumberNode) i).line; - } - if (Opcodes.GOTO == i.getOpcode()) { - final String line = getSource().getLine(lineNumber); - if (line.indexOf('$') < 0) { - throw new AssertionError( - "No tag at line " + lineNumber); - } - final String tag = line.substring( - line.indexOf('$') + "$line-".length(), - line.lastIndexOf('$')); - tags.add(tag); - } - } - } + private void gotos() throws IOException { final Set expected = new HashSet(); @@ -261,7 +187,46 @@ public class FinallyTest extends ValidationTestBase { expected.add("alwaysCompletesAbruptly.0"); } - assertEquals(expected, tags); + assertEquals(expected, getTagsWithGotos()); + } + + private Set getTagsWithGotos() throws IOException { + final Set gotoTags = new HashSet(); + + byte[] b = TargetLoader.getClassDataAsBytes(FinallyTarget.class); + b = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(b), b); + + final ClassNode classNode = new ClassNode(); + new ClassReader(b).accept(classNode, 0); + for (final MethodNode m : classNode.methods) { + if ("main".equals(m.name)) { + // skip it + continue; + } + int lineNumber = -1; + for (AbstractInsnNode i = m.instructions + .getFirst(); i != null; i = i.getNext()) { + if (AbstractInsnNode.LINE == i.getType()) { + lineNumber = ((LineNumberNode) i).line; + } + if (Opcodes.GOTO == i.getOpcode()) { + String tag = tags.get(Integer.valueOf(lineNumber)); + if (tag == null) { + throw new AssertionError( + "No tag at line " + lineNumber); + } + gotoTags.add(tag); + } + } + } + + return gotoTags; + } + + public void tag(final Line line, String tag) { + assertFalse("duplicate tag " + tag, tags.containsValue(tag)); + assertNull("duplicate tag in " + line, + tags.put(Integer.valueOf(line.getNr()), tag)); } } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ImplicitFieldInitializationTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ImplicitFieldInitializationTest.java index d87d039b..3b226c37 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ImplicitFieldInitializationTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ImplicitFieldInitializationTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.ImplicitFieldInitializationTarget; -import org.junit.Test; /** * Test of a implicit field initialization. @@ -25,15 +23,4 @@ public class ImplicitFieldInitializationTest extends ValidationTestBase { super(ImplicitFieldInitializationTarget.class); } - @Test - public void testCoverageResult() { - - assertLine("classdef", ICounter.FULLY_COVERED); - assertLine("field1", ICounter.EMPTY); - assertLine("field2", ICounter.FULLY_COVERED); - assertLine("field3", ICounter.EMPTY); - assertLine("field4", ICounter.FULLY_COVERED); - - } - } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/InterfaceClassInitializerTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/InterfaceClassInitializerTest.java index 9e13debb..c56293c0 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/InterfaceClassInitializerTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/InterfaceClassInitializerTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.InterfaceClassInitializerTarget; -import org.junit.Test; /** * Tests of static initializer in interfaces. @@ -31,14 +29,4 @@ public class InterfaceClassInitializerTest extends ValidationTestBase { targetClass.getField("CONST1").get(null); } - @Test - public void testCoverageResult() { - - assertLine("const1", ICounter.EMPTY); - assertLine("const2", ICounter.EMPTY); - - assertLine("const3", ICounter.FULLY_COVERED); - assertLine("const4", ICounter.FULLY_COVERED); - } - } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SynchronizedTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SynchronizedTest.java index c1498be1..821f5377 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SynchronizedTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SynchronizedTest.java @@ -11,10 +11,9 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.Source.Line; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.SynchronizedTarget; -import org.junit.Test; /** * Test of filtering of a bytecode that is generated for a synchronized @@ -26,48 +25,29 @@ public class SynchronizedTest extends ValidationTestBase { super(SynchronizedTarget.class); } - /** - * {@link SynchronizedTarget#normal()} - */ - @Test - public void normal() { - assertLine("before", ICounter.FULLY_COVERED); - // when compiled with ECJ next line covered partly without filter: - assertLine("monitorEnter", ICounter.FULLY_COVERED); - assertLine("body", ICounter.FULLY_COVERED); + public void assertMonitorEnterImplicitException(final Line line) { if (isJDKCompiler) { - // without filter next line covered partly: - assertLine("monitorExit", ICounter.FULLY_COVERED); + assertFullyCovered(line); } else { - assertLine("monitorExit", ICounter.EMPTY); + assertPartlyCovered(line); } - assertLine("after", ICounter.FULLY_COVERED); } - /** - * {@link SynchronizedTarget#explicitException()} - */ - @Test - public void explicitException() { - assertLine("explicitException.monitorEnter", ICounter.FULLY_COVERED); - assertLine("explicitException.exception", ICounter.FULLY_COVERED); - // when compiled with javac next line covered fully without filter: - assertLine("explicitException.monitorExit", ICounter.EMPTY); + public void assertMonitorExit(final Line line) { + if (isJDKCompiler) { + // without filter next line covered partly: + assertFullyCovered(line); + } else { + assertEmpty(line); + } } - /** - * {@link SynchronizedTarget#implicitException()} - */ - @Test - public void implicitException() { - assertLine("implicitException.monitorEnter", isJDKCompiler - ? ICounter.FULLY_COVERED : ICounter.PARTLY_COVERED); - assertLine("implicitException.exception", ICounter.NOT_COVERED); + public void assertMonitorExitImplicitException(final Line line) { if (isJDKCompiler) { // without filter next line covered partly: - assertLine("implicitException.monitorExit", ICounter.NOT_COVERED); + assertNotCovered(line); } else { - assertLine("implicitException.monitorExit", ICounter.EMPTY); + assertEmpty(line); } } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SyntheticTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SyntheticTest.java index f1f8372e..82b5128d 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SyntheticTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SyntheticTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java5; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java5.targets.SyntheticTarget; -import org.junit.Test; /** * Test of filtering of synthetic methods. @@ -25,14 +23,8 @@ public class SyntheticTest extends ValidationTestBase { super(SyntheticTarget.class); } - @Test - public void testCoverageResult() { + public void test_method_count() { assertMethodCount(5); - - assertLine("classdef", ICounter.EMPTY); - assertLine("field", ICounter.EMPTY); - - assertLine("inner.classdef", ICounter.EMPTY); } } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/AnnotationInitializerTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/AnnotationInitializerTarget.java index 95171b3b..c53a2068 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/AnnotationInitializerTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/AnnotationInitializerTarget.java @@ -16,8 +16,8 @@ package org.jacoco.core.test.validation.java5.targets; */ public @interface AnnotationInitializerTarget { - Object CONST = new Object(); // $line-const$ + Object CONST = new Object(); // assertFullyCovered() - int value() default 0; // $line-value$ + int value() default 0; // assertEmpty() } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BadCycleClassTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BadCycleClassTarget.java index 27b48dcc..e5c40409 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BadCycleClassTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BadCycleClassTarget.java @@ -26,15 +26,15 @@ public class BadCycleClassTarget { public static class Child extends Base { static { - Stubs.logEvent("childclinit"); // $line-childclinit$ + Stubs.logEvent("childclinit"); // assertFullyCovered() } public Child() { - Stubs.logEvent("childinit"); // $line-childinit$ + Stubs.logEvent("childinit"); // assertFullyCovered() } void someMethod() { - Stubs.logEvent("childsomeMethod"); // $line-childsomeMethod$ + Stubs.logEvent("childsomeMethod"); // assertFullyCovered() } } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BooleanExpressionsTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BooleanExpressionsTarget.java index a0b4ff50..249e6719 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BooleanExpressionsTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/BooleanExpressionsTarget.java @@ -24,95 +24,95 @@ public class BooleanExpressionsTarget { public static void main(String[] args) { - // 1. Boolean comparison result (one case) - nop(i2() > 3); // $line-booleancmp1$ + /* 1. Boolean comparison result (one case) */ + nop(i2() > 3); // assertPartlyCovered(1, 1) - // 2. Boolean comparison result (both cases) + /* 2. Boolean comparison result (both cases) */ for (int i = 0; i < 2; i++) { - nop(i < 1); // $line-booleancmp2$ + nop(i < 1); // assertFullyCovered(0, 2) } - // 3. And - if (f() & f()) { // $line-andFF$ + /* 3. And */ + if (f() & f()) { // assertFullyCovered(1, 1) nop(); } - if (f() & t()) { // $line-andFT$ + if (f() & t()) { // assertFullyCovered(1, 1) nop(); } - if (t() & f()) { // $line-andTF$ + if (t() & f()) { // assertFullyCovered(1, 1) nop(); } - if (t() & t()) { // $line-andTT$ + if (t() & t()) { // assertFullyCovered(1, 1) nop(); } - // 4. Conditional And - if (f() && f()) { // $line-conditionalandFF$ + /* 4. Conditional And */ + if (f() && f()) { // assertPartlyCovered(3, 1) nop(); } - if (f() && t()) { // $line-conditionalandFT$ + if (f() && t()) { // assertPartlyCovered(3, 1) nop(); } - if (t() && f()) { // $line-conditionalandTF$ + if (t() && f()) { // assertFullyCovered(2, 2) nop(); } - if (t() && t()) { // $line-conditionalandTT$ + if (t() && t()) { // assertFullyCovered(2, 2) nop(); } - // 5. Or - if (f() | f()) { // $line-orFF$ + /* 5. Or */ + if (f() | f()) { // assertFullyCovered(1, 1) nop(); } - if (f() | t()) { // $line-orFT$ + if (f() | t()) { // assertFullyCovered(1, 1) nop(); } - if (t() | f()) { // $line-orTF$ + if (t() | f()) { // assertFullyCovered(1, 1) nop(); } - if (t() | t()) { // $line-orTT$ + if (t() | t()) { // assertFullyCovered(1, 1) nop(); } - // 6. Conditional Or - if (f() || f()) { // $line-conditionalorFF$ + /* 6. Conditional Or */ + if (f() || f()) { // assertFullyCovered(2, 2) nop(); } - if (f() || t()) { // $line-conditionalorFT$ + if (f() || t()) { // assertFullyCovered(2, 2) nop(); } - if (t() || f()) { // $line-conditionalorTF$ + if (t() || f()) { // assertPartlyCovered(3, 1) nop(); } - if (t() || t()) { // $line-conditionalorTT$ + if (t() || t()) { // assertPartlyCovered(3, 1) nop(); } - // 7. Exclusive Or - if (f() ^ f()) { // $line-xorFF$ + /* 7. Exclusive Or */ + if (f() ^ f()) { // assertFullyCovered(1, 1) nop(); } - if (f() ^ t()) { // $line-xorFT$ + if (f() ^ t()) { // assertFullyCovered(1, 1) nop(); } - if (t() ^ f()) { // $line-xorTF$ + if (t() ^ f()) { // assertFullyCovered(1, 1) nop(); } - if (t() ^ t()) { // $line-xorTT$ + if (t() ^ t()) { // assertFullyCovered(1, 1) nop(); } - // 8. Conditional Operator - nop(t() ? i1() : i2()); // $line-condT$ - nop(f() ? i1() : i2()); // $line-condF$ + /* 8. Conditional Operator */ + nop(t() ? i1() : i2()); // assertPartlyCovered(1, 1) + nop(f() ? i1() : i2()); // assertPartlyCovered(1, 1) - // 9. Not (one case) - nop(!t()); // $line-notT$ - nop(!f()); // $line-notF$ + /* 9. Not (one case) */ + nop(!t()); // assertPartlyCovered(1, 1) + nop(!f()); // assertPartlyCovered(1, 1) - // 10. Not (both cases) + /* 10. Not (both cases) */ for (boolean b : new boolean[] { true, false }) { - nop(!b); // $line-notTF$ + nop(!b); // assertFullyCovered(0, 2) } } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ClassInitializerTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ClassInitializerTarget.java index a8978362..373e33f5 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ClassInitializerTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ClassInitializerTarget.java @@ -20,28 +20,28 @@ import org.jacoco.core.test.validation.targets.Stubs; */ public class ClassInitializerTarget { - // No code required to initialize these fields: + /* No code required to initialize these fields: */ - public static final int CONST1 = 3; // $line-const1$ + public static final int CONST1 = 3; // assertEmpty() - public static final String CONST2 = "Hello"; // $line-const2$ + public static final String CONST2 = "Hello"; // assertEmpty() - // These fields are initialized within + /* These fields are initialized within */ - public static final int CONST3 = i1(); // $line-const3$ + public static final int CONST3 = i1(); // assertFullyCovered() - public static final Object CONST4 = new Object(); // $line-const4$ + public static final Object CONST4 = new Object(); // assertFullyCovered() - public static int field1 = 3; // $line-field1$ + public static int field1 = 3; // assertFullyCovered() - public static String field2 = "Hello"; // $line-field2$ + public static String field2 = "Hello"; // assertFullyCovered() - public static int field3 = i1(); // $line-field3$ + public static int field3 = i1(); // assertFullyCovered() - public static Object field4 = new Object(); // $line-field4$ + public static Object field4 = new Object(); // assertFullyCovered() static { - Stubs.nop(); // $line-staticblock$ + Stubs.nop(); // assertFullyCovered() } private ClassInitializerTarget() { diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ConstructorsTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ConstructorsTarget.java index 99ff020d..5376299c 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ConstructorsTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ConstructorsTarget.java @@ -18,20 +18,31 @@ import static org.jacoco.core.test.validation.targets.Stubs.nop; */ public class ConstructorsTarget { - ConstructorsTarget() { // $line-packageLocal$ + /* not filtered because not private: */ + ConstructorsTarget() { // assertFullyCovered() } - private ConstructorsTarget(Object arg) { // $line-arg$ + /* not filtered because has argument: */ + private ConstructorsTarget(Object arg) { // assertFullyCovered() } private static class Super extends ConstructorsTarget { private Super() { - super(null); // $line-super$ + /* + * not filtered because not empty - prepares arguments for super + * constructor: + */ + super(null); // assertFullyCovered() } } private class Inner { - private Inner() { // $line-inner$ + /* + * not filtered because contains initialization of a field to hold + * reference to an instance of outer class that is passed as an + * argument: + */ + private Inner() { // assertFullyCovered() } } @@ -39,28 +50,35 @@ public class ConstructorsTarget { @SuppressWarnings("unused") private final Object field = this; - private InnerStatic() { // $line-innerStatic$ + /* + * not filtered because not empty - contains initialization of a field: + */ + private InnerStatic() { // assertFullyCovered() } } - public static class PublicDefault { // $line-publicDefault$ + /* + * not filtered because default constructor for not private inner classes is + * not private: + */ + public static class PublicDefault { // assertFullyCovered() } - static class PackageLocalDefault { // $line-packageLocalDefault$ + static class PackageLocalDefault { // assertFullyCovered() } - private static class PrivateDefault { // $line-privateDefault$ + private static class PrivateDefault { // assertEmpty() } private static class PrivateNonEmptyNoArg { private PrivateNonEmptyNoArg() { - nop(); // $line-privateNonEmptyNoArg$ + nop(); // assertFullyCovered() } } private static class PrivateEmptyNoArg { - private PrivateEmptyNoArg() { // $line-privateEmptyNoArg$ - } // $line-return$ + private PrivateEmptyNoArg() { // assertEmpty() + } // assertEmpty() } public static void main(String[] args) { diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructureBeforeSuperConstructorTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructureBeforeSuperConstructorTarget.java index ffc1d5f7..20317b8b 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructureBeforeSuperConstructorTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructureBeforeSuperConstructorTarget.java @@ -23,7 +23,7 @@ import org.jacoco.core.test.validation.targets.Stubs.SuperClass; public class ControlStructureBeforeSuperConstructorTarget extends SuperClass { public ControlStructureBeforeSuperConstructorTarget() { - super(t() || f()); // $line-super$ + super(t() || f()); // assertPartlyCovered(3, 1) } public static void main(String[] args) { diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructuresTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructuresTarget.java index 3152a8b1..669a48db 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructuresTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ControlStructuresTarget.java @@ -52,41 +52,41 @@ public class ControlStructuresTarget { private static void unconditionalExecution() { - nop(); // $line-unconditional$ + nop(); // assertFullyCovered() } private static void missedIfBlock() { - if (f()) { // $line-iffalse$ - nop(); // $line-missedif$ + if (f()) { // assertFullyCovered(1, 1) + nop(); // assertNotCovered() } else { - nop(); // $line-executedelse$ + nop(); // assertFullyCovered() } } private static void executedIfBlock() { - if (t()) { // $line-iftrue$ - nop(); // $line-executedif$ + if (t()) { // assertFullyCovered(1, 1) + nop(); // assertFullyCovered() } else { - nop(); // $line-missedelse$ + nop(); // assertNotCovered() } } private static void missedWhileBlock() { - while (f()) { // $line-whilefalse$ - nop(); // $line-missedwhile$ + while (f()) { // assertFullyCovered(1, 1) + nop(); // assertNotCovered() } } private static void alwaysExecutedWhileBlock() { - while (t()) { // $line-whiletrue$ + while (t()) { // assertFullyCovered(1, 1) if (t()) { break; } @@ -97,8 +97,8 @@ public class ControlStructuresTarget { private static void executedWhileBlock() { int i = 0; - while (i++ < 3) { // $line-whiletruefalse$ - nop(); // $line-executedwhile$ + while (i++ < 3) { // assertFullyCovered(0, 2) + nop(); // assertFullyCovered() } } @@ -106,57 +106,57 @@ public class ControlStructuresTarget { private static void executedDoWhileBlock() { do { - nop(); // $line-executeddowhile$ - } while (f()); // $line-executeddowhilefalse$ + nop(); // assertFullyCovered() + } while (f()); // assertFullyCovered(1, 1) } private static void missedForBlock() { - for (nop(); f(); nop()) { // $line-missedforincrementer$ - nop(); // $line-missedfor$ + for (nop(); f(); nop()) { // assertPartlyCovered(1, 1) + nop(); // assertNotCovered() } } private static void executedForBlock() { - for (int j = 0; j < 1; j++) { // $line-executedforincrementer$ - nop(); // $line-executedfor$ + for (int j = 0; j < 1; j++) { // assertFullyCovered(0, 2) + nop(); // assertFullyCovered() } } private static void missedForEachBlock() { - for (Object o : Collections.emptyList()) { // $line-missedforeachincrementer$ - nop(o); // $line-missedforeach$ + for (Object o : Collections.emptyList()) { // assertPartlyCovered(1, 1) + nop(o); // assertNotCovered() } } private static void executedForEachBlock() { - for (Object o : Collections.singleton(new Object())) { // $line-executedforeachincrementer$ - nop(o); // $line-executedforeach$ + for (Object o : Collections.singleton(new Object())) { // assertFullyCovered(0,2) + nop(o); // assertFullyCovered() } } private static void tableSwitchWithHit() { - switch (i2()) { // $line-tswitch1$ + switch (i2()) { // assertFullyCovered(3, 1) case 1: - nop(); // $line-tswitch1case1$ + nop(); // assertNotCovered() break; case 2: - nop(); // $line-tswitch1case2$ + nop(); // assertFullyCovered() break; case 3: - nop(); // $line-tswitch1case3$ + nop(); // assertNotCovered() break; default: - nop(); // $line-tswitch1default$ + nop(); // assertNotCovered() break; } @@ -164,33 +164,33 @@ public class ControlStructuresTarget { private static void continuedTableSwitchWithHit() { - switch (i2()) { // $line-tswitch2$ + switch (i2()) { // assertFullyCovered(3, 1) case 1: - nop(); // $line-tswitch2case1$ + nop(); // assertNotCovered() case 2: - nop(); // $line-tswitch2case2$ + nop(); // assertFullyCovered() case 3: - nop(); // $line-tswitch2case3$ + nop(); // assertFullyCovered() default: - nop(); // $line-tswitch2default$ + nop(); // assertFullyCovered() } } private static void tableSwitchWithoutHit() { - switch (i2()) { // $line-tswitch3$ + switch (i2()) { // assertFullyCovered(3, 1) case 3: - nop(); // $line-tswitch3case1$ + nop(); // assertNotCovered() break; case 4: - nop(); // $line-tswitch3case2$ + nop(); // assertNotCovered() break; case 5: - nop(); // $line-tswitch3case3$ + nop(); // assertNotCovered() break; default: - nop(); // $line-tswitch3default$ + nop(); // assertFullyCovered() break; } @@ -198,18 +198,18 @@ public class ControlStructuresTarget { private static void lookupSwitchWithHit() { - switch (i2()) { // $line-lswitch1$ + switch (i2()) { // assertFullyCovered(3, 1) case -123: - nop(); // $line-lswitch1case1$ + nop(); // assertNotCovered() break; case 2: - nop(); // $line-lswitch1case2$ + nop(); // assertFullyCovered() break; case 456: - nop(); // $line-lswitch1case3$ + nop(); // assertNotCovered() break; default: - nop(); // $line-lswitch1default$ + nop(); // assertNotCovered() break; } @@ -217,33 +217,33 @@ public class ControlStructuresTarget { private static void continuedLookupSwitchWithHit() { - switch (i2()) { // $line-lswitch2$ + switch (i2()) { // assertFullyCovered(3, 1) case -123: - nop(); // $line-lswitch2case1$ + nop(); // assertNotCovered() case 2: - nop(); // $line-lswitch2case2$ + nop(); // assertFullyCovered() case 456: - nop(); // $line-lswitch2case3$ + nop(); // assertFullyCovered() default: - nop(); // $line-lswitch2default$ + nop(); // assertFullyCovered() } } private static void lookupSwitchWithoutHit() { - switch (i2()) { // $line-lswitch3$ + switch (i2()) { // assertFullyCovered(3, 1) case -123: - nop(); // $line-lswitch3case1$ + nop(); // assertNotCovered() break; case 456: - nop(); // $line-lswitch3case2$ + nop(); // assertNotCovered() break; case 789: - nop(); // $line-lswitch3case3$ + nop(); // assertNotCovered() break; default: - nop(); // $line-lswitch3default$ + nop(); // assertFullyCovered() break; } @@ -253,9 +253,9 @@ public class ControlStructuresTarget { while (true) { if (t()) { - break; // $line-executedbreak$ + break; // assertFullyCovered() } - nop(); // $line-missedafterbreak$ + nop(); // assertNotCovered() } } @@ -264,9 +264,9 @@ public class ControlStructuresTarget { for (int j = 0; j < 1; j++) { if (t()) { - continue; // $line-executedcontinue$ + continue; // assertFullyCovered() } - nop(); // $line-missedaftercontinue$ + nop(); // assertNotCovered() } } @@ -274,20 +274,20 @@ public class ControlStructuresTarget { private static void conditionalReturn() { if (t()) { - return; // $line-conditionalreturn$ + return; // assertFullyCovered() } - nop(); // $line-afterconditionalreturn$ + nop(); // assertNotCovered() } private static void implicitReturn() { - } // $line-implicitreturn$ + } // assertFullyCovered() private static void explicitReturn() { - return; // $line-explicitreturn$ + return; // assertFullyCovered() - } // $line-afterexplicitreturn$ + } // assertEmpty() } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumConstructorTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumConstructorTarget.java index 7d232bd7..d8b3e23b 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumConstructorTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumConstructorTarget.java @@ -18,26 +18,32 @@ import static org.jacoco.core.test.validation.targets.Stubs.nop; */ public class EnumConstructorTarget { - private enum ImplicitConstructor { // $line-implicitConstructor$ + /* + * Implicit constructor should be filtered. without filter next line is + * partly covered: + */ + private enum ImplicitConstructor { // assertFullyCovered() } + /* Explicit non empty constructor should not be filtered: */ private enum ExplicitNonEmptyConstructor { ; ExplicitNonEmptyConstructor() { - nop(); // $line-explicitNonEmptyConstructor$ + nop(); // assertNotCovered() } } - @SuppressWarnings("unused") + /* Explicit empty constructor should be filtered: */ private enum ExplicitEmptyConstructor { ; ExplicitEmptyConstructor() { - } // $line-explicitEmptyConstructor$ + /* without filter next line is not covered: */ + } // assertEmpty() ExplicitEmptyConstructor(Object p) { - } // $line-explicitEmptyConstructorWithParameter$ + } // assertNotCovered() } public static void main(String[] args) { diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumImplicitMethodsTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumImplicitMethodsTarget.java index ff589f78..9862d0fd 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumImplicitMethodsTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumImplicitMethodsTarget.java @@ -13,20 +13,20 @@ package org.jacoco.core.test.validation.java5.targets; import org.jacoco.core.test.validation.targets.Stubs; -public enum EnumImplicitMethodsTarget { // $line-classdef$ +public enum EnumImplicitMethodsTarget { // assertFullyCovered() - CONST(Stubs.f() ? new Object() : new Object()); // $line-const$ + CONST(Stubs.f() ? new Object() : new Object()); // assertPartlyCovered(1, 1) static { - } // $line-staticblock$ + } // assertFullyCovered() /** - * Unlike in {@link ConstructorsTarget regular classes}, even if enum has explicit - * constructor, {@code clinit} method in any case has a reference to the - * line of enum definition. + * Unlike in {@link ConstructorsTarget regular classes}, even if enum has + * explicit constructor, {@code clinit} method in any case has a reference + * to the line of enum definition. */ - EnumImplicitMethodsTarget(Object o) { // $line-super$ - } // $line-constructor$ + EnumImplicitMethodsTarget(Object o) { // assertFullyCovered() + } // assertFullyCovered() /** * This method should not be excluded from analysis unlike implicitly @@ -34,7 +34,7 @@ public enum EnumImplicitMethodsTarget { // $line-classdef$ * definition in case of javac and to the first line in case of ECJ. */ public void valueOf() { - } // $line-customValueOfMethod$ + } // assertNotCovered() /** * This method should not be excluded from analysis unlike implicitly @@ -42,7 +42,7 @@ public enum EnumImplicitMethodsTarget { // $line-classdef$ * definition in case of javac and to the first line in case of ECJ. */ public void values(Object o) { - } // $line-customValuesMethod$ + } // assertNotCovered() public static void main(String[] args) { } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumSwitchTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumSwitchTarget.java index 47447e5a..d2393bff 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumSwitchTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumSwitchTarget.java @@ -23,7 +23,7 @@ public class EnumSwitchTarget { } private static void example(E e) { - switch (e) { // $line-switch$ + switch (e) { // assertSwitch() case V1: nop("V1"); break; diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExceptionsTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExceptionsTarget.java index 1896e64d..3b4e3479 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExceptionsTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExceptionsTarget.java @@ -51,92 +51,104 @@ public class ExceptionsTarget { } } + /** + * Currently no coverage at all, as we don't see when a block aborts + * somewhere in the middle. + */ private static void implicitNullPointerException(int[] a) { - nop(); // $line-implicitNullPointerException.before$ - a[0] = 0; // $line-implicitNullPointerException.exception$ - nop(); // $line-implicitNullPointerException.after$ + nop(); // assertNotCovered() + a[0] = 0; // assertNotCovered() + nop(); // assertNotCovered() } + /** + * For each line with method invocations a extra probe is inserted. + * Therefore the lines before the exception are marked as covered. + */ private static void implicitException() { - nop(); // $line-implicitException.before$ - ex(); // $line-implicitException.exception$ - nop(); // $line-implicitException.after$ + nop(); // assertFullyCovered() + ex(); // assertNotCovered() + nop(); // assertNotCovered() } private static void explicitException() { - nop(); // $line-explicitException.before$ - throw new StubException(); // $line-explicitException.throw$ + nop(); // assertFullyCovered() + throw new StubException(); // assertFullyCovered() } private static void noExceptionTryCatch() { - nop(); // $line-noExceptionTryCatch.beforeBlock$ + nop(); // assertFullyCovered() try { - nop(); // $line-noExceptionTryCatch.tryBlock$ - } catch (StubException e) { // $line-noExceptionTryCatch.catch$ - nop(); // $line-noExceptionTryCatch.catchBlock$ - } // $line-noExceptionTryCatch.catchBlockEnd$ - } // $line-noExceptionTryCatch.afterBlock$ + nop(); // assertFullyCovered() + } catch (StubException e) { // assertCatchNoException() + nop(); // assertNotCovered() + } // assertCatchBlockEndNoException() + } // assertFullyCovered() private static void implicitExceptionTryCatch() { - nop(); // $line-implicitExceptionTryCatch.beforeBlock$ + nop(); // assertFullyCovered() try { - nop(); // $line-implicitExceptionTryCatch.before$ - ex(); // $line-implicitExceptionTryCatch.exception$ - nop(); // $line-implicitExceptionTryCatch.after$ - } catch (StubException e) { // $line-implicitExceptionTryCatch.catch$ - nop(); // $line-implicitExceptionTryCatch.catchBlock$ - } // $line-implicitExceptionTryCatch.catchBlockEnd$ - } // $line-implicitExceptionTryCatch.afterBlock$ - + nop(); // assertFullyCovered() + ex(); // assertNotCovered() + nop(); // assertNotCovered() + } catch (StubException e) { // assertCatchImplicitException() + nop(); // assertFullyCovered() + } // assertCatchBlockEndImplicitException() + } // assertFullyCovered() + + /** + * As the try/catch block is entered at one branch of the condition should + * be marked as executed + */ private static void implicitExceptionTryCatchAfterCondition() { - if (f()) { // $line-implicitExceptionTryCatchAfterCondition.condition$ + if (f()) { // assertFullyCovered(1, 1) return; } try { - ex(); // $line-implicitExceptionTryCatchAfterCondition.exception$ + ex(); // assertNotCovered() } catch (StubException e) { - nop(); // $line-implicitExceptionTryCatchAfterCondition.catchBlock$ + nop(); // assertFullyCovered() } } private static void explicitExceptionTryCatch() { - nop(); // $line-explicitExceptionTryCatch.beforeBlock$ + nop(); // assertFullyCovered() try { - nop(); // $line-explicitExceptionTryCatch.before$ - throw new StubException(); // $line-explicitExceptionTryCatch.throw$ - } catch (StubException e) { // $line-explicitExceptionTryCatch.catch$ - nop(); // $line-explicitExceptionTryCatch.catchBlock$ - } // $line-explicitExceptionTryCatch.catchBlockEnd$ - } // $line-explicitExceptionTryCatch.afterBlock$ + nop(); // assertFullyCovered() + throw new StubException(); // assertFullyCovered() + } catch (StubException e) { // assertFullyCovered() + nop(); // assertFullyCovered() + } // assertEmpty() + } // assertFullyCovered() private static void noExceptionFinally() { - nop(); // $line-noExceptionFinally.beforeBlock$ + nop(); // assertFullyCovered() try { - nop(); // $line-noExceptionFinally.tryBlock$ - } finally { // $line-noExceptionFinally.finally$ - nop(); // $line-noExceptionFinally.finallyBlock$ - } // $line-noExceptionFinally.finallyBlockEnd$ - } // $line-noExceptionFinally.afterBlock$ + nop(); // assertFullyCovered() + } finally { // assertFinally() + nop(); // assertFullyCovered() + } // assertEmpty() + } // assertFullyCovered() private static void implicitExceptionFinally() { - nop(); // $line-implicitExceptionFinally.beforeBlock$ + nop(); // assertFullyCovered() try { - nop(); // $line-implicitExceptionFinally.before$ - ex(); // $line-implicitExceptionFinally.exception$ - nop(); // $line-implicitExceptionFinally.after$ - } finally { // $line-implicitExceptionFinally.finally$ - nop(); // $line-implicitExceptionFinally.finallyBlock$ - } // $line-implicitExceptionFinally.finallyBlockEnd$ - } // $line-implicitExceptionFinally.afterBlock$ + nop(); // assertFullyCovered() + ex(); // assertNotCovered() + nop(); // assertNotCovered() + } finally { // assertFinallyImplicitException() + nop(); // assertFullyCovered() + } // assertEmpty() + } // assertNotCovered() private static void explicitExceptionFinally() { - nop(); // $line-explicitExceptionFinally.beforeBlock$ + nop(); // assertFullyCovered() try { - nop(); // $line-explicitExceptionFinally.before$ - throw new StubException(); // $line-explicitExceptionFinally.throw$ - } finally { // $line-explicitExceptionFinally.finally$ - nop(); // $line-explicitExceptionFinally.finallyBlock$ - } // $line-explicitExceptionFinally.finallyBlockEnd$ - } // $line-explicitExceptionFinally.afterBlock$ + nop(); // assertFullyCovered() + throw new StubException(); // assertFullyCovered() + } finally { // assertFinally() + nop(); // assertFullyCovered() + } // assertBlockEndImplicitException() + } // assertEmpty() } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExplicitInitialFrameTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExplicitInitialFrameTarget.java index bc089fc7..475e01fe 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExplicitInitialFrameTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExplicitInitialFrameTarget.java @@ -23,7 +23,7 @@ public class ExplicitInitialFrameTarget { public static void main(String[] args) { do { - nop(); // $line-dowhilebody$ + nop(); // assertFullyCovered() } while (f()); } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FieldInitializationInTwoConstructorsTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FieldInitializationInTwoConstructorsTarget.java index 58bf6890..4c8ec8fc 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FieldInitializationInTwoConstructorsTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FieldInitializationInTwoConstructorsTarget.java @@ -17,15 +17,15 @@ package org.jacoco.core.test.validation.java5.targets; */ public class FieldInitializationInTwoConstructorsTarget { - Object field1 = null; // $line-field1$ + Object field1 = null; // assertPartlyCovered() - int field2 = 123; // $line-field2$ + int field2 = 123; // assertPartlyCovered() public FieldInitializationInTwoConstructorsTarget() { - } // $line-constr1$ + } // assertFullyCovered() public FieldInitializationInTwoConstructorsTarget(String arg) { - } // $line-constr2$ + } // assertNotCovered() public static void main(String[] args) { new FieldInitializationInTwoConstructorsTarget(); diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FinallyTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FinallyTarget.java index 2c317e95..3010786e 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FinallyTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FinallyTarget.java @@ -35,11 +35,11 @@ public class FinallyTarget { Object in = null; try { in = open(t); - } finally { // $line-example.0$ - if (in != null) { // $line-example.1$ - nop(); // $line-example.2$ - } // $line-example.3$ - } // $line-example.4$ + } finally { // assertFinally() tag("example.0") + if (in != null) { // assertFullyCovered(0, 2) + nop(); // assertFullyCovered() tag("example.2") + } // assertEmpty() + } // assertEmpty() } private static Object open(boolean t) { @@ -47,80 +47,93 @@ public class FinallyTarget { return new Object(); } + /** + * GOTO instructions at the end of duplicates of finally block might have + * line number of a last instruction of finally block and hence lead to + * unexpected coverage results, like for example in case of ECJ for + * {@link FinallyTarget#catchNotExecuted()}, + * {@link FinallyTarget#emptyCatch()}. So we decided to ignore them, even if + * they can correspond to a real break statement. + *

    + * See also JDK-8180141 and + * JDK-7008643. + */ private static void breakStatement() { - for (int i = 0; i < 1; i++) { // $line-breakStatement.for$ + for (int i = 0; i < 1; i++) { // tag("breakStatement.for") try { if (f()) { - break; // $line-breakStatement$ + break; // assertEmpty() tag("breakStatement") } } finally { - nop("finally"); // $line-breakStatement.1$ - } // $line-breakStatement.2$ + nop("finally"); // assertFullyCovered() tag("breakStatement.1") + } // assertEmpty() tag("breakStatement.2") } } private static void catchNotExecuted() { try { nop("try"); - } catch (Exception e) { // $line-catchNotExecuted$ - nop("catch"); // $line-catchNotExecuted.catch$ - } finally { // $line-catchNotExecuted.0$ - nop("finally"); // $line-catchNotExecuted.1$ - } // $line-catchNotExecuted.2$ + } catch (Exception e) { // tag("catchNotExecuted") + nop("catch"); // assertNotCovered() + } finally { // assertEmpty() + nop("finally"); // assertFullyCovered() tag("catchNotExecuted.1") + } // assertEmpty() tag("catchNotExecuted.2") } private static void emptyCatch() { try { nop("try"); - } catch (Exception e) { // $line-emptyCatch$ - // empty - } finally { // $line-emptyCatch.0$ - nop("finally"); // $line-emptyCatch.1$ - } // $line-emptyCatch.2$ + } catch (Exception e) { // tag("emptyCatch") + /* empty */ + } finally { // assertEmpty() + nop("finally"); // assertFullyCovered() tag("emptyCatch.1") + } // assertEmpty() tag("emptyCatch.2") } private static void twoRegions() { try { - // jump to another region associated with same handler: - if (t()) { // $line-twoRegions.if$ - nop(); // $line-twoRegions.region.1$ - return; // $line-twoRegions.return.1$ + /* jump to another region associated with same handler: */ + if (t()) { // assertFullyCovered(1, 1) + nop(); // assertFullyCovered() + return; // assertTwoRegionsReturn1() } else { - nop(); // $line-twoRegions.region.2$ - return; // $line-twoRegions.return.2$ + nop(); // assertNotCovered() + return; // assertTwoRegionsReturn2() } - } finally { // $line-twoRegions.0$ - nop(); // $line-twoRegions.1$ - } // $line-twoRegions.2$ + } finally { // assertEmpty() + nop(); // assertTwoRegions1() + } // assertEmpty() } private static void nested() { try { nop(); - } finally { // $line-nested.0$ - try { // $line-nested.1$ - nop(); // $line-nested.2$ - } finally { // $line-nested.3$ - nop(); // $line-nested.4$ - } // $line-nested.5$ - } // $line-nested.6$ + } finally { // assertFinally() tag("nested.0") + try { // assertEmpty() + nop(); // assertFullyCovered() + } finally { // assertFinally() tag("nested.3") + nop(); // assertFullyCovered() + } // assertEmpty() tag("nested.5") + } // assertEmpty() tag("nested.6") } private static void emptyTry() { try { - // empty - } finally { // $line-emptyTry.0$ - nop(); // $line-emptyTry.1$ - } // $line-emptyTry.2$ + /* empty */ + } finally { // assertEmpty() + nop(); // assertEmptyTry1() + } // assertEmptyTry2() tag("emptyTry.2") } @SuppressWarnings("finally") private static void alwaysCompletesAbruptly() { try { nop(); - } finally { // $line-alwaysCompletesAbruptly.0$ - return; // $line-alwaysCompletesAbruptly.1$ - } // $line-alwaysCompletesAbruptly.2$ + } finally { // assertAlwaysCompletesAbruptly0()tag("alwaysCompletesAbruptly.0") + return; // assertAlwaysCompletesAbruptly1() + } // assertEmpty() } public static void main(String[] args) { diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ImplicitFieldInitializationTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ImplicitFieldInitializationTarget.java index 6ddf8cbd..1cdb75e3 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ImplicitFieldInitializationTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ImplicitFieldInitializationTarget.java @@ -14,15 +14,15 @@ package org.jacoco.core.test.validation.java5.targets; /** * This test target has instance members with implicit initializers. */ -public class ImplicitFieldInitializationTarget { // $line-classdef$ +public class ImplicitFieldInitializationTarget { // assertFullyCovered() - Object field1; // $line-field1$ + Object field1; // assertEmpty() - Object field2 = this; // $line-field2$ + Object field2 = this; // assertFullyCovered() - int field3; // $line-field3$ + int field3; // assertEmpty() - int field4 = 2000; // $line-field4$ + int field4 = 2000; // assertFullyCovered() public static void main(String[] args) { new ImplicitFieldInitializationTarget(); diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/InterfaceClassInitializerTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/InterfaceClassInitializerTarget.java index 2debf6bd..efcd44ee 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/InterfaceClassInitializerTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/InterfaceClassInitializerTarget.java @@ -18,16 +18,16 @@ import static org.jacoco.core.test.validation.targets.Stubs.i1; */ public interface InterfaceClassInitializerTarget { - // No code required to initialize these fields: + /* No code required to initialize these fields: */ - static final int CONST1 = 12345; // $line-const1$ + static final int CONST1 = 12345; // assertEmpty() - static final String CONST2 = "const"; // $line-const2$ + static final String CONST2 = "const"; // assertEmpty() - // These fields are initialized within + /* These fields are initialized within */ - static final int CONST3 = i1(); // $line-const3$ + static final int CONST3 = i1(); // assertFullyCovered() - static final Object CONST4 = new Object(); // $line-const4$ + static final Object CONST4 = new Object(); // assertFullyCovered() } diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SynchronizedTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SynchronizedTarget.java index 5bea5758..a8055d69 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SynchronizedTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SynchronizedTarget.java @@ -24,23 +24,24 @@ public class SynchronizedTarget { private static final Object lock = new Object(); private static void normal() { - nop(); // $line-before$ - synchronized (lock) { // $line-monitorEnter$ - nop(); // $line-body$ - } // $line-monitorExit$ - nop(); // $line-after$ + nop(); // assertFullyCovered() + /* when compiled with ECJ next line covered partly without filter: */ + synchronized (lock) { // assertFullyCovered() + nop(); // assertFullyCovered() + } // assertMonitorExit() + nop(); // assertFullyCovered() } private static void explicitException() { - synchronized (lock) { // $line-explicitException.monitorEnter$ - throw new StubException(); // $line-explicitException.exception$ - } // $line-explicitException.monitorExit$ + synchronized (lock) { // assertFullyCovered() + throw new StubException(); // assertFullyCovered() + } // assertEmpty() } private static void implicitException() { - synchronized (lock) { // $line-implicitException.monitorEnter$ - ex(); // $line-implicitException.exception$ - } // $line-implicitException.monitorExit$ + synchronized (lock) { // assertMonitorEnterImplicitException() + ex(); // assertNotCovered() + } // assertMonitorExitImplicitException() } public static void main(String[] args) { diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SyntheticTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SyntheticTarget.java index 79f41b10..14ae3c09 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SyntheticTarget.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SyntheticTarget.java @@ -14,9 +14,9 @@ package org.jacoco.core.test.validation.java5.targets; /** * This test target results in synthetic methods. */ -public class SyntheticTarget { // $line-classdef$ +public class SyntheticTarget { // assertEmpty() - private static int counter; // $line-field$ + private static int counter; // assertEmpty() /** * {@link org.jacoco.core.test.validation.java5.targets.ConstructorsTarget @@ -27,7 +27,7 @@ public class SyntheticTarget { // $line-classdef$ private SyntheticTarget() { } - static class Inner extends SyntheticTarget { // $line-inner.classdef$ + static class Inner extends SyntheticTarget { // assertEmpty() Inner() { } diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java index 04fe6f5d..f291c174 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java @@ -11,10 +11,9 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java7; -import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.Source.Line; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java7.targets.StringSwitchTarget; -import org.junit.Test; /** * Test of filtering of a bytecode that is generated for a String in switch @@ -26,41 +25,22 @@ public class StringSwitchTest extends ValidationTestBase { super(StringSwitchTarget.class); } - /** - * {@link StringSwitchTarget#covered(Object)} - */ - @Test - public void covered() { + public void assertSwitchCovered(final Line line) { if (isJDKCompiler) { - assertLine("covered.switch", ICounter.FULLY_COVERED, 0, 4); + assertFullyCovered(line, 0, 4); } else { - assertLine("covered.switch", ICounter.PARTLY_COVERED, 2, 7); + // Filtering for ECJ not yet implemented: + assertPartlyCovered(line, 2, 7); } - assertLine("covered.case1", ICounter.FULLY_COVERED); - assertLine("covered.case2", ICounter.FULLY_COVERED); - assertLine("covered.case3", ICounter.FULLY_COVERED); - assertLine("covered.default", ICounter.FULLY_COVERED); } - /** - * {@link StringSwitchTarget#notCovered(Object)} - */ - @Test - public void notCovered() { - assertLine("notCovered", ICounter.NOT_COVERED, isJDKCompiler ? 4 : 9, - 0); - } - - /** - * {@link StringSwitchTarget#handwritten(String)} - */ - @Test - public void handwritten() { - assertLine("handwritten.firstSwitch", ICounter.FULLY_COVERED, 2, 1); - assertLine("handwritten.ignored", ICounter.FULLY_COVERED, 1, 1); - assertLine("handwritten.secondSwitch", ICounter.FULLY_COVERED, 3, 1); - assertLine("handwritten.case1", ICounter.FULLY_COVERED); - assertLine("handwritten.case2", ICounter.NOT_COVERED); + public void assertSwitchNotCovered(final Line line) { + if (isJDKCompiler) { + assertNotCovered(line, 4, 0); + } else { + // Filtering for ECJ not yet implemented: + assertNotCovered(line, 9, 0); + } } } diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java index 9eb02571..0078258a 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/TryWithResourcesTest.java @@ -11,10 +11,9 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java7; -import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.Source.Line; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java7.targets.TryWithResourcesTarget; -import org.junit.Test; /** * Test of filtering of a bytecode that is generated for a try-with-resources @@ -26,192 +25,60 @@ public class TryWithResourcesTest extends ValidationTestBase { super(TryWithResourcesTarget.class); } - /** - * {@link TryWithResourcesTarget#test()} - */ - @Test - public void test() { - assertLine("test.before", ICounter.FULLY_COVERED); - // without filter next line covered partly: + public void assertTry(final Line line) { + // without filter this line is covered partly: if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("test.try", ICounter.FULLY_COVERED); + assertFullyCovered(line); } else { - assertLine("test.try", ICounter.EMPTY); + assertEmpty(line); } - assertLine("test.open1", ICounter.FULLY_COVERED); - assertLine("test.open2", ICounter.FULLY_COVERED); - assertLine("test.open3", ICounter.FULLY_COVERED); - assertLine("test.body", ICounter.FULLY_COVERED); - // without filter next line has branches: - assertLine("test.close", ICounter.EMPTY); - assertLine("test.catch", ICounter.NOT_COVERED); - assertLine("test.finally", ICounter.FULLY_COVERED); - } - - /** - * {@link TryWithResourcesTarget#test2()} - */ - @Test - public void test2() { - assertLine("test2.before", ICounter.FULLY_COVERED); - // without filter next line covered partly: - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("test2.try", ICounter.FULLY_COVERED); - } else { - assertLine("test2.try", ICounter.EMPTY); - } - assertLine("test2.open1", ICounter.FULLY_COVERED); - assertLine("test2.open2", ICounter.FULLY_COVERED); - assertLine("test2.open3", ICounter.FULLY_COVERED); - assertLine("test2.body", ICounter.FULLY_COVERED); - // without filter next line has branches: - assertLine("test2.close", ICounter.EMPTY); - assertLine("test2.catch", ICounter.NOT_COVERED); - assertLine("test2.finally", ICounter.FULLY_COVERED); - assertLine("test2.after", ICounter.FULLY_COVERED); } - /** - * {@link TryWithResourcesTarget#returnInBody()} - */ - @Test - public void returnInBody() { - // without filter next line covered partly: - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("returnInBody.try", ICounter.FULLY_COVERED); - } else { - assertLine("returnInBody.try", ICounter.EMPTY); - } - assertLine("returnInBody.open", ICounter.FULLY_COVERED); - + public void assertReturnInBodyClose(final Line line) { // without filter next line has branches: if (isJDKCompiler) { // https://bugs.openjdk.java.net/browse/JDK-8134759 // javac 7 and 8 up to 8u92 are affected if (JAVA_VERSION.isBefore("1.8.0_92")) { - assertLine("returnInBody.close", ICounter.FULLY_COVERED); + assertFullyCovered(line); } else { - assertLine("returnInBody.close", ICounter.EMPTY); + assertEmpty(line); } } else { - assertLine("returnInBody.close", ICounter.EMPTY); + assertEmpty(line); } - - assertLine("returnInBody.return", ICounter.FULLY_COVERED); } - /** - * {@link TryWithResourcesTarget#nested()} - */ - @Test - public void nested() { - // without filter next line covered partly: - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("nested.try1", ICounter.FULLY_COVERED); - } else { - assertLine("nested.try1", ICounter.EMPTY); - } - assertLine("nested.open1", ICounter.FULLY_COVERED); - assertLine("nested.catch1", ICounter.NOT_COVERED); - - // without filter next line covered partly: - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("nested.try2", ICounter.FULLY_COVERED); - } else { - assertLine("nested.try2", ICounter.EMPTY); - } - assertLine("nested.body", ICounter.FULLY_COVERED); - assertLine("nested.catch2", ICounter.NOT_COVERED); - assertLine("nested.finally2", ICounter.FULLY_COVERED); - - // next lines not covered on exceptional path: - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("nested.try3", ICounter.FULLY_COVERED); - } else { - assertLine("nested.try3", ICounter.EMPTY); - } - assertLine("nested.open3", ICounter.FULLY_COVERED); - assertLine("nested.body3", ICounter.FULLY_COVERED); - assertLine("nested.catch3", ICounter.NOT_COVERED); - assertLine("nested.finally3", ICounter.FULLY_COVERED); - - // without filter next lines have branches: - assertLine("nested.close3", ICounter.EMPTY); - assertLine("nested.close2", ICounter.EMPTY); - assertLine("nested.close1", ICounter.EMPTY); - } - - /** - * {@link TryWithResourcesTarget#returnInCatch()} - */ - @Test - public void returnInCatch() { - // without filter next line covered partly: - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("returnInCatch.try1", ICounter.FULLY_COVERED); - } else { - assertLine("returnInCatch.try1", ICounter.EMPTY); - } - assertLine("returnInCatch.open", ICounter.FULLY_COVERED); - assertLine("returnInCatch.finally1", ICounter.PARTLY_COVERED, 1, 1); - // without filter next line has branches: - assertLine("returnInCatch.close", ICounter.EMPTY); - - assertLine("returnInCatch.try2", ICounter.EMPTY); - assertLine("returnInCatch.finally2", ICounter.PARTLY_COVERED, 1, 1); - } - - /* - * Corner cases - */ - - /** - * {@link TryWithResourcesTarget#handwritten()} - */ - @Test - public void handwritten() { + public void assertHandwritten(final Line line) { if (isJDKCompiler) { - assertLine("handwritten", /* partly when ECJ: */ICounter.EMPTY); + assertEmpty(line); + } else { + assertFullyCovered(line, 1, 1); } } - /** - * {@link TryWithResourcesTarget#empty()} - */ - @Test - public void empty() { - if (!isJDKCompiler || JAVA_VERSION.isBefore("11")) { - assertLine("empty.try", ICounter.FULLY_COVERED); - } else { - assertLine("empty.try", ICounter.EMPTY); - } - assertLine("empty.open", ICounter.FULLY_COVERED); + public void assertEmptyClose(final Line line) { if (!isJDKCompiler) { - assertLine("empty.close", ICounter.PARTLY_COVERED, 7, 1); + assertPartlyCovered(line, 7, 1); } else if (JAVA_VERSION.isBefore("8")) { - assertLine("empty.close", ICounter.PARTLY_COVERED, 6, 2); + assertPartlyCovered(line, 6, 2); } else if (JAVA_VERSION.isBefore("9")) { - assertLine("empty.close", ICounter.PARTLY_COVERED, 2, 2); + assertPartlyCovered(line, 2, 2); } else { - assertLine("empty.close", ICounter.FULLY_COVERED); + assertFullyCovered(line); } } - /** - * {@link TryWithResourcesTarget#throwInBody()} - */ - @Test - public void throwInBody() { + public void assertThrowInBodyClose(final Line line) { // not filtered - assertLine("throwInBody.try", ICounter.NOT_COVERED); - if (!isJDKCompiler){ - assertLine("throwInBody.close", ICounter.NOT_COVERED, 6, 0); + if (!isJDKCompiler) { + assertNotCovered(line, 6, 0); } else if (JAVA_VERSION.isBefore("9")) { - assertLine("throwInBody.close", ICounter.NOT_COVERED, 4, 0); + assertNotCovered(line, 4, 0); } else if (JAVA_VERSION.isBefore("11")) { - assertLine("throwInBody.close", ICounter.NOT_COVERED); + assertNotCovered(line); } else { - assertLine("throwInBody.close", ICounter.EMPTY); + assertEmpty(line); } } diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java index 8e182a4f..cdbf9f51 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java @@ -19,24 +19,24 @@ import static org.jacoco.core.test.validation.targets.Stubs.nop; public class StringSwitchTarget { private static void covered(Object s) { - switch (String.valueOf(s)) { // $line-covered.switch$ + switch (String.valueOf(s)) { // assertSwitchCovered() case "a": - nop("case a"); // $line-covered.case1$ + nop("case a"); // assertFullyCovered() break; case "b": - nop("case b"); // $line-covered.case2$ + nop("case b"); // assertFullyCovered() break; case "\0a": - nop("case \0a"); // $line-covered.case3$ + nop("case \0a"); // assertFullyCovered() break; default: - nop("case default"); // $line-covered.default$ + nop("case default"); // assertFullyCovered() break; } } private static void notCovered(Object s) { - switch (String.valueOf(s)) { // $line-notCovered$ + switch (String.valueOf(s)) { // assertSwitchNotCovered() case "a": nop("case a"); break; @@ -54,9 +54,9 @@ public class StringSwitchTarget { private static void handwritten(String s) { int c = -1; - switch (s.hashCode()) { // $line-handwritten.firstSwitch$ + switch (s.hashCode()) { // assertFullyCovered(2, 1) case 97: - if ("a".equals(s)) { // $line-handwritten.ignored$ + if ("a".equals(s)) { // assertFullyCovered(1, 1) c = 0; } else if ("\0a".equals(s)) { c = 1; @@ -68,12 +68,12 @@ public class StringSwitchTarget { } break; } - switch (c) { // $line-handwritten.secondSwitch$ + switch (c) { // assertFullyCovered(3, 1) case 0: - nop("case a"); // $line-handwritten.case1$ + nop("case a"); // assertFullyCovered() break; case 1: - nop("case \0a"); // $line-handwritten.case2$ + nop("case \0a"); // assertNotCovered() break; case 2: nop("case b"); diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/TryWithResourcesTarget.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/TryWithResourcesTarget.java index 08d9cdab..cdb5b06d 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/TryWithResourcesTarget.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/TryWithResourcesTarget.java @@ -34,77 +34,79 @@ public class TryWithResourcesTarget { * of resource. */ private static Object test() throws Exception { - nop(); // $line-test.before$ - try ( // $line-test.try$ - Resource r1 = new Resource(); // $line-test.open1$ - Closeable r2 = new Resource(); // $line-test.open2$ - AutoCloseable r3 = new Resource() // $line-test.open3$ + nop(); // assertFullyCovered() + try ( // assertTry() + Resource r1 = new Resource(); // assertFullyCovered() + Closeable r2 = new Resource(); // assertFullyCovered() + AutoCloseable r3 = new Resource() // assertFullyCovered() ) { - return read(r1, r2, r3); // $line-test.body$ - } // $line-test.close$ + return read(r1, r2, r3); // assertFullyCovered() + /* without filter next line has branches: */ + } // assertEmpty() catch (Exception e) { - nop(); // $line-test.catch$ + nop(); // assertNotCovered() throw e; } finally { - nop(); // $line-test.finally$ + nop(); // assertFullyCovered() } } private static void test2() throws Exception { - nop(); // $line-test2.before$ - try ( // $line-test2.try$ - Resource r1 = new Resource(); // $line-test2.open1$ - Closeable r2 = new Resource(); // $line-test2.open2$ - AutoCloseable r3 = new Resource() // $line-test2.open3$ + nop(); // assertFullyCovered() + try ( // assertTry() + Resource r1 = new Resource(); // assertFullyCovered() + Closeable r2 = new Resource(); // assertFullyCovered() + AutoCloseable r3 = new Resource() // assertFullyCovered() ) { - read(r1, r2, r3); // $line-test2.body$ - } // $line-test2.close$ + read(r1, r2, r3); // assertFullyCovered() + /* without filter next line has branches: */ + } // assertEmpty() catch (Exception e) { - nop(); // $line-test2.catch$ + nop(); // assertNotCovered() } finally { - nop(); // $line-test2.finally$ + nop(); // assertFullyCovered() } - nop(); // $line-test2.after$ + nop(); // assertFullyCovered() } private static Object returnInBody() throws IOException { - try ( // $line-returnInBody.try$ - Closeable r = new Resource() // $line-returnInBody.open$ + try ( // assertTry() + Closeable r = new Resource() // assertFullyCovered() ) { - return read(r); // $line-returnInBody.return$ - } // $line-returnInBody.close$ + return read(r); // assertFullyCovered() + } // assertReturnInBodyClose() } private static void nested() { - try ( // $line-nested.try1$ - Resource r1 = new Resource() // $line-nested.open1$ + try ( // assertTry() + Resource r1 = new Resource() // assertFullyCovered() ) { - try ( // $line-nested.try2$ - Resource r2 = new Resource() // $line-nested.open2$ + try ( // assertTry() + Resource r2 = new Resource() // assertFullyCovered() ) { - nop(r1.toString() + r2.toString()); // $line-nested.body$ - } // $line-nested.close2$ + nop(r1.toString() + r2.toString()); // assertFullyCovered() + } // assertEmpty() catch (Exception e) { - nop(); // $line-nested.catch2$ + nop(); // assertNotCovered() } finally { - nop(); // $line-nested.finally2$ + nop(); // assertFullyCovered() } - } // $line-nested.close1$ + } // assertEmpty() catch (Exception e) { - nop(); // $line-nested.catch1$ + nop(); // assertNotCovered() } finally { - try ( // $line-nested.try3$ - Resource r2 = new Resource() // $line-nested.open3$ + try ( // assertTry() + Resource r2 = new Resource() // assertFullyCovered() ) { - nop(r2); // $line-nested.body3$ - } // $line-nested.close3$ + nop(r2); // assertFullyCovered() + } // assertEmpty() catch (Exception e) { - nop(); // $line-nested.catch3$ + nop(); // assertNotCovered() } finally { - nop(); // $line-nested.finally3$ + nop(); // assertFullyCovered() } } @@ -117,23 +119,24 @@ public class TryWithResourcesTarget { * happens without it. */ private static Object returnInCatch() { - try ( // $line-returnInCatch.try1$ - Resource r = new Resource() // $line-returnInCatch.open$ + try ( // assertTry() + Resource r = new Resource() // assertFullyCovered() ) { read(r); - } // $line-returnInCatch.close$ + /* without filter next line has branches: */ + } // assertEmpty() catch (Exception e) { return null; } finally { - nop(!f()); // $line-returnInCatch.finally1$ + nop(!f()); // assertPartlyCovered(1, 1) } - try { // $line-returnInCatch.try2$ + try { // assertEmpty() read(new Resource()); } catch (Exception e) { return null; } finally { - nop(!f()); // $line-returnInCatch.finally2$ + nop(!f()); // assertPartlyCovered(1, 1) } return null; @@ -147,27 +150,15 @@ public class TryWithResourcesTarget { return r1.toString(); } - public static void main(String[] args) throws Exception { - test(); - test2(); - returnInBody(); - nested(); - - returnInCatch(); - - empty(); - handwritten(); - } - /* * Corner cases */ private static void empty() throws Exception { - try ( // $line-empty.try$ - Closeable r = new Resource() // $line-empty.open$ + try ( // assertTry() + Closeable r = new Resource() // assertFullyCovered() ) { - } // $line-empty.close$ + } // assertEmptyClose() } private static void handwritten() throws IOException { @@ -179,7 +170,7 @@ public class TryWithResourcesTarget { primaryExc = t; throw t; } finally { - if (r != null) { // $line-handwritten$ + if (r != null) { // assertHandwritten() if (primaryExc != null) { try { r.close(); @@ -194,11 +185,23 @@ public class TryWithResourcesTarget { } private static void throwInBody() throws IOException { - try ( // $line-throwInBody.try$ + try ( // assertNotCovered() Closeable r = new Resource()) { nop(r); throw new RuntimeException(); - } // $line-throwInBody.close$ + } // assertThrowInBodyClose() + } + + public static void main(String[] args) throws Exception { + test(); + test2(); + returnInBody(); + nested(); + + returnInCatch(); + + empty(); + handwritten(); } } diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/AnnotationOnLocalVariableTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/AnnotationOnLocalVariableTest.java index 0b9a3c1d..e1f88bf8 100644 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/AnnotationOnLocalVariableTest.java +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/AnnotationOnLocalVariableTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java8; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java8.targets.AnnotationOnLocalVariableTarget; -import org.junit.Test; /** * Test of ASM bug @@ -26,11 +24,4 @@ public class AnnotationOnLocalVariableTest extends ValidationTestBase { super(AnnotationOnLocalVariableTarget.class); } - @Test - public void testCoverageResult() { - - assertLine("var", ICounter.FULLY_COVERED); - - } - } diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/BadCycleInterfaceTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/BadCycleInterfaceTest.java index b9f0a469..b1591b34 100644 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/BadCycleInterfaceTest.java +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/BadCycleInterfaceTest.java @@ -11,7 +11,7 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java8; -import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.Source.Line; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java8.targets.BadCycleInterfaceTarget; import org.junit.Test; @@ -26,25 +26,41 @@ public class BadCycleInterfaceTest extends ValidationTestBase { } @Test - public void test() throws Exception { + public void method_execution_sequence() throws Exception { + if (JAVA_VERSION.isBefore("1.8.0_152")) { + assertLogEvents("baseclinit", "childdefaultmethod", "childclinit", + "childstaticmethod"); + } else { + assertLogEvents("childclinit", "childstaticmethod"); + } + } + + public void assertBaseClInit(final Line line) { if (JAVA_VERSION.isBefore("1.8.0_152")) { // Incorrect interpetation of JVMS 5.5 in JDK 8 causes a default // method to be called before the static initializer of an interface // (see JDK-8098557 and JDK-8164302): - assertLine("baseclinit", ICounter.FULLY_COVERED); - assertLine("childdefault", ICounter.FULLY_COVERED); + assertFullyCovered(line); - assertLogEvents("baseclinit", "childdefaultmethod", "childclinit", - "childstaticmethod"); } else { // This shouldn't happen with JDK 9 (see also JDK-8043275) // and starting with JDK 8u152 (see JDK-8167607): - assertLine("baseclinit", ICounter.EMPTY); - assertLine("childdefault", ICounter.NOT_COVERED); - assertLogEvents("childclinit", "childstaticmethod"); + assertEmpty(line); + } + } + + public void assertChildDefault(final Line line) throws Exception { + if (JAVA_VERSION.isBefore("1.8.0_152")) { + // Incorrect interpetation of JVMS 5.5 in JDK 8 causes a default + // method to be called before the static initializer of an interface + // (see JDK-8098557 and JDK-8164302): + assertFullyCovered(line); + + } else { + // This shouldn't happen with JDK 9 (see also JDK-8043275) + // and starting with JDK 8u152 (see JDK-8167607): + assertNotCovered(line); } - assertLine("childclinit", ICounter.FULLY_COVERED); - assertLine("childstatic", ICounter.FULLY_COVERED); } } diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceDefaultMethodsTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceDefaultMethodsTest.java index 4701e27f..2317d7c5 100644 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceDefaultMethodsTest.java +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceDefaultMethodsTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java8; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java8.targets.InterfaceDefaultMethodsTarget; -import org.junit.Test; /** * Tests of static initializer and default methods in interfaces. @@ -25,11 +23,4 @@ public class InterfaceDefaultMethodsTest extends ValidationTestBase { super(InterfaceDefaultMethodsTarget.class); } - @Test - public void testCoverageResult() { - assertLine("clinit", ICounter.FULLY_COVERED); - assertLine("m1", ICounter.FULLY_COVERED); - assertLine("m2", ICounter.NOT_COVERED); - } - } diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceOnlyDefaultMethodsTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceOnlyDefaultMethodsTest.java index e0ffc723..07fc9f51 100644 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceOnlyDefaultMethodsTest.java +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/InterfaceOnlyDefaultMethodsTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java8; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java8.targets.InterfaceOnlyDefaultMethodsTarget; -import org.junit.Test; /** * Tests of default methods in interfaces. @@ -25,10 +23,4 @@ public class InterfaceOnlyDefaultMethodsTest extends ValidationTestBase { super(InterfaceOnlyDefaultMethodsTarget.class); } - @Test - public void testCoverageResult() { - assertLine("m1", ICounter.FULLY_COVERED); - assertLine("m2", ICounter.NOT_COVERED); - } - } diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTest.java index 1d97a3dc..bc137c91 100644 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTest.java +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaExpressionsTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java8; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java8.targets.LambdaExpressionsTarget; -import org.junit.Test; /** * Tests for different lambda expressions. @@ -25,13 +23,4 @@ public class LambdaExpressionsTest extends ValidationTestBase { super(LambdaExpressionsTarget.class); } - @Test - public void testCoverageResult() { - - // Coverage of lambda bodies - assertLine("executedlambdabody", ICounter.FULLY_COVERED); - assertLine("notexecutedlambdabody", ICounter.NOT_COVERED); - - } - } diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaInInterfaceTest.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaInInterfaceTest.java index 4d4d184f..7888d610 100644 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaInInterfaceTest.java +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/LambdaInInterfaceTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java8; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java8.targets.LambdaInInterfaceTarget; -import org.junit.Test; /** * Tests a constant with a lambda value in an interface. @@ -30,12 +28,4 @@ public class LambdaInInterfaceTest extends ValidationTestBase { ((Runnable) targetClass.getField("RUN").get(null)).run(); } - @Test - public void testCoverageResult() { - - // Coverage of lambda body - assertLine("lambdabody", ICounter.FULLY_COVERED); - - } - } diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/AnnotationOnLocalVariableTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/AnnotationOnLocalVariableTarget.java index b2d6acbf..315d6c90 100644 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/AnnotationOnLocalVariableTarget.java +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/AnnotationOnLocalVariableTarget.java @@ -34,7 +34,7 @@ public class AnnotationOnLocalVariableTarget { public static void main(String[] args) { @NonNull - Object o = legacy(); // $line-var$ + Object o = legacy(); // assertFullyCovered() } } diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/BadCycleInterfaceTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/BadCycleInterfaceTarget.java index bac69f81..1f1215ec 100644 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/BadCycleInterfaceTarget.java +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/BadCycleInterfaceTarget.java @@ -18,7 +18,7 @@ public class BadCycleInterfaceTarget { public interface Base { static final Object BASE_CONST = new Child() { { - Stubs.logEvent("baseclinit"); // $line-baseclinit$ + Stubs.logEvent("baseclinit"); // assertBaseClInit() } }.childDefaultMethod(); @@ -29,17 +29,17 @@ public class BadCycleInterfaceTarget { public interface Child extends Base { static final Object CHILD_CONST = new Object() { { - Stubs.logEvent("childclinit"); // $line-childclinit$ + Stubs.logEvent("childclinit"); // assertFullyCovered() } }; default Object childDefaultMethod() { - Stubs.logEvent("childdefaultmethod"); // $line-childdefault$ + Stubs.logEvent("childdefaultmethod"); // assertChildDefault() return null; } static void childStaticMethod() { - Stubs.logEvent("childstaticmethod"); // $line-childstatic$ + Stubs.logEvent("childstaticmethod"); // assertFullyCovered() } } diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceDefaultMethodsTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceDefaultMethodsTarget.java index 2c8a13db..b7390f73 100644 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceDefaultMethodsTarget.java +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceDefaultMethodsTarget.java @@ -14,18 +14,19 @@ package org.jacoco.core.test.validation.java8.targets; import static org.jacoco.core.test.validation.targets.Stubs.i1; /** - * This test target is an interface with a class initializer and default methods. + * This test target is an interface with a class initializer and default + * methods. */ public interface InterfaceDefaultMethodsTarget { - public static final int CONST = i1(); // $line-clinit$ + public static final int CONST = i1(); // assertFullyCovered() default void m1() { - return; // $line-m1$ + return; // assertFullyCovered() } default void m2() { - return; // $line-m2$ + return; // assertNotCovered() } public class Impl implements InterfaceDefaultMethodsTarget { @@ -34,7 +35,7 @@ public interface InterfaceDefaultMethodsTarget { m1(); } } - + public static void main(String[] args) { new Impl(); } diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceOnlyDefaultMethodsTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceOnlyDefaultMethodsTarget.java index dd96e0ad..6ae4c5cb 100644 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceOnlyDefaultMethodsTarget.java +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/InterfaceOnlyDefaultMethodsTarget.java @@ -16,14 +16,14 @@ package org.jacoco.core.test.validation.java8.targets; */ public interface InterfaceOnlyDefaultMethodsTarget { - // no , only default methods: + /* no , only default methods: */ default void m1() { - return; // $line-m1$ + return; // assertFullyCovered() } default void m2() { - return; // $line-m2$ + return; // assertNotCovered() } public class Impl implements InterfaceOnlyDefaultMethodsTarget { diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaExpressionsTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaExpressionsTarget.java index a8c7bd8b..5a26d0b0 100644 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaExpressionsTarget.java +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaExpressionsTarget.java @@ -23,11 +23,11 @@ public class LambdaExpressionsTarget { public static void main(String[] args) { exec(() -> { - nop(); // $line-executedlambdabody$ + nop(); // assertFullyCovered() }); - + noexec(() -> { - nop(); // $line-notexecutedlambdabody$ + nop(); // assertNotCovered() }); } diff --git a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaInInterfaceTarget.java b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaInInterfaceTarget.java index 4a9db74b..5759ca5f 100644 --- a/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaInInterfaceTarget.java +++ b/org.jacoco.core.test.validation.java8/src/org/jacoco/core/test/validation/java8/targets/LambdaInInterfaceTarget.java @@ -19,7 +19,7 @@ import static org.jacoco.core.test.validation.targets.Stubs.nop; public interface LambdaInInterfaceTarget { public static final Runnable RUN = () -> { - nop(); // $line-lambdabody$ + nop(); // assertFullyCovered() }; } diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinTopLevelFunctionTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinTopLevelFunctionTest.java index a647be4a..6d5a00f5 100644 --- a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinTopLevelFunctionTest.java +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinTopLevelFunctionTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.kotlin; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.kotlin.targets.KotlinTopLevelFunctionTargetKt; -import org.junit.Test; /** * Test of top level function. @@ -25,9 +23,4 @@ public class KotlinTopLevelFunctionTest extends ValidationTestBase { super(KotlinTopLevelFunctionTargetKt.class); } - @Test - public void test() { - assertLine("fun", ICounter.FULLY_COVERED); - } - } diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinWhenExpressionTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinWhenExpressionTest.java index 22e920a0..a4f9615f 100644 --- a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinWhenExpressionTest.java +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinWhenExpressionTest.java @@ -11,10 +11,8 @@ *******************************************************************************/ package org.jacoco.core.test.validation.kotlin; -import org.jacoco.core.analysis.ICounter; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.kotlin.targets.KotlinWhenExpressionTarget; -import org.junit.Test; /** * Test of when expressions. @@ -25,64 +23,4 @@ public class KotlinWhenExpressionTest extends ValidationTestBase { super(KotlinWhenExpressionTarget.class); } - /** - * {@link KotlinWhenExpressionTarget#whenSealed(KotlinWhenExpressionTarget.Sealed)} - */ - @Test - public void whenSealed() { - assertLine("whenSealed.when", ICounter.FULLY_COVERED); - assertLine("whenSealed.case1", ICounter.FULLY_COVERED, 0, 2); - // without filter next line covered partly and has one uncovered branch: - assertLine("whenSealed.case2", ICounter.FULLY_COVERED); - assertLine("whenSealed.return", ICounter.FULLY_COVERED); - } - - /** - * {@link KotlinWhenExpressionTarget#whenSealedRedundantElse(KotlinWhenExpressionTarget.Sealed)} - */ - @Test - public void whenSealedRedundantElse() { - assertLine("whenSealedRedundantElse.when", ICounter.FULLY_COVERED); - assertLine("whenSealedRedundantElse.case1", ICounter.FULLY_COVERED, 0, 2); - assertLine("whenSealedRedundantElse.case2", ICounter.FULLY_COVERED, 1, 1); - assertLine("whenSealedRedundantElse.else", ICounter.NOT_COVERED); - assertLine("whenSealedRedundantElse.return", ICounter.FULLY_COVERED); - } - - /** - * {@link KotlinWhenExpressionTarget#whenEnum(KotlinWhenExpressionTarget.Enum)} - */ - @Test - public void whenEnum() { - assertLine("whenEnum.when", ICounter.FULLY_COVERED, 1, 2); - assertLine("whenEnum.case1", ICounter.FULLY_COVERED); - assertLine("whenEnum.case2", ICounter.PARTLY_COVERED); - assertLine("whenEnum.return", ICounter.FULLY_COVERED); - } - - /** - * {@link KotlinWhenExpressionTarget#whenEnumRedundantElse(KotlinWhenExpressionTarget.Enum)} - */ - @Test - public void whenEnumRedundantElse() { - assertLine("whenEnumRedundantElse.when", ICounter.FULLY_COVERED, 1, 2); - assertLine("whenEnumRedundantElse.case1", ICounter.FULLY_COVERED); - assertLine("whenEnumRedundantElse.case2", ICounter.FULLY_COVERED); - assertLine("whenEnumRedundantElse.else", ICounter.NOT_COVERED); - assertLine("whenEnumRedundantElse.return", ICounter.FULLY_COVERED); - } - - /** - * {@link KotlinWhenExpressionTarget#whenString(String)} - */ - @Test - public void whenString() { - assertLine("whenString.when", ICounter.FULLY_COVERED, 2, 7); - assertLine("whenString.case1", ICounter.FULLY_COVERED); - assertLine("whenString.case2", ICounter.FULLY_COVERED); - assertLine("whenString.case2", ICounter.FULLY_COVERED); - assertLine("whenString.else", ICounter.FULLY_COVERED); - assertLine("whenString.return", ICounter.FULLY_COVERED); - } - } diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinTopLevelFunctionTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinTopLevelFunctionTarget.kt index 424e58c0..9ec485d3 100644 --- a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinTopLevelFunctionTarget.kt +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinTopLevelFunctionTarget.kt @@ -15,4 +15,4 @@ package org.jacoco.core.test.validation.kotlin.targets * This test target is top level function. */ fun main(args: Array) { -} // $line-fun$ +} // assertFullyCovered() diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt index 73e3dae4..193977dd 100644 --- a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt @@ -21,40 +21,40 @@ object KotlinWhenExpressionTarget { object Sealed2 : Sealed() } - private fun whenSealed(p: Sealed): Int = when (p) { // $line-whenSealed.when$ - is Sealed.Sealed1 -> 1 // $line-whenSealed.case1$ - is Sealed.Sealed2 -> 2 // $line-whenSealed.case2$ - } // $line-whenSealed.return$ + private fun whenSealed(p: Sealed): Int = when (p) { // assertFullyCovered() + is Sealed.Sealed1 -> 1 // assertFullyCovered(0, 2) + is Sealed.Sealed2 -> 2 // assertFullyCovered() + } // assertFullyCovered() @Suppress("REDUNDANT_ELSE_IN_WHEN") - private fun whenSealedRedundantElse(p: Sealed): Int = when (p) { // $line-whenSealedRedundantElse.when$ - is Sealed.Sealed1 -> 1 // $line-whenSealedRedundantElse.case1$ - is Sealed.Sealed2 -> 2 // $line-whenSealedRedundantElse.case2$ - else -> throw NoWhenBranchMatchedException() // $line-whenSealedRedundantElse.else$ - } // $line-whenSealedRedundantElse.return$ + private fun whenSealedRedundantElse(p: Sealed): Int = when (p) { // assertFullyCovered() + is Sealed.Sealed1 -> 1 // assertFullyCovered(0, 2) + is Sealed.Sealed2 -> 2 // assertFullyCovered(1, 1) + else -> throw NoWhenBranchMatchedException() // assertNotCovered() + } // assertFullyCovered() private enum class Enum { A, B } - private fun whenEnum(p: Enum): Int = when (p) { // $line-whenEnum.when$ - Enum.A -> 1 // $line-whenEnum.case1$ - Enum.B -> 2 // $line-whenEnum.case2$ - } // $line-whenEnum.return$ + private fun whenEnum(p: Enum): Int = when (p) { // assertFullyCovered(1, 2) + Enum.A -> 1 // assertFullyCovered() + Enum.B -> 2 // assertPartlyCovered() + } // assertFullyCovered() @Suppress("REDUNDANT_ELSE_IN_WHEN") - private fun whenEnumRedundantElse(p: Enum): Int = when (p) { // $line-whenEnumRedundantElse.when$ - Enum.A -> 1 // $line-whenEnumRedundantElse.case1$ - Enum.B -> 2 // $line-whenEnumRedundantElse.case2$ - else -> throw NoWhenBranchMatchedException() // $line-whenEnumRedundantElse.else$ - } // $line-whenEnumRedundantElse.return$ + private fun whenEnumRedundantElse(p: Enum): Int = when (p) { // assertFullyCovered(1, 2) + Enum.A -> 1 // assertFullyCovered() + Enum.B -> 2 // assertFullyCovered() + else -> throw NoWhenBranchMatchedException() // assertNotCovered() + } // assertFullyCovered() - private fun whenString(p: String): Int = when (p) { // $line-whenString.when$ - "a" -> 1 // $line-whenString.case1$ - "b" -> 2 // $line-whenString.case2$ - "\u0000a" -> 3 // $line-whenString.case3$ - else -> 4 // $line-whenString.else$ - } // $line-whenString.return$ + private fun whenString(p: String): Int = when (p) { // assertFullyCovered(2, 7) + "a" -> 1 // assertFullyCovered() + "b" -> 2 // assertFullyCovered() + "\u0000a" -> 3 // assertFullyCovered() + else -> 4 // assertFullyCovered() + } // assertFullyCovered() @JvmStatic fun main(args: Array) { diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/Source.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/Source.java index 6d2d7172..45d236c0 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/Source.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/Source.java @@ -12,92 +12,157 @@ package org.jacoco.core.test.validation; import java.io.BufferedReader; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.jacoco.core.analysis.IBundleCoverage; +import org.jacoco.core.analysis.IClassCoverage; +import org.jacoco.core.analysis.ICoverageNode; +import org.jacoco.core.analysis.ILine; +import org.jacoco.core.analysis.IPackageCoverage; +import org.jacoco.core.analysis.ISourceFileCoverage; + /** - * Reads a single source file and allows access to it through special probe - * comments in the following format //$line-tag$. + * Reads a single source file and allows access to its line coverage. */ public class Source { - private static final Pattern TAG_PATTERN = Pattern - .compile("\\$line-(.*)\\$"); + private static final String SRC_LOCATION = "src/"; + + private static final String SRC_ENCODING = "UTF-8"; + + private static final Pattern COMMENT_PATTERN = Pattern + .compile("(?null + */ + public String getComment() { + final Matcher matcher = COMMENT_PATTERN.matcher(text); + return matcher.find() ? matcher.group(1) : null; + } + + @Override + public String toString() { + return "line " + nr; + } - private final List lines = new ArrayList(); + } - private final Map tags = new HashMap(); + private final List lines; + + private final ISourceFileCoverage coverage; /** * Reads a source file from the given reader. * * @param reader - * the reader to read from + * the reader to read from, will be closed + * @param coverage + * corresponding coverage data * @throws IOException * if an I/O error occurs */ - public Source(final Reader reader) throws IOException { + public Source(final Reader reader, ISourceFileCoverage coverage) + throws IOException { + this.lines = new ArrayList(); + this.coverage = coverage; final BufferedReader buffer = new BufferedReader(reader); + int nr = 1; for (String l = buffer.readLine(); l != null; l = buffer.readLine()) { - addLine(l); + lines.add(new Line(nr, l, coverage.getLine(nr))); + nr++; } buffer.close(); } - private void addLine(final String l) { - lines.add(l); - final Matcher m = TAG_PATTERN.matcher(l); - if (m.find()) { - final String tag = m.group(1); - if (tags.put(tag, Integer.valueOf(lines.size())) != null) { - throw new IllegalArgumentException("Duplicate tag: " + tag); - } - } - } - /** - * Returns all lines of the source file as a list. - * * @return all lines of the source file */ - public List getLines() { + public List getLines() { return Collections.unmodifiableList(lines); } /** - * Returns the line with the given number - * - * @param nr - * line number (first line is 1) - * @return line content + * @return the corresponding coverage node */ - public String getLine(int nr) { - return lines.get(nr - 1); + public ISourceFileCoverage getCoverage() { + return coverage; } /** - * Returns the line number with the given tag + * Loads the source file which holds the given target class. * - * @param tag - * tag from a //$line-tag$ marker - * @return line number (first line is 1) - * @throws NoSuchElementException - * if there is no such tag + * @param target + * the target class we want the source for + * @param bundle + * the bundle containing the analyzed class and its source file + * @return a {@link Source} instance */ - public int getLineNumber(String tag) throws NoSuchElementException { - final Integer nr = tags.get(tag); - if (nr == null) { - throw new NoSuchElementException("Unknown tag: " + tag); + public static Source load(Class target, IBundleCoverage bundle) + throws IOException { + final IPackageCoverage pkgCov = findByName(bundle.getPackages(), + vm(target.getPackage().getName())); + final IClassCoverage clsCov = findByName(pkgCov.getClasses(), + vm(target.getName())); + final ISourceFileCoverage srcCov = findByName(pkgCov.getSourceFiles(), + clsCov.getSourceFileName()); + return new Source(open(SRC_LOCATION + pkgCov.getName() + "/" + + clsCov.getSourceFileName()), srcCov); + } + + private static T findByName(Collection nodes, + String name) { + for (T node : nodes) { + if (name.equals(node.getName())) { + return node; + } } - return nr.intValue(); + throw new AssertionError("Node not found: " + name); + } + + private static String vm(String javaname) { + return javaname.replace('.', '/'); + } + + private static Reader open(String file) throws IOException { + return new InputStreamReader(new FileInputStream(file), SRC_ENCODING); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/SourceTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/SourceTest.java index 6d422c60..577e324c 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/SourceTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/SourceTest.java @@ -12,12 +12,15 @@ package org.jacoco.core.test.validation; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import java.io.IOException; import java.io.StringReader; -import java.util.Arrays; -import java.util.NoSuchElementException; +import java.util.List; +import org.jacoco.core.internal.analysis.CounterImpl; +import org.jacoco.core.internal.analysis.SourceFileCoverageImpl; +import org.jacoco.core.test.validation.Source.Line; import org.junit.Test; /** @@ -26,53 +29,108 @@ import org.junit.Test; public class SourceTest { @Test - public void testGetLines1() throws IOException { - String src = "\na\nbb\n"; - final Source s = new Source(new StringReader(src)); - assertEquals(Arrays.asList("", "a", "bb"), s.getLines()); + public void should_parse_lines() throws IOException { + String src = "aaa\nbbb\n;"; + + final Source s = new Source(new StringReader(src), + new SourceFileCoverageImpl("Foo", "foo")); + + List lines = s.getLines(); + assertEquals(3, lines.size()); + assertEquals("aaa", lines.get(0).getText()); + assertEquals("bbb", lines.get(1).getText()); + assertEquals(";", lines.get(2).getText()); } @Test - public void testGetLines2() throws IOException { - String src = "aa\nbb\n;"; - final Source s = new Source(new StringReader(src)); - assertEquals(Arrays.asList("aa", "bb", ";"), s.getLines()); + public void should_parse_empty_lines() throws IOException { + String src = "\naaa\n\nbbb\n"; + + final Source s = new Source(new StringReader(src), + new SourceFileCoverageImpl("Foo", "foo")); + + List lines = s.getLines(); + assertEquals(4, lines.size()); + assertEquals("", lines.get(0).getText()); + assertEquals("aaa", lines.get(1).getText()); + assertEquals("", lines.get(2).getText()); + assertEquals("bbb", lines.get(3).getText()); } @Test - public void testGetLines3() throws IOException { - String src = "xx\r\nyy"; - final Source s = new Source(new StringReader(src)); - assertEquals(Arrays.asList("xx", "yy"), s.getLines()); + public void should_parse_crnl_separator() throws IOException { + String src = "aaa\r\nbbb"; + + final Source s = new Source(new StringReader(src), + new SourceFileCoverageImpl("Foo", "foo")); + + List lines = s.getLines(); + assertEquals(2, lines.size()); + assertEquals("aaa", lines.get(0).getText()); + assertEquals("bbb", lines.get(1).getText()); } @Test - public void testGetLine() throws IOException { - String src = "Hello\n\nWorld!"; - final Source s = new Source(new StringReader(src)); - assertEquals("Hello", s.getLine(1)); - assertEquals("", s.getLine(2)); - assertEquals("World!", s.getLine(3)); + public void should_calculate_line_numbers() throws IOException { + String src = "a\nb\nc"; + + final Source s = new Source(new StringReader(src), + new SourceFileCoverageImpl("Foo", "foo")); + + List lines = s.getLines(); + assertEquals(3, lines.size()); + assertEquals(1, lines.get(0).getNr()); + assertEquals(2, lines.get(1).getNr()); + assertEquals(3, lines.get(2).getNr()); } @Test - public void testGetLineNumber() throws IOException { - String src = "a\nb$line-tag$\nc\nd\ne$line-tagx$\nf"; - final Source s = new Source(new StringReader(src)); - assertEquals(2, s.getLineNumber("tag"), 0.0); + public void line_should_implement_toString() throws IOException { + String src = "a\nb"; + + final Source s = new Source(new StringReader(src), + new SourceFileCoverageImpl("Foo", "foo")); + + List lines = s.getLines(); + assertEquals(2, lines.size()); + assertEquals("line 1", lines.get(0).toString()); + assertEquals("line 2", lines.get(1).toString()); } - @Test(expected = NoSuchElementException.class) - public void testGetLineNumberNegative() throws IOException { - String src = "a\nb$line-tag$\nc\nd\ne\nf"; - final Source s = new Source(new StringReader(src)); - s.getLineNumber("ag"); + @Test + public void line_should_provide_corresponding_coverage() + throws IOException { + String src = "a\nb\nc"; + SourceFileCoverageImpl sc = new SourceFileCoverageImpl("Foo", "foo"); + sc.increment(CounterImpl.getInstance(1, 0), CounterImpl.COUNTER_0_0, 1); + sc.increment(CounterImpl.getInstance(2, 0), CounterImpl.COUNTER_0_0, 2); + sc.increment(CounterImpl.getInstance(3, 0), CounterImpl.COUNTER_0_0, 3); + + final Source s = new Source(new StringReader(src), sc); + + List lines = s.getLines(); + assertEquals(3, lines.size()); + assertEquals(1, lines.get(0).getCoverage().getInstructionCounter() + .getMissedCount()); + assertEquals(2, lines.get(1).getCoverage().getInstructionCounter() + .getMissedCount()); + assertEquals(3, lines.get(2).getCoverage().getInstructionCounter() + .getMissedCount()); } - @Test(expected = IllegalArgumentException.class) - public void testDuplicateTag() throws IOException { - String src = "a\nb$line-tag$\nc\nd\ne$line-tag$\nf"; - new Source(new StringReader(src)); + @Test + public void line_should_return_comment() throws IOException { + String src = "aaa\nbbb // test()\n}//nospaces()\n/* http://jacoco.org/ */"; + + final Source s = new Source(new StringReader(src), + new SourceFileCoverageImpl("Foo", "foo")); + + List lines = s.getLines(); + assertEquals(4, lines.size()); + assertNull(lines.get(0).getComment()); + assertEquals(" test()", lines.get(1).getComment()); + assertEquals("nospaces()", lines.get(2).getComment()); + assertNull(lines.get(3).getComment()); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutor.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutor.java new file mode 100644 index 00000000..2cd3483a --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutor.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import java.lang.reflect.InvocationTargetException; + +/** + * Executes statements against a given Java object instance. + */ +class StatementExecutor implements StatementParser.IStatementVisitor { + + private final Object target; + private final Object[] prefixArgs; + + StatementExecutor(Object target, Object... prefixArgs) { + this.target = target; + this.prefixArgs = prefixArgs; + } + + public void visitInvocation(String ctx, String name, Object... args) { + args = concat(prefixArgs, args); + try { + target.getClass().getMethod(name, getTypes(args)).invoke(target, + args); + } catch (InvocationTargetException e) { + Throwable te = e.getTargetException(); + if (te instanceof AssertionError) { + throw (AssertionError) te; + } + throw new RuntimeException("Invocation error in " + ctx, te); + } catch (Exception e) { + throw new RuntimeException("Invocation error in " + ctx, e); + } + } + + private static Object[] concat(Object[] a, Object[] b) { + final Object[] result = new Object[a.length + b.length]; + System.arraycopy(a, 0, result, 0, a.length); + System.arraycopy(b, 0, result, a.length, b.length); + return result; + } + + private static Class[] getTypes(Object[] instances) { + final Class[] classes = new Class[instances.length]; + for (int i = 0; i < instances.length; i++) { + Class c = instances[i].getClass(); + if (c == Integer.class) { + // We always use primitive int parameters: + c = Integer.TYPE; + } + classes[i] = c; + } + return classes; + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutorTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutorTest.java new file mode 100644 index 00000000..a0e9af0e --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutorTest.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +/** + * Unit tests for {@link StatementExecutor}. + */ +public class StatementExecutorTest { + + @Rule + public ExpectedException exception = ExpectedException.none(); + + private Map> invocations; + + @Before + public void setup() { + invocations = new HashMap>(); + } + + @Test + public void should_prefix_arguments() { + StatementExecutor executor = new StatementExecutor(this, + "Hello", "world"); + + executor.visitInvocation("ctx", "target1", "!"); + + assertEquals(Arrays.asList("Hello", "world", "!"), + invocations.get("target1")); + } + + @Test + public void should_call_method_with_int_argument() { + StatementExecutor executor = new StatementExecutor(this); + + executor.visitInvocation("ctx", "target2", Integer.valueOf(42)); + + assertEquals(Arrays.asList(Integer.valueOf(42)), + invocations.get("target2")); + } + + @Test + public void should_preserve_AssertionError() { + exception.expect(AssertionError.class); + exception.expectMessage("Original AssertionError."); + StatementExecutor executor = new StatementExecutor(this); + + executor.visitInvocation("ctx", "target3"); + } + + @Test + public void should_wrap_other_exceptions() { + exception.expect(RuntimeException.class); + exception.expectMessage("Invocation error in ctx"); + StatementExecutor executor = new StatementExecutor(this); + + executor.visitInvocation("ctx", "target4"); + } + + @Test + public void should_throw_RuntimeException_when_method_cannot_be_invoked() { + exception.expect(RuntimeException.class); + exception.expectMessage("Invocation error in ctx"); + StatementExecutor executor = new StatementExecutor(this); + + executor.visitInvocation("ctx", "doesNotExist"); + } + + public void target1(String a, String b, String c) { + invocations.put("target1", Arrays.asList(a, b, c)); + } + + public void target2(int i) { + invocations.put("target2", Arrays.asList(Integer.valueOf(i))); + } + + public void target3() { + throw new AssertionError("Original AssertionError."); + } + + public void target4() throws IOException { + throw new IOException("Original IOException."); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParser.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParser.java new file mode 100644 index 00000000..4f84fb8a --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParser.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import java.io.IOException; +import java.io.StreamTokenizer; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; + +/** + * Simple parser for Java like method invocation statements. For example: + * + *

    + * foo("BAR", 42)
    + * 
    + * + * Method parameters can only be String or int literals. + */ +class StatementParser { + + /** + * Call-back interface for parsed statements. + */ + public interface IStatementVisitor { + + /** + * Called when a method invocation has been paresed. + * + * @param ctx + * context information for error messages + * @param name + * local method name + * @param args + * argument values + */ + void visitInvocation(String ctx, String name, Object... args); + + } + + /** + * Parses the given source. + * + * @param source + * source string to parse + * @param visitor + * visitor to emit parsed statements + * @param ctx + * context information to include in error messages + */ + public static void parse(String source, IStatementVisitor visitor, + String ctx) throws IOException { + new StatementParser(source, visitor, ctx).parse(); + } + + private final IStatementVisitor visitor; + private final StreamTokenizer tokenizer; + private final String ctx; + + private StatementParser(String source, IStatementVisitor visitor, + String ctx) { + this.visitor = visitor; + this.ctx = ctx; + tokenizer = new StreamTokenizer(new StringReader(source)); + tokenizer.resetSyntax(); + tokenizer.whitespaceChars(' ', ' '); + tokenizer.whitespaceChars('\t', '\t'); + tokenizer.wordChars('a', 'z'); + tokenizer.wordChars('A', 'Z'); + tokenizer.quoteChar('"'); + tokenizer.parseNumbers(); + } + + private void parse() throws IOException { + while (!accept(StreamTokenizer.TT_EOF)) { + invocation(); + } + } + + private void invocation() throws IOException { + final String name = expect(StreamTokenizer.TT_WORD).sval; + final List args = new ArrayList(); + expect('('); + if (!accept(')')) { + args.add(argument()); + while (!accept(')')) { + expect(','); + args.add(argument()); + } + } + visitor.visitInvocation(ctx, name, args.toArray()); + } + + private Object argument() throws IOException { + if (accept(StreamTokenizer.TT_NUMBER)) { + return Integer.valueOf((int) tokenizer.nval); + } + if (accept('"')) { + return tokenizer.sval; + } + throw syntaxError(); + } + + private boolean accept(final int type) throws IOException { + final boolean match = tokenizer.nextToken() == type; + if (!match) { + tokenizer.pushBack(); + } + return match; + } + + private StreamTokenizer expect(final int type) throws IOException { + if (tokenizer.nextToken() != type) { + throw syntaxError(); + } + return tokenizer; + } + + private IOException syntaxError() { + return new IOException("Invalid syntax at " + ctx); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParserTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParserTest.java new file mode 100644 index 00000000..32601980 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParserTest.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.test.validation; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.jacoco.core.test.validation.StatementParser.IStatementVisitor; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +/** + * Unit tests for {@link StatementParser} + */ +public class StatementParserTest { + + private IStatementVisitor visitor; + + private List actualInvocations; + private List expectedInvocations; + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Before + public void setup() { + actualInvocations = new ArrayList(); + expectedInvocations = new ArrayList(); + visitor = new IStatementVisitor() { + public void visitInvocation(String ctx, String name, + Object... args) { + actualInvocations.add(invocationStr(ctx, name, args)); + } + }; + } + + @After + public void teardown() { + assertEquals(expectedInvocations, actualInvocations); + } + + @Test + public void should_parse_empty_string() throws IOException { + StatementParser.parse("", visitor, "Foo.java"); + } + + @Test + public void should_parse_invocation_without_params() throws IOException { + StatementParser.parse("run()", visitor, "Foo.java"); + expectInvocation("Foo.java", "run"); + } + + @Test + public void should_parse_invocation_with_one_int_parameter() + throws IOException { + StatementParser.parse("ask(42)", visitor, "Foo.java"); + expectInvocation("Foo.java", "ask", Integer.valueOf(42)); + } + + @Test + public void should_parse_invocation_with_one_string_parameter() + throws IOException { + StatementParser.parse("say(\"hello\")", visitor, "Foo.java"); + expectInvocation("Foo.java", "say", "hello"); + } + + @Test + public void should_parse_invocation_with_two_parameters() + throws IOException { + StatementParser.parse("add(1000, 234)", visitor, "Foo.java"); + expectInvocation("Foo.java", "add", Integer.valueOf(1000), + Integer.valueOf(234)); + } + + @Test + public void should_parse_invocation_with_mixed_parameter_types() + throws IOException { + StatementParser.parse("mix(1, \"two\", 3)", visitor, "Foo.java"); + expectInvocation("Foo.java", "mix", Integer.valueOf(1), "two", + Integer.valueOf(3)); + } + + @Test + public void should_parse_multiple_invocations() throws IOException { + StatementParser.parse("start() stop()", visitor, "Foo.java"); + expectInvocation("Foo.java", "start"); + expectInvocation("Foo.java", "stop"); + } + + @Test + public void should_fail_when_parenthesis_is_missing() throws IOException { + exception.expect(IOException.class); + StatementParser.parse("bad(", visitor, "Foo.java"); + } + + @Test + public void should_fail_when_argument1_is_missing() throws IOException { + exception.expect(IOException.class); + StatementParser.parse("bad(,2)", visitor, "Foo.java"); + } + + @Test + public void should_fail_when_argument2_is_missing() throws IOException { + exception.expect(IOException.class); + StatementParser.parse("bad(1,)", visitor, "Foo.java"); + } + + @Test + public void should_give_context_info_when_parsing_fails() + throws IOException { + exception.expect(IOException.class); + exception.expectMessage("Invalid syntax at Foo.java:32"); + StatementParser.parse("bad", visitor, "Foo.java:32"); + } + + private void expectInvocation(String ctx, String name, Object... args) { + expectedInvocations.add(invocationStr(ctx, name, args)); + } + + private String invocationStr(String ctx, String name, Object... args) { + return String.format("%s:%s%s", ctx, name, Arrays.asList(args)); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java index bd92cecc..15908e53 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java @@ -12,26 +12,24 @@ package org.jacoco.core.test.validation; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Method; import java.util.Arrays; import org.jacoco.core.analysis.Analyzer; import org.jacoco.core.analysis.CoverageBuilder; -import org.jacoco.core.analysis.IClassCoverage; import org.jacoco.core.analysis.ICounter; import org.jacoco.core.analysis.ILine; -import org.jacoco.core.analysis.ISourceFileCoverage; import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.internal.analysis.CounterImpl; import org.jacoco.core.test.InstrumentingLoader; import org.jacoco.core.test.TargetLoader; +import org.jacoco.core.test.validation.Source.Line; import org.jacoco.core.test.validation.targets.Stubs; import org.junit.Before; +import org.junit.Test; /** * Base class for validation tests. It executes the given class under code @@ -55,8 +53,6 @@ public abstract class ValidationTestBase { private final Class target; - private ISourceFileCoverage sourceCoverage; - private Source source; private InstrumentingLoader loader; @@ -88,79 +84,98 @@ public abstract class ValidationTestBase { for (ExecutionData data : store.getContents()) { analyze(analyzer, data); } - - final String srcName = findSourceFileName(builder, - target.getName().replace('.', '/')); - - source = new Source(new FileReader("src/" + srcName)); - - for (ISourceFileCoverage file : builder.getSourceFiles()) { - if (srcName.equals(file.getPackageName() + "/" + file.getName())) { - sourceCoverage = file; - return; - } - } - fail("No source node found for " + srcName); + source = Source.load(target, builder.getBundle("Test")); } private void analyze(final Analyzer analyzer, final ExecutionData data) throws IOException { - final byte[] bytes = TargetLoader.getClassDataAsBytes( - target.getClassLoader(), data.getName()); + final byte[] bytes = TargetLoader + .getClassDataAsBytes(target.getClassLoader(), data.getName()); analyzer.analyzeClass(bytes, data.getName()); } - private static String findSourceFileName( - final CoverageBuilder coverageBuilder, final String className) { - for (IClassCoverage classCoverage : coverageBuilder.getClasses()) { - if (className.equals(classCoverage.getName())) { - return classCoverage.getPackageName() + '/' - + classCoverage.getSourceFileName(); + /** + * All single line comments are interpreted as statements in the following + * format: + * + *
    +	 * // statement1() statement2()
    +	 * 
    + */ + @Test + public void execute_assertions_in_comments() throws IOException { + for (Line line : source.getLines()) { + String exec = line.getComment(); + if (exec != null) { + StatementParser.parse(exec, new StatementExecutor(this, line), + line.toString()); } } - throw new AssertionError(); } - protected final Source getSource() { - return source; + /* + * Predefined assertion methods: + */ + + private void assertCoverage(final Line line, final int insnStatus, + final int missedBranches, final int coveredBranches) { + final ILine coverage = line.getCoverage(); + + String msg = String.format("Instructions in %s: %s", line, + line.getText()); + final int actualStatus = coverage.getInstructionCounter().getStatus(); + assertEquals(msg, STATUS_NAME[insnStatus], STATUS_NAME[actualStatus]); + + msg = String.format("Branches in %s: %s", line, line.getText()); + assertEquals(msg, + CounterImpl.getInstance(missedBranches, coveredBranches), + coverage.getBranchCounter()); } - protected void assertMethodCount(final int expectedTotal) { - assertEquals(expectedTotal, - sourceCoverage.getMethodCounter().getTotalCount()); + public void assertFullyCovered(final Line line, final int missedBranches, + final int coveredBranches) { + assertCoverage(line, ICounter.FULLY_COVERED, missedBranches, + coveredBranches); } - protected void assertLine(final String tag, final int status) { - privateAssertLine(tag, status, 0, 0); + public void assertFullyCovered(final Line line) { + assertFullyCovered(line, 0, 0); } - protected void assertLine(final String tag, final int status, - final int missedBranches, final int coveredBranches) { - if (missedBranches == 0 && coveredBranches == 0) { - throw new IllegalArgumentException( - "Omit redundant specification of zero number of branches"); - } - privateAssertLine(tag, status, missedBranches, coveredBranches); + public void assertPartlyCovered(final Line line, final int missedBranches, + final int coveredBranches) { + assertCoverage(line, ICounter.PARTLY_COVERED, missedBranches, + coveredBranches); } - private void privateAssertLine(final String tag, final int status, - final int missedBranches, final int coveredBranches) { - final int nr = source.getLineNumber(tag); - final ILine line = sourceCoverage.getLine(nr); - final String lineMsg = String.format("line %s: %s", Integer.valueOf(nr), - source.getLine(nr)); - final int insnStatus = line.getInstructionCounter().getStatus(); - assertEquals("Instructions in " + lineMsg, STATUS_NAME[status], - STATUS_NAME[insnStatus]); - assertEquals("Branches in " + lineMsg, - CounterImpl.getInstance(missedBranches, coveredBranches), - line.getBranchCounter()); + public void assertPartlyCovered(final Line line) { + assertPartlyCovered(line, 0, 0); + } + + public void assertNotCovered(final Line line, final int missedBranches, + final int coveredBranches) { + assertCoverage(line, ICounter.NOT_COVERED, missedBranches, + coveredBranches); + } + + public void assertNotCovered(final Line line) { + assertNotCovered(line, 0, 0); + } + + public void assertEmpty(final Line line) { + assertCoverage(line, ICounter.EMPTY, 0, 0); } protected void assertLogEvents(String... events) throws Exception { - final Method getter = Class.forName(Stubs.class.getName(), false, - loader).getMethod("getLogEvents"); + final Method getter = Class + .forName(Stubs.class.getName(), false, loader) + .getMethod("getLogEvents"); assertEquals("Log events", Arrays.asList(events), getter.invoke(null)); } + protected void assertMethodCount(final int expectedTotal) { + assertEquals(expectedTotal, + source.getCoverage().getMethodCounter().getTotalCount()); + } + } -- cgit v1.2.3 From c1cfe5777ef7acbe361b1172554c855243aa67f2 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 10 Aug 2018 07:24:20 +0200 Subject: Add source filename to assertion messages (#727) This simplifies navigation in IDEs. --- org.jacoco.core.test/src/org/jacoco/core/test/validation/Source.java | 4 ++-- .../src/org/jacoco/core/test/validation/SourceTest.java | 4 ++-- .../src/org/jacoco/core/test/validation/StatementExecutor.java | 4 ++-- .../src/org/jacoco/core/test/validation/StatementExecutorTest.java | 4 ++-- .../src/org/jacoco/core/test/validation/StatementParser.java | 2 +- .../src/org/jacoco/core/test/validation/StatementParserTest.java | 2 +- .../src/org/jacoco/core/test/validation/ValidationTestBase.java | 5 ++--- 7 files changed, 12 insertions(+), 13 deletions(-) diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/Source.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/Source.java index 45d236c0..6a60493b 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/Source.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/Source.java @@ -45,7 +45,7 @@ public class Source { /** * Represents a single line in a source file. */ - public static class Line { + public class Line { private final int nr; private final String text; @@ -80,7 +80,7 @@ public class Source { @Override public String toString() { - return "line " + nr; + return Source.this.coverage.getName() + ":" + nr; } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/SourceTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/SourceTest.java index 577e324c..dac2b32d 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/SourceTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/SourceTest.java @@ -93,8 +93,8 @@ public class SourceTest { List lines = s.getLines(); assertEquals(2, lines.size()); - assertEquals("line 1", lines.get(0).toString()); - assertEquals("line 2", lines.get(1).toString()); + assertEquals("Foo:1", lines.get(0).toString()); + assertEquals("Foo:2", lines.get(1).toString()); } @Test diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutor.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutor.java index 2cd3483a..9ab1be68 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutor.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutor.java @@ -36,9 +36,9 @@ class StatementExecutor implements StatementParser.IStatementVisitor { if (te instanceof AssertionError) { throw (AssertionError) te; } - throw new RuntimeException("Invocation error in " + ctx, te); + throw new RuntimeException("Invocation error (" + ctx + ")", te); } catch (Exception e) { - throw new RuntimeException("Invocation error in " + ctx, e); + throw new RuntimeException("Invocation error (" + ctx + ")", e); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutorTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutorTest.java index a0e9af0e..2f186205 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutorTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementExecutorTest.java @@ -72,7 +72,7 @@ public class StatementExecutorTest { @Test public void should_wrap_other_exceptions() { exception.expect(RuntimeException.class); - exception.expectMessage("Invocation error in ctx"); + exception.expectMessage("Invocation error (ctx)"); StatementExecutor executor = new StatementExecutor(this); executor.visitInvocation("ctx", "target4"); @@ -81,7 +81,7 @@ public class StatementExecutorTest { @Test public void should_throw_RuntimeException_when_method_cannot_be_invoked() { exception.expect(RuntimeException.class); - exception.expectMessage("Invocation error in ctx"); + exception.expectMessage("Invocation error (ctx)"); StatementExecutor executor = new StatementExecutor(this); executor.visitInvocation("ctx", "doesNotExist"); diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParser.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParser.java index 4f84fb8a..560d665e 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParser.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParser.java @@ -126,7 +126,7 @@ class StatementParser { } private IOException syntaxError() { - return new IOException("Invalid syntax at " + ctx); + return new IOException("Invalid syntax (" + ctx + ")"); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParserTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParserTest.java index 32601980..eccf5c33 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParserTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/StatementParserTest.java @@ -125,7 +125,7 @@ public class StatementParserTest { public void should_give_context_info_when_parsing_fails() throws IOException { exception.expect(IOException.class); - exception.expectMessage("Invalid syntax at Foo.java:32"); + exception.expectMessage("Invalid syntax (Foo.java:32)"); StatementParser.parse("bad", visitor, "Foo.java:32"); } diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java index 15908e53..d8b5e727 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java @@ -121,12 +121,11 @@ public abstract class ValidationTestBase { final int missedBranches, final int coveredBranches) { final ILine coverage = line.getCoverage(); - String msg = String.format("Instructions in %s: %s", line, - line.getText()); + String msg = String.format("Instructions (%s)", line); final int actualStatus = coverage.getInstructionCounter().getStatus(); assertEquals(msg, STATUS_NAME[insnStatus], STATUS_NAME[actualStatus]); - msg = String.format("Branches in %s: %s", line, line.getText()); + msg = String.format("Branches (%s)", line); assertEquals(msg, CounterImpl.getInstance(missedBranches, coveredBranches), coverage.getBranchCounter()); -- cgit v1.2.3 From 90af0853aed1cf9290acb81ed0cde1699cc00718 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Sun, 12 Aug 2018 23:02:56 +0200 Subject: Add tests for Kotlin `lateinit` properties and `data class`es (#709) --- .../validation/kotlin/KotlinDataClassTest.java | 26 +++++++++++ .../test/validation/kotlin/KotlinLateinitTest.java | 26 +++++++++++ .../kotlin/targets/KotlinDataClassTarget.kt | 50 ++++++++++++++++++++++ .../kotlin/targets/KotlinLateinitTarget.kt | 27 ++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinDataClassTest.java create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinLateinitTest.java create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinDataClassTarget.kt create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinLateinitTarget.kt diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinDataClassTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinDataClassTest.java new file mode 100644 index 00000000..3594f1d4 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinDataClassTest.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Fabian Mastenbroek - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.kotlin.targets.KotlinDataClassTarget; + +/** + * Test of data classes. + */ +public class KotlinDataClassTest extends ValidationTestBase { + + public KotlinDataClassTest() { + super(KotlinDataClassTarget.class); + } + +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinLateinitTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinLateinitTest.java new file mode 100644 index 00000000..78b31b15 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinLateinitTest.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Fabian Mastenbroek - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.kotlin.targets.KotlinLateinitTarget; + +/** + * Test of lateinit properties. + */ +public class KotlinLateinitTest extends ValidationTestBase { + + public KotlinLateinitTest() { + super(KotlinLateinitTarget.class); + } + +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinDataClassTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinDataClassTarget.kt new file mode 100644 index 00000000..ba66ceeb --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinDataClassTarget.kt @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Fabian Mastenbroek - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin.targets + +import org.jacoco.core.test.validation.targets.Stubs.nop + +/** + * This test target is `data class`. + */ +object KotlinDataClassTarget { + + data class DataClass( // assertFullyCovered() + val valNoRead: Int, // assertNotCovered() + val valRead: Int, // assertFullyCovered() + var varNoReadNoWrite: Int, // assertNotCovered() + var varNoWrite: Int, // assertPartlyCovered() + var varNoRead: Int, // assertPartlyCovered() + var varReadWrite: Int // assertFullyCovered() + ) // assertEmpty() + + data class DataClassOverrideNotCovered(val v: Int) { + override fun toString(): String = "" // assertNotCovered() + } + + data class DataClassOverrideCovered(val v: Int) { + override fun toString(): String = "" // assertFullyCovered() + } + + @JvmStatic + fun main(args: Array) { + val d = DataClass(0, 0, 0, 0, 0, 0) + nop(d.valRead) + nop(d.varNoWrite) + d.varNoRead = 1 + nop(d.varReadWrite) + d.varReadWrite = 1 + + DataClassOverrideNotCovered(0) + DataClassOverrideCovered(0).toString() + } +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinLateinitTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinLateinitTarget.kt new file mode 100644 index 00000000..78d135c2 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinLateinitTarget.kt @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Fabian Mastenbroek - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin.targets + +import org.jacoco.core.test.validation.targets.Stubs.nop + +/** + * This test target is `lateinit` property. + */ +object KotlinLateinitTarget { + private lateinit var x: String + + @JvmStatic + fun main(args: Array) { + x = "" + nop(x) // assertFullyCovered() + } +} -- cgit v1.2.3 From aa778680a3adc19eb59a1c96b570d9d1fe4a8145 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 13 Aug 2018 22:23:21 +0200 Subject: Filter switch on String that javac compiles into lookupswitch (#730) --- .../test/validation/java7/StringSwitchTest.java | 9 ++++++ .../java7/targets/StringSwitchTarget.java | 17 ++++++++++ .../filter/StringSwitchJavacFilterTest.java | 36 +++++++++++++++++----- .../internal/analysis/filter/AbstractMatcher.java | 19 ++++++++++++ .../analysis/filter/StringSwitchJavacFilter.java | 3 +- 5 files changed, 76 insertions(+), 8 deletions(-) diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java index f291c174..242a55f5 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java @@ -43,4 +43,13 @@ public class StringSwitchTest extends ValidationTestBase { } } + public void assertLookupswitch(final Line line) { + if (isJDKCompiler) { + assertNotCovered(line, 3, 0); + } else { + // Filtering for ECJ not yet implemented: + assertNotCovered(line, 7, 0); + } + } + } diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java index cdbf9f51..7b1bc291 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java @@ -84,6 +84,23 @@ public class StringSwitchTarget { } } + /** + * In this case javac generates LOOKUPSWITCH for second switch. + */ + private static void lookupswitch(Object s) { + switch (String.valueOf(s)) { // assertLookupswitch() + case "a": + nop("case a"); + break; + case "b": + nop("case b"); + break; + default: + nop("default"); + break; + } + } + public static void main(String[] args) { covered(""); covered("a"); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java index ec976d52..e83ae0e6 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java @@ -32,13 +32,14 @@ public class StringSwitchJavacFilterTest implements IFilterOutput { private AbstractInsnNode fromInclusive; private AbstractInsnNode toInclusive; - @Test - public void should_filter_code_generated_by_javac() { + private AbstractInsnNode expectedFromInclusive; + private AbstractInsnNode expectedToInclusive; + + private void createFirstSwitch() { final Label h1 = new Label(); final Label h1_2 = new Label(); final Label h2 = new Label(); final Label secondSwitch = new Label(); - final Label cases = new Label(); m.visitInsn(Opcodes.ICONST_M1); m.visitVarInsn(Opcodes.ISTORE, 2); @@ -48,7 +49,7 @@ public class StringSwitchJavacFilterTest implements IFilterOutput { "()I", false); m.visitLookupSwitchInsn(secondSwitch, new int[] { 97, 98 }, new Label[] { h1, h2 }); - final AbstractInsnNode fromInclusive = m.instructions.getLast(); + expectedFromInclusive = m.instructions.getLast(); m.visitLabel(h1); m.visitVarInsn(Opcodes.ALOAD, 1); @@ -87,15 +88,36 @@ public class StringSwitchJavacFilterTest implements IFilterOutput { m.visitVarInsn(Opcodes.ISTORE, 2); m.visitLabel(secondSwitch); - final AbstractInsnNode toInclusive = m.instructions.getLast(); + expectedToInclusive = m.instructions.getLast(); m.visitVarInsn(Opcodes.ILOAD, 2); + } + + @Test + public void should_filter_code_generated_by_javac() { + createFirstSwitch(); + + final Label cases = new Label(); m.visitTableSwitchInsn(0, 2, cases); m.visitLabel(cases); filter.filter(m, new FilterContextMock(), this); - assertEquals(fromInclusive, this.fromInclusive); - assertEquals(toInclusive, this.toInclusive); + assertEquals(expectedFromInclusive, this.fromInclusive); + assertEquals(expectedToInclusive, this.toInclusive); + } + + @Test + public void should_filter_when_javac_generates_lookupswitch() { + createFirstSwitch(); + + final Label cases = new Label(); + m.visitLookupSwitchInsn(cases, null, new Label[] {}); + m.visitLabel(cases); + + filter.filter(m, new FilterContextMock(), this); + + assertEquals(expectedFromInclusive, this.fromInclusive); + assertEquals(expectedToInclusive, this.toInclusive); } @Test diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java index 9e07153b..9b01e777 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java @@ -110,6 +110,25 @@ abstract class AbstractMatcher { } } + /** + * Moves {@link #cursor} to next instruction if it is + * TABLESWITCH or LOOKUPSWITCH, otherwise sets it + * to null. + */ + final void nextIsSwitch() { + next(); + if (cursor == null) { + return; + } + switch (cursor.getOpcode()) { + case Opcodes.TABLESWITCH: + case Opcodes.LOOKUPSWITCH: + return; + default: + cursor = null; + } + } + /** * Moves {@link #cursor} to next instruction if it has given opcode, * otherwise sets it to null. diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java index c61bc752..72b5f536 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java @@ -91,7 +91,8 @@ public final class StringSwitchJavacFilter implements IFilter { } } nextIsVar(Opcodes.ILOAD, "c"); - nextIs(Opcodes.TABLESWITCH); + // Can be TABLESWITCH or LOOKUPSWITCH depending on number of cases + nextIsSwitch(); return cursor != null; } } -- cgit v1.2.3 From f2c79fe18060e5cdaf6ad4f921f3ee374f7f0b69 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 13 Aug 2018 22:58:27 +0200 Subject: Update changelog This was forgotten in aa778680a3adc19eb59a1c96b570d9d1fe4a8145. --- org.jacoco.doc/docroot/doc/changes.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 2a7f1039..fd5ebcc0 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -49,6 +49,10 @@ (GitHub #667).
  • Question mark in filter expressions now correctly matches exactly one character (GitHub #672).
  • +
  • Part of bytecode that javac generates for switch statement on + java.lang.String values with a small number cases is now correctly + filtered out during generation of report + (GitHub #730).
  • Non-functional Changes

    -- cgit v1.2.3 From 29a770dd29cd5ed4a7ad7896c33eda670b2750f2 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Tue, 14 Aug 2018 13:17:18 +0200 Subject: Build with JDK 12 EA in Travis (#732) --- .travis.sh | 6 ++++++ .travis.yml | 1 + org.jacoco.build/pom.xml | 16 +++++++++++++--- org.jacoco.doc/docroot/doc/build.html | 22 ++++++++++++++-------- org.jacoco.doc/docroot/doc/environment.html | 2 +- 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/.travis.sh b/.travis.sh index 62fd54e5..9efcce94 100755 --- a/.travis.sh +++ b/.travis.sh @@ -63,6 +63,9 @@ case "$JDK" in 11-ea) install_jdk $JDK11_EA_URL ;; +12-ea) + install_jdk $JDK12_EA_URL + ;; esac # Do not use "~/.mavenrc" set by Travis (https://github.com/travis-ci/travis-ci/issues/3893), @@ -94,6 +97,9 @@ case "$JDK" in 11-ea) mvn -V -B -e verify -Dbytecode.version=11 ;; +12-ea) + mvn -V -B -e verify -Dbytecode.version=11 + ;; *) echo "Incorrect JDK [$JDK]" exit 1; diff --git a/.travis.yml b/.travis.yml index 17782084..da301639 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,5 +26,6 @@ env: - JDK=9 - JDK=10 - JDK=11-ea + - JDK=12-ea script: ./.travis.sh diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index f23b9b09..dc34e9de 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -677,17 +677,27 @@ + maven-jdk9 - [9,) + [9,12) - 6 + + maven-jdk12 + + [12,) + + + 7 + + + integration-tests @@ -899,7 +909,7 @@ - 6 + 7 diff --git a/org.jacoco.doc/docroot/doc/build.html b/org.jacoco.doc/docroot/doc/build.html index dd922580..c27d947a 100644 --- a/org.jacoco.doc/docroot/doc/build.html +++ b/org.jacoco.doc/docroot/doc/build.html @@ -11,8 +11,11 @@ border-collapse: collapse; padding: 3px; } + table tbody tr td { + border-left: #b0b0b0 3px solid; + } table tbody tr td:nth-child(2) { - border-right: #b0b0b0 3px solid; + border-left: none; } th { background-color:#e0e0e0; @@ -102,23 +105,25 @@ JDK 9 JDK 10 JDK 11 + JDK 12 - org.jacoco.core.test.validation.kotlin - excluded from build - compiled into bytecode version 50 (Java 6) + org.jacoco.core.test.validation.java8 + excluded from build + compiled into bytecode version 52 (Java 8) org.jacoco.core.test.validation.java7 excluded from build - compiled into bytecode version 51 (Java 7) + compiled into bytecode version 51 (Java 7) - org.jacoco.core.test.validation.java8 - excluded from build - compiled into bytecode version 52 (Java 8) + org.jacoco.core.test.validation.kotlin + excluded from build + compiled into bytecode version 50 (Java 6) + compiled into bytecode version 51 (Java 7) all other modules @@ -163,6 +168,7 @@
  • mvn clean install -Djdk.version=9 -Dbytecode.version=9
  • mvn clean install -Djdk.version=10 -Dbytecode.version=10
  • mvn clean install -Djdk.version=11 -Dbytecode.version=11
  • +
  • mvn clean install -Djdk.version=12 -Dbytecode.version=11
  • diff --git a/org.jacoco.doc/docroot/doc/environment.html b/org.jacoco.doc/docroot/doc/environment.html index 0cca8520..77c06a0c 100644 --- a/org.jacoco.doc/docroot/doc/environment.html +++ b/org.jacoco.doc/docroot/doc/environment.html @@ -68,7 +68,7 @@

    The minimum supported JRE version for JaCoCo is Java 5. To guarantee compatibility JaCoCo release builds should always be executed using JDK 5. - In addition we run builds with 6, 7, 8, 9, 10 and 11 JDKs. + In addition we run builds with 6, 7, 8, 9, 10, 11 and 12 JDKs.

    Build

    -- cgit v1.2.3 From 1283826e5c230f833036266c24b7921ae5f51142 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Tue, 14 Aug 2018 22:47:58 +0200 Subject: Add filter for classes and methods with annotation `Generated` (#731) --- .../validation/java5/AnnotationGeneratedTest.java | 23 ++++ .../java5/targets/AnnotationGeneratedTarget.java | 92 ++++++++++++++ .../filter/AnnotationGeneratedFilterTest.java | 137 +++++++++++++++++++++ .../analysis/filter/GroovyGeneratedFilterTest.java | 86 ------------- .../analysis/filter/LombokGeneratedFilterTest.java | 86 ------------- .../filter/AbstractAnnotatedMethodFilter.java | 66 ---------- .../analysis/filter/AnnotationGeneratedFilter.java | 63 ++++++++++ .../core/internal/analysis/filter/Filters.java | 7 +- .../analysis/filter/GroovyGeneratedFilter.java | 36 ------ .../analysis/filter/LombokGeneratedFilter.java | 36 ------ org.jacoco.doc/docroot/doc/changes.html | 4 + 11 files changed, 322 insertions(+), 314 deletions(-) create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationGeneratedTest.java create mode 100644 org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/AnnotationGeneratedTarget.java create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilterTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java delete mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractAnnotatedMethodFilter.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java delete mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilter.java delete mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilter.java diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationGeneratedTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationGeneratedTest.java new file mode 100644 index 00000000..3532d9e6 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationGeneratedTest.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.AnnotationGeneratedTarget; + +public class AnnotationGeneratedTest extends ValidationTestBase { + + public AnnotationGeneratedTest() { + super(AnnotationGeneratedTarget.class); + } + +} diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/AnnotationGeneratedTarget.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/AnnotationGeneratedTarget.java new file mode 100644 index 00000000..bfff621c --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/AnnotationGeneratedTarget.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +public class AnnotationGeneratedTarget { + + private static class RetentionPolicyRuntime { + + @Retention(RetentionPolicy.RUNTIME) + @interface Generated { + } + + @RetentionPolicyRuntime.Generated + static void annotatedMethod() { + nop(); // assertEmpty() + } + + @RetentionPolicyRuntime.Generated + static class AnnotatedClass { + AnnotatedClass() { + nop(); // assertEmpty() + } + } + + } + + private static class RetentionPolicyClass { + + @Retention(RetentionPolicy.CLASS) + @interface Generated { + } + + @RetentionPolicyClass.Generated + static void annotatedMethod() { + nop(); // assertEmpty() + } + + @RetentionPolicyClass.Generated + static class AnnotatedClass { + AnnotatedClass() { + nop(); // assertEmpty() + } + } + + } + + private static class RetentionPolicySource { + + @Retention(RetentionPolicy.SOURCE) + @interface Generated { + } + + @RetentionPolicySource.Generated + static void annotatedMethod() { + nop(); // assertFullyCovered() + } + + @RetentionPolicySource.Generated + static class AnnotatedClass { + AnnotatedClass() { + nop(); // assertFullyCovered() + } + } + + } + + public static void main(String[] args) { + RetentionPolicyRuntime.annotatedMethod(); + new RetentionPolicyRuntime.AnnotatedClass(); + + RetentionPolicyClass.annotatedMethod(); + new RetentionPolicyClass.AnnotatedClass(); + + RetentionPolicySource.annotatedMethod(); + new RetentionPolicySource.AnnotatedClass(); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java new file mode 100644 index 00000000..a76680ce --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class AnnotationGeneratedFilterTest implements IFilterOutput { + + private final IFilter filter = new AnnotationGeneratedFilter(); + + private final FilterContextMock context = new FilterContextMock(); + + private AbstractInsnNode fromInclusive; + private AbstractInsnNode toInclusive; + + @Test + public void should_filter_methods_annotated_with_runtime_visible_org_groovy_transform_Generated() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "hashCode", "()I", null, null); + m.visitAnnotation("Lgroovy/transform/Generated;", true); + + m.visitInsn(Opcodes.ICONST_0); + m.visitInsn(Opcodes.IRETURN); + + filter.filter(m, context, this); + + assertEquals(m.instructions.getFirst(), fromInclusive); + assertEquals(m.instructions.getLast(), toInclusive); + } + + @Test + public void should_filter_methods_annotated_with_runtime_invisible_lombok_Generated() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "hashCode", "()I", null, null); + m.visitAnnotation("Llombok/Generated;", false); + + m.visitInsn(Opcodes.ICONST_0); + m.visitInsn(Opcodes.IRETURN); + + filter.filter(m, context, this); + + assertEquals(m.instructions.getFirst(), fromInclusive); + assertEquals(m.instructions.getLast(), toInclusive); + } + + @Test + public void should_filter_classes_annotated_with_runtime_visible_org_immutables_value_Generated() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "hashCode", "()I", null, null); + + m.visitInsn(Opcodes.ICONST_0); + m.visitInsn(Opcodes.IRETURN); + + context.classAnnotations.add("Lorg/immutables/value/Generated;"); + + filter.filter(m, context, this); + + assertEquals(m.instructions.getFirst(), fromInclusive); + assertEquals(m.instructions.getLast(), toInclusive); + } + + @Test + public void should_filter_when_annotation_is_inner() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "hashCode", "()I", null, null); + + m.visitInsn(Opcodes.ICONST_0); + m.visitInsn(Opcodes.IRETURN); + + context.classAnnotations.add("Lorg/example/Class$Generated;"); + + filter.filter(m, context, this); + + assertEquals(m.instructions.getFirst(), fromInclusive); + assertEquals(m.instructions.getLast(), toInclusive); + } + + @Test + public void should_not_filter_when_no_annotations() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "hashCode", "()I", null, null); + + m.visitInsn(Opcodes.ICONST_0); + m.visitInsn(Opcodes.IRETURN); + + filter.filter(m, context, this); + + assertNull(fromInclusive); + assertNull(toInclusive); + } + + @Test + public void should_not_filter_when_other_annotations() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "hashCode", "()I", null, null); + m.visitAnnotation("LOtherAnnotation;", true); + + m.visitInsn(Opcodes.ICONST_0); + m.visitInsn(Opcodes.IRETURN); + + context.classAnnotations.add("LOtherAnnotation;"); + + filter.filter(m, context, this); + + assertNull(fromInclusive); + assertNull(toInclusive); + } + + public void ignore(final AbstractInsnNode fromInclusive, + final AbstractInsnNode toInclusive) { + assertNull(this.fromInclusive); + this.fromInclusive = fromInclusive; + this.toInclusive = toInclusive; + } + + public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { + fail(); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilterTest.java deleted file mode 100644 index f890cde3..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilterTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.internal.analysis.filter; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - -import org.jacoco.core.internal.instr.InstrSupport; -import org.junit.Test; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.MethodNode; - -public class GroovyGeneratedFilterTest implements IFilterOutput { - - private final IFilter filter = new GroovyGeneratedFilter(); - - private AbstractInsnNode fromInclusive; - private AbstractInsnNode toInclusive; - - @Test - public void testNoAnnotations() { - final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, - "hashCode", "()I", null, null); - - m.visitInsn(Opcodes.ICONST_0); - m.visitInsn(Opcodes.IRETURN); - - filter.filter(m, new FilterContextMock(), this); - - assertNull(fromInclusive); - assertNull(toInclusive); - } - - @Test - public void testOtherAnnotation() { - final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, - "hashCode", "()I", null, null); - m.visitAnnotation("Lother/Annotation;", true); - - m.visitInsn(Opcodes.ICONST_0); - m.visitInsn(Opcodes.IRETURN); - - filter.filter(m, new FilterContextMock(), this); - - assertNull(fromInclusive); - assertNull(toInclusive); - } - - @Test - public void testGroovyGeneratedAnnotation() { - final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, - "hashCode", "()I", null, null); - m.visitAnnotation("Lgroovy/transform/Generated;", true); - - m.visitInsn(Opcodes.ICONST_0); - m.visitInsn(Opcodes.IRETURN); - - filter.filter(m, new FilterContextMock(), this); - - assertEquals(m.instructions.getFirst(), fromInclusive); - assertEquals(m.instructions.getLast(), toInclusive); - } - - public void ignore(final AbstractInsnNode fromInclusive, - final AbstractInsnNode toInclusive) { - assertNull(this.fromInclusive); - this.fromInclusive = fromInclusive; - this.toInclusive = toInclusive; - } - - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java deleted file mode 100644 index 6821af12..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.internal.analysis.filter; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - -import org.jacoco.core.internal.instr.InstrSupport; -import org.junit.Test; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.MethodNode; - -public class LombokGeneratedFilterTest implements IFilterOutput { - - private final IFilter filter = new LombokGeneratedFilter(); - - private AbstractInsnNode fromInclusive; - private AbstractInsnNode toInclusive; - - @Test - public void testNoAnnotations() { - final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, - "hashCode", "()I", null, null); - - m.visitInsn(Opcodes.ICONST_0); - m.visitInsn(Opcodes.IRETURN); - - filter.filter(m, new FilterContextMock(), this); - - assertNull(fromInclusive); - assertNull(toInclusive); - } - - @Test - public void testOtherAnnotation() { - final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, - "hashCode", "()I", null, null); - m.visitAnnotation("Lother/Annotation;", false); - - m.visitInsn(Opcodes.ICONST_0); - m.visitInsn(Opcodes.IRETURN); - - filter.filter(m, new FilterContextMock(), this); - - assertNull(fromInclusive); - assertNull(toInclusive); - } - - @Test - public void testLombokGeneratedAnnotation() { - final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, - "hashCode", "()I", null, null); - m.visitAnnotation("Llombok/Generated;", false); - - m.visitInsn(Opcodes.ICONST_0); - m.visitInsn(Opcodes.IRETURN); - - filter.filter(m, new FilterContextMock(), this); - - assertEquals(m.instructions.getFirst(), fromInclusive); - assertEquals(m.instructions.getLast(), toInclusive); - } - - public void ignore(final AbstractInsnNode fromInclusive, - final AbstractInsnNode toInclusive) { - assertNull(this.fromInclusive); - this.fromInclusive = fromInclusive; - this.toInclusive = toInclusive; - } - - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); - } - -} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractAnnotatedMethodFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractAnnotatedMethodFilter.java deleted file mode 100644 index 7981bc6a..00000000 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractAnnotatedMethodFilter.java +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.internal.analysis.filter; - -import java.util.List; - -import org.objectweb.asm.tree.AnnotationNode; -import org.objectweb.asm.tree.MethodNode; - -/** - * Filters annotated methods. - */ -abstract class AbstractAnnotatedMethodFilter implements IFilter { - private final String descType; - - /** - * Configures a new filter instance. - * - * @param annotationType - * VM type of the annotation - */ - protected AbstractAnnotatedMethodFilter(final String annotationType) { - this.descType = "L" + annotationType + ";"; - } - - public void filter(final MethodNode methodNode, - final IFilterContext context, final IFilterOutput output) { - if (hasAnnotation(methodNode)) { - output.ignore(methodNode.instructions.getFirst(), - methodNode.instructions.getLast()); - } - } - - private boolean hasAnnotation(final MethodNode methodNode) { - final List annotations = getAnnotations(methodNode); - if (annotations != null) { - for (final AnnotationNode annotation : annotations) { - if (descType.equals(annotation.desc)) { - return true; - } - } - } - return false; - } - - /** - * Retrieves the annotations to search from a method. Depending on the - * retention of the annotation this is either - * visibleAnnotations or invisibleAnnotations. - * - * @param methodNode - * method to retrieve annotations from - * @return list of annotations - */ - abstract List getAnnotations(final MethodNode methodNode); - -} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java new file mode 100644 index 00000000..aae93f69 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import java.util.List; + +import org.objectweb.asm.tree.AnnotationNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Filters classes and methods annotated with + * {@link java.lang.annotation.RetentionPolicy#RUNTIME runtime visible} and + * {@link java.lang.annotation.RetentionPolicy#CLASS invisible} annotation whose + * simple name is Generated. + */ +public final class AnnotationGeneratedFilter implements IFilter { + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + + for (String annotation : context.getClassAnnotations()) { + if (matches(annotation)) { + output.ignore(methodNode.instructions.getFirst(), + methodNode.instructions.getLast()); + return; + } + } + + if (presentIn(methodNode.invisibleAnnotations) + || presentIn(methodNode.visibleAnnotations)) { + output.ignore(methodNode.instructions.getFirst(), + methodNode.instructions.getLast()); + } + + } + + private static boolean matches(final String annotation) { + return "Generated;".equals( + annotation.substring(Math.max(annotation.lastIndexOf('/'), + annotation.lastIndexOf('$')) + 1)); + } + + private static boolean presentIn(final List annotations) { + if (annotations != null) { + for (AnnotationNode annotation : annotations) { + if (matches(annotation.desc)) { + return true; + } + } + } + return false; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index 2e719221..b235cfb8 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -31,10 +31,9 @@ public final class Filters implements IFilter { new TryWithResourcesJavac11Filter(), new TryWithResourcesJavacFilter(), new TryWithResourcesEcjFilter(), new FinallyFilter(), new PrivateEmptyNoArgConstructorFilter(), - new StringSwitchJavacFilter(), new LombokGeneratedFilter(), - new GroovyGeneratedFilter(), new EnumEmptyConstructorFilter(), - new KotlinGeneratedFilter(), new KotlinLateinitFilter(), - new KotlinWhenSealedFilter()); + new StringSwitchJavacFilter(), new EnumEmptyConstructorFilter(), + new AnnotationGeneratedFilter(), new KotlinGeneratedFilter(), + new KotlinLateinitFilter(), new KotlinWhenSealedFilter()); private final IFilter[] filters; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilter.java deleted file mode 100644 index 816cc4cd..00000000 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilter.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.internal.analysis.filter; - -import java.util.List; - -import org.objectweb.asm.tree.AnnotationNode; -import org.objectweb.asm.tree.MethodNode; - -/** - * Filters methods annotated with @groovy.transform.Generated. - */ -public final class GroovyGeneratedFilter extends AbstractAnnotatedMethodFilter { - - /** - * New filter. - */ - public GroovyGeneratedFilter() { - super("groovy/transform/Generated"); - } - - @Override - List getAnnotations(final MethodNode methodNode) { - return methodNode.visibleAnnotations; - } - -} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilter.java deleted file mode 100644 index b35e741f..00000000 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilter.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.internal.analysis.filter; - -import java.util.List; - -import org.objectweb.asm.tree.AnnotationNode; -import org.objectweb.asm.tree.MethodNode; - -/** - * Filters methods annotated with @lombok.Generated. - */ -public final class LombokGeneratedFilter extends AbstractAnnotatedMethodFilter { - - /** - * New filter. - */ - public LombokGeneratedFilter() { - super("lombok/Generated"); - } - - @Override - List getAnnotations(final MethodNode methodNode) { - return methodNode.invisibleAnnotations; - } - -} diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index fd5ebcc0..1e747b3e 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -40,6 +40,10 @@ when expressions that list all cases of sealed class is filtered out during generation of report (GitHub #721). +
  • Classes and methods annotated with runtime visible and invisible annotation + whose simple name is Generated are filtered out during + generation of report + (GitHub #731).
  • Fixed Bugs

    -- cgit v1.2.3 From d0e461a331989925776199978d22d8db82ceba03 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 15 Aug 2018 15:15:40 +0200 Subject: Simplify unit tests of filters (#734) --- .../filter/AnnotationGeneratedFilterTest.java | 56 +++++---------- .../filter/EnumEmptyConstructorFilterTest.java | 51 ++++---------- .../internal/analysis/filter/EnumFilterTest.java | 51 ++++---------- .../analysis/filter/FilterContextMock.java | 3 + .../internal/analysis/filter/FilterTestBase.java | 79 ++++++++++++++++++++++ .../analysis/filter/FinallyFilterTest.java | 3 + .../analysis/filter/KotlinGeneratedFilterTest.java | 56 ++++----------- .../analysis/filter/KotlinLateinitFilterTest.java | 27 ++------ .../filter/KotlinWhenSealedFilterTest.java | 45 +++--------- .../PrivateEmptyNoArgConstructorFilterTest.java | 27 ++------ .../filter/StringSwitchJavacFilterTest.java | 38 +++-------- .../analysis/filter/SynchronizedFilterTest.java | 41 ++++------- .../analysis/filter/SyntheticFilterTest.java | 39 +++-------- .../filter/TryWithResourcesEcjFilterTest.java | 49 +++----------- .../filter/TryWithResourcesJavac11FilterTest.java | 53 +++------------ .../filter/TryWithResourcesJavacFilterTest.java | 75 ++++---------------- 16 files changed, 226 insertions(+), 467 deletions(-) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java index a76680ce..26070e49 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java @@ -11,25 +11,18 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; -public class AnnotationGeneratedFilterTest implements IFilterOutput { +/** + * Unit tests for {@link AnnotationGeneratedFilter}. + */ +public class AnnotationGeneratedFilterTest extends FilterTestBase { private final IFilter filter = new AnnotationGeneratedFilter(); - private final FilterContextMock context = new FilterContextMock(); - - private AbstractInsnNode fromInclusive; - private AbstractInsnNode toInclusive; - @Test public void should_filter_methods_annotated_with_runtime_visible_org_groovy_transform_Generated() { final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, @@ -39,10 +32,9 @@ public class AnnotationGeneratedFilterTest implements IFilterOutput { m.visitInsn(Opcodes.ICONST_0); m.visitInsn(Opcodes.IRETURN); - filter.filter(m, context, this); + filter.filter(m, context, output); - assertEquals(m.instructions.getFirst(), fromInclusive); - assertEquals(m.instructions.getLast(), toInclusive); + assertMethodIgnored(m); } @Test @@ -54,10 +46,9 @@ public class AnnotationGeneratedFilterTest implements IFilterOutput { m.visitInsn(Opcodes.ICONST_0); m.visitInsn(Opcodes.IRETURN); - filter.filter(m, context, this); + filter.filter(m, context, output); - assertEquals(m.instructions.getFirst(), fromInclusive); - assertEquals(m.instructions.getLast(), toInclusive); + assertMethodIgnored(m); } @Test @@ -70,10 +61,9 @@ public class AnnotationGeneratedFilterTest implements IFilterOutput { context.classAnnotations.add("Lorg/immutables/value/Generated;"); - filter.filter(m, context, this); + filter.filter(m, context, output); - assertEquals(m.instructions.getFirst(), fromInclusive); - assertEquals(m.instructions.getLast(), toInclusive); + assertMethodIgnored(m); } @Test @@ -86,10 +76,9 @@ public class AnnotationGeneratedFilterTest implements IFilterOutput { context.classAnnotations.add("Lorg/example/Class$Generated;"); - filter.filter(m, context, this); + filter.filter(m, context, output); - assertEquals(m.instructions.getFirst(), fromInclusive); - assertEquals(m.instructions.getLast(), toInclusive); + assertMethodIgnored(m); } @Test @@ -100,10 +89,9 @@ public class AnnotationGeneratedFilterTest implements IFilterOutput { m.visitInsn(Opcodes.ICONST_0); m.visitInsn(Opcodes.IRETURN); - filter.filter(m, context, this); + filter.filter(m, context, output); - assertNull(fromInclusive); - assertNull(toInclusive); + assertIgnored(); } @Test @@ -117,21 +105,9 @@ public class AnnotationGeneratedFilterTest implements IFilterOutput { context.classAnnotations.add("LOtherAnnotation;"); - filter.filter(m, context, this); - - assertNull(fromInclusive); - assertNull(toInclusive); - } - - public void ignore(final AbstractInsnNode fromInclusive, - final AbstractInsnNode toInclusive) { - assertNull(this.fromInclusive); - this.fromInclusive = fromInclusive; - this.toInclusive = toInclusive; - } + filter.filter(m, context, output); - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); + assertIgnored(); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java index 961bd321..b9752a56 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java @@ -11,25 +11,18 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; -public class EnumEmptyConstructorFilterTest implements IFilterOutput { +/** + * Unit tests for {@link EnumEmptyConstructorFilter}. + */ +public class EnumEmptyConstructorFilterTest extends FilterTestBase { private final EnumEmptyConstructorFilter filter = new EnumEmptyConstructorFilter(); - private final FilterContextMock context = new FilterContextMock(); - - private AbstractInsnNode fromInclusive; - private AbstractInsnNode toInclusive; - @Test public void should_filter() { final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, @@ -43,10 +36,9 @@ public class EnumEmptyConstructorFilterTest implements IFilterOutput { m.visitInsn(Opcodes.RETURN); context.superClassName = "java/lang/Enum"; - filter.filter(m, context, this); + filter.filter(m, context, output); - assertEquals(m.instructions.getFirst(), fromInclusive); - assertEquals(m.instructions.getLast(), toInclusive); + assertIgnored(new Range(m.instructions.getFirst(), m.instructions.getLast())); } /** @@ -73,10 +65,9 @@ public class EnumEmptyConstructorFilterTest implements IFilterOutput { m.visitInsn(Opcodes.RETURN); context.superClassName = "java/lang/Enum"; - filter.filter(m, context, this); + filter.filter(m, context, output); - assertNull(fromInclusive); - assertNull(toInclusive); + assertIgnored(); } /** @@ -101,10 +92,9 @@ public class EnumEmptyConstructorFilterTest implements IFilterOutput { m.visitInsn(Opcodes.RETURN); context.superClassName = "java/lang/Enum"; - filter.filter(m, context, this); + filter.filter(m, context, output); - assertNull(fromInclusive); - assertNull(toInclusive); + assertIgnored(); } /** @@ -124,10 +114,9 @@ public class EnumEmptyConstructorFilterTest implements IFilterOutput { m.visitInsn(Opcodes.NOP); context.superClassName = "java/lang/Enum"; - filter.filter(m, context, this); + filter.filter(m, context, output); - assertNull(fromInclusive); - assertNull(toInclusive); + assertIgnored(); } @Test @@ -137,21 +126,9 @@ public class EnumEmptyConstructorFilterTest implements IFilterOutput { null); m.visitInsn(Opcodes.NOP); - filter.filter(m, context, this); - - assertNull(fromInclusive); - assertNull(toInclusive); - } - - public void ignore(AbstractInsnNode fromInclusive, - AbstractInsnNode toInclusive) { - assertNull(this.fromInclusive); - this.fromInclusive = fromInclusive; - this.toInclusive = toInclusive; - } + filter.filter(m, context, output); - public void merge(AbstractInsnNode i1, AbstractInsnNode i2) { - fail(); + assertIgnored(); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java index eca9d445..e5c2a9b6 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java @@ -11,25 +11,18 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; -public class EnumFilterTest implements IFilterOutput { +/** + * Unit tests for {@link EnumFilter}. + */ +public class EnumFilterTest extends FilterTestBase { private final EnumFilter filter = new EnumFilter(); - private final FilterContextMock context = new FilterContextMock(); - - private AbstractInsnNode fromInclusive; - private AbstractInsnNode toInclusive; - @Test public void testValues() { final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, @@ -37,10 +30,9 @@ public class EnumFilterTest implements IFilterOutput { m.visitInsn(Opcodes.NOP); context.superClassName = "java/lang/Enum"; - filter.filter(m, context, this); + filter.filter(m, context, output); - assertEquals(m.instructions.getFirst(), fromInclusive); - assertEquals(m.instructions.getLast(), toInclusive); + assertMethodIgnored(m); } @Test @@ -49,10 +41,9 @@ public class EnumFilterTest implements IFilterOutput { "values", "()V", null, null); m.visitInsn(Opcodes.NOP); - filter.filter(m, context, this); + filter.filter(m, context, output); - assertNull(fromInclusive); - assertNull(toInclusive); + assertIgnored(); } @Test @@ -62,10 +53,9 @@ public class EnumFilterTest implements IFilterOutput { m.visitInsn(Opcodes.NOP); context.superClassName = "java/lang/Enum"; - filter.filter(m, context, this); + filter.filter(m, context, output); - assertEquals(m.instructions.getFirst(), fromInclusive); - assertEquals(m.instructions.getLast(), toInclusive); + assertMethodIgnored(m); } @Test @@ -75,10 +65,9 @@ public class EnumFilterTest implements IFilterOutput { m.visitInsn(Opcodes.NOP); context.superClassName = "java/lang/Enum"; - filter.filter(m, context, this); + filter.filter(m, context, output); - assertNull(fromInclusive); - assertNull(toInclusive); + assertIgnored(); } @Test @@ -87,21 +76,9 @@ public class EnumFilterTest implements IFilterOutput { "values", "()[LFoo;", null, null); m.visitInsn(Opcodes.NOP); - filter.filter(m, context, this); - - assertNull(fromInclusive); - assertNull(toInclusive); - } - - public void ignore(final AbstractInsnNode fromInclusive, - final AbstractInsnNode toInclusive) { - assertNull(this.fromInclusive); - this.fromInclusive = fromInclusive; - this.toInclusive = toInclusive; - } + filter.filter(m, context, output); - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); + assertIgnored(); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java index ce487a6e..4be4a491 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java @@ -14,6 +14,9 @@ package org.jacoco.core.internal.analysis.filter; import java.util.HashSet; import java.util.Set; +/** + * {@link IFilterContext} mock for unit tests. + */ public class FilterContextMock implements IFilterContext { public String className = "Foo"; diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java new file mode 100644 index 00000000..50bb59f3 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; + +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Base class for tests of {@link IFilter} implementations. + */ +public abstract class FilterTestBase { + + protected final FilterContextMock context = new FilterContextMock(); + + private final List ignoredRanges = new ArrayList(); + + protected final IFilterOutput output = new IFilterOutput() { + public void ignore(final AbstractInsnNode fromInclusive, + final AbstractInsnNode toInclusive) { + final Range range = new Range(); + range.fromInclusive = fromInclusive; + range.toInclusive = toInclusive; + ignoredRanges.add(range); + } + + public void merge(final AbstractInsnNode i1, + final AbstractInsnNode i2) { + fail(); + } + }; + + final void assertIgnored(Range... ranges) { + assertArrayEquals(ranges, ignoredRanges.toArray(new Range[0])); + } + + final void assertMethodIgnored(final MethodNode m) { + assertIgnored( + new Range(m.instructions.getFirst(), m.instructions.getLast())); + } + + static class Range { + AbstractInsnNode fromInclusive; + AbstractInsnNode toInclusive; + + Range() { + } + + Range(AbstractInsnNode fromInclusive, AbstractInsnNode toInclusive) { + this.fromInclusive = fromInclusive; + this.toInclusive = toInclusive; + } + + @Override + public boolean equals(Object obj) { + if (obj.getClass() == Range.class) { + final Range other = (Range) obj; + return this.fromInclusive.equals(other.fromInclusive) + && this.toInclusive.equals(other.toInclusive); + } + return false; + } + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java index a2f5a73e..987f3398 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java @@ -24,6 +24,9 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; +/** + * Unit tests for {@link FinallyFilter}. + */ public class FinallyFilterTest implements IFilterOutput { private final IFilter filter = new FinallyFilter(); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilterTest.java index 197f9d0f..561eea20 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilterTest.java @@ -11,26 +11,19 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; -public class KotlinGeneratedFilterTest implements IFilterOutput { +/** + * Unit tests for {@link KotlinGeneratedFilter}. + */ +public class KotlinGeneratedFilterTest extends FilterTestBase { private final IFilter filter = new KotlinGeneratedFilter(); - private final FilterContextMock context = new FilterContextMock(); - - private AbstractInsnNode fromInclusive; - private AbstractInsnNode toInclusive; - @Test public void testNoLinesForKotlinWithDebug() { final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, @@ -40,9 +33,9 @@ public class KotlinGeneratedFilterTest implements IFilterOutput { context.classAnnotations .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); - filter.filter(m, context, this); + filter.filter(m, context, output); - assertMethodSkipped(m); + assertMethodIgnored(m); } @Test @@ -56,9 +49,9 @@ public class KotlinGeneratedFilterTest implements IFilterOutput { context.classAnnotations .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); - filter.filter(m, context, this); + filter.filter(m, context, output); - assertNotApplicable(); + assertIgnored(); } @Test @@ -68,9 +61,9 @@ public class KotlinGeneratedFilterTest implements IFilterOutput { m.visitInsn(Opcodes.ICONST_0); m.visitInsn(Opcodes.IRETURN); - filter.filter(m, context, this); + filter.filter(m, context, output); - assertNotApplicable(); + assertIgnored(); } @Test @@ -83,9 +76,9 @@ public class KotlinGeneratedFilterTest implements IFilterOutput { .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); context.sourceFileName = null; - filter.filter(m, context, this); + filter.filter(m, context, output); - assertNotApplicable(); + assertIgnored(); } @Test @@ -99,30 +92,9 @@ public class KotlinGeneratedFilterTest implements IFilterOutput { .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); context.sourceFileName = null; - filter.filter(m, context, this); - - assertNotApplicable(); - } - - private void assertNotApplicable() { - assertNull(fromInclusive); - assertNull(toInclusive); - } - - private void assertMethodSkipped(MethodNode m) { - assertEquals(m.instructions.getFirst(), fromInclusive); - assertEquals(m.instructions.getLast(), toInclusive); - } - - public void ignore(final AbstractInsnNode fromInclusive, - final AbstractInsnNode toInclusive) { - assertNull(this.fromInclusive); - this.fromInclusive = fromInclusive; - this.toInclusive = toInclusive; - } + filter.filter(m, context, output); - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); + assertIgnored(); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java index a2306f8a..0d63c17e 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java @@ -11,10 +11,6 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Label; @@ -22,15 +18,16 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; -public class KotlinLateinitFilterTest implements IFilterOutput { +/** + * Unit tests for {@link KotlinLateinitFilter}. + */ +public class KotlinLateinitFilterTest extends FilterTestBase { + private final KotlinLateinitFilter filter = new KotlinLateinitFilter(); private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, "name", "()V", null, null); - private AbstractInsnNode fromInclusive; - private AbstractInsnNode toInclusive; - @Test public void testLateinitBranchIsFiltered() { final Label l1 = new Label(); @@ -55,20 +52,10 @@ public class KotlinLateinitFilterTest implements IFilterOutput { m.visitLabel(l2); m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "android/os/PowerManager$WakeLock", "acquire", "", false); - filter.filter(m, new FilterContextMock(), this); - assertEquals(expectedFrom, fromInclusive); - assertEquals(expectedTo, toInclusive); - } + filter.filter(m, context, output); - public void ignore(AbstractInsnNode fromInclusive, - AbstractInsnNode toInclusive) { - assertNull(this.fromInclusive); - this.fromInclusive = fromInclusive; - this.toInclusive = toInclusive; + assertIgnored(new Range(expectedFrom, expectedTo)); } - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); - } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilterTest.java index 92b0de33..fe61f60f 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilterTest.java @@ -11,20 +11,16 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.util.ArrayList; -import java.util.List; - import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; -public class KotlinWhenSealedFilterTest implements IFilterOutput { +/** + * Unit tests for {@link KotlinWhenSealedFilter}. + */ +public class KotlinWhenSealedFilterTest extends FilterTestBase { private final KotlinWhenSealedFilter filter = new KotlinWhenSealedFilter(); @@ -55,15 +51,9 @@ public class KotlinWhenSealedFilterTest implements IFilterOutput { m.visitInsn(Opcodes.ATHROW); range2.toInclusive = m.instructions.getLast(); - filter.filter(m, new FilterContextMock(), this); - - assertEquals(2, ignoredRanges.size()); + filter.filter(m, context, output); - assertEquals(range1.fromInclusive, ignoredRanges.get(0).fromInclusive); - assertEquals(range1.toInclusive, ignoredRanges.get(0).toInclusive); - - assertEquals(range2.fromInclusive, ignoredRanges.get(1).fromInclusive); - assertEquals(range2.toInclusive, ignoredRanges.get(1).toInclusive); + assertIgnored(range1, range2); } @Test @@ -84,28 +74,9 @@ public class KotlinWhenSealedFilterTest implements IFilterOutput { m.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Throwable"); m.visitInsn(Opcodes.ATHROW); - filter.filter(m, new FilterContextMock(), this); - - assertEquals(0, ignoredRanges.size()); - } - - static class Range { - AbstractInsnNode fromInclusive; - AbstractInsnNode toInclusive; - } - - private final List ignoredRanges = new ArrayList(); - - public void ignore(final AbstractInsnNode fromInclusive, - final AbstractInsnNode toInclusive) { - final Range range = new Range(); - range.fromInclusive = fromInclusive; - range.toInclusive = toInclusive; - this.ignoredRanges.add(range); - } + filter.filter(m, context, output); - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); + assertIgnored(); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java index d3db0423..3817f82b 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java @@ -11,22 +11,18 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; -public class PrivateEmptyNoArgConstructorFilterTest implements IFilterOutput { +/** + * Unit tests for {@link PrivateEmptyNoArgConstructorFilter}. + */ +public class PrivateEmptyNoArgConstructorFilterTest extends FilterTestBase { private final IFilter filter = new PrivateEmptyNoArgConstructorFilter(); - private AbstractInsnNode fromInclusive; - private AbstractInsnNode toInclusive; - @Test public void test() { final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, @@ -37,20 +33,9 @@ public class PrivateEmptyNoArgConstructorFilterTest implements IFilterOutput { "()V", false); m.visitInsn(Opcodes.RETURN); - filter.filter(m, new FilterContextMock(), this); - - assertEquals(m.instructions.getFirst(), fromInclusive); - assertEquals(m.instructions.getLast(), toInclusive); - } - - public void ignore(final AbstractInsnNode fromInclusive, - final AbstractInsnNode toInclusive) { - this.fromInclusive = fromInclusive; - this.toInclusive = toInclusive; - } + filter.filter(m, context, output); - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); + assertMethodIgnored(m); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java index e83ae0e6..6298bec4 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java @@ -11,10 +11,6 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Label; @@ -22,16 +18,16 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; -public class StringSwitchJavacFilterTest implements IFilterOutput { +/** + * Unit tests for {@link StringSwitchJavacFilter}. + */ +public class StringSwitchJavacFilterTest extends FilterTestBase { private final IFilter filter = new StringSwitchJavacFilter(); private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, "name", "()V", null, null); - private AbstractInsnNode fromInclusive; - private AbstractInsnNode toInclusive; - private AbstractInsnNode expectedFromInclusive; private AbstractInsnNode expectedToInclusive; @@ -100,10 +96,9 @@ public class StringSwitchJavacFilterTest implements IFilterOutput { m.visitTableSwitchInsn(0, 2, cases); m.visitLabel(cases); - filter.filter(m, new FilterContextMock(), this); + filter.filter(m, context, output); - assertEquals(expectedFromInclusive, this.fromInclusive); - assertEquals(expectedToInclusive, this.toInclusive); + assertIgnored(new Range(expectedFromInclusive, expectedToInclusive)); } @Test @@ -114,10 +109,9 @@ public class StringSwitchJavacFilterTest implements IFilterOutput { m.visitLookupSwitchInsn(cases, null, new Label[] {}); m.visitLabel(cases); - filter.filter(m, new FilterContextMock(), this); + filter.filter(m, context, output); - assertEquals(expectedFromInclusive, this.fromInclusive); - assertEquals(expectedToInclusive, this.toInclusive); + assertIgnored(new Range(expectedFromInclusive, expectedToInclusive)); } @Test @@ -162,21 +156,9 @@ public class StringSwitchJavacFilterTest implements IFilterOutput { m.visitLabel(cases); - filter.filter(m, new FilterContextMock(), this); - - assertNull(this.fromInclusive); - assertNull(this.toInclusive); - } - - public void ignore(final AbstractInsnNode fromInclusive, - final AbstractInsnNode toInclusive) { - assertNull(this.fromInclusive); - this.fromInclusive = fromInclusive; - this.toInclusive = toInclusive; - } + filter.filter(m, context, output); - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); + assertIgnored(); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java index b0f5f3d0..5e42df2c 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java @@ -11,28 +11,23 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.MethodNode; -public class SynchronizedFilterTest implements IFilterOutput { +/** + * Unit tests for {@link SynchronizedFilter}. + */ +public class SynchronizedFilterTest extends FilterTestBase { private final SynchronizedFilter filter = new SynchronizedFilter(); private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, "name", "()V", null, null); - private AbstractInsnNode fromInclusive; - private AbstractInsnNode toInclusive; - @Test public void javac() { final Label start = new Label(); @@ -64,9 +59,10 @@ public class SynchronizedFilterTest implements IFilterOutput { m.visitLabel(exit); m.visitInsn(Opcodes.RETURN); - filter.filter(m, new FilterContextMock(), this); - assertEquals(handler.info, fromInclusive); - assertEquals(((LabelNode) exit.info).getPrevious(), toInclusive); + filter.filter(m, context, output); + + assertIgnored(new Range((LabelNode) handler.info, + ((LabelNode) exit.info).getPrevious())); } /** @@ -117,8 +113,9 @@ public class SynchronizedFilterTest implements IFilterOutput { m.visitLabel(exit); m.visitInsn(Opcodes.RETURN); - filter.filter(m, new FilterContextMock(), this); - assertNull(fromInclusive); + filter.filter(m, context, output); + + assertIgnored(); } @Test @@ -152,20 +149,10 @@ public class SynchronizedFilterTest implements IFilterOutput { m.visitLabel(exit); m.visitInsn(Opcodes.RETURN); - filter.filter(m, new FilterContextMock(), this); - assertEquals(handler.info, fromInclusive); - assertEquals(((LabelNode) exit.info).getPrevious(), toInclusive); - } - - public void ignore(AbstractInsnNode fromInclusive, - AbstractInsnNode toInclusive) { - assertNull(this.fromInclusive); - this.fromInclusive = fromInclusive; - this.toInclusive = toInclusive; - } + filter.filter(m, context, output); - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); + assertIgnored(new Range((LabelNode) handler.info, + ((LabelNode) exit.info).getPrevious())); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java index 2574ca50..011fc542 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java @@ -11,33 +11,27 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; -public class SyntheticFilterTest implements IFilterOutput { +/** + * Unit tests for {@link SyntheticFilter}. + */ +public class SyntheticFilterTest extends FilterTestBase { private final SyntheticFilter filter = new SyntheticFilter(); - private AbstractInsnNode fromInclusive; - private AbstractInsnNode toInclusive; - @Test public void testNonSynthetic() { final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, "name", "()V", null, null); m.visitInsn(Opcodes.NOP); - filter.filter(m, new FilterContextMock(), this); + filter.filter(m, context, output); - assertNull(fromInclusive); - assertNull(toInclusive); + assertIgnored(); } @Test @@ -46,10 +40,9 @@ public class SyntheticFilterTest implements IFilterOutput { Opcodes.ACC_SYNTHETIC, "name", "()V", null, null); m.visitInsn(Opcodes.NOP); - filter.filter(m, new FilterContextMock(), this); + filter.filter(m, context, output); - assertEquals(m.instructions.getFirst(), fromInclusive); - assertEquals(m.instructions.getLast(), toInclusive); + assertMethodIgnored(m); } @Test @@ -58,21 +51,9 @@ public class SyntheticFilterTest implements IFilterOutput { Opcodes.ACC_SYNTHETIC, "lambda$1", "()V", null, null); m.visitInsn(Opcodes.NOP); - filter.filter(m, new FilterContextMock(), this); - - assertNull(fromInclusive); - assertNull(toInclusive); - } - - public void ignore(final AbstractInsnNode fromInclusive, - final AbstractInsnNode toInclusive) { - assertNull(this.fromInclusive); - this.fromInclusive = fromInclusive; - this.toInclusive = toInclusive; - } + filter.filter(m, context, output); - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); + assertIgnored(); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilterTest.java index 3a8bdf49..417c14c7 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilterTest.java @@ -11,20 +11,16 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.util.ArrayList; -import java.util.List; - import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; -public class TryWithResourcesEcjFilterTest implements IFilterOutput { +/** + * Unit tests for {@link TryWithResourcesEcjFilter}. + */ +public class TryWithResourcesEcjFilterTest extends FilterTestBase { private final TryWithResourcesEcjFilter filter = new TryWithResourcesEcjFilter(); @@ -310,15 +306,9 @@ public class TryWithResourcesEcjFilterTest implements IFilterOutput { // additional handlers m.visitInsn(Opcodes.NOP); - filter.filter(m, new FilterContextMock(), this); - - assertEquals(2, from.size()); - - assertEquals(range0.fromInclusive, from.get(0)); - assertEquals(range0.toInclusive, to.get(0)); + filter.filter(m, context, output); - assertEquals(range1.fromInclusive, from.get(1)); - assertEquals(range1.toInclusive, to.get(1)); + assertIgnored(range0, range1); } /** @@ -598,32 +588,9 @@ public class TryWithResourcesEcjFilterTest implements IFilterOutput { // additional handlers m.visitInsn(Opcodes.NOP); - filter.filter(m, new FilterContextMock(), this); - - assertEquals(2, from.size()); - - assertEquals(range0.fromInclusive, from.get(0)); - assertEquals(range0.toInclusive, to.get(0)); - - assertEquals(range1.fromInclusive, from.get(1)); - assertEquals(range1.toInclusive, to.get(1)); - } - - static class Range { - AbstractInsnNode fromInclusive; - AbstractInsnNode toInclusive; - } - - private final List from = new ArrayList(); - private final List to = new ArrayList(); - - public void ignore(AbstractInsnNode from, AbstractInsnNode to) { - this.from.add(from); - this.to.add(to); - } + filter.filter(m, context, output); - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); + assertIgnored(range0, range1); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11FilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11FilterTest.java index f012d87b..0dc8c814 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11FilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11FilterTest.java @@ -15,21 +15,15 @@ import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -public class TryWithResourcesJavac11FilterTest implements IFilterOutput { +/** + * Unit tests for {@link TryWithResourcesJavac11Filter}. + */ +public class TryWithResourcesJavac11FilterTest extends FilterTestBase { private final TryWithResourcesJavac11Filter filter = new TryWithResourcesJavac11Filter(); - private final FilterContextMock context = new FilterContextMock(); - private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, "name", "()V", null, null); @@ -80,16 +74,9 @@ public class TryWithResourcesJavac11FilterTest implements IFilterOutput { m.visitLabel(e); - filter.filter(m, context, this); - - assertEquals(2, from.size()); - assertEquals(2, to.size()); + filter.filter(m, context, output); - assertEquals(range1.fromInclusive, from.get(0)); - assertEquals(range1.toInclusive, to.get(0)); - - assertEquals(range2.fromInclusive, from.get(1)); - assertEquals(range2.toInclusive, to.get(1)); + assertIgnored(range1, range2); } /** @@ -143,33 +130,9 @@ public class TryWithResourcesJavac11FilterTest implements IFilterOutput { m.visitLabel(e); - filter.filter(m, context, this); - - assertEquals(2, from.size()); - assertEquals(2, to.size()); - - assertEquals(range1.fromInclusive, from.get(0)); - assertEquals(range1.toInclusive, to.get(0)); - - assertEquals(range2.fromInclusive, from.get(1)); - assertEquals(range2.toInclusive, to.get(1)); - } - - static class Range { - AbstractInsnNode fromInclusive; - AbstractInsnNode toInclusive; - } - - private final List from = new ArrayList(); - private final List to = new ArrayList(); - - public void ignore(AbstractInsnNode from, AbstractInsnNode to) { - this.from.add(from); - this.to.add(to); - } + filter.filter(m, context, output); - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); + assertIgnored(range1, range2); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilterTest.java index 7a7cc1ce..be9134e7 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilterTest.java @@ -11,20 +11,16 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.util.ArrayList; -import java.util.List; - import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Test; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; -public class TryWithResourcesJavacFilterTest implements IFilterOutput { +/** + * Unit tests for {@link TryWithResourcesJavacFilter}. + */ +public class TryWithResourcesJavacFilterTest extends FilterTestBase { private final TryWithResourcesJavacFilter filter = new TryWithResourcesJavacFilter(); @@ -219,21 +215,9 @@ public class TryWithResourcesJavacFilterTest implements IFilterOutput { m.visitVarInsn(Opcodes.ALOAD, 8); m.visitInsn(Opcodes.ATHROW); - filter.filter(m, new FilterContextMock(), this); - - assertEquals(4, from.size()); - - assertEquals(range0.fromInclusive, from.get(0)); - assertEquals(range0.toInclusive, to.get(0)); - - assertEquals(range1.fromInclusive, from.get(1)); - assertEquals(range1.toInclusive, to.get(1)); + filter.filter(m, context, output); - assertEquals(range2.fromInclusive, from.get(2)); - assertEquals(range2.toInclusive, to.get(2)); - - assertEquals(range3.fromInclusive, from.get(3)); - assertEquals(range3.toInclusive, to.get(3)); + assertIgnored(range0, range1, range2, range3); } /** @@ -548,21 +532,9 @@ public class TryWithResourcesJavacFilterTest implements IFilterOutput { m.visitVarInsn(Opcodes.ALOAD, 11); m.visitInsn(Opcodes.ATHROW); - filter.filter(m, new FilterContextMock(), this); - - assertEquals(4, from.size()); - - assertEquals(range0.fromInclusive, from.get(0)); - assertEquals(range0.toInclusive, to.get(0)); - - assertEquals(range1.fromInclusive, from.get(1)); - assertEquals(range1.toInclusive, to.get(1)); - - assertEquals(range2.fromInclusive, from.get(2)); - assertEquals(range2.toInclusive, to.get(2)); + filter.filter(m, context, output); - assertEquals(range3.fromInclusive, from.get(3)); - assertEquals(range3.toInclusive, to.get(3)); + assertIgnored(range0, range1, range2, range3); } /** @@ -726,15 +698,9 @@ public class TryWithResourcesJavacFilterTest implements IFilterOutput { m.visitLabel(end); - filter.filter(m, new FilterContextMock(), this); + filter.filter(m, context, output); - assertEquals(2, from.size()); - - assertEquals(range0.fromInclusive, from.get(0)); - assertEquals(range0.toInclusive, to.get(0)); - - assertEquals(range1.fromInclusive, from.get(1)); - assertEquals(range1.toInclusive, to.get(1)); + assertIgnored(range0, range1); } /** @@ -794,26 +760,9 @@ public class TryWithResourcesJavacFilterTest implements IFilterOutput { m.visitVarInsn(Opcodes.ALOAD, 4); m.visitInsn(Opcodes.ATHROW); - filter.filter(m, new FilterContextMock(), this); - - assertEquals(0, from.size()); - } - - static class Range { - AbstractInsnNode fromInclusive; - AbstractInsnNode toInclusive; - } - - private final List from = new ArrayList(); - private final List to = new ArrayList(); - - public void ignore(AbstractInsnNode from, AbstractInsnNode to) { - this.from.add(from); - this.to.add(to); - } + filter.filter(m, context, output); - public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) { - fail(); + assertIgnored(); } } -- cgit v1.2.3 From 436f0227c0a7563547870cb2a56f36cd1b4cf754 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Thu, 16 Aug 2018 11:44:10 +0200 Subject: Add experimental support for Java 12 class files (#738) --- .travis.sh | 2 +- .../src/org/jacoco/core/instr/ClassFileVersionsTest.java | 6 ++++++ .../src/org/jacoco/core/internal/ContentTypeDetectorTest.java | 7 +++++++ .../src/org/jacoco/core/internal/instr/InstrSupportTest.java | 1 + .../src/org/jacoco/core/internal/ContentTypeDetector.java | 1 + org.jacoco.doc/docroot/doc/build.html | 2 +- org.jacoco.doc/docroot/doc/changes.html | 2 ++ 7 files changed, 19 insertions(+), 2 deletions(-) diff --git a/.travis.sh b/.travis.sh index 9efcce94..83111c83 100755 --- a/.travis.sh +++ b/.travis.sh @@ -98,7 +98,7 @@ case "$JDK" in mvn -V -B -e verify -Dbytecode.version=11 ;; 12-ea) - mvn -V -B -e verify -Dbytecode.version=11 + mvn -V -B -e verify -Dbytecode.version=12 ;; *) echo "Incorrect JDK [$JDK]" diff --git a/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java index 1c9afee0..38bd8083 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java @@ -23,6 +23,7 @@ import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; import static org.objectweb.asm.Opcodes.POP; import static org.objectweb.asm.Opcodes.RETURN; import static org.objectweb.asm.Opcodes.V11; +import static org.objectweb.asm.Opcodes.V12; import static org.objectweb.asm.Opcodes.V1_1; import static org.objectweb.asm.Opcodes.V1_2; import static org.objectweb.asm.Opcodes.V1_3; @@ -107,6 +108,11 @@ public class ClassFileVersionsTest { testVersion(V11, true); } + @Test + public void test_12() throws IOException { + testVersion(V12, true); + } + private void testVersion(int version, boolean frames) throws IOException { final byte[] original = createClass(version, frames); 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 4d95dd47..fe443f8d 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 @@ -128,6 +128,13 @@ public class ContentTypeDetectorTest { assertContent(); } + @Test + public void should_detect_java_12() throws IOException { + initData(0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x38); + assertEquals(ContentTypeDetector.CLASSFILE, detector.getType()); + assertContent(); + } + @Test public void testMachObjectFile() throws IOException { initData(0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x02); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java index 95bd0437..c1b3044b 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java @@ -59,6 +59,7 @@ public class InstrSupportTest { assertTrue(InstrSupport.needsFrames(Opcodes.V9)); assertTrue(InstrSupport.needsFrames(BytecodeVersion.V10)); assertTrue(InstrSupport.needsFrames(Opcodes.V11)); + assertTrue(InstrSupport.needsFrames(Opcodes.V12)); } @Test diff --git a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java index 0df14607..0fcf5371 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java @@ -85,6 +85,7 @@ public class ContentTypeDetector { case Opcodes.V9: case BytecodeVersion.V10: case Opcodes.V11: + case Opcodes.V12: return CLASSFILE; } } diff --git a/org.jacoco.doc/docroot/doc/build.html b/org.jacoco.doc/docroot/doc/build.html index c27d947a..692101e4 100644 --- a/org.jacoco.doc/docroot/doc/build.html +++ b/org.jacoco.doc/docroot/doc/build.html @@ -168,7 +168,7 @@
  • mvn clean install -Djdk.version=9 -Dbytecode.version=9
  • mvn clean install -Djdk.version=10 -Dbytecode.version=10
  • mvn clean install -Djdk.version=11 -Dbytecode.version=11
  • -
  • mvn clean install -Djdk.version=12 -Dbytecode.version=11
  • +
  • mvn clean install -Djdk.version=12 -Dbytecode.version=12
  • diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 1e747b3e..46509396 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -24,6 +24,8 @@
    • Experimental support for Java 11 class files (GitHub #719).
    • +
    • Experimental support for Java 12 class files + (GitHub #738).
    • Branches and instructions generated by javac 11 for try-with-resources statement are filtered out (GitHub #669).
    • -- cgit v1.2.3 From 63d55acf9071446e9ea6706d6a65c94d87faca17 Mon Sep 17 00:00:00 2001 From: Lukas Krejci Date: Fri, 17 Aug 2018 02:56:13 +0200 Subject: Maven goal `report-aggregate` should consider dependencies specified using version range (#658) --- .../it/it-report-aggregate/child2v2/pom.xml | 25 ++++++++++++++++++++++ .../child2v2/src/main/java/package2/Example2.java | 19 ++++++++++++++++ .../src/test/java/package2/Example2Test.java | 23 ++++++++++++++++++++ .../it/it-report-aggregate/pom.xml | 1 + .../it/it-report-aggregate/report/pom.xml | 2 +- .../it/it-report-aggregate/verify.bsh | 10 +++++++-- .../src/org/jacoco/maven/ReportAggregateMojo.java | 22 ++++++++++++++++++- org.jacoco.doc/docroot/doc/changes.html | 3 +++ 8 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 jacoco-maven-plugin.test/it/it-report-aggregate/child2v2/pom.xml create mode 100644 jacoco-maven-plugin.test/it/it-report-aggregate/child2v2/src/main/java/package2/Example2.java create mode 100644 jacoco-maven-plugin.test/it/it-report-aggregate/child2v2/src/test/java/package2/Example2Test.java diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child2v2/pom.xml b/jacoco-maven-plugin.test/it/it-report-aggregate/child2v2/pom.xml new file mode 100644 index 00000000..9dba70ce --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child2v2/pom.xml @@ -0,0 +1,25 @@ + + + + 4.0.0 + + + jacoco + it-report-aggregate + 1.0-SNAPSHOT + + + child2 + 2.0-SNAPSHOT + + diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child2v2/src/main/java/package2/Example2.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child2v2/src/main/java/package2/Example2.java new file mode 100644 index 00000000..2e2d0405 --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child2v2/src/main/java/package2/Example2.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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, Jan Wloka - initial API and implementation + * + *******************************************************************************/ +package package2; + +public class Example2 { + + public void a() { + } + +} diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child2v2/src/test/java/package2/Example2Test.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child2v2/src/test/java/package2/Example2Test.java new file mode 100644 index 00000000..21149e22 --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child2v2/src/test/java/package2/Example2Test.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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, Jan Wloka - initial API and implementation + * + *******************************************************************************/ +package package2; + +import org.junit.Test; + +public class Example2Test { + + @Test + public void test() { + new Example2().a(); + } + +} diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/pom.xml b/jacoco-maven-plugin.test/it/it-report-aggregate/pom.xml index 4575ee20..34a34538 100644 --- a/jacoco-maven-plugin.test/it/it-report-aggregate/pom.xml +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/pom.xml @@ -26,6 +26,7 @@ child1 child1-test child2 + child2v2 report diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/report/pom.xml b/jacoco-maven-plugin.test/it/it-report-aggregate/report/pom.xml index cbf3e97e..b2ace062 100644 --- a/jacoco-maven-plugin.test/it/it-report-aggregate/report/pom.xml +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/report/pom.xml @@ -38,7 +38,7 @@ jacoco child2 - ${project.version} + [2-SNAPSHOT,) runtime diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh b/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh index 80f6bc29..8cdcd272 100644 --- a/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh @@ -22,8 +22,14 @@ if ( !Pattern.compile( "Loading execution data file \\S*child1-test.target.jacoc throw new RuntimeException( "Execution data from child1-test was not loaded." ); } -if ( !Pattern.compile( "Loading execution data file \\S*child2.target.jacoco.exec").matcher( buildLog ).find() ) { - throw new RuntimeException( "Execution data from child2 was not loaded." ); +if ( !new File( basedir, "child2/target/jacoco.exec" ).isFile()) { + throw new RuntimeException( "No execution data in child2v2." ); +} +if ( Pattern.compile( "Loading execution data file \\S*child2.target.jacoco.exec").matcher( buildLog ).find() ) { + throw new RuntimeException( "Execution data from child2 was loaded, whereas range should exclude it." ); +} +if ( !Pattern.compile( "Loading execution data file \\S*child2v2.target.jacoco.exec").matcher( buildLog ).find() ) { + throw new RuntimeException( "Execution data from child2v2 was not loaded." ); } if ( !Pattern.compile( "Loading execution data file \\S*report.target.jacoco.exec").matcher( buildLog ).find() ) { diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/ReportAggregateMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/ReportAggregateMojo.java index 5597ddfa..890d277c 100644 --- a/jacoco-maven-plugin/src/org/jacoco/maven/ReportAggregateMojo.java +++ b/jacoco-maven-plugin/src/org/jacoco/maven/ReportAggregateMojo.java @@ -19,6 +19,9 @@ import java.util.List; import java.util.Locale; import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; +import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; +import org.apache.maven.artifact.versioning.VersionRange; import org.apache.maven.model.Dependency; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; @@ -177,11 +180,28 @@ public class ReportAggregateMojo extends AbstractReportMojo { return result; } + /** + * Note that if dependency specified using version range and reactor + * contains multiple modules with same artifactId and groupId but of + * different versions, then first dependency which matches range will be + * selected. For example in case of range [0,2] if version 1 is + * before version 2 in reactor, then version 1 will be selected. + */ private MavenProject findProjectFromReactor(final Dependency d) { + final VersionRange depVersionAsRange; + try { + depVersionAsRange = VersionRange + .createFromVersionSpec(d.getVersion()); + } catch (InvalidVersionSpecificationException e) { + throw new AssertionError(e); + } + for (final MavenProject p : reactorProjects) { + final DefaultArtifactVersion pv = new DefaultArtifactVersion( + p.getVersion()); if (p.getGroupId().equals(d.getGroupId()) && p.getArtifactId().equals(d.getArtifactId()) - && p.getVersion().equals(d.getVersion())) { + && depVersionAsRange.containsVersion(pv)) { return p; } } diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 46509396..35c61284 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -46,6 +46,9 @@ whose simple name is Generated are filtered out during generation of report (GitHub #731). +
    • Maven goal report-aggregate now also considers dependencies + specified using version range. Idea and implementation by Lukas Krejc + (GitHub #658).

    Fixed Bugs

    -- cgit v1.2.3 From 146526006670ec200c25a4efd100fe35d01a7aa0 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 17 Aug 2018 16:09:31 +0200 Subject: Remove useless jacoco.fileSets from documentation of MergeMojo (#739) --- jacoco-maven-plugin/src/org/jacoco/maven/MergeMojo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/MergeMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/MergeMojo.java index bcddf2ae..8b882e08 100644 --- a/jacoco-maven-plugin/src/org/jacoco/maven/MergeMojo.java +++ b/jacoco-maven-plugin/src/org/jacoco/maven/MergeMojo.java @@ -59,7 +59,7 @@ public class MergeMojo extends AbstractJacocoMojo { * * */ - @Parameter(property = "jacoco.fileSets", required = true) + @Parameter(required = true) private List fileSets; @Override -- cgit v1.2.3 From 3208aad8a26528558fafe5f1b44f9d1525c1c9d0 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 17 Aug 2018 13:44:37 +0200 Subject: Fix typo --- jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh b/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh index 8cdcd272..9c2d6c9d 100644 --- a/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh @@ -23,7 +23,7 @@ if ( !Pattern.compile( "Loading execution data file \\S*child1-test.target.jacoc } if ( !new File( basedir, "child2/target/jacoco.exec" ).isFile()) { - throw new RuntimeException( "No execution data in child2v2." ); + throw new RuntimeException( "No execution data in child2." ); } if ( Pattern.compile( "Loading execution data file \\S*child2.target.jacoco.exec").matcher( buildLog ).find() ) { throw new RuntimeException( "Execution data from child2 was loaded, whereas range should exclude it." ); -- cgit v1.2.3 From 4741fb65cbebd799fece1c36ebc131cb0945a159 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 17 Aug 2018 21:37:09 +0200 Subject: Add filter for bytecode that ECJ generates for String in switch (#735) --- .../test/validation/java7/StringSwitchTest.java | 28 ---- .../java7/targets/StringSwitchTarget.java | 6 +- .../core/internal/analysis/MethodAnalyzerTest.java | 40 +++++- .../internal/analysis/filter/FilterTestBase.java | 6 + .../analysis/filter/FinallyFilterTest.java | 5 + .../analysis/filter/StringSwitchEcjFilterTest.java | 141 +++++++++++++++++++++ .../core/internal/analysis/MethodAnalyzer.java | 28 +++- .../core/internal/analysis/filter/Filters.java | 7 +- .../internal/analysis/filter/IFilterOutput.java | 14 ++ .../analysis/filter/StringSwitchEcjFilter.java | 108 ++++++++++++++++ org.jacoco.doc/docroot/doc/changes.html | 4 + 11 files changed, 350 insertions(+), 37 deletions(-) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java index 242a55f5..0a40c010 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/StringSwitchTest.java @@ -11,7 +11,6 @@ *******************************************************************************/ package org.jacoco.core.test.validation.java7; -import org.jacoco.core.test.validation.Source.Line; import org.jacoco.core.test.validation.ValidationTestBase; import org.jacoco.core.test.validation.java7.targets.StringSwitchTarget; @@ -25,31 +24,4 @@ public class StringSwitchTest extends ValidationTestBase { super(StringSwitchTarget.class); } - public void assertSwitchCovered(final Line line) { - if (isJDKCompiler) { - assertFullyCovered(line, 0, 4); - } else { - // Filtering for ECJ not yet implemented: - assertPartlyCovered(line, 2, 7); - } - } - - public void assertSwitchNotCovered(final Line line) { - if (isJDKCompiler) { - assertNotCovered(line, 4, 0); - } else { - // Filtering for ECJ not yet implemented: - assertNotCovered(line, 9, 0); - } - } - - public void assertLookupswitch(final Line line) { - if (isJDKCompiler) { - assertNotCovered(line, 3, 0); - } else { - // Filtering for ECJ not yet implemented: - assertNotCovered(line, 7, 0); - } - } - } diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java index 7b1bc291..db933f78 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java @@ -19,7 +19,7 @@ import static org.jacoco.core.test.validation.targets.Stubs.nop; public class StringSwitchTarget { private static void covered(Object s) { - switch (String.valueOf(s)) { // assertSwitchCovered() + switch (String.valueOf(s)) { // assertFullyCovered(0, 4) case "a": nop("case a"); // assertFullyCovered() break; @@ -36,7 +36,7 @@ public class StringSwitchTarget { } private static void notCovered(Object s) { - switch (String.valueOf(s)) { // assertSwitchNotCovered() + switch (String.valueOf(s)) { // assertNotCovered(4, 0) case "a": nop("case a"); break; @@ -88,7 +88,7 @@ public class StringSwitchTarget { * In this case javac generates LOOKUPSWITCH for second switch. */ private static void lookupswitch(Object s) { - switch (String.valueOf(s)) { // assertLookupswitch() + switch (String.valueOf(s)) { // assertNotCovered(3, 0) case "a": nop("case a"); break; diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java index 114ebb59..de3ec4d9 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java @@ -14,6 +14,9 @@ package org.jacoco.core.internal.analysis; import static org.junit.Assert.assertEquals; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; import org.jacoco.core.analysis.ILine; import org.jacoco.core.analysis.IMethodCoverage; @@ -449,7 +452,7 @@ public class MethodAnalyzerTest implements IProbeIdGenerator { assertLine(1002, 0, 1, 0, 0); } - // === Scenario: table switch === + // === Scenario: table switch with and without replace filtering === private void createTableSwitch() { final Label l0 = new Label(); @@ -494,6 +497,41 @@ public class MethodAnalyzerTest implements IProbeIdGenerator { assertEquals(4, nextProbeId); } + private static final IFilter SWITCH_FILTER = new IFilter() { + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + final AbstractInsnNode i = methodNode.instructions.get(3); + assertEquals(Opcodes.TABLESWITCH, i.getOpcode()); + final AbstractInsnNode t1 = methodNode.instructions.get(6); + assertEquals(Opcodes.BIPUSH, t1.getOpcode()); + final AbstractInsnNode t2 = methodNode.instructions.get(13); + assertEquals(Opcodes.BIPUSH, t2.getOpcode()); + + final Set newTargets = new HashSet(); + newTargets.add(t1); + newTargets.add(t2); + output.replaceBranches(i, newTargets); + } + }; + + @Test + public void table_switch_with_filter_should_show_2_branches_when_original_replaced() { + createTableSwitch(); + runMethodAnalzer(SWITCH_FILTER); + + assertLine(1001, 2, 0, 2, 0); + } + + @Test + public void table_switch_with_filter_should_show_full_branch_coverage_when_new_targets_covered() { + createTableSwitch(); + probes[0] = true; + probes[1] = true; + runMethodAnalzer(SWITCH_FILTER); + + assertLine(1001, 0, 2, 0, 2); + } + @Test public void table_switch_should_show_missed_when_no_probes_are_executed() { createTableSwitch(); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java index 50bb59f3..12064123 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java @@ -16,6 +16,7 @@ import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.List; +import java.util.Set; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; @@ -42,6 +43,11 @@ public abstract class FilterTestBase { final AbstractInsnNode i2) { fail(); } + + public void replaceBranches(final AbstractInsnNode source, + final Set newTargets) { + fail(); + } }; final void assertIgnored(Range... ranges) { diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java index 987f3398..843790ec 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java @@ -421,4 +421,9 @@ public class FinallyFilterTest implements IFilterOutput { } } + public void replaceBranches(final AbstractInsnNode source, + final Set newTargets) { + fail(); + } + } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java new file mode 100644 index 00000000..e1bfcb82 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Unit tests for {@link StringSwitchEcjFilter}. + */ +public class StringSwitchEcjFilterTest { + + private final IFilter filter = new StringSwitchEcjFilter(); + + private final FilterContextMock context = new FilterContextMock(); + + private AbstractInsnNode fromInclusive; + private AbstractInsnNode toInclusive; + + private AbstractInsnNode source; + private Set newTargets; + + private final IFilterOutput output = new IFilterOutput() { + public void ignore(final AbstractInsnNode fromInclusive, + final AbstractInsnNode toInclusive) { + assertNull(StringSwitchEcjFilterTest.this.fromInclusive); + StringSwitchEcjFilterTest.this.fromInclusive = fromInclusive; + StringSwitchEcjFilterTest.this.toInclusive = toInclusive; + } + + public void merge(final AbstractInsnNode i1, + final AbstractInsnNode i2) { + fail(); + } + + public void replaceBranches(final AbstractInsnNode source, + final Set newTargets) { + assertNull(StringSwitchEcjFilterTest.this.source); + StringSwitchEcjFilterTest.this.source = source; + StringSwitchEcjFilterTest.this.newTargets = newTargets; + } + }; + + @Test + public void should_filter() { + final Set expectedNewTargets = new HashSet(); + + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "name", "()V", null, null); + + final Label case1 = new Label(); + final Label case2 = new Label(); + final Label case3 = new Label(); + final Label caseDefault = new Label(); + final Label h1 = new Label(); + final Label h2 = new Label(); + + m.visitVarInsn(Opcodes.ALOAD, 1); + + m.visitVarInsn(Opcodes.ASTORE, 2); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", + "()I", false); + m.visitTableSwitchInsn(97, 98, caseDefault, h1, h2); + + m.visitLabel(h1); + final AbstractInsnNode expectedFromInclusive = m.instructions.getLast(); + + m.visitVarInsn(Opcodes.ALOAD, 2); + m.visitLdcInsn("a"); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", + "(Ljava/lang/Object;)Z", false); + // if equal "a", then goto its case + m.visitJumpInsn(Opcodes.IFNE, case1); + + m.visitVarInsn(Opcodes.ALOAD, 2); + m.visitLdcInsn("\0a"); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", + "(Ljava/lang/Object;)Z", false); + // if equal "\0a", then goto its case + m.visitJumpInsn(Opcodes.IFNE, case2); + + // goto default case + m.visitJumpInsn(Opcodes.GOTO, caseDefault); + + m.visitLabel(h2); + + m.visitVarInsn(Opcodes.ALOAD, 2); + m.visitLdcInsn("b"); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", + "(Ljava/lang/Object;)Z", false); + // if equal "b", then goto its case + m.visitJumpInsn(Opcodes.IFNE, case3); + + // goto default case + m.visitJumpInsn(Opcodes.GOTO, caseDefault); + final AbstractInsnNode expectedToInclusive = m.instructions.getLast(); + + m.visitLabel(caseDefault); + m.visitInsn(Opcodes.RETURN); + expectedNewTargets.add(m.instructions.getLast()); + m.visitLabel(case1); + m.visitInsn(Opcodes.RETURN); + expectedNewTargets.add(m.instructions.getLast()); + m.visitLabel(case2); + m.visitInsn(Opcodes.RETURN); + expectedNewTargets.add(m.instructions.getLast()); + m.visitLabel(case3); + m.visitInsn(Opcodes.RETURN); + expectedNewTargets.add(m.instructions.getLast()); + + filter.filter(m, context, output); + + assertEquals(expectedFromInclusive.getPrevious(), source); + assertEquals(expectedNewTargets, newTargets); + assertEquals(expectedFromInclusive, fromInclusive); + assertEquals(expectedToInclusive, toInclusive); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java index ba862adc..82b97466 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java @@ -173,6 +173,13 @@ public class MethodAnalyzer extends MethodProbesVisitor } } + private final Map> replacements = new HashMap>(); + + public void replaceBranches(final AbstractInsnNode source, + final Set newTargets) { + replacements.put(source, newTargets); + } + @Override public void visitLabel(final Label label) { currentLabel.add(label); @@ -362,6 +369,7 @@ public class MethodAnalyzer extends MethodProbesVisitor for (final CoveredProbe p : coveredProbes) { p.instruction.setCovered(p.branch); } + // Merge: for (final Instruction i : instructions) { final AbstractInsnNode m = i.getNode(); @@ -371,6 +379,7 @@ public class MethodAnalyzer extends MethodProbesVisitor nodeToInstruction.get(r).merge(i); } } + // Report result: coverage.ensureCapacity(firstLine, lastLine); for (final Instruction i : instructions) { @@ -378,8 +387,23 @@ public class MethodAnalyzer extends MethodProbesVisitor continue; } - final int total = i.getBranches(); - final int covered = i.getCoveredBranches(); + final int total; + final int covered; + final Set r = replacements.get(i.getNode()); + if (r != null) { + int cb = 0; + for (AbstractInsnNode b : r) { + if (nodeToInstruction.get(b).getCoveredBranches() > 0) { + cb++; + } + } + total = r.size(); + covered = cb; + } else { + total = i.getBranches(); + covered = i.getCoveredBranches(); + } + final ICounter instrCounter = covered == 0 ? CounterImpl.COUNTER_1_0 : CounterImpl.COUNTER_0_1; final ICounter branchCounter = total > 1 diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index b235cfb8..bdb0854b 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -31,9 +31,10 @@ public final class Filters implements IFilter { new TryWithResourcesJavac11Filter(), new TryWithResourcesJavacFilter(), new TryWithResourcesEcjFilter(), new FinallyFilter(), new PrivateEmptyNoArgConstructorFilter(), - new StringSwitchJavacFilter(), new EnumEmptyConstructorFilter(), - new AnnotationGeneratedFilter(), new KotlinGeneratedFilter(), - new KotlinLateinitFilter(), new KotlinWhenSealedFilter()); + new StringSwitchJavacFilter(), new StringSwitchEcjFilter(), + new EnumEmptyConstructorFilter(), new AnnotationGeneratedFilter(), + new KotlinGeneratedFilter(), new KotlinLateinitFilter(), + new KotlinWhenSealedFilter()); private final IFilter[] filters; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java index 4ca9b814..bbcbf00e 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java @@ -11,6 +11,8 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; +import java.util.Set; + import org.objectweb.asm.tree.AbstractInsnNode; /** @@ -41,4 +43,16 @@ public interface IFilterOutput { */ void merge(AbstractInsnNode i1, AbstractInsnNode i2); + /** + * Marks instruction whose outgoing branches should be replaced during + * computation of coverage. + * + * @param source + * instruction which branches should be replaced + * @param newTargets + * new targets of branches + */ + void replaceBranches(AbstractInsnNode source, + Set newTargets); + } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java new file mode 100644 index 00000000..cbd2a216 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import java.util.HashSet; +import java.util.Set; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LookupSwitchInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TableSwitchInsnNode; + +/** + * Filters code that is generated by ECJ for a switch statement + * with a String. + */ +public final class StringSwitchEcjFilter implements IFilter { + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + final Matcher matcher = new Matcher(); + for (AbstractInsnNode i = methodNode.instructions + .getFirst(); i != null; i = i.getNext()) { + matcher.match(i, output); + } + } + + private static class Matcher extends AbstractMatcher { + public void match(final AbstractInsnNode start, + final IFilterOutput output) { + + cursor = start; + + nextIsVar(Opcodes.ASTORE, "s"); + nextIsInvokeVirtual("java/lang/String", "hashCode"); + nextIsSwitch(); + if (cursor == null) { + return; + } + + final AbstractInsnNode s = cursor; + final int hashCodes; + final LabelNode defaultLabel; + if (s.getOpcode() == Opcodes.LOOKUPSWITCH) { + final LookupSwitchInsnNode lookupSwitch = (LookupSwitchInsnNode) cursor; + defaultLabel = lookupSwitch.dflt; + hashCodes = lookupSwitch.labels.size(); + } else { + final TableSwitchInsnNode tableSwitch = (TableSwitchInsnNode) cursor; + defaultLabel = tableSwitch.dflt; + hashCodes = tableSwitch.labels.size(); + } + + final Set replacements = new HashSet(); + replacements.add(instructionAfterLabel(defaultLabel)); + + for (int i = 0; i < hashCodes; i++) { + while (true) { + nextIsVar(Opcodes.ALOAD, "s"); + nextIs(Opcodes.LDC); + nextIsInvokeVirtual("java/lang/String", "equals"); + // jump to case + nextIs(Opcodes.IFNE); + if (cursor == null) { + return; + } + + replacements.add(instructionAfterLabel( + ((JumpInsnNode) cursor).label)); + + if (cursor.getNext().getOpcode() == Opcodes.GOTO) { + // end of comparisons for same hashCode + // jump to default + nextIs(Opcodes.GOTO); + break; + } + } + } + + output.ignore(s.getNext(), cursor); + output.replaceBranches(s, replacements); + } + } + + private static AbstractInsnNode instructionAfterLabel( + final LabelNode label) { + AbstractInsnNode i = label.getNext(); + while (i.getType() == AbstractInsnNode.FRAME + || i.getType() == AbstractInsnNode.LABEL + || i.getType() == AbstractInsnNode.LINE) { + i = i.getNext(); + } + return i; + } + +} diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 35c61284..46208992 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -31,6 +31,10 @@ (GitHub #669).
  • Synthetic classes are filtered out during generation of report (GitHub #668).
  • +
  • Part of bytecode generated by ECJ for switch statements on + java.lang.String values is filtered out during generation of + report + (GitHub #735).
  • Methods added by the Kotlin compiler are filtered out during generation of report. Idea and implementation by Nikolay Krasko (GitHub #689).
  • -- cgit v1.2.3 From 68ab19f3463bf5076485185fe2abe5ec8a726679 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 17 Aug 2018 22:14:15 +0200 Subject: Remove unused imports --- .../src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java | 1 - .../jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java | 2 -- 2 files changed, 3 deletions(-) diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java index de3ec4d9..d0484093 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java @@ -14,7 +14,6 @@ package org.jacoco.core.internal.analysis; import static org.junit.Assert.assertEquals; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashSet; import java.util.Set; diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java index e1bfcb82..d00b843e 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java @@ -15,9 +15,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; -import java.util.ArrayList; import java.util.HashSet; -import java.util.List; import java.util.Set; import org.jacoco.core.internal.instr.InstrSupport; -- cgit v1.2.3 From e629bf0fd2613ab887726800a3f935d3d51de71e Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sat, 18 Aug 2018 06:18:55 +0200 Subject: Filter switch on String for which ECJ omits last goto (#741) --- .../java7/targets/StringSwitchTarget.java | 14 ++++ .../internal/analysis/filter/FilterTestBase.java | 14 +++- .../analysis/filter/StringSwitchEcjFilterTest.java | 93 ++++++++++++---------- .../analysis/filter/StringSwitchEcjFilter.java | 2 + org.jacoco.doc/docroot/doc/changes.html | 3 +- 5 files changed, 82 insertions(+), 44 deletions(-) diff --git a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java index db933f78..f6293e5a 100644 --- a/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java +++ b/org.jacoco.core.test.validation.java7/src/org/jacoco/core/test/validation/java7/targets/StringSwitchTarget.java @@ -101,6 +101,17 @@ public class StringSwitchTarget { } } + private static void default_is_first(Object s) { + switch (String.valueOf(s)) { // assertFullyCovered(0, 2) + default: + nop("default"); + break; + case "a": + nop("case a"); + break; + } + } + public static void main(String[] args) { covered(""); covered("a"); @@ -108,6 +119,9 @@ public class StringSwitchTarget { covered("\0a"); handwritten("a"); + + default_is_first(""); + default_is_first("a"); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java index 12064123..2be69a1e 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java @@ -12,10 +12,14 @@ package org.jacoco.core.internal.analysis.filter; import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import org.objectweb.asm.tree.AbstractInsnNode; @@ -30,6 +34,8 @@ public abstract class FilterTestBase { private final List ignoredRanges = new ArrayList(); + private final Map> replacedBranches = new HashMap>(); + protected final IFilterOutput output = new IFilterOutput() { public void ignore(final AbstractInsnNode fromInclusive, final AbstractInsnNode toInclusive) { @@ -46,7 +52,7 @@ public abstract class FilterTestBase { public void replaceBranches(final AbstractInsnNode source, final Set newTargets) { - fail(); + replacedBranches.put(source, newTargets); } }; @@ -59,6 +65,12 @@ public abstract class FilterTestBase { new Range(m.instructions.getFirst(), m.instructions.getLast())); } + final void assertReplacedBranches(final AbstractInsnNode source, + final Set newTargets) { + assertEquals(Collections.singletonMap(source, newTargets), + replacedBranches); + } + static class Range { AbstractInsnNode fromInclusive; AbstractInsnNode toInclusive; diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java index d00b843e..6301723b 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java @@ -11,10 +11,6 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - import java.util.HashSet; import java.util.Set; @@ -28,39 +24,10 @@ import org.objectweb.asm.tree.MethodNode; /** * Unit tests for {@link StringSwitchEcjFilter}. */ -public class StringSwitchEcjFilterTest { +public class StringSwitchEcjFilterTest extends FilterTestBase { private final IFilter filter = new StringSwitchEcjFilter(); - private final FilterContextMock context = new FilterContextMock(); - - private AbstractInsnNode fromInclusive; - private AbstractInsnNode toInclusive; - - private AbstractInsnNode source; - private Set newTargets; - - private final IFilterOutput output = new IFilterOutput() { - public void ignore(final AbstractInsnNode fromInclusive, - final AbstractInsnNode toInclusive) { - assertNull(StringSwitchEcjFilterTest.this.fromInclusive); - StringSwitchEcjFilterTest.this.fromInclusive = fromInclusive; - StringSwitchEcjFilterTest.this.toInclusive = toInclusive; - } - - public void merge(final AbstractInsnNode i1, - final AbstractInsnNode i2) { - fail(); - } - - public void replaceBranches(final AbstractInsnNode source, - final Set newTargets) { - assertNull(StringSwitchEcjFilterTest.this.source); - StringSwitchEcjFilterTest.this.source = source; - StringSwitchEcjFilterTest.this.newTargets = newTargets; - } - }; - @Test public void should_filter() { final Set expectedNewTargets = new HashSet(); @@ -81,9 +48,9 @@ public class StringSwitchEcjFilterTest { m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); m.visitTableSwitchInsn(97, 98, caseDefault, h1, h2); + final AbstractInsnNode switchNode = m.instructions.getLast(); m.visitLabel(h1); - final AbstractInsnNode expectedFromInclusive = m.instructions.getLast(); m.visitVarInsn(Opcodes.ALOAD, 2); m.visitLdcInsn("a"); @@ -115,9 +82,6 @@ public class StringSwitchEcjFilterTest { m.visitJumpInsn(Opcodes.GOTO, caseDefault); final AbstractInsnNode expectedToInclusive = m.instructions.getLast(); - m.visitLabel(caseDefault); - m.visitInsn(Opcodes.RETURN); - expectedNewTargets.add(m.instructions.getLast()); m.visitLabel(case1); m.visitInsn(Opcodes.RETURN); expectedNewTargets.add(m.instructions.getLast()); @@ -127,13 +91,58 @@ public class StringSwitchEcjFilterTest { m.visitLabel(case3); m.visitInsn(Opcodes.RETURN); expectedNewTargets.add(m.instructions.getLast()); + m.visitLabel(caseDefault); + m.visitInsn(Opcodes.RETURN); + expectedNewTargets.add(m.instructions.getLast()); + + filter.filter(m, context, output); + + assertReplacedBranches(switchNode, expectedNewTargets); + assertIgnored(new Range(switchNode.getNext(), expectedToInclusive)); + } + + @Test + public void should_filter_when_default_is_first() { + final Set expectedNewTargets = new HashSet(); + + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "name", "()V", null, null); + + final Label case1 = new Label(); + final Label caseDefault = new Label(); + final Label h1 = new Label(); + + m.visitVarInsn(Opcodes.ALOAD, 1); + + m.visitVarInsn(Opcodes.ASTORE, 2); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", + "()I", false); + m.visitLookupSwitchInsn(caseDefault, new int[] { 97 }, + new Label[] { h1 }); + final AbstractInsnNode switchNode = m.instructions.getLast(); + + m.visitLabel(h1); + + m.visitVarInsn(Opcodes.ALOAD, 2); + m.visitLdcInsn("a"); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", + "(Ljava/lang/Object;)Z", false); + // if equal "a", then goto its case + m.visitJumpInsn(Opcodes.IFNE, case1); + + final AbstractInsnNode expectedToInclusive = m.instructions.getLast(); + + m.visitLabel(caseDefault); + m.visitInsn(Opcodes.RETURN); + expectedNewTargets.add(m.instructions.getLast()); + m.visitLabel(case1); + m.visitInsn(Opcodes.RETURN); + expectedNewTargets.add(m.instructions.getLast()); filter.filter(m, context, output); - assertEquals(expectedFromInclusive.getPrevious(), source); - assertEquals(expectedNewTargets, newTargets); - assertEquals(expectedFromInclusive, fromInclusive); - assertEquals(expectedToInclusive, toInclusive); + assertReplacedBranches(switchNode, expectedNewTargets); + assertIgnored(new Range(switchNode.getNext(), expectedToInclusive)); } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java index cbd2a216..d4be1819 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java @@ -85,6 +85,8 @@ public final class StringSwitchEcjFilter implements IFilter { // jump to default nextIs(Opcodes.GOTO); break; + } else if (cursor.getNext() == defaultLabel) { + break; } } } diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 46208992..2f21e359 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -34,7 +34,8 @@
  • Part of bytecode generated by ECJ for switch statements on java.lang.String values is filtered out during generation of report - (GitHub #735).
  • + (GitHub #735, + #741).
  • Methods added by the Kotlin compiler are filtered out during generation of report. Idea and implementation by Nikolay Krasko (GitHub #689).
  • -- cgit v1.2.3 From 32073eafa35718ef7a95df979f2202282e1e4eb1 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sat, 18 Aug 2018 08:01:29 +0200 Subject: Add filter for Kotlin when-expressions with String (#737) --- .../kotlin/targets/KotlinWhenExpressionTarget.kt | 6 +- .../filter/KotlinWhenStringFilterTest.java | 138 +++++++++++++++++++++ .../core/internal/analysis/filter/Filters.java | 2 +- .../analysis/filter/KotlinWhenStringFilter.java | 110 ++++++++++++++++ org.jacoco.doc/docroot/doc/changes.html | 4 + 5 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt index 193977dd..458e87f0 100644 --- a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt @@ -49,11 +49,12 @@ object KotlinWhenExpressionTarget { else -> throw NoWhenBranchMatchedException() // assertNotCovered() } // assertFullyCovered() - private fun whenString(p: String): Int = when (p) { // assertFullyCovered(2, 7) + private fun whenString(p: String): Int = when (p) { // assertFullyCovered(0, 5) "a" -> 1 // assertFullyCovered() "b" -> 2 // assertFullyCovered() "\u0000a" -> 3 // assertFullyCovered() - else -> 4 // assertFullyCovered() + "\u0000b" -> 4 // assertFullyCovered() + else -> 5 // assertFullyCovered() } // assertFullyCovered() @JvmStatic @@ -74,6 +75,7 @@ object KotlinWhenExpressionTarget { whenString("a") whenString("b") whenString("\u0000a") + whenString("\u0000b") } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java new file mode 100644 index 00000000..4f5ea493 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +import java.util.HashSet; +import java.util.Set; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Unit tests for {@link KotlinWhenStringFilter}. + */ +public class KotlinWhenStringFilterTest { + + private final IFilter filter = new KotlinWhenStringFilter(); + + private final FilterContextMock context = new FilterContextMock(); + + private AbstractInsnNode fromInclusive; + private AbstractInsnNode toInclusive; + + private AbstractInsnNode source; + private Set newTargets; + + private final IFilterOutput output = new IFilterOutput() { + public void ignore(final AbstractInsnNode fromInclusive, + final AbstractInsnNode toInclusive) { + assertNull(KotlinWhenStringFilterTest.this.fromInclusive); + KotlinWhenStringFilterTest.this.fromInclusive = fromInclusive; + KotlinWhenStringFilterTest.this.toInclusive = toInclusive; + } + + public void merge(final AbstractInsnNode i1, + final AbstractInsnNode i2) { + fail(); + } + + public void replaceBranches(final AbstractInsnNode source, + final Set newTargets) { + assertNull(KotlinWhenStringFilterTest.this.source); + KotlinWhenStringFilterTest.this.source = source; + KotlinWhenStringFilterTest.this.newTargets = newTargets; + } + }; + + @Test + public void should_filter() { + final Set expectedNewTargets = new HashSet(); + + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "name", "()V", null, null); + + final Label h1 = new Label(); + final Label sameHash = new Label(); + final Label h2 = new Label(); + final Label case1 = new Label(); + final Label case2 = new Label(); + final Label case3 = new Label(); + final Label defaultCase = new Label(); + + m.visitVarInsn(Opcodes.ALOAD, 1); + + m.visitVarInsn(Opcodes.ASTORE, 2); + m.visitVarInsn(Opcodes.ALOAD, 2); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", + "()I", false); + m.visitTableSwitchInsn(97, 98, defaultCase, h1, h2); + + // case "a" + m.visitLabel(h1); + final AbstractInsnNode expectedFromInclusive = m.instructions.getLast(); + + m.visitVarInsn(Opcodes.ALOAD, 2); + m.visitLdcInsn("a"); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", + "(Ljava/lang/Object;)Z", false); + m.visitJumpInsn(Opcodes.IFEQ, sameHash); + m.visitJumpInsn(Opcodes.GOTO, case1); + + // case "\u0000a" + m.visitLabel(sameHash); + m.visitVarInsn(Opcodes.ALOAD, 2); + m.visitLdcInsn("\u0000a"); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", + "(Ljava/lang/Object;)Z", false); + m.visitJumpInsn(Opcodes.IFEQ, defaultCase); + m.visitJumpInsn(Opcodes.GOTO, case2); + + // case "b" + m.visitLabel(h2); + m.visitVarInsn(Opcodes.ALOAD, 2); + m.visitLdcInsn("\u0000a"); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", + "(Ljava/lang/Object;)Z", false); + m.visitJumpInsn(Opcodes.IFEQ, defaultCase); + m.visitJumpInsn(Opcodes.GOTO, case3); + final AbstractInsnNode expectedToInclusive = m.instructions.getLast(); + + m.visitLabel(case1); + m.visitInsn(Opcodes.RETURN); + expectedNewTargets.add(m.instructions.getLast()); + m.visitLabel(case2); + m.visitInsn(Opcodes.RETURN); + expectedNewTargets.add(m.instructions.getLast()); + m.visitLabel(case3); + m.visitInsn(Opcodes.RETURN); + expectedNewTargets.add(m.instructions.getLast()); + m.visitLabel(defaultCase); + m.visitInsn(Opcodes.RETURN); + expectedNewTargets.add(m.instructions.getLast()); + + filter.filter(m, context, output); + + assertEquals(expectedFromInclusive.getPrevious(), source); + assertEquals(expectedNewTargets, newTargets); + assertEquals(expectedFromInclusive, fromInclusive); + assertEquals(expectedToInclusive, toInclusive); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index bdb0854b..a8446eac 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -34,7 +34,7 @@ public final class Filters implements IFilter { new StringSwitchJavacFilter(), new StringSwitchEcjFilter(), new EnumEmptyConstructorFilter(), new AnnotationGeneratedFilter(), new KotlinGeneratedFilter(), new KotlinLateinitFilter(), - new KotlinWhenSealedFilter()); + new KotlinWhenSealedFilter(), new KotlinWhenStringFilter()); private final IFilter[] filters; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java new file mode 100644 index 00000000..861c7bfb --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import java.util.HashSet; +import java.util.Set; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LookupSwitchInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TableSwitchInsnNode; + +/** + * Filters bytecode that Kotlin compiler generates for when + * expressions with a String. + */ +public final class KotlinWhenStringFilter implements IFilter { + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + final Matcher matcher = new Matcher(); + for (AbstractInsnNode i = methodNode.instructions + .getFirst(); i != null; i = i.getNext()) { + matcher.match(i, output); + } + } + + private static class Matcher extends AbstractMatcher { + public void match(final AbstractInsnNode start, + final IFilterOutput output) { + + cursor = start; + + nextIsVar(Opcodes.ASTORE, "s"); + nextIsVar(Opcodes.ALOAD, "s"); + nextIsInvokeVirtual("java/lang/String", "hashCode"); + nextIsSwitch(); + if (cursor == null) { + return; + } + + final AbstractInsnNode s = cursor; + final int hashCodes; + final LabelNode defaultLabel; + if (s.getOpcode() == Opcodes.LOOKUPSWITCH) { + final LookupSwitchInsnNode lookupSwitch = (LookupSwitchInsnNode) cursor; + defaultLabel = lookupSwitch.dflt; + hashCodes = lookupSwitch.labels.size(); + } else { + final TableSwitchInsnNode tableSwitch = (TableSwitchInsnNode) cursor; + defaultLabel = tableSwitch.dflt; + hashCodes = tableSwitch.labels.size(); + } + + final Set replacements = new HashSet(); + replacements.add(instructionAfterLabel(defaultLabel)); + + for (int i = 0; i < hashCodes; i++) { + while (true) { + nextIsVar(Opcodes.ALOAD, "s"); + nextIs(Opcodes.LDC); + nextIsInvokeVirtual("java/lang/String", "equals"); + // jump to next comparison or default case + nextIs(Opcodes.IFEQ); + final JumpInsnNode jump = (JumpInsnNode) cursor; + // jump to case + nextIs(Opcodes.GOTO); + if (cursor == null) { + return; + } + + replacements.add(instructionAfterLabel( + ((JumpInsnNode) cursor).label)); + + if (jump.label == defaultLabel) { + // end of comparisons for same hashCode + break; + } + } + } + + output.ignore(s.getNext(), cursor); + output.replaceBranches(s, replacements); + } + } + + private static AbstractInsnNode instructionAfterLabel( + final LabelNode label) { + AbstractInsnNode i = label.getNext(); + while (i.getType() == AbstractInsnNode.FRAME + || i.getType() == AbstractInsnNode.LABEL + || i.getType() == AbstractInsnNode.LINE) { + i = i.getNext(); + } + return i; + } + +} diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 2f21e359..8e34066f 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -47,6 +47,10 @@ when expressions that list all cases of sealed class is filtered out during generation of report (GitHub #721). +
  • Additional bytecode generated by Kotlin compiler for when + expressions on kotlin.String values is filtered out during + generation of report + (GitHub #737).
  • Classes and methods annotated with runtime visible and invisible annotation whose simple name is Generated are filtered out during generation of report -- cgit v1.2.3 From 215f7668ed71165375b2cf804ae0974647050a25 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sat, 18 Aug 2018 20:07:22 +0200 Subject: Add filter for Kotlin when-expressions that list all cases of enum (#729) --- jacoco/pom.xml | 2 +- .../kotlin/targets/KotlinWhenExpressionTarget.kt | 4 +- .../internal/analysis/filter/FilterTestBase.java | 5 + .../analysis/filter/KotlinWhenFilterTest.java | 123 +++++++++++++++++++++ .../filter/KotlinWhenSealedFilterTest.java | 82 -------------- .../core/internal/analysis/filter/Filters.java | 2 +- .../internal/analysis/filter/KotlinWhenFilter.java | 113 +++++++++++++++++++ .../analysis/filter/KotlinWhenSealedFilter.java | 62 ----------- org.jacoco.doc/docroot/doc/changes.html | 7 +- 9 files changed, 249 insertions(+), 151 deletions(-) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilterTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilterTest.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java delete mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilter.java diff --git a/jacoco/pom.xml b/jacoco/pom.xml index 887a2a31..28fb3446 100644 --- a/jacoco/pom.xml +++ b/jacoco/pom.xml @@ -110,7 +110,7 @@ - 4200000 + 4300000 3400000 ${project.build.directory}/jacoco-${qualified.bundle.version}.zip diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt index 458e87f0..3f3e0989 100644 --- a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt @@ -37,9 +37,9 @@ object KotlinWhenExpressionTarget { A, B } - private fun whenEnum(p: Enum): Int = when (p) { // assertFullyCovered(1, 2) + private fun whenEnum(p: Enum): Int = when (p) { // assertFullyCovered(0, 2) Enum.A -> 1 // assertFullyCovered() - Enum.B -> 2 // assertPartlyCovered() + Enum.B -> 2 // assertFullyCovered() } // assertFullyCovered() @Suppress("REDUNDANT_ELSE_IN_WHEN") diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java index 2be69a1e..68c99eae 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java @@ -13,6 +13,7 @@ package org.jacoco.core.internal.analysis.filter; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.ArrayList; @@ -65,6 +66,10 @@ public abstract class FilterTestBase { new Range(m.instructions.getFirst(), m.instructions.getLast())); } + final void assertNoReplacedBranches() { + assertTrue(replacedBranches.isEmpty()); + } + final void assertReplacedBranches(final AbstractInsnNode source, final Set newTargets) { assertEquals(Collections.singletonMap(source, newTargets), diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilterTest.java new file mode 100644 index 00000000..e88304a1 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilterTest.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import java.util.HashSet; +import java.util.Set; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Unit tests for {@link KotlinWhenFilter}. + */ +public class KotlinWhenFilterTest extends FilterTestBase { + + private final KotlinWhenFilter filter = new KotlinWhenFilter(); + + private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "name", "()V", null, null); + + @Test + public void should_filter_implicit_else() { + final Label label = new Label(); + + final Range range1 = new Range(); + + m.visitInsn(Opcodes.NOP); + + m.visitJumpInsn(Opcodes.IFEQ, label); + range1.fromInclusive = m.instructions.getLast(); + range1.toInclusive = m.instructions.getLast(); + + m.visitInsn(Opcodes.NOP); + + final Range range2 = new Range(); + m.visitLabel(label); + range2.fromInclusive = m.instructions.getLast(); + m.visitTypeInsn(Opcodes.NEW, "kotlin/NoWhenBranchMatchedException"); + m.visitInsn(Opcodes.DUP); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, + "kotlin/NoWhenBranchMatchedException", "", "()V", false); + m.visitInsn(Opcodes.ATHROW); + range2.toInclusive = m.instructions.getLast(); + + filter.filter(m, context, output); + + assertIgnored(range1, range2); + assertNoReplacedBranches(); + } + + @Test + public void should_not_filter_explicit_else() { + final Label label = new Label(); + + m.visitInsn(Opcodes.NOP); + + m.visitJumpInsn(Opcodes.IFEQ, label); + + m.visitInsn(Opcodes.NOP); + + m.visitLabel(label); + m.visitTypeInsn(Opcodes.NEW, "kotlin/NoWhenBranchMatchedException"); + m.visitInsn(Opcodes.DUP); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, + "kotlin/NoWhenBranchMatchedException", "", "()V", false); + m.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Throwable"); + m.visitInsn(Opcodes.ATHROW); + + filter.filter(m, context, output); + + assertIgnored(); + assertNoReplacedBranches(); + } + + @Test + public void should_filter_implicit_default() { + final Label case1 = new Label(); + final Label caseDefault = new Label(); + final Label after = new Label(); + + m.visitInsn(Opcodes.NOP); + + m.visitTableSwitchInsn(0, 0, caseDefault, case1); + final AbstractInsnNode switchNode = m.instructions.getLast(); + final Set newTargets = new HashSet(); + + m.visitLabel(case1); + m.visitInsn(Opcodes.ICONST_1); + newTargets.add(m.instructions.getLast()); + m.visitJumpInsn(Opcodes.GOTO, after); + + final Range range1 = new Range(); + m.visitLabel(caseDefault); + range1.fromInclusive = m.instructions.getLast(); + m.visitTypeInsn(Opcodes.NEW, "kotlin/NoWhenBranchMatchedException"); + m.visitInsn(Opcodes.DUP); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, + "kotlin/NoWhenBranchMatchedException", "", "()V", false); + m.visitInsn(Opcodes.ATHROW); + range1.toInclusive = m.instructions.getLast(); + + m.visitLabel(after); + + filter.filter(m, context, output); + + assertIgnored(range1); + assertReplacedBranches(switchNode, newTargets); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilterTest.java deleted file mode 100644 index fe61f60f..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilterTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.internal.analysis.filter; - -import org.jacoco.core.internal.instr.InstrSupport; -import org.junit.Test; -import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.MethodNode; - -/** - * Unit tests for {@link KotlinWhenSealedFilter}. - */ -public class KotlinWhenSealedFilterTest extends FilterTestBase { - - private final KotlinWhenSealedFilter filter = new KotlinWhenSealedFilter(); - - private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, - "name", "()V", null, null); - - @Test - public void should_filter_implicit_else() { - final Label label = new Label(); - - final Range range1 = new Range(); - - m.visitInsn(Opcodes.NOP); - - m.visitJumpInsn(Opcodes.IFEQ, label); - range1.fromInclusive = m.instructions.getLast(); - range1.toInclusive = m.instructions.getLast(); - - m.visitInsn(Opcodes.NOP); - - final Range range2 = new Range(); - m.visitLabel(label); - range2.fromInclusive = m.instructions.getLast(); - m.visitTypeInsn(Opcodes.NEW, "kotlin/NoWhenBranchMatchedException"); - m.visitInsn(Opcodes.DUP); - m.visitMethodInsn(Opcodes.INVOKESPECIAL, - "kotlin/NoWhenBranchMatchedException", "", "()V", false); - m.visitInsn(Opcodes.ATHROW); - range2.toInclusive = m.instructions.getLast(); - - filter.filter(m, context, output); - - assertIgnored(range1, range2); - } - - @Test - public void should_not_filter_explicit_else() { - final Label label = new Label(); - - m.visitInsn(Opcodes.NOP); - - m.visitJumpInsn(Opcodes.IFEQ, label); - - m.visitInsn(Opcodes.NOP); - - m.visitLabel(label); - m.visitTypeInsn(Opcodes.NEW, "kotlin/NoWhenBranchMatchedException"); - m.visitInsn(Opcodes.DUP); - m.visitMethodInsn(Opcodes.INVOKESPECIAL, - "kotlin/NoWhenBranchMatchedException", "", "()V", false); - m.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Throwable"); - m.visitInsn(Opcodes.ATHROW); - - filter.filter(m, context, output); - - assertIgnored(); - } - -} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index a8446eac..03c85d7d 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -34,7 +34,7 @@ public final class Filters implements IFilter { new StringSwitchJavacFilter(), new StringSwitchEcjFilter(), new EnumEmptyConstructorFilter(), new AnnotationGeneratedFilter(), new KotlinGeneratedFilter(), new KotlinLateinitFilter(), - new KotlinWhenSealedFilter(), new KotlinWhenStringFilter()); + new KotlinWhenFilter(), new KotlinWhenStringFilter()); private final IFilter[] filters; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java new file mode 100644 index 00000000..24b90c0e --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LookupSwitchInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TableSwitchInsnNode; + +/** + * Filters bytecode that Kotlin compiler generates for when + * expressions which list all cases of enum or + * sealed class, i.e. which don't require explicit + * else. + */ +public final class KotlinWhenFilter implements IFilter { + + private static final String EXCEPTION = "kotlin/NoWhenBranchMatchedException"; + + private final Matcher matcher = new Matcher(); + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + for (AbstractInsnNode i = methodNode.instructions + .getFirst(); i != null; i = i.getNext()) { + matcher.match(i, output); + } + } + + private static class Matcher extends AbstractMatcher { + void match(final AbstractInsnNode start, final IFilterOutput output) { + if (start.getType() != InsnNode.LABEL) { + return; + } + cursor = start; + + nextIsNew(EXCEPTION); + nextIs(Opcodes.DUP); + nextIsInvokeSuper(EXCEPTION, "()V"); + nextIs(Opcodes.ATHROW); + + for (AbstractInsnNode i = cursor; i != null; i = i.getPrevious()) { + if (i.getOpcode() == Opcodes.IFEQ + && ((JumpInsnNode) i).label == start) { + output.ignore(i, i); + output.ignore(start, cursor); + return; + + } else if (getDefaultLabel(i) == start) { + ignoreDefaultBranch(i, output); + output.ignore(start, cursor); + return; + + } + } + } + } + + private static LabelNode getDefaultLabel(final AbstractInsnNode i) { + switch (i.getOpcode()) { + case Opcodes.LOOKUPSWITCH: + return ((LookupSwitchInsnNode) i).dflt; + case Opcodes.TABLESWITCH: + return ((TableSwitchInsnNode) i).dflt; + default: + return null; + } + } + + private static void ignoreDefaultBranch(final AbstractInsnNode switchNode, + final IFilterOutput output) { + final List labels; + if (switchNode.getOpcode() == Opcodes.LOOKUPSWITCH) { + labels = ((LookupSwitchInsnNode) switchNode).labels; + } else { + labels = ((TableSwitchInsnNode) switchNode).labels; + } + final Set newTargets = new HashSet(); + for (LabelNode label : labels) { + newTargets.add(instructionAfterLabel(label)); + } + output.replaceBranches(switchNode, newTargets); + } + + private static AbstractInsnNode instructionAfterLabel( + final LabelNode label) { + AbstractInsnNode i = label.getNext(); + while (i.getType() == AbstractInsnNode.FRAME + || i.getType() == AbstractInsnNode.LABEL + || i.getType() == AbstractInsnNode.LINE) { + i = i.getNext(); + } + return i; + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilter.java deleted file mode 100644 index ae0d8455..00000000 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenSealedFilter.java +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.internal.analysis.filter; - -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.InsnNode; -import org.objectweb.asm.tree.JumpInsnNode; -import org.objectweb.asm.tree.MethodNode; - -/** - * Filters bytecode that Kotlin compiler generates for when - * expressions which list all cases of sealed class, i.e. which - * don't require explicit else. - */ -public final class KotlinWhenSealedFilter implements IFilter { - - private static final String EXCEPTION = "kotlin/NoWhenBranchMatchedException"; - - private final Matcher matcher = new Matcher(); - - public void filter(final MethodNode methodNode, - final IFilterContext context, final IFilterOutput output) { - for (AbstractInsnNode i = methodNode.instructions - .getFirst(); i != null; i = i.getNext()) { - matcher.match(i, output); - } - } - - private static class Matcher extends AbstractMatcher { - void match(final AbstractInsnNode start, final IFilterOutput output) { - if (start.getType() != InsnNode.LABEL) { - return; - } - cursor = start; - - nextIsNew(EXCEPTION); - nextIs(Opcodes.DUP); - nextIsInvokeSuper(EXCEPTION, "()V"); - nextIs(Opcodes.ATHROW); - - for (AbstractInsnNode i = cursor; i != null; i = i.getPrevious()) { - if (i.getOpcode() == Opcodes.IFEQ - && ((JumpInsnNode) i).label == start) { - output.ignore(i, i); - output.ignore(start, cursor); - return; - } - } - } - } - -} diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 8e34066f..2c1dc6ef 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -44,9 +44,10 @@ Fabian Mastenbroek (GitHub #707).
  • Bytecode generated by Kotlin compiler for implicit else of - when expressions that list all cases of sealed class - is filtered out during generation of report - (GitHub #721).
  • + when expressions that list all cases of enum or + sealed class is filtered out during generation of report + (GitHub #721, + #729).
  • Additional bytecode generated by Kotlin compiler for when expressions on kotlin.String values is filtered out during generation of report -- cgit v1.2.3 From 3288f34c193fc3276af74bdfc0471b7435bc6a74 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sat, 18 Aug 2018 23:15:38 +0200 Subject: Do not use `~/.m2/settings.xml` provided by Travis (#742) --- .travis.sh | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.travis.sh b/.travis.sh index 83111c83..81fdf16f 100755 --- a/.travis.sh +++ b/.travis.sh @@ -85,20 +85,25 @@ case "$JDK" in mvn -V -B -e -f org.jacoco.build verify sonar:sonar deploy:deploy -DdeployAtEnd -Djdk.version=5 --toolchains=./.travis/toolchains.xml --settings=./.travis/settings.xml -Dsonar.host.url=${SONARQUBE_URL} -Dsonar.login=${SONARQUBE_TOKEN} python ./.travis/trigger-site-deployment.py else - mvn -V -B -e verify -Djdk.version=5 --toolchains=./.travis/toolchains.xml + mvn -V -B -e verify -Djdk.version=5 --toolchains=./.travis/toolchains.xml \ + --settings=./.travis/settings.xml fi ;; 6 | 7 | 8 | 9) - mvn -V -B -e verify -Djdk.version=${JDK} -Dbytecode.version=${JDK} -Decj=${ECJ:-} --toolchains=./.travis/travis-toolchains.xml + mvn -V -B -e verify -Djdk.version=${JDK} -Dbytecode.version=${JDK} -Decj=${ECJ:-} --toolchains=./.travis/travis-toolchains.xml \ + --settings=./.travis/settings.xml ;; 10) - mvn -V -B -e verify -Dbytecode.version=10 + mvn -V -B -e verify -Dbytecode.version=10 \ + --settings=./.travis/settings.xml ;; 11-ea) - mvn -V -B -e verify -Dbytecode.version=11 + mvn -V -B -e verify -Dbytecode.version=11 \ + --settings=./.travis/settings.xml ;; 12-ea) - mvn -V -B -e verify -Dbytecode.version=12 + mvn -V -B -e verify -Dbytecode.version=12 \ + --settings=./.travis/settings.xml ;; *) echo "Incorrect JDK [$JDK]" -- cgit v1.2.3 From 0484d9ddba3842612f364dec9d0ce9de6a6203ca Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sun, 19 Aug 2018 02:28:46 +0200 Subject: Use FilterTestBase in KotlinWhenStringFilterTest --- .../filter/KotlinWhenStringFilterTest.java | 42 +++------------------- 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java index 4f5ea493..b5d32942 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java @@ -11,10 +11,6 @@ *******************************************************************************/ package org.jacoco.core.internal.analysis.filter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - import java.util.HashSet; import java.util.Set; @@ -28,39 +24,10 @@ import org.objectweb.asm.tree.MethodNode; /** * Unit tests for {@link KotlinWhenStringFilter}. */ -public class KotlinWhenStringFilterTest { +public class KotlinWhenStringFilterTest extends FilterTestBase { private final IFilter filter = new KotlinWhenStringFilter(); - private final FilterContextMock context = new FilterContextMock(); - - private AbstractInsnNode fromInclusive; - private AbstractInsnNode toInclusive; - - private AbstractInsnNode source; - private Set newTargets; - - private final IFilterOutput output = new IFilterOutput() { - public void ignore(final AbstractInsnNode fromInclusive, - final AbstractInsnNode toInclusive) { - assertNull(KotlinWhenStringFilterTest.this.fromInclusive); - KotlinWhenStringFilterTest.this.fromInclusive = fromInclusive; - KotlinWhenStringFilterTest.this.toInclusive = toInclusive; - } - - public void merge(final AbstractInsnNode i1, - final AbstractInsnNode i2) { - fail(); - } - - public void replaceBranches(final AbstractInsnNode source, - final Set newTargets) { - assertNull(KotlinWhenStringFilterTest.this.source); - KotlinWhenStringFilterTest.this.source = source; - KotlinWhenStringFilterTest.this.newTargets = newTargets; - } - }; - @Test public void should_filter() { final Set expectedNewTargets = new HashSet(); @@ -129,10 +96,9 @@ public class KotlinWhenStringFilterTest { filter.filter(m, context, output); - assertEquals(expectedFromInclusive.getPrevious(), source); - assertEquals(expectedNewTargets, newTargets); - assertEquals(expectedFromInclusive, fromInclusive); - assertEquals(expectedToInclusive, toInclusive); + assertReplacedBranches(expectedFromInclusive.getPrevious(), + expectedNewTargets); + assertIgnored(new Range(expectedFromInclusive, expectedToInclusive)); } } -- cgit v1.2.3 From 6bbb012ddb61ee25c67c1ec166535f84c2f7d085 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 20 Aug 2018 12:17:09 +0200 Subject: Add support for Java 11 and 12 class files with "preview features" (#743) --- .../jacoco/core/internal/ContentTypeDetectorTest.java | 16 ++++++++++++++++ .../org/jacoco/core/internal/ContentTypeDetector.java | 2 ++ org.jacoco.doc/docroot/doc/changes.html | 9 +++++---- 3 files changed, 23 insertions(+), 4 deletions(-) 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 fe443f8d..75fdae01 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 @@ -128,6 +128,14 @@ public class ContentTypeDetectorTest { assertContent(); } + @Test + public void should_detect_java_11_with_preview_features() + throws IOException { + initData(0xCA, 0xFE, 0xBA, 0xBE, 0xFF, 0xFF, 0x00, 0x37); + assertEquals(ContentTypeDetector.CLASSFILE, detector.getType()); + assertContent(); + } + @Test public void should_detect_java_12() throws IOException { initData(0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x38); @@ -135,6 +143,14 @@ public class ContentTypeDetectorTest { assertContent(); } + @Test + public void should_detect_java_12_with_preview_features() + throws IOException { + initData(0xCA, 0xFE, 0xBA, 0xBE, 0xFF, 0xFF, 0x00, 0x38); + assertEquals(ContentTypeDetector.CLASSFILE, detector.getType()); + assertContent(); + } + @Test public void testMachObjectFile() throws IOException { initData(0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x02); diff --git a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java index 0fcf5371..c74d3374 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java @@ -85,7 +85,9 @@ public class ContentTypeDetector { case Opcodes.V9: case BytecodeVersion.V10: case Opcodes.V11: + case Opcodes.V11 | Opcodes.V_PREVIEW_EXPERIMENTAL: case Opcodes.V12: + case Opcodes.V12 | Opcodes.V_PREVIEW_EXPERIMENTAL: return CLASSFILE; } } diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 2c1dc6ef..8fe43911 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -22,10 +22,11 @@

    New Features

      -
    • Experimental support for Java 11 class files - (GitHub #719).
    • -
    • Experimental support for Java 12 class files - (GitHub #738).
    • +
    • Experimental support for Java 11 and Java 12 class files, including + JEP 12 "preview features" + (GitHub #719, + #738, + #743).
    • Branches and instructions generated by javac 11 for try-with-resources statement are filtered out (GitHub #669).
    • -- cgit v1.2.3 From 964778bb48e3bbc63f5e9b174e7af371aa1f05ae Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 20 Aug 2018 19:53:21 +0200 Subject: StringSwitchEcjFilter and KotlinWhenStringFilter should use correct VarInsnNode (#746) --- .../internal/analysis/filter/KotlinWhenStringFilterTest.java | 4 ++++ .../internal/analysis/filter/StringSwitchEcjFilterTest.java | 10 ++++++++++ .../core/internal/analysis/filter/KotlinWhenStringFilter.java | 8 +++++--- .../core/internal/analysis/filter/StringSwitchEcjFilter.java | 7 +++++-- org.jacoco.doc/docroot/doc/changes.html | 6 ++++-- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java index b5d32942..02bdeb1c 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java @@ -43,8 +43,12 @@ public class KotlinWhenStringFilterTest extends FilterTestBase { final Label case3 = new Label(); final Label defaultCase = new Label(); + // filter should not remember this unrelated slot + m.visitLdcInsn(""); + m.visitVarInsn(Opcodes.ASTORE, 1); m.visitVarInsn(Opcodes.ALOAD, 1); + // switch (...) m.visitVarInsn(Opcodes.ASTORE, 2); m.visitVarInsn(Opcodes.ALOAD, 2); m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java index 6301723b..ca790b66 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java @@ -42,8 +42,13 @@ public class StringSwitchEcjFilterTest extends FilterTestBase { final Label h1 = new Label(); final Label h2 = new Label(); + // filter should not remember this unrelated slot + m.visitLdcInsn(""); + m.visitVarInsn(Opcodes.ASTORE, 1); m.visitVarInsn(Opcodes.ALOAD, 1); + // switch (...) + m.visitInsn(Opcodes.DUP); m.visitVarInsn(Opcodes.ASTORE, 2); m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); @@ -112,8 +117,13 @@ public class StringSwitchEcjFilterTest extends FilterTestBase { final Label caseDefault = new Label(); final Label h1 = new Label(); + // filter should not remember this unrelated slot + m.visitLdcInsn(""); + m.visitVarInsn(Opcodes.ASTORE, 1); m.visitVarInsn(Opcodes.ALOAD, 1); + // switch (...) + m.visitInsn(Opcodes.DUP); m.visitVarInsn(Opcodes.ASTORE, 2); m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", "()I", false); diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java index 861c7bfb..b8694c24 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java @@ -21,6 +21,7 @@ import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.LookupSwitchInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TableSwitchInsnNode; +import org.objectweb.asm.tree.VarInsnNode; /** * Filters bytecode that Kotlin compiler generates for when @@ -41,15 +42,16 @@ public final class KotlinWhenStringFilter implements IFilter { public void match(final AbstractInsnNode start, final IFilterOutput output) { + if (Opcodes.ALOAD != start.getOpcode()) { + return; + } cursor = start; - - nextIsVar(Opcodes.ASTORE, "s"); - nextIsVar(Opcodes.ALOAD, "s"); nextIsInvokeVirtual("java/lang/String", "hashCode"); nextIsSwitch(); if (cursor == null) { return; } + vars.put("s", (VarInsnNode) start); final AbstractInsnNode s = cursor; final int hashCodes; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java index d4be1819..6c52d3b9 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java @@ -21,6 +21,7 @@ import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.LookupSwitchInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TableSwitchInsnNode; +import org.objectweb.asm.tree.VarInsnNode; /** * Filters code that is generated by ECJ for a switch statement @@ -41,14 +42,16 @@ public final class StringSwitchEcjFilter implements IFilter { public void match(final AbstractInsnNode start, final IFilterOutput output) { + if (Opcodes.ASTORE != start.getOpcode()) { + return; + } cursor = start; - - nextIsVar(Opcodes.ASTORE, "s"); nextIsInvokeVirtual("java/lang/String", "hashCode"); nextIsSwitch(); if (cursor == null) { return; } + vars.put("s", (VarInsnNode) start); final AbstractInsnNode s = cursor; final int hashCodes; diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 8fe43911..cd5c32f0 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -36,7 +36,8 @@ java.lang.String values is filtered out during generation of report (GitHub #735, - #741). + #741, + #746).
    • Methods added by the Kotlin compiler are filtered out during generation of report. Idea and implementation by Nikolay Krasko (GitHub #689).
    • @@ -52,7 +53,8 @@
    • Additional bytecode generated by Kotlin compiler for when expressions on kotlin.String values is filtered out during generation of report - (GitHub #737).
    • + (GitHub #737, + #746).
    • Classes and methods annotated with runtime visible and invisible annotation whose simple name is Generated are filtered out during generation of report -- cgit v1.2.3 From 1cd039a534b9e9354b1a7f6de797c0a99d75291c Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 20 Aug 2018 21:18:12 +0200 Subject: All merged instructions should have same covered branches (#747) Because result of merge might be used to compute coverage of instructions with replaced branches. --- .../org/jacoco/core/internal/analysis/MethodAnalyzer.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java index 82b97466..78adf91a 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java @@ -370,7 +370,7 @@ public class MethodAnalyzer extends MethodProbesVisitor p.instruction.setCovered(p.branch); } - // Merge: + // Merge into representative instruction: for (final Instruction i : instructions) { final AbstractInsnNode m = i.getNode(); final AbstractInsnNode r = findRepresentative(m); @@ -380,6 +380,16 @@ public class MethodAnalyzer extends MethodProbesVisitor } } + // Merge from representative instruction, because result of merge might + // be used to compute coverage of instructions with replaced branches: + for (final Instruction i : instructions) { + final AbstractInsnNode m = i.getNode(); + final AbstractInsnNode r = findRepresentative(m); + if (r != m) { + i.merge(nodeToInstruction.get(r)); + } + } + // Report result: coverage.ensureCapacity(firstLine, lastLine); for (final Instruction i : instructions) { -- cgit v1.2.3 From 1e01244a7b82a61149523c1be475505062e6c297 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 20 Aug 2018 22:07:57 +0200 Subject: KotlinWhenFilter should be stateless (#749) --- .../src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java | 3 +-- org.jacoco.doc/docroot/doc/changes.html | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java index 24b90c0e..a39356f9 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java @@ -34,10 +34,9 @@ public final class KotlinWhenFilter implements IFilter { private static final String EXCEPTION = "kotlin/NoWhenBranchMatchedException"; - private final Matcher matcher = new Matcher(); - public void filter(final MethodNode methodNode, final IFilterContext context, final IFilterOutput output) { + final Matcher matcher = new Matcher(); for (AbstractInsnNode i = methodNode.instructions .getFirst(); i != null; i = i.getNext()) { matcher.match(i, output); diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index cd5c32f0..7ef9c2b2 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -49,7 +49,8 @@ when expressions that list all cases of enum or sealed class is filtered out during generation of report (GitHub #721, - #729).
    • + #729, + #749).
    • Additional bytecode generated by Kotlin compiler for when expressions on kotlin.String values is filtered out during generation of report -- cgit v1.2.3 From 215a9414a2b7f8129ae818380af49f7cc37ba926 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 20 Aug 2018 23:36:45 +0200 Subject: Get rid of unnecessary instances of Matcher in KotlinLateinitFilter (#750) --- .../analysis/filter/KotlinLateinitFilter.java | 32 ++++++++++------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java index c1aee3ad..65ee2131 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java @@ -24,34 +24,30 @@ public class KotlinLateinitFilter implements IFilter { private final static String OWNER = "kotlin/jvm/internal/Intrinsics"; private final static String NAME = "throwUninitializedPropertyAccessException"; - public void filter(final MethodNode methodNode, final IFilterContext context, - final IFilterOutput output) { + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + final Matcher matcher = new Matcher(); for (AbstractInsnNode i = methodNode.instructions .getFirst(); i != null; i = i.getNext()) { - if (i.getOpcode() != Opcodes.IFNONNULL) { - continue; - } - - final AbstractInsnNode end = new Matcher(i).match(); - - if (end != null) { - output.ignore(i, end); - } + matcher.match(i, output); } } private static class Matcher extends AbstractMatcher { - private final AbstractInsnNode start; - - private Matcher(final AbstractInsnNode start) { - this.start = start; - } + public void match(final AbstractInsnNode start, + final IFilterOutput output) { - private AbstractInsnNode match() { + if (Opcodes.IFNONNULL != start.getOpcode()) { + return; + } cursor = start; + nextIs(Opcodes.LDC); nextIsInvokeStatic(OWNER, NAME); - return cursor; + + if (cursor != null) { + output.ignore(start, cursor); + } } } } -- cgit v1.2.3 From e4b56a390c1ecf5643641c7edc0f5a468af354d0 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Tue, 21 Aug 2018 17:56:41 +0200 Subject: Clarify entry in changelog (#752) --- org.jacoco.doc/docroot/doc/changes.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 7ef9c2b2..5db24f10 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -38,8 +38,9 @@ (GitHub #735, #741, #746).
    • -
    • Methods added by the Kotlin compiler are filtered out during generation - of report. Idea and implementation by Nikolay Krasko +
    • Methods added by the Kotlin compiler that do not have line numbers are + filtered out during generation of report. Idea and implementation by + Nikolay Krasko (GitHub #689).
    • Branch added by the Kotlin compiler for reading from lateinit property is filtered out during generation of report. Implementation by -- cgit v1.2.3 From 485bc5e4d99d9da7f6a4619be187b836928bab1d Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Tue, 21 Aug 2018 19:20:02 +0200 Subject: Prepare release v0.8.2 --- jacoco-maven-plugin.test/pom.xml | 2 +- jacoco-maven-plugin/pom.xml | 2 +- jacoco/pom.xml | 2 +- org.jacoco.agent.rt.test/pom.xml | 2 +- org.jacoco.agent.rt/pom.xml | 2 +- org.jacoco.agent.test/pom.xml | 2 +- org.jacoco.agent/pom.xml | 2 +- org.jacoco.ant.test/pom.xml | 2 +- org.jacoco.ant/pom.xml | 2 +- org.jacoco.build/pom.xml | 2 +- org.jacoco.cli.test/pom.xml | 2 +- org.jacoco.cli/pom.xml | 2 +- org.jacoco.core.test.validation.java5/pom.xml | 2 +- org.jacoco.core.test.validation.java7/pom.xml | 2 +- org.jacoco.core.test.validation.java8/pom.xml | 2 +- org.jacoco.core.test.validation.kotlin/pom.xml | 2 +- org.jacoco.core.test.validation/pom.xml | 2 +- org.jacoco.core.test/pom.xml | 2 +- org.jacoco.core/pom.xml | 2 +- org.jacoco.doc/docroot/doc/changes.html | 2 +- org.jacoco.doc/pom.xml | 2 +- org.jacoco.examples.test/pom.xml | 2 +- org.jacoco.examples/pom.xml | 2 +- org.jacoco.report.test/pom.xml | 2 +- org.jacoco.report/pom.xml | 2 +- org.jacoco.tests/pom.xml | 2 +- pom.xml | 2 +- 27 files changed, 27 insertions(+), 27 deletions(-) diff --git a/jacoco-maven-plugin.test/pom.xml b/jacoco-maven-plugin.test/pom.xml index f922eb57..c3c08243 100644 --- a/jacoco-maven-plugin.test/pom.xml +++ b/jacoco-maven-plugin.test/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.tests - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.tests diff --git a/jacoco-maven-plugin/pom.xml b/jacoco-maven-plugin/pom.xml index 4ce884f7..02288571 100644 --- a/jacoco-maven-plugin/pom.xml +++ b/jacoco-maven-plugin/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.build - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.build diff --git a/jacoco/pom.xml b/jacoco/pom.xml index 28fb3446..3e60cf9b 100644 --- a/jacoco/pom.xml +++ b/jacoco/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.build diff --git a/org.jacoco.agent.rt.test/pom.xml b/org.jacoco.agent.rt.test/pom.xml index a52b505b..b336565a 100644 --- a/org.jacoco.agent.rt.test/pom.xml +++ b/org.jacoco.agent.rt.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.tests diff --git a/org.jacoco.agent.rt/pom.xml b/org.jacoco.agent.rt/pom.xml index e9461ee6..299ba695 100644 --- a/org.jacoco.agent.rt/pom.xml +++ b/org.jacoco.agent.rt/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.build diff --git a/org.jacoco.agent.test/pom.xml b/org.jacoco.agent.test/pom.xml index 195b56b5..a282c6d9 100644 --- a/org.jacoco.agent.test/pom.xml +++ b/org.jacoco.agent.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.tests diff --git a/org.jacoco.agent/pom.xml b/org.jacoco.agent/pom.xml index 63e277da..9fc9d6e9 100644 --- a/org.jacoco.agent/pom.xml +++ b/org.jacoco.agent/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.build diff --git a/org.jacoco.ant.test/pom.xml b/org.jacoco.ant.test/pom.xml index bf843b14..f5fec7ae 100644 --- a/org.jacoco.ant.test/pom.xml +++ b/org.jacoco.ant.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.tests diff --git a/org.jacoco.ant/pom.xml b/org.jacoco.ant/pom.xml index 734f78ec..6558e082 100644 --- a/org.jacoco.ant/pom.xml +++ b/org.jacoco.ant/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.build diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index dc34e9de..da9be69e 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -14,7 +14,7 @@ org.jacoco org.jacoco.build - 0.8.2-SNAPSHOT + 0.8.2 pom JaCoCo diff --git a/org.jacoco.cli.test/pom.xml b/org.jacoco.cli.test/pom.xml index bed30a63..616c65bd 100644 --- a/org.jacoco.cli.test/pom.xml +++ b/org.jacoco.cli.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.tests diff --git a/org.jacoco.cli/pom.xml b/org.jacoco.cli/pom.xml index 344e9b7d..533aa6f3 100644 --- a/org.jacoco.cli/pom.xml +++ b/org.jacoco.cli/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.build diff --git a/org.jacoco.core.test.validation.java5/pom.xml b/org.jacoco.core.test.validation.java5/pom.xml index 241dbc36..01306b82 100644 --- a/org.jacoco.core.test.validation.java5/pom.xml +++ b/org.jacoco.core.test.validation.java5/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.core.test.validation - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.core.test.validation diff --git a/org.jacoco.core.test.validation.java7/pom.xml b/org.jacoco.core.test.validation.java7/pom.xml index d2136541..0a41bdd3 100644 --- a/org.jacoco.core.test.validation.java7/pom.xml +++ b/org.jacoco.core.test.validation.java7/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.core.test.validation - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.core.test.validation diff --git a/org.jacoco.core.test.validation.java8/pom.xml b/org.jacoco.core.test.validation.java8/pom.xml index b682ab88..67a29b3c 100644 --- a/org.jacoco.core.test.validation.java8/pom.xml +++ b/org.jacoco.core.test.validation.java8/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.core.test.validation - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.core.test.validation diff --git a/org.jacoco.core.test.validation.kotlin/pom.xml b/org.jacoco.core.test.validation.kotlin/pom.xml index d9e76806..3457b828 100644 --- a/org.jacoco.core.test.validation.kotlin/pom.xml +++ b/org.jacoco.core.test.validation.kotlin/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.core.test.validation - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.core.test.validation diff --git a/org.jacoco.core.test.validation/pom.xml b/org.jacoco.core.test.validation/pom.xml index ae677de8..8c0f8acf 100644 --- a/org.jacoco.core.test.validation/pom.xml +++ b/org.jacoco.core.test.validation/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.tests - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.tests diff --git a/org.jacoco.core.test/pom.xml b/org.jacoco.core.test/pom.xml index 9e80508e..d0463d3e 100644 --- a/org.jacoco.core.test/pom.xml +++ b/org.jacoco.core.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.tests diff --git a/org.jacoco.core/pom.xml b/org.jacoco.core/pom.xml index 30468f9a..ff76b0fa 100644 --- a/org.jacoco.core/pom.xml +++ b/org.jacoco.core/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.build diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 5db24f10..7a32f0f7 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -18,7 +18,7 @@

      Change History

      -

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

      +

      Release 0.8.2 (2018/08/21)

      New Features

        diff --git a/org.jacoco.doc/pom.xml b/org.jacoco.doc/pom.xml index bd21643a..47cafa4e 100644 --- a/org.jacoco.doc/pom.xml +++ b/org.jacoco.doc/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.build diff --git a/org.jacoco.examples.test/pom.xml b/org.jacoco.examples.test/pom.xml index 7bc59a13..0a94c085 100644 --- a/org.jacoco.examples.test/pom.xml +++ b/org.jacoco.examples.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.tests diff --git a/org.jacoco.examples/pom.xml b/org.jacoco.examples/pom.xml index d930b8e1..b859cdce 100644 --- a/org.jacoco.examples/pom.xml +++ b/org.jacoco.examples/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.build diff --git a/org.jacoco.report.test/pom.xml b/org.jacoco.report.test/pom.xml index 3c26a0ed..b55958d2 100644 --- a/org.jacoco.report.test/pom.xml +++ b/org.jacoco.report.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.tests diff --git a/org.jacoco.report/pom.xml b/org.jacoco.report/pom.xml index 5086a406..b077ba00 100644 --- a/org.jacoco.report/pom.xml +++ b/org.jacoco.report/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.build diff --git a/org.jacoco.tests/pom.xml b/org.jacoco.tests/pom.xml index 8e49ba70..42ef032f 100644 --- a/org.jacoco.tests/pom.xml +++ b/org.jacoco.tests/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.build - 0.8.2-SNAPSHOT + 0.8.2 ../org.jacoco.build diff --git a/pom.xml b/pom.xml index baffcaba..324e3fe2 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.jacoco root - 0.8.2-SNAPSHOT + 0.8.2 pom -- cgit v1.2.3 From 9dfd348cc084a469e41623ee335aaaace97692e3 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 22 Aug 2018 12:39:05 +0200 Subject: Prepare for next development iteration --- jacoco-maven-plugin.test/pom.xml | 2 +- jacoco-maven-plugin/pom.xml | 2 +- jacoco/pom.xml | 2 +- org.jacoco.agent.rt.test/pom.xml | 2 +- org.jacoco.agent.rt/pom.xml | 2 +- org.jacoco.agent.test/pom.xml | 2 +- org.jacoco.agent/pom.xml | 2 +- org.jacoco.ant.test/pom.xml | 2 +- org.jacoco.ant/pom.xml | 2 +- org.jacoco.build/pom.xml | 2 +- org.jacoco.cli.test/pom.xml | 2 +- org.jacoco.cli/pom.xml | 2 +- org.jacoco.core.test.validation.java5/pom.xml | 2 +- org.jacoco.core.test.validation.java7/pom.xml | 2 +- org.jacoco.core.test.validation.java8/pom.xml | 2 +- org.jacoco.core.test.validation.kotlin/pom.xml | 2 +- org.jacoco.core.test.validation/pom.xml | 2 +- org.jacoco.core.test/pom.xml | 2 +- org.jacoco.core/pom.xml | 2 +- org.jacoco.doc/docroot/doc/changes.html | 2 ++ org.jacoco.doc/pom.xml | 2 +- org.jacoco.examples.test/pom.xml | 2 +- org.jacoco.examples/pom.xml | 2 +- org.jacoco.report.test/pom.xml | 2 +- org.jacoco.report/pom.xml | 2 +- org.jacoco.tests/pom.xml | 2 +- pom.xml | 2 +- 27 files changed, 28 insertions(+), 26 deletions(-) diff --git a/jacoco-maven-plugin.test/pom.xml b/jacoco-maven-plugin.test/pom.xml index c3c08243..1879580a 100644 --- a/jacoco-maven-plugin.test/pom.xml +++ b/jacoco-maven-plugin.test/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.tests - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.tests diff --git a/jacoco-maven-plugin/pom.xml b/jacoco-maven-plugin/pom.xml index 02288571..f3819f0f 100644 --- a/jacoco-maven-plugin/pom.xml +++ b/jacoco-maven-plugin/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.build - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.build diff --git a/jacoco/pom.xml b/jacoco/pom.xml index 3e60cf9b..a3bdceea 100644 --- a/jacoco/pom.xml +++ b/jacoco/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.agent.rt.test/pom.xml b/org.jacoco.agent.rt.test/pom.xml index b336565a..15b340a3 100644 --- a/org.jacoco.agent.rt.test/pom.xml +++ b/org.jacoco.agent.rt.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.agent.rt/pom.xml b/org.jacoco.agent.rt/pom.xml index 299ba695..baf36e62 100644 --- a/org.jacoco.agent.rt/pom.xml +++ b/org.jacoco.agent.rt/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.agent.test/pom.xml b/org.jacoco.agent.test/pom.xml index a282c6d9..7f91dfc3 100644 --- a/org.jacoco.agent.test/pom.xml +++ b/org.jacoco.agent.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.agent/pom.xml b/org.jacoco.agent/pom.xml index 9fc9d6e9..0093135c 100644 --- a/org.jacoco.agent/pom.xml +++ b/org.jacoco.agent/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.ant.test/pom.xml b/org.jacoco.ant.test/pom.xml index f5fec7ae..90615d7c 100644 --- a/org.jacoco.ant.test/pom.xml +++ b/org.jacoco.ant.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.ant/pom.xml b/org.jacoco.ant/pom.xml index 6558e082..4d3a5849 100644 --- a/org.jacoco.ant/pom.xml +++ b/org.jacoco.ant/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index da9be69e..f765fbfb 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -14,7 +14,7 @@ org.jacoco org.jacoco.build - 0.8.2 + 0.8.3-SNAPSHOT pom JaCoCo diff --git a/org.jacoco.cli.test/pom.xml b/org.jacoco.cli.test/pom.xml index 616c65bd..05976340 100644 --- a/org.jacoco.cli.test/pom.xml +++ b/org.jacoco.cli.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.cli/pom.xml b/org.jacoco.cli/pom.xml index 533aa6f3..cb27c8bf 100644 --- a/org.jacoco.cli/pom.xml +++ b/org.jacoco.cli/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.core.test.validation.java5/pom.xml b/org.jacoco.core.test.validation.java5/pom.xml index 01306b82..12a2efcf 100644 --- a/org.jacoco.core.test.validation.java5/pom.xml +++ b/org.jacoco.core.test.validation.java5/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.core.test.validation - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.core.test.validation diff --git a/org.jacoco.core.test.validation.java7/pom.xml b/org.jacoco.core.test.validation.java7/pom.xml index 0a41bdd3..810b2690 100644 --- a/org.jacoco.core.test.validation.java7/pom.xml +++ b/org.jacoco.core.test.validation.java7/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.core.test.validation - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.core.test.validation diff --git a/org.jacoco.core.test.validation.java8/pom.xml b/org.jacoco.core.test.validation.java8/pom.xml index 67a29b3c..0e2789f7 100644 --- a/org.jacoco.core.test.validation.java8/pom.xml +++ b/org.jacoco.core.test.validation.java8/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.core.test.validation - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.core.test.validation diff --git a/org.jacoco.core.test.validation.kotlin/pom.xml b/org.jacoco.core.test.validation.kotlin/pom.xml index 3457b828..a50fe3f2 100644 --- a/org.jacoco.core.test.validation.kotlin/pom.xml +++ b/org.jacoco.core.test.validation.kotlin/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.core.test.validation - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.core.test.validation diff --git a/org.jacoco.core.test.validation/pom.xml b/org.jacoco.core.test.validation/pom.xml index 8c0f8acf..37da4a2f 100644 --- a/org.jacoco.core.test.validation/pom.xml +++ b/org.jacoco.core.test.validation/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.tests - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.core.test/pom.xml b/org.jacoco.core.test/pom.xml index d0463d3e..5ab620b8 100644 --- a/org.jacoco.core.test/pom.xml +++ b/org.jacoco.core.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.core/pom.xml b/org.jacoco.core/pom.xml index ff76b0fa..f2f791f8 100644 --- a/org.jacoco.core/pom.xml +++ b/org.jacoco.core/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 7a32f0f7..dc364940 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -18,6 +18,8 @@

        Change History

        +

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

        +

        Release 0.8.2 (2018/08/21)

        New Features

        diff --git a/org.jacoco.doc/pom.xml b/org.jacoco.doc/pom.xml index 47cafa4e..74fcc5b4 100644 --- a/org.jacoco.doc/pom.xml +++ b/org.jacoco.doc/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.examples.test/pom.xml b/org.jacoco.examples.test/pom.xml index 0a94c085..f9e882e0 100644 --- a/org.jacoco.examples.test/pom.xml +++ b/org.jacoco.examples.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.examples/pom.xml b/org.jacoco.examples/pom.xml index b859cdce..505b87c1 100644 --- a/org.jacoco.examples/pom.xml +++ b/org.jacoco.examples/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.report.test/pom.xml b/org.jacoco.report.test/pom.xml index b55958d2..9eb54072 100644 --- a/org.jacoco.report.test/pom.xml +++ b/org.jacoco.report.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.tests diff --git a/org.jacoco.report/pom.xml b/org.jacoco.report/pom.xml index b077ba00..0bf3a161 100644 --- a/org.jacoco.report/pom.xml +++ b/org.jacoco.report/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.build diff --git a/org.jacoco.tests/pom.xml b/org.jacoco.tests/pom.xml index 42ef032f..b47f60bd 100644 --- a/org.jacoco.tests/pom.xml +++ b/org.jacoco.tests/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.build - 0.8.2 + 0.8.3-SNAPSHOT ../org.jacoco.build diff --git a/pom.xml b/pom.xml index 324e3fe2..b14d216b 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.jacoco root - 0.8.2 + 0.8.3-SNAPSHOT pom -- cgit v1.2.3 From 01b961b755bd47164739896d2d9c0960e882fd40 Mon Sep 17 00:00:00 2001 From: "Marc R. Hoffmann" Date: Wed, 3 Oct 2018 21:16:27 +0200 Subject: No need to modify class bytes for Java 10 support (#740) --- .../core/test/validation/java5/FinallyTest.java | 2 - .../core/test/validation/java5/FramesTest.java | 4 -- .../validation/java5/StructuredLockingTest.java | 4 -- .../src/org/jacoco/core/analysis/AnalyzerTest.java | 10 ++- .../jacoco/core/instr/ClassFileVersionsTest.java | 6 +- .../org/jacoco/core/instr/InstrumenterTest.java | 10 ++- .../jacoco/core/instr/ResizeInstructionsTest.java | 5 -- .../jacoco/core/internal/BytecodeVersionTest.java | 62 ----------------- .../org/jacoco/core/internal/data/CRC64Test.java | 3 +- .../core/internal/instr/InstrSupportTest.java | 10 ++- .../runtime/ModifiedSystemClassRuntimeTest.java | 26 ------- .../src/org/jacoco/core/analysis/Analyzer.java | 5 +- .../src/org/jacoco/core/instr/Instrumenter.java | 13 ++-- .../org/jacoco/core/internal/BytecodeVersion.java | 81 ---------------------- .../jacoco/core/internal/ContentTypeDetector.java | 2 +- .../jacoco/core/internal/instr/InstrSupport.java | 15 ++++ .../internal/instr/ProbeArrayStrategyFactory.java | 3 +- .../core/runtime/ModifiedSystemClassRuntime.java | 10 +-- 18 files changed, 46 insertions(+), 225 deletions(-) delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/BytecodeVersionTest.java delete mode 100644 org.jacoco.core/src/org/jacoco/core/internal/BytecodeVersion.java diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java index 82fb08cc..3987ecaa 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java @@ -21,7 +21,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.test.TargetLoader; import org.jacoco.core.test.validation.Source.Line; import org.jacoco.core.test.validation.ValidationTestBase; @@ -194,7 +193,6 @@ public class FinallyTest extends ValidationTestBase { final Set gotoTags = new HashSet(); byte[] b = TargetLoader.getClassDataAsBytes(FinallyTarget.class); - b = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(b), b); final ClassNode classNode = new ClassNode(); new ClassReader(b).accept(classNode, 0); diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FramesTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FramesTest.java index 2d502c31..a8bd1bca 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FramesTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FramesTest.java @@ -18,7 +18,6 @@ import java.io.PrintWriter; import java.io.StringWriter; import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.instr.InstrSupport; import org.jacoco.core.runtime.IRuntime; import org.jacoco.core.runtime.SystemPropertiesRuntime; @@ -87,9 +86,6 @@ public class FramesTest { } private byte[] calculateFrames(byte[] source) { - source = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.get(source), - source); - ClassReader rc = new ClassReader(source); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); diff --git a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/StructuredLockingTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/StructuredLockingTest.java index 8243c4bc..1d197bf9 100644 --- a/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/StructuredLockingTest.java +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/StructuredLockingTest.java @@ -20,7 +20,6 @@ import java.util.List; import java.util.Set; import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.runtime.IRuntime; import org.jacoco.core.runtime.SystemPropertiesRuntime; import org.jacoco.core.test.TargetLoader; @@ -65,9 +64,6 @@ public class StructuredLockingTest { Instrumenter instrumenter = new Instrumenter(runtime); byte[] instrumented = instrumenter.instrument(source, "TestTarget"); - final int version = BytecodeVersion.get(instrumented); - instrumented = BytecodeVersion.downgradeIfNeeded(version, instrumented); - ClassNode cn = new ClassNode(); new ClassReader(instrumented).accept(cn, 0); for (MethodNode mn : cn.methods) { 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 d8828340..b52c6e32 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 @@ -11,6 +11,7 @@ *******************************************************************************/ package org.jacoco.core.analysis; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -36,7 +37,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.jacoco.core.data.ExecutionDataStore; -import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.data.CRC64; import org.jacoco.core.test.TargetLoader; import org.junit.Before; @@ -90,12 +90,16 @@ public class AnalyzerTest { } @Test - public void should_analyze_java10_class() throws Exception { - final byte[] bytes = createClass(BytecodeVersion.V10); + public void should_not_modify_class_bytes_to_support_next_version() + throws Exception { + final byte[] originalBytes = createClass(Opcodes.V12); + final byte[] bytes = new byte[originalBytes.length]; + System.arraycopy(originalBytes, 0, bytes, 0, originalBytes.length); final long expectedClassId = CRC64.classId(bytes); analyzer.analyzeClass(bytes, ""); + assertArrayEquals(originalBytes, bytes); assertEquals(expectedClassId, classes.get("Foo").getId()); } diff --git a/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java index 38bd8083..338d85d3 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/instr/ClassFileVersionsTest.java @@ -22,6 +22,7 @@ import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; import static org.objectweb.asm.Opcodes.POP; import static org.objectweb.asm.Opcodes.RETURN; +import static org.objectweb.asm.Opcodes.V10; import static org.objectweb.asm.Opcodes.V11; import static org.objectweb.asm.Opcodes.V12; import static org.objectweb.asm.Opcodes.V1_1; @@ -36,7 +37,6 @@ import static org.objectweb.asm.Opcodes.V9; import java.io.IOException; -import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.instr.InstrSupport; import org.jacoco.core.runtime.IRuntime; import org.jacoco.core.runtime.SystemPropertiesRuntime; @@ -100,7 +100,7 @@ public class ClassFileVersionsTest { @Test public void test_10() throws IOException { - testVersion(BytecodeVersion.V10, true); + testVersion(V10, true); } @Test @@ -124,8 +124,6 @@ public class ClassFileVersionsTest { } private void assertFrames(byte[] source, final boolean expected) { - int version = BytecodeVersion.get(source); - source = BytecodeVersion.downgradeIfNeeded(version, source); new ClassReader(source) .accept(new ClassVisitor(InstrSupport.ASM_API_VERSION) { 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 85882352..94828edf 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 @@ -35,7 +35,6 @@ import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import org.jacoco.core.analysis.AnalyzerTest; -import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.data.CRC64; import org.jacoco.core.internal.instr.InstrSupport; import org.jacoco.core.runtime.IExecutionDataAccessorGenerator; @@ -97,17 +96,16 @@ public class InstrumenterTest { } @Test - public void should_instrument_java10_class() throws Exception { - final byte[] originalBytes = createClass(BytecodeVersion.V10); + public void should_not_modify_class_bytes_to_support_next_version() + throws Exception { + final byte[] originalBytes = createClass(Opcodes.V12); final byte[] bytes = new byte[originalBytes.length]; System.arraycopy(originalBytes, 0, bytes, 0, originalBytes.length); final long expectedClassId = CRC64.classId(bytes); - final byte[] instrumentedBytes = instrumenter.instrument(bytes, ""); + instrumenter.instrument(bytes, ""); assertArrayEquals(originalBytes, bytes); - assertEquals(BytecodeVersion.V10, - BytecodeVersion.get(instrumentedBytes)); assertEquals(expectedClassId, accessorGenerator.classId); } diff --git a/org.jacoco.core.test/src/org/jacoco/core/instr/ResizeInstructionsTest.java b/org.jacoco.core.test/src/org/jacoco/core/instr/ResizeInstructionsTest.java index fb639ca3..02016445 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/instr/ResizeInstructionsTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/instr/ResizeInstructionsTest.java @@ -15,8 +15,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import org.jacoco.core.instr.Instrumenter; -import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.instr.InstrSupport; import org.jacoco.core.runtime.IRuntime; import org.jacoco.core.runtime.RuntimeData; @@ -62,8 +60,6 @@ public class ResizeInstructionsTest { @Test public void should_not_loose_InnerClasses_attribute() throws Exception { byte[] source = TargetLoader.getClassDataAsBytes(Inner.class); - final int version = BytecodeVersion.get(source); - source = BytecodeVersion.downgradeIfNeeded(version, source); final ClassReader cr = new ClassReader(source); final ClassWriter cw = new ClassWriter(0); @@ -81,7 +77,6 @@ public class ResizeInstructionsTest { } }, 0); source = cw.toByteArray(); - BytecodeVersion.set(source, version); final byte[] bytes = instrumenter.instrument(source, ""); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/BytecodeVersionTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/BytecodeVersionTest.java deleted file mode 100644 index 6bc4ca9e..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/BytecodeVersionTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.internal; - -import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Opcodes; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; - -public class BytecodeVersionTest { - - @Test - public void should_get_and_set_major_version() { - final byte[] bytes = createClass(Opcodes.V1_1); - assertEquals(45, BytecodeVersion.get(bytes)); - - BytecodeVersion.set(bytes, Opcodes.V1_2); - assertEquals(46, BytecodeVersion.get(bytes)); - } - - @Test - public void should_return_original_when_not_java10() { - final byte[] originalBytes = createClass(Opcodes.V9); - - final byte[] bytes = BytecodeVersion.downgradeIfNeeded(Opcodes.V9, - originalBytes); - - assertSame(originalBytes, bytes); - } - - @Test - public void should_return_copy_when_java10() { - final byte[] originalBytes = createClass(BytecodeVersion.V10); - - final byte[] bytes = BytecodeVersion - .downgradeIfNeeded(BytecodeVersion.V10, originalBytes); - - assertNotSame(originalBytes, bytes); - assertEquals(Opcodes.V9, BytecodeVersion.get(bytes)); - assertEquals(BytecodeVersion.V10, BytecodeVersion.get(originalBytes)); - } - - private static byte[] createClass(final int version) { - final ClassWriter cw = new ClassWriter(0); - cw.visit(version, 0, "Foo", null, "java/lang/Object", null); - cw.visitEnd(); - return cw.toByteArray(); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/data/CRC64Test.java b/org.jacoco.core.test/src/org/jacoco/core/internal/data/CRC64Test.java index 39f7d508..ffb60801 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/data/CRC64Test.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/data/CRC64Test.java @@ -16,7 +16,6 @@ import static org.junit.Assert.assertEquals; import java.io.UnsupportedEncodingException; import org.jacoco.core.data.ExecutionDataWriter; -import org.jacoco.core.internal.BytecodeVersion; import org.junit.Test; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; @@ -29,7 +28,7 @@ public class CRC64Test { @Test public void except_java_9_checksums_should_be_different_for_different_bytecode_versions() { assertEquals(0x589E9080A572741EL, - CRC64.classId(createClass(BytecodeVersion.V10))); + CRC64.classId(createClass(Opcodes.V10))); // should remove workaround for Java 9 // during change of exec file version diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java index c1b3044b..dda12bfd 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java @@ -15,7 +15,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import org.jacoco.core.internal.BytecodeVersion; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -42,6 +41,13 @@ public class InstrSupportTest { trace = new TraceMethodVisitor(printer); } + @Test + public void getVersionMajor_should_return_major_version_number() { + final byte[] bytes = new byte[] { (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, + (byte) 0xBE, /* minor */ 0x00, 0x03, /* major */ 0x00, 0x2D }; + assertEquals(45, InstrSupport.getVersionMajor(bytes)); + } + @Test public void needFrames_should_return_false_for_versions_less_than_1_6() { assertFalse(InstrSupport.needsFrames(Opcodes.V1_1)); @@ -57,7 +63,7 @@ public class InstrSupportTest { assertTrue(InstrSupport.needsFrames(Opcodes.V1_7)); assertTrue(InstrSupport.needsFrames(Opcodes.V1_8)); assertTrue(InstrSupport.needsFrames(Opcodes.V9)); - assertTrue(InstrSupport.needsFrames(BytecodeVersion.V10)); + assertTrue(InstrSupport.needsFrames(Opcodes.V10)); assertTrue(InstrSupport.needsFrames(Opcodes.V11)); assertTrue(InstrSupport.needsFrames(Opcodes.V12)); } diff --git a/org.jacoco.core.test/src/org/jacoco/core/runtime/ModifiedSystemClassRuntimeTest.java b/org.jacoco.core.test/src/org/jacoco/core/runtime/ModifiedSystemClassRuntimeTest.java index 03a58018..8a968840 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/runtime/ModifiedSystemClassRuntimeTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/runtime/ModifiedSystemClassRuntimeTest.java @@ -25,12 +25,8 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; -import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.test.TargetLoader; import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.tree.ClassNode; /** * Unit tests for {@link ModifiedSystemClassRuntime}. @@ -49,28 +45,6 @@ public class ModifiedSystemClassRuntimeTest extends RuntimeTestBase { ModifiedSystemClassRuntime.createFor(inst, TARGET_CLASS_NAME); } - @Test - public void should_instrument_java10_class() { - final byte[] bytes = createClass(BytecodeVersion.V10); - - byte[] instrumented = ModifiedSystemClassRuntime.instrument(bytes, - "accessField"); - - assertEquals(BytecodeVersion.V10, BytecodeVersion.get(instrumented)); - instrumented = BytecodeVersion.downgradeIfNeeded(BytecodeVersion.V10, - instrumented); - final ClassNode classNode = new ClassNode(); - new ClassReader(instrumented).accept(classNode, 0); - assertEquals("accessField", classNode.fields.get(0).name); - } - - private static byte[] createClass(final int version) { - final ClassWriter cw = new ClassWriter(0); - cw.visit(version, 0, "Foo", null, "java/lang/Object", null); - cw.visitEnd(); - return cw.toByteArray(); - } - /** This static member emulate the instrumented system class. */ public static Object accessField; 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 92d640d2..01ffd5d3 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java @@ -22,7 +22,6 @@ import java.util.zip.ZipInputStream; import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.ExecutionDataStore; -import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.ContentTypeDetector; import org.jacoco.core.internal.InputStreams; import org.jacoco.core.internal.Pack200Streams; @@ -113,9 +112,7 @@ public class Analyzer { private void analyzeClass(final byte[] source) { final long classId = CRC64.classId(source); - final int version = BytecodeVersion.get(source); - final byte[] b = BytecodeVersion.downgradeIfNeeded(version, source); - final ClassReader reader = new ClassReader(b); + final ClassReader reader = new ClassReader(source); if ((reader.getAccess() & Opcodes.ACC_SYNTHETIC) != 0) { return; } 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 da956fd9..1b18f908 100644 --- a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java +++ b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java @@ -21,7 +21,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; -import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.ContentTypeDetector; import org.jacoco.core.internal.InputStreams; import org.jacoco.core.internal.Pack200Streams; @@ -84,10 +83,7 @@ public class Instrumenter { private byte[] instrument(final byte[] source) { final long classId = CRC64.classId(source); - final int originalVersion = BytecodeVersion.get(source); - final byte[] b = BytecodeVersion.downgradeIfNeeded(originalVersion, - source); - final ClassReader reader = new ClassReader(b); + final ClassReader reader = new ClassReader(source); final ClassWriter writer = new ClassWriter(reader, 0) { @Override protected String getCommonSuperClass(final String type1, @@ -97,13 +93,12 @@ public class Instrumenter { }; final IProbeArrayStrategy strategy = ProbeArrayStrategyFactory .createFor(classId, reader, accessorGenerator); + final int version = InstrSupport.getVersionMajor(source); final ClassVisitor visitor = new ClassProbesAdapter( new ClassInstrumenter(strategy, writer), - InstrSupport.needsFrames(originalVersion)); + InstrSupport.needsFrames(version)); reader.accept(visitor, ClassReader.EXPAND_FRAMES); - final byte[] instrumented = writer.toByteArray(); - BytecodeVersion.set(instrumented, originalVersion); - return instrumented; + return writer.toByteArray(); } /** diff --git a/org.jacoco.core/src/org/jacoco/core/internal/BytecodeVersion.java b/org.jacoco.core/src/org/jacoco/core/internal/BytecodeVersion.java deleted file mode 100644 index c24828b3..00000000 --- a/org.jacoco.core/src/org/jacoco/core/internal/BytecodeVersion.java +++ /dev/null @@ -1,81 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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: - * Evgeny Mandrikov - initial API and implementation - * - *******************************************************************************/ -package org.jacoco.core.internal; - -import org.objectweb.asm.Opcodes; - -/** - * Utilities to read and modify bytecode version in bytes of class. Main purpose - * of this class is to deal with bytecode versions which are not yet supported - * by ASM. - */ -public final class BytecodeVersion { - - private static final int VERSION_INDEX = 6; - - /** - * Version of the Java 10 class file format. - */ - public static final int V10 = Opcodes.V9 + 1; - - private BytecodeVersion() { - } - - /** - * Gets major of bytecode version number from given bytes of class. - * - * @param b - * bytes of class - * @return version of bytecode - */ - public static int get(final byte[] b) { - return (short) (((b[VERSION_INDEX] & 0xFF) << 8) - | (b[VERSION_INDEX + 1] & 0xFF)); - } - - /** - * Sets major of bytecode version in given bytes of class. - * - * @param b - * bytes of class - * @param version - * version of bytecode to set - */ - public static void set(final byte[] b, final int version) { - b[VERSION_INDEX] = (byte) (version >>> 8); - b[VERSION_INDEX + 1] = (byte) version; - } - - /** - * Returns given bytes of class if its major bytecode version is less that - * {@link #V10}, otherwise returns copy where major version set to - * {@link Opcodes#V9}. - * - * @param version - * version of bytecode - * @param source - * bytes of class - * @return given bytes of class if version is less than {@link #V10}, - * otherwise copy where version set to {@link Opcodes#V9} - */ - public static byte[] downgradeIfNeeded(final int version, - final byte[] source) { - if (V10 != version) { - return source; - } - final byte[] b = new byte[source.length]; - System.arraycopy(source, 0, b, 0, source.length); - set(b, Opcodes.V9); - return b; - } - -} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java index c74d3374..5ef3a9a0 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java @@ -83,7 +83,7 @@ public class ContentTypeDetector { case Opcodes.V1_7: case Opcodes.V1_8: case Opcodes.V9: - case BytecodeVersion.V10: + case Opcodes.V10: case Opcodes.V11: case Opcodes.V11 | Opcodes.V_PREVIEW_EXPERIMENTAL: case Opcodes.V12: diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java index 1d4cf2a3..c4569c28 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java @@ -13,6 +13,7 @@ package org.jacoco.core.internal.instr; import static java.lang.String.format; +import org.objectweb.asm.ClassReader; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -157,6 +158,20 @@ public final class InstrSupport { */ static final int CLINIT_ACC = Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC; + private static final int MAJOR_VERSION_INDEX = 6; + + /** + * Gets major of bytecode version number from given bytes of class. + * + * @param b + * bytes of class + * @return version of bytecode + */ + public static int getVersionMajor(final byte[] b) { + return (short) (((b[MAJOR_VERSION_INDEX] & 0xFF) << 8) + | (b[MAJOR_VERSION_INDEX + 1] & 0xFF)); + } + /** * Determines whether the given class file version requires stackmap frames. * diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java index a4fb82b0..4e1938f2 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java @@ -11,7 +11,6 @@ *******************************************************************************/ package org.jacoco.core.internal.instr; -import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.flow.ClassProbesAdapter; import org.jacoco.core.runtime.IExecutionDataAccessorGenerator; import org.objectweb.asm.ClassReader; @@ -44,7 +43,7 @@ public final class ProbeArrayStrategyFactory { final IExecutionDataAccessorGenerator accessorGenerator) { final String className = reader.getClassName(); - final int version = BytecodeVersion.get(reader.b); + final int version = InstrSupport.getVersionMajor(reader.b); if (isInterfaceOrModule(reader)) { final ProbeCounter counter = getProbeCounter(reader); diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java index e51242d8..6d31358f 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java @@ -19,7 +19,6 @@ import java.lang.instrument.Instrumentation; import java.lang.reflect.Field; import java.security.ProtectionDomain; -import org.jacoco.core.internal.BytecodeVersion; import org.jacoco.core.internal.instr.InstrSupport; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; @@ -154,10 +153,7 @@ public class ModifiedSystemClassRuntime extends AbstractRuntime { */ public static byte[] instrument(final byte[] source, final String accessFieldName) { - final int originalVersion = BytecodeVersion.get(source); - final byte[] b = BytecodeVersion.downgradeIfNeeded(originalVersion, - source); - final ClassReader reader = new ClassReader(b); + final ClassReader reader = new ClassReader(source); final ClassWriter writer = new ClassWriter(reader, 0); reader.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, writer) { @@ -168,9 +164,7 @@ public class ModifiedSystemClassRuntime extends AbstractRuntime { } }, ClassReader.EXPAND_FRAMES); - final byte[] instrumented = writer.toByteArray(); - BytecodeVersion.set(instrumented, originalVersion); - return instrumented; + return writer.toByteArray(); } private static void createDataField(final ClassVisitor visitor, -- cgit v1.2.3 From 37ed339d89dac0cfb528a7e694b9ab3596afac54 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 3 Oct 2018 21:37:40 +0200 Subject: Remove unused import --- org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java | 1 - 1 file changed, 1 deletion(-) diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java index c4569c28..b1d48f7d 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java @@ -13,7 +13,6 @@ package org.jacoco.core.internal.instr; import static java.lang.String.format; -import org.objectweb.asm.ClassReader; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; -- cgit v1.2.3 From 9c6bb3371efdad77175d6bbf3ee139d3b7c9356f Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 5 Oct 2018 02:09:18 +0200 Subject: Add filter for Kotlin "unsafe" cast operator (#761) --- .../kotlin/KotlinUnsafeCastOperatorTest.java | 26 ++++++++ .../targets/KotlinUnsafeCastOperatorTarget.kt | 28 +++++++++ .../filter/KotlinUnsafeCastOperatorFilterTest.java | 52 ++++++++++++++++ .../core/internal/analysis/filter/Filters.java | 3 +- .../filter/KotlinUnsafeCastOperatorFilter.java | 71 ++++++++++++++++++++++ org.jacoco.doc/docroot/doc/changes.html | 7 +++ 6 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinUnsafeCastOperatorTest.java create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinUnsafeCastOperatorTarget.kt create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilterTest.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinUnsafeCastOperatorTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinUnsafeCastOperatorTest.java new file mode 100644 index 00000000..475d902b --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinUnsafeCastOperatorTest.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.kotlin.targets.KotlinUnsafeCastOperatorTarget; + +/** + * Test of "unsafe" cast operator. + */ +public class KotlinUnsafeCastOperatorTest extends ValidationTestBase { + + public KotlinUnsafeCastOperatorTest() { + super(KotlinUnsafeCastOperatorTarget.class); + } + +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinUnsafeCastOperatorTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinUnsafeCastOperatorTarget.kt new file mode 100644 index 00000000..a4f5ccda --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinUnsafeCastOperatorTarget.kt @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin.targets + +/** + * This test target is "unsafe" cast operator. + */ +object KotlinUnsafeCastOperatorTarget { + + private fun nullable(): String? { + return "" + } + + @JvmStatic + fun main(args: Array) { + nullable() as String // assertFullyCovered() + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilterTest.java new file mode 100644 index 00000000..eb942519 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilterTest.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Unit tests for {@link KotlinUnsafeCastOperatorFilter}. + */ +public class KotlinUnsafeCastOperatorFilterTest extends FilterTestBase { + + private final KotlinUnsafeCastOperatorFilter filter = new KotlinUnsafeCastOperatorFilter(); + + private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "name", "()V", null, null); + + @Test + public void should_filter() { + final Label label = new Label(); + + m.visitInsn(Opcodes.DUP); + m.visitJumpInsn(Opcodes.IFNONNULL, label); + final AbstractInsnNode expectedFrom = m.instructions.getLast(); + m.visitTypeInsn(Opcodes.NEW, "kotlin/TypeCastException"); + m.visitInsn(Opcodes.DUP); + m.visitLdcInsn("null cannot be cast to non-null type kotlin.String"); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, "kotlin/TypeCastException", + "", "(Ljava/lang/String;)V", false); + m.visitInsn(Opcodes.ATHROW); + final AbstractInsnNode expectedTo = m.instructions.getLast(); + m.visitLabel(label); + + filter.filter(m, context, output); + + assertIgnored(new Range(expectedFrom, expectedTo)); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index 03c85d7d..f6a7a1df 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -34,7 +34,8 @@ public final class Filters implements IFilter { new StringSwitchJavacFilter(), new StringSwitchEcjFilter(), new EnumEmptyConstructorFilter(), new AnnotationGeneratedFilter(), new KotlinGeneratedFilter(), new KotlinLateinitFilter(), - new KotlinWhenFilter(), new KotlinWhenStringFilter()); + new KotlinWhenFilter(), new KotlinWhenStringFilter(), + new KotlinUnsafeCastOperatorFilter()); private final IFilter[] filters; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java new file mode 100644 index 00000000..b65cac27 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Filters branch in bytecode that Kotlin compiler generates for "unsafe" cast + * operator. + */ +public final class KotlinUnsafeCastOperatorFilter implements IFilter { + + private static final String KOTLIN_TYPE_CAST_EXCEPTION = "kotlin/TypeCastException"; + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + final Matcher matcher = new Matcher(); + for (AbstractInsnNode i = methodNode.instructions + .getFirst(); i != null; i = i.getNext()) { + matcher.match(i, output); + } + } + + private static class Matcher extends AbstractMatcher { + public void match(final AbstractInsnNode start, + final IFilterOutput output) { + + if (Opcodes.IFNONNULL != start.getOpcode()) { + return; + } + cursor = start; + + nextIsNew(KOTLIN_TYPE_CAST_EXCEPTION); + nextIs(Opcodes.DUP); + nextIs(Opcodes.LDC); + if (cursor == null) { + return; + } + final LdcInsnNode ldc = (LdcInsnNode) cursor; + if (!(ldc.cst instanceof String && ((String) ldc.cst) + .startsWith("null cannot be cast to non-null type"))) { + return; + } + nextIsInvokeSuper(KOTLIN_TYPE_CAST_EXCEPTION, + "(Ljava/lang/String;)V"); + nextIs(Opcodes.ATHROW); + if (cursor == null) { + return; + } + if (cursor.getNext() != ((JumpInsnNode) start).label) { + return; + } + + output.ignore(start, cursor); + } + } + +} diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index dc364940..94184856 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -20,6 +20,13 @@

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

        +

        New Features

        +
          +
        • Branch added by the Kotlin compiler for "unsafe" cast operator is filtered + out during generation of report + (GitHub #761).
        • +
        +

        Release 0.8.2 (2018/08/21)

        New Features

        -- cgit v1.2.3 From cd401754e14d28a5c123e4eebc958215911c8695 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Tue, 9 Oct 2018 16:33:58 +0200 Subject: Add new Jenkins plugin to list of third-party integrations (#762) --- org.jacoco.doc/docroot/doc/integrations.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/org.jacoco.doc/docroot/doc/integrations.html b/org.jacoco.doc/docroot/doc/integrations.html index 2797013c..60188915 100644 --- a/org.jacoco.doc/docroot/doc/integrations.html +++ b/org.jacoco.doc/docroot/doc/integrations.html @@ -100,6 +100,10 @@ IntelliJ IDEA Since version 11.1, see documentation + + Jenkins + GSoC project of Shenyu Zheng, see project page + Jenkins GSoC project of Ognjen Bubalo, see documentation -- cgit v1.2.3 From 9d0feaed1d2dfd56647cba3c5e04907bf1bac337 Mon Sep 17 00:00:00 2001 From: Renuka Fernando Date: Thu, 11 Oct 2018 07:24:09 +0530 Subject: make constant values readable --- .../org/jacoco/core/runtime/CommandLineSupport.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java b/org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java index 1493afb7..a85933d7 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java @@ -79,11 +79,11 @@ final class CommandLineSupport { } final List args = new ArrayList(); final StringBuilder current = new StringBuilder(); - int mode = M_STRIPWHITESPACE; + int mode = M_STRIP_WHITESPACE; int endChar = BLANK; for (final char c : commandline.toCharArray()) { switch (mode) { - case M_STRIPWHITESPACE: + case M_STRIP_WHITESPACE: if (!Character.isWhitespace(c)) { if (c == QUOTE) { endChar = QUOTE; @@ -91,13 +91,13 @@ final class CommandLineSupport { current.append(c); endChar = BLANK; } - mode = M_PARSEARGUMENT; + mode = M_PARSE_ARGUMENT; } break; - case M_PARSEARGUMENT: + case M_PARSE_ARGUMENT: if (c == endChar) { addArgument(args, current); - mode = M_STRIPWHITESPACE; + mode = M_STRIP_WHITESPACE; } else if (c == SLASH) { current.append(SLASH); mode = M_ESCAPED; @@ -110,11 +110,11 @@ final class CommandLineSupport { current.setCharAt(current.length() - 1, c); } else if (c == endChar) { addArgument(args, current); - mode = M_STRIPWHITESPACE; + mode = M_STRIP_WHITESPACE; } else { current.append(c); } - mode = M_PARSEARGUMENT; + mode = M_PARSE_ARGUMENT; break; } } @@ -130,8 +130,8 @@ final class CommandLineSupport { } } - private static final int M_STRIPWHITESPACE = 0; - private static final int M_PARSEARGUMENT = 1; + private static final int M_STRIP_WHITESPACE = 0; + private static final int M_PARSE_ARGUMENT = 1; private static final int M_ESCAPED = 2; private CommandLineSupport() { -- cgit v1.2.3 From 1d0840fb1ab54ac6c76d640d7eb0e4efd4ba373c Mon Sep 17 00:00:00 2001 From: Renuka Fernando Date: Thu, 11 Oct 2018 07:24:24 +0530 Subject: fix typos --- .../src/org/jacoco/core/runtime/CommandLineSupport.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java b/org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java index a85933d7..63236506 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java @@ -54,13 +54,13 @@ final class CommandLineSupport { */ static String quote(final List args) { final StringBuilder result = new StringBuilder(); - boolean seperate = false; + boolean separate = false; for (final String arg : args) { - if (seperate) { + if (separate) { result.append(BLANK); } result.append(quote(arg)); - seperate = true; + separate = true; } return result.toString(); } @@ -70,7 +70,7 @@ final class CommandLineSupport { * present. * * @param commandline - * combinded command line + * combined command line * @return list of arguments */ static List split(final String commandline) { -- cgit v1.2.3 From fbba3b5b439033b5f4df9701b7d2fa60668fd460 Mon Sep 17 00:00:00 2001 From: Thomas Traude Date: Thu, 18 Oct 2018 04:42:45 +0200 Subject: Remove redundant modifiers in interfaces (#768) --- .../jacoco/agent/rt/internal/IExceptionLogger.java | 2 +- .../agent/rt/internal/output/IAgentOutput.java | 7 +++---- .../src/org/jacoco/ant/CoverageTask.java | 4 ++-- .../src/org/jacoco/core/test/perf/IPerfOutput.java | 2 +- .../org/jacoco/core/test/perf/IPerfScenario.java | 2 +- .../org/jacoco/core/analysis/IBundleCoverage.java | 2 +- .../org/jacoco/core/analysis/IClassCoverage.java | 16 +++++++-------- .../src/org/jacoco/core/analysis/ICounter.java | 24 +++++++++++----------- .../org/jacoco/core/analysis/ICoverageNode.java | 24 +++++++++++----------- .../org/jacoco/core/analysis/ICoverageVisitor.java | 2 +- .../src/org/jacoco/core/analysis/ILine.java | 6 +++--- .../org/jacoco/core/analysis/IMethodCoverage.java | 4 ++-- .../org/jacoco/core/analysis/IPackageCoverage.java | 4 ++-- .../jacoco/core/analysis/ISourceFileCoverage.java | 2 +- .../src/org/jacoco/core/analysis/ISourceNode.java | 8 ++++---- .../jacoco/core/data/IExecutionDataVisitor.java | 2 +- .../org/jacoco/core/data/ISessionInfoVisitor.java | 2 +- .../src/org/jacoco/core/internal/flow/IFrame.java | 2 +- .../jacoco/core/internal/instr/IProbeInserter.java | 2 +- .../runtime/IExecutionDataAccessorGenerator.java | 4 ++-- .../jacoco/core/runtime/IRemoteCommandVisitor.java | 3 +-- .../src/org/jacoco/core/runtime/IRuntime.java | 4 ++-- .../src/org/jacoco/report/ILanguageNames.java | 16 +++++++-------- .../src/org/jacoco/report/IMultiReportOutput.java | 4 ++-- .../src/org/jacoco/report/IReportVisitor.java | 4 ++-- .../src/org/jacoco/report/ISourceFileLocator.java | 4 ++-- .../report/internal/html/IHTMLReportContext.java | 16 +++++++-------- .../org/jacoco/report/internal/html/ILinkable.java | 6 +++--- .../report/internal/html/index/IIndexUpdate.java | 2 +- .../internal/html/table/IColumnRenderer.java | 10 ++++----- .../report/internal/html/table/ITableItem.java | 2 +- 31 files changed, 95 insertions(+), 97 deletions(-) diff --git a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/IExceptionLogger.java b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/IExceptionLogger.java index 6e5c1292..cf0f60ae 100644 --- a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/IExceptionLogger.java +++ b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/IExceptionLogger.java @@ -32,6 +32,6 @@ public interface IExceptionLogger { * @param ex * exception to log */ - public void logExeption(Exception ex); + void logExeption(Exception ex); } diff --git a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/output/IAgentOutput.java b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/output/IAgentOutput.java index ce8e5ddc..62161ec4 100644 --- a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/output/IAgentOutput.java +++ b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/output/IAgentOutput.java @@ -33,8 +33,7 @@ public interface IAgentOutput { * @throws Exception * in case startup fails */ - public void startup(final AgentOptions options, final RuntimeData data) - throws Exception; + void startup(AgentOptions options, RuntimeData data) throws Exception; /** * Shutdown the agent controller and clean up any resources it has created. @@ -42,7 +41,7 @@ public interface IAgentOutput { * @throws Exception * in case shutdown fails */ - public void shutdown() throws Exception; + void shutdown() throws Exception; /** * Write all execution data in the runtime to a location determined by the @@ -53,6 +52,6 @@ public interface IAgentOutput { * @throws IOException * in case writing fails */ - public void writeExecutionData(boolean reset) throws IOException; + void writeExecutionData(boolean reset) throws IOException; } diff --git a/org.jacoco.ant/src/org/jacoco/ant/CoverageTask.java b/org.jacoco.ant/src/org/jacoco/ant/CoverageTask.java index 9cc9f2b5..f64f7c09 100644 --- a/org.jacoco.ant/src/org/jacoco/ant/CoverageTask.java +++ b/org.jacoco.ant/src/org/jacoco/ant/CoverageTask.java @@ -179,7 +179,7 @@ public class CoverageTask extends AbstractCoverageTask implements TaskContainer * @return true if this enhancer is capable of enhancing * the requested task type */ - public boolean supportsTask(String taskname); + boolean supportsTask(String taskname); /** * Attempt to enhance the supplied task with coverage information. This @@ -192,6 +192,6 @@ public class CoverageTask extends AbstractCoverageTask implements TaskContainer * Thrown if this enhancer can handle this type of task, but * this instance can not be enhanced for some reason. */ - public void enhanceTask(Task task) throws BuildException; + void enhanceTask(Task task) throws BuildException; } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/perf/IPerfOutput.java b/org.jacoco.core.test/src/org/jacoco/core/test/perf/IPerfOutput.java index 2298111e..56b6ab87 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/perf/IPerfOutput.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/perf/IPerfOutput.java @@ -17,7 +17,7 @@ package org.jacoco.core.test.perf; public interface IPerfOutput { /** Indicator for no reference time given */ - public static final long NO_REFERENCE = Long.MIN_VALUE; + long NO_REFERENCE = Long.MIN_VALUE; /** * Reports the result of a time measurement with a optional reference time diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/perf/IPerfScenario.java b/org.jacoco.core.test/src/org/jacoco/core/test/perf/IPerfScenario.java index 471b839b..557464a6 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/perf/IPerfScenario.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/perf/IPerfScenario.java @@ -22,6 +22,6 @@ public interface IPerfScenario { * * @param output */ - public void run(IPerfOutput output) throws Exception; + void run(IPerfOutput output) throws Exception; } diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java index afcdc1aa..c678ff46 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java @@ -25,6 +25,6 @@ public interface IBundleCoverage extends ICoverageNode { * * @return all packages */ - public Collection getPackages(); + Collection getPackages(); } \ No newline at end of file diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java index f72b7a85..45db04a2 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java @@ -27,7 +27,7 @@ public interface IClassCoverage extends ISourceNode { * * @return class identifier */ - public long getId(); + long getId(); /** * Returns if the the analyzed class does match the execution data provided. @@ -37,14 +37,14 @@ public interface IClassCoverage extends ISourceNode { * @return true if this class does not match to the provided * execution data. */ - public boolean isNoMatch(); + boolean isNoMatch(); /** * Returns the VM signature of the class. * * @return VM signature of the class (may be null) */ - public String getSignature(); + String getSignature(); /** * Returns the VM name of the superclass. @@ -52,34 +52,34 @@ public interface IClassCoverage extends ISourceNode { * @return VM name of the super class (may be null, i.e. * java/lang/Object) */ - public String getSuperName(); + String getSuperName(); /** * Returns the VM names of implemented/extended interfaces. * * @return VM names of implemented/extended interfaces */ - public String[] getInterfaceNames(); + String[] getInterfaceNames(); /** * Returns the VM name of the package this class belongs to. * * @return VM name of the package */ - public String getPackageName(); + String getPackageName(); /** * Returns the optional name of the corresponding source file. * * @return name of the corresponding source file */ - public String getSourceFileName(); + String getSourceFileName(); /** * Returns the methods included in this class. * * @return methods of this class */ - public Collection getMethods(); + Collection getMethods(); } \ No newline at end of file diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java b/org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java index 5f30e02b..6124e281 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java @@ -20,7 +20,7 @@ public interface ICounter { /** * Different values provided by a counter. */ - public enum CounterValue { + enum CounterValue { /** Total number of items */ TOTALCOUNT, @@ -41,22 +41,22 @@ public interface ICounter { /** * Status flag for no items (value is 0x00). */ - public static final int EMPTY = 0x00; + int EMPTY = 0x00; /** * Status flag when all items are not covered (value is 0x01). */ - public static final int NOT_COVERED = 0x01; + int NOT_COVERED = 0x01; /** * Status flag when all items are covered (value is 0x02). */ - public static final int FULLY_COVERED = 0x02; + int FULLY_COVERED = 0x02; /** * Status flag when items are partly covered (value is 0x03). */ - public static final int PARTLY_COVERED = NOT_COVERED | FULLY_COVERED; + int PARTLY_COVERED = NOT_COVERED | FULLY_COVERED; /** * Returns the counter value of the given type. @@ -65,28 +65,28 @@ public interface ICounter { * value type to return * @return counter value */ - public double getValue(CounterValue value); + double getValue(CounterValue value); /** * Returns the total count of items. * * @return total count of items */ - public int getTotalCount(); + int getTotalCount(); /** * Returns the count of covered items. * * @return count of covered items */ - public int getCoveredCount(); + int getCoveredCount(); /** * Returns the count of missed items. * * @return count of missed items */ - public int getMissedCount(); + int getMissedCount(); /** * Calculates the ratio of covered to total count items. If total count @@ -94,7 +94,7 @@ public interface ICounter { * * @return ratio of covered to total count items */ - public double getCoveredRatio(); + double getCoveredRatio(); /** * Calculates the ratio of missed to total count items. If total count items @@ -102,7 +102,7 @@ public interface ICounter { * * @return ratio of missed to total count items */ - public double getMissedRatio(); + double getMissedRatio(); /** * Returns the coverage status of this counter. @@ -114,6 +114,6 @@ public interface ICounter { * * @return status of this line */ - public int getStatus(); + int getStatus(); } diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java index 0756f410..f7605278 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java @@ -20,7 +20,7 @@ public interface ICoverageNode { /** * Type of a Java element represented by a {@link ICoverageNode} instance. */ - public enum ElementType { + enum ElementType { /** Method */ METHOD, @@ -45,7 +45,7 @@ public interface ICoverageNode { /** * Different counter types supported by JaCoCo. */ - public enum CounterEntity { + enum CounterEntity { /** Counter for instructions */ INSTRUCTION, @@ -71,56 +71,56 @@ public interface ICoverageNode { * * @return type of this node */ - public abstract ElementType getElementType(); + ElementType getElementType(); /** * Returns the name of this node. * * @return name of this node */ - public String getName(); + String getName(); /** * Returns the counter for byte code instructions. * * @return counter for instructions */ - public abstract ICounter getInstructionCounter(); + ICounter getInstructionCounter(); /** * Returns the counter for branches. * * @return counter for branches */ - public ICounter getBranchCounter(); + ICounter getBranchCounter(); /** * Returns the counter for lines. * * @return counter for lines */ - public ICounter getLineCounter(); + ICounter getLineCounter(); /** * Returns the counter for cyclomatic complexity. * * @return counter for complexity */ - public ICounter getComplexityCounter(); + ICounter getComplexityCounter(); /** * Returns the counter for methods. * * @return counter for methods */ - public ICounter getMethodCounter(); + ICounter getMethodCounter(); /** * Returns the counter for classes. * * @return counter for classes */ - public ICounter getClassCounter(); + ICounter getClassCounter(); /** * Generic access to the the counters. @@ -129,7 +129,7 @@ public interface ICoverageNode { * entity we're we want to have the counter for * @return counter for the given entity */ - public ICounter getCounter(CounterEntity entity); + ICounter getCounter(CounterEntity entity); /** * Creates a plain copy of this node. While {@link ICoverageNode} @@ -139,6 +139,6 @@ public interface ICoverageNode { * * @return copy with counters only */ - public ICoverageNode getPlainCopy(); + ICoverageNode getPlainCopy(); } \ No newline at end of file diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java index 5a71859f..e516f858 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java @@ -23,6 +23,6 @@ public interface ICoverageVisitor { * @param coverage * coverage data for a class */ - public void visitCoverage(IClassCoverage coverage); + void visitCoverage(IClassCoverage coverage); } diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ILine.java b/org.jacoco.core/src/org/jacoco/core/analysis/ILine.java index cdd91eba..1728aa39 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/ILine.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/ILine.java @@ -22,14 +22,14 @@ public interface ILine { * * @return instruction counter */ - public ICounter getInstructionCounter(); + ICounter getInstructionCounter(); /** * Returns the branches counter for this line. * * @return branches counter */ - public ICounter getBranchCounter(); + ICounter getBranchCounter(); /** * Returns the coverage status of this line, calculated from the @@ -42,6 +42,6 @@ public interface ILine { * * @return status of this line */ - public int getStatus(); + int getStatus(); } diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java index 3bd75169..5442f987 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java @@ -22,13 +22,13 @@ public interface IMethodCoverage extends ISourceNode { * * @return descriptor */ - public String getDesc(); + String getDesc(); /** * Returns the generic signature of the method if defined. * * @return generic signature or null */ - public String getSignature(); + String getSignature(); } \ No newline at end of file diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java index 8ff1a184..759e3672 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java @@ -28,13 +28,13 @@ public interface IPackageCoverage extends ICoverageNode { * * @return all classes */ - public Collection getClasses(); + Collection getClasses(); /** * Returns all source files in this package. * * @return all source files */ - public Collection getSourceFiles(); + Collection getSourceFiles(); } \ No newline at end of file diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ISourceFileCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/ISourceFileCoverage.java index 6a49490b..9aa98aba 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/ISourceFileCoverage.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/ISourceFileCoverage.java @@ -22,6 +22,6 @@ public interface ISourceFileCoverage extends ISourceNode { * * @return package name */ - public String getPackageName(); + String getPackageName(); } \ No newline at end of file diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java b/org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java index d6c90e5a..2deb23f6 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java @@ -18,7 +18,7 @@ package org.jacoco.core.analysis; public interface ISourceNode extends ICoverageNode { /** Place holder for unknown lines (no debug information) */ - public static int UNKNOWN_LINE = -1; + int UNKNOWN_LINE = -1; /** * The number of the first line coverage information is available for. If no @@ -26,7 +26,7 @@ public interface ISourceNode extends ICoverageNode { * * @return number of the first line or {@link #UNKNOWN_LINE} */ - public int getFirstLine(); + int getFirstLine(); /** * The number of the last line coverage information is available for. If no @@ -34,7 +34,7 @@ public interface ISourceNode extends ICoverageNode { * * @return number of the last line or {@link #UNKNOWN_LINE} */ - public int getLastLine(); + int getLastLine(); /** * Returns the line information for given line. @@ -43,6 +43,6 @@ public interface ISourceNode extends ICoverageNode { * line number of interest * @return line information */ - public ILine getLine(int nr); + ILine getLine(int nr); } diff --git a/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java b/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java index b2bccd6c..1499c337 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java +++ b/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java @@ -24,6 +24,6 @@ public interface IExecutionDataVisitor { * @param data * execution data for a class */ - public void visitClassExecution(ExecutionData data); + void visitClassExecution(ExecutionData data); } diff --git a/org.jacoco.core/src/org/jacoco/core/data/ISessionInfoVisitor.java b/org.jacoco.core/src/org/jacoco/core/data/ISessionInfoVisitor.java index 23e7711d..38799057 100644 --- a/org.jacoco.core/src/org/jacoco/core/data/ISessionInfoVisitor.java +++ b/org.jacoco.core/src/org/jacoco/core/data/ISessionInfoVisitor.java @@ -25,6 +25,6 @@ public interface ISessionInfoVisitor { * @param info * session information */ - public void visitSessionInfo(final SessionInfo info); + void visitSessionInfo(SessionInfo info); } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/IFrame.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/IFrame.java index 09e99064..80ac5fcf 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/flow/IFrame.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/IFrame.java @@ -24,6 +24,6 @@ public interface IFrame { * @param mv * method visitor to emit frame event to */ - void accept(final MethodVisitor mv); + void accept(MethodVisitor mv); } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeInserter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeInserter.java index e6c8dc59..e50b2915 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeInserter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeInserter.java @@ -23,6 +23,6 @@ interface IProbeInserter { * @param id * id of the probe to insert */ - public void insertProbe(final int id); + void insertProbe(int id); } diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/IExecutionDataAccessorGenerator.java b/org.jacoco.core/src/org/jacoco/core/runtime/IExecutionDataAccessorGenerator.java index 00783121..852f8aa1 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/IExecutionDataAccessorGenerator.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/IExecutionDataAccessorGenerator.java @@ -45,7 +45,7 @@ public interface IExecutionDataAccessorGenerator { * @return additional stack size required by the implementation, including * the instance pushed to the stack */ - public int generateDataAccessor(final long classid, final String classname, - final int probecount, MethodVisitor mv); + int generateDataAccessor(long classid, String classname, int probecount, + MethodVisitor mv); } diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/IRemoteCommandVisitor.java b/org.jacoco.core/src/org/jacoco/core/runtime/IRemoteCommandVisitor.java index c4b12f1c..c50f992a 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/IRemoteCommandVisitor.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/IRemoteCommandVisitor.java @@ -28,7 +28,6 @@ public interface IRemoteCommandVisitor { * @throws IOException * in case of problems with the remote connection */ - public void visitDumpCommand(final boolean dump, final boolean reset) - throws IOException; + void visitDumpCommand(boolean dump, boolean reset) throws IOException; } diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java index 9eee8fba..adeba569 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java @@ -26,12 +26,12 @@ public interface IRuntime extends IExecutionDataAccessorGenerator { * @throws Exception * any internal problem during startup */ - public void startup(RuntimeData data) throws Exception; + void startup(RuntimeData data) throws Exception; /** * Allows the coverage runtime to cleanup internals. This class should be * called when classes instrumented for this runtime are not used any more. */ - public void shutdown(); + void shutdown(); } diff --git a/org.jacoco.report/src/org/jacoco/report/ILanguageNames.java b/org.jacoco.report/src/org/jacoco/report/ILanguageNames.java index 0e669bbe..d20e9d18 100644 --- a/org.jacoco.report/src/org/jacoco/report/ILanguageNames.java +++ b/org.jacoco.report/src/org/jacoco/report/ILanguageNames.java @@ -23,7 +23,7 @@ public interface ILanguageNames { * vm name of a package * @return language specific notation for the package */ - public String getPackageName(String vmname); + String getPackageName(String vmname); /** * Calculates the language specific name of a class. @@ -39,8 +39,8 @@ public interface ILanguageNames { * vm names of interfaces of the class (may be null) * @return language specific notation of the class */ - public String getClassName(String vmname, String vmsignature, - String vmsuperclass, String[] vminterfaces); + String getClassName(String vmname, String vmsignature, String vmsuperclass, + String[] vminterfaces); /** * Calculates the language specific qualified name of a class. @@ -49,7 +49,7 @@ public interface ILanguageNames { * vm name of a class * @return language specific qualified notation of the class */ - public String getQualifiedClassName(String vmname); + String getQualifiedClassName(String vmname); /** * Calculates the language specific name of a method. @@ -64,8 +64,8 @@ public interface ILanguageNames { * vm signature of the method (may be null) * @return language specific notation for the method */ - public String getMethodName(String vmclassname, String vmmethodname, - String vmdesc, String vmsignature); + String getMethodName(String vmclassname, String vmmethodname, String vmdesc, + String vmsignature); /** * Calculates the language specific fully qualified name of a method. @@ -80,7 +80,7 @@ public interface ILanguageNames { * vm signature of the method (may be null) * @return language specific notation for the method */ - public String getQualifiedMethodName(String vmclassname, - String vmmethodname, String vmdesc, String vmsignature); + String getQualifiedMethodName(String vmclassname, String vmmethodname, + String vmdesc, String vmsignature); } diff --git a/org.jacoco.report/src/org/jacoco/report/IMultiReportOutput.java b/org.jacoco.report/src/org/jacoco/report/IMultiReportOutput.java index c249ea96..9e215a6f 100644 --- a/org.jacoco.report/src/org/jacoco/report/IMultiReportOutput.java +++ b/org.jacoco.report/src/org/jacoco/report/IMultiReportOutput.java @@ -29,7 +29,7 @@ public interface IMultiReportOutput { * @throws IOException * if the creation fails */ - public OutputStream createFile(String path) throws IOException; + OutputStream createFile(String path) throws IOException; /** * Closes the underlying resource container. @@ -37,6 +37,6 @@ public interface IMultiReportOutput { * @throws IOException * if closing fails */ - public void close() throws IOException; + void close() throws IOException; } diff --git a/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java b/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java index 6b145cff..2648c8d9 100644 --- a/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java +++ b/org.jacoco.report/src/org/jacoco/report/IReportVisitor.java @@ -38,7 +38,7 @@ public interface IReportVisitor extends IReportGroupVisitor { * @throws IOException * in case of IO problems with the report writer */ - public void visitInfo(List sessionInfos, + void visitInfo(List sessionInfos, Collection executionData) throws IOException; /** @@ -47,6 +47,6 @@ public interface IReportVisitor extends IReportGroupVisitor { * @throws IOException * in case of IO problems with the report writer */ - public void visitEnd() throws IOException; + void visitEnd() throws IOException; } diff --git a/org.jacoco.report/src/org/jacoco/report/ISourceFileLocator.java b/org.jacoco.report/src/org/jacoco/report/ISourceFileLocator.java index ed5809ed..9c08a317 100644 --- a/org.jacoco.report/src/org/jacoco/report/ISourceFileLocator.java +++ b/org.jacoco.report/src/org/jacoco/report/ISourceFileLocator.java @@ -31,7 +31,7 @@ public interface ISourceFileLocator { * @throws IOException * in case of problems while opening the file */ - public Reader getSourceFile(String packageName, String fileName) + Reader getSourceFile(String packageName, String fileName) throws IOException; /** @@ -39,6 +39,6 @@ public interface ISourceFileLocator { * * @return tab width as number of blanks */ - public int getTabWidth(); + int getTabWidth(); } diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/IHTMLReportContext.java b/org.jacoco.report/src/org/jacoco/report/internal/html/IHTMLReportContext.java index 49499deb..0ce0b678 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/IHTMLReportContext.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/IHTMLReportContext.java @@ -28,55 +28,55 @@ public interface IHTMLReportContext { * * @return static resources */ - public Resources getResources(); + Resources getResources(); /** * Returns the language names call-back used in this report. * * @return language names */ - public ILanguageNames getLanguageNames(); + ILanguageNames getLanguageNames(); /** * Returns a table for rendering coverage nodes. * * @return table for rendering */ - public Table getTable(); + Table getTable(); /** * Returns a string of textual information to include in every page footer. * * @return footer text or empty string */ - public String getFooterText(); + String getFooterText(); /** * Returns the link to the sessions page. * * @return sessions page link */ - public ILinkable getSessionsPage(); + ILinkable getSessionsPage(); /** * Returns the encoding of the generated HTML documents. * * @return encoding for generated HTML documents */ - public String getOutputEncoding(); + String getOutputEncoding(); /** * Returns the service for index updates. * * @return sevice for indes updates */ - public IIndexUpdate getIndexUpdate(); + IIndexUpdate getIndexUpdate(); /** * Returns the locale used to format numbers and dates. * * @return locale for numbers and dates */ - public Locale getLocale(); + Locale getLocale(); } \ No newline at end of file diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/ILinkable.java b/org.jacoco.report/src/org/jacoco/report/internal/html/ILinkable.java index 900e4955..1e803f53 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/ILinkable.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/ILinkable.java @@ -26,20 +26,20 @@ public interface ILinkable { * folder where the link should be inserted * @return relative link or null if the target does not exist */ - public String getLink(final ReportOutputFolder base); + String getLink(ReportOutputFolder base); /** * Returns the display label used for the link. * * @return display label */ - public String getLinkLabel(); + String getLinkLabel(); /** * Optional style class to be associated with the link. * * @return link style class or null */ - public String getLinkStyle(); + String getLinkStyle(); } diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/index/IIndexUpdate.java b/org.jacoco.report/src/org/jacoco/report/internal/html/index/IIndexUpdate.java index b6910fc1..8aa892d7 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/index/IIndexUpdate.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/index/IIndexUpdate.java @@ -27,6 +27,6 @@ public interface IIndexUpdate { * @param classid * identifier of the class */ - public void addClass(ILinkable link, long classid); + void addClass(ILinkable link, long classid); } diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/table/IColumnRenderer.java b/org.jacoco.report/src/org/jacoco/report/internal/html/table/IColumnRenderer.java index 76724eab..fa02556b 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/table/IColumnRenderer.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/table/IColumnRenderer.java @@ -36,7 +36,7 @@ public interface IColumnRenderer { * the summary of all coverage data items in the table * @return true if the column should be visible */ - public boolean init(List items, ICoverageNode total); + boolean init(List items, ICoverageNode total); /** * Renders the footer for this column. @@ -52,8 +52,8 @@ public interface IColumnRenderer { * @throws IOException * in case of IO problems with the element output */ - public void footer(HTMLElement td, ICoverageNode total, - Resources resources, ReportOutputFolder base) throws IOException; + void footer(HTMLElement td, ICoverageNode total, Resources resources, + ReportOutputFolder base) throws IOException; /** * Renders a single item in this column. @@ -69,7 +69,7 @@ public interface IColumnRenderer { * @throws IOException * in case of IO problems with the element output */ - public void item(HTMLElement td, ITableItem item, Resources resources, + void item(HTMLElement td, ITableItem item, Resources resources, ReportOutputFolder base) throws IOException; /** @@ -77,6 +77,6 @@ public interface IColumnRenderer { * * @return comparator for this column */ - public Comparator getComparator(); + Comparator getComparator(); } diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/table/ITableItem.java b/org.jacoco.report/src/org/jacoco/report/internal/html/table/ITableItem.java index dbed41f0..cb15d1c0 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/table/ITableItem.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/table/ITableItem.java @@ -24,6 +24,6 @@ public interface ITableItem extends ILinkable { * * @return node data */ - public ICoverageNode getNode(); + ICoverageNode getNode(); } -- cgit v1.2.3 From 529642a0e36965512166236fcac25ba0a20d3b97 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 24 Oct 2018 13:14:51 +0200 Subject: Normalize line endings --- org.jacoco.doc/docroot/doc/resources/doc.css | 450 +++++++++++++-------------- 1 file changed, 225 insertions(+), 225 deletions(-) diff --git a/org.jacoco.doc/docroot/doc/resources/doc.css b/org.jacoco.doc/docroot/doc/resources/doc.css index 3e62c597..ec89c32a 100644 --- a/org.jacoco.doc/docroot/doc/resources/doc.css +++ b/org.jacoco.doc/docroot/doc/resources/doc.css @@ -1,225 +1,225 @@ -.el_jar { - padding-left:18px; - background-image:url(jar.gif); - background-position:left center; - background-repeat:no-repeat; -} - -.el_test { - padding-left:18px; - background-image:url(test.gif); - background-position:left center; - background-repeat:no-repeat; -} - -.el_testsuite { - padding-left:18px; - background-image:url(testsuite.gif); - background-position:left center; - background-repeat:no-repeat; -} - -p.intro { - margin-left:20px; - padding-left:4px; - border-left:#cccca0 4px solid; - font-style:italic -} - -p.hint { - margin-left:20px; - padding-left:4px; - border-left:#cccca0 4px solid; - font-style:italic -} - -.high { - background-color:#ffff80; -} - -div#content a[href^='http://'], a[href^='https://'] { - display:inline-block; - padding-left:15px; - background:transparent url(extern.gif) center left no-repeat; -} - -/* === Definitions from report.css start here: === */ - -body, td { - font-family:sans-serif; - font-size:10pt; -} - -h1 { - font-weight:bold; - font-size:18pt; -} - -.breadcrumb { - border:#d6d3ce 1px solid; - padding:2px 4px 2px 4px; -} - - -.el_report { - padding-left:18px; - background-image:url(report.gif); - background-position:left center; - background-repeat:no-repeat; -} - -.el_group { - padding-left:18px; - background-image:url(group.gif); - background-position:left center; - background-repeat:no-repeat; -} - -.el_bundle { - padding-left:18px; - background-image:url(bundle.gif); - background-position:left center; - background-repeat:no-repeat; -} - -.el_package { - padding-left:18px; - background-image:url(package.gif); - background-position:left center; - background-repeat:no-repeat; -} - -.el_class { - padding-left:18px; - background-image:url(class.gif); - background-position:left center; - background-repeat:no-repeat; -} - -.el_source { - padding-left:18px; - background-image:url(source.gif); - background-position:left center; - background-repeat:no-repeat; -} - -.el_method { - padding-left:18px; - background-image:url(method.gif); - background-position:left center; - background-repeat:no-repeat; -} - -.el_session { - padding-left:18px; - background-image:url(session.gif); - background-position:left center; - background-repeat:no-repeat; -} - -pre.source { - border:#d6d3ce 1px solid; - font-family:monospace; -} - -pre.source ol { - margin-bottom: 0px; - margin-top: 0px; -} - -pre.source li { - border-left: 1px solid #D6D3CE; - color: #A0A0A0; - padding-left: 0px; -} - -pre.source span.fc { - background-color:#ccffcc; -} - -pre.source span.nc { - background-color:#ffcccc; -} - -pre.source span.pc { - background-color:#ffffcc; -} - - -table.coverage { - empty-cells:show; - border-collapse:collapse; -} - -table.coverage thead { - background-color:#e0e0e0; -} - -table.coverage thead td { - white-space:nowrap; - padding:2px 8px 0px 8px; - border-bottom:#b0b0b0 1px solid; -} - -table.coverage thead td.ctr1 { - text-align:right; - padding-right:4px; - border-left:#cccccc 1px solid; -} - -table.coverage thead td.ctr2 { - text-align:right; - padding-left:4px; -} - -table.coverage tbody td { - vertical-align:top; - padding:2px 8px 2px 8px; - border-bottom:#d6d3ce 1px solid; -} - -table.coverage tbody tr:hover { - background: #f0f0d0 !important; -} - -table.coverage tbody td.ctr1 { - text-align:right; - padding-right:4px; - border-left:#e8e8e8 1px solid; -} - -table.coverage tbody td.ctr2 { - text-align:right; - padding-left:4px; -} - -table.coverage tfoot td { - padding:2px 8px 2px 8px; -} - -table.coverage tfoot td.ctr1 { - text-align:right; - padding-right:4px; - border-left:#e8e8e8 1px solid; -} - -table.coverage tfoot td.ctr2 { - text-align:right; - padding-left:4px; -} - -.footer { - margin-top:20px; - border-top:#d6d3ce 1px solid; - padding-top:2px; - font-size:8pt; - color:#a0a0a0; -} - -.footer a { - color:#a0a0a0; -} - -.right { - float:right; -} +.el_jar { + padding-left:18px; + background-image:url(jar.gif); + background-position:left center; + background-repeat:no-repeat; +} + +.el_test { + padding-left:18px; + background-image:url(test.gif); + background-position:left center; + background-repeat:no-repeat; +} + +.el_testsuite { + padding-left:18px; + background-image:url(testsuite.gif); + background-position:left center; + background-repeat:no-repeat; +} + +p.intro { + margin-left:20px; + padding-left:4px; + border-left:#cccca0 4px solid; + font-style:italic +} + +p.hint { + margin-left:20px; + padding-left:4px; + border-left:#cccca0 4px solid; + font-style:italic +} + +.high { + background-color:#ffff80; +} + +div#content a[href^='http://'], a[href^='https://'] { + display:inline-block; + padding-left:15px; + background:transparent url(extern.gif) center left no-repeat; +} + +/* === Definitions from report.css start here: === */ + +body, td { + font-family:sans-serif; + font-size:10pt; +} + +h1 { + font-weight:bold; + font-size:18pt; +} + +.breadcrumb { + border:#d6d3ce 1px solid; + padding:2px 4px 2px 4px; +} + + +.el_report { + padding-left:18px; + background-image:url(report.gif); + background-position:left center; + background-repeat:no-repeat; +} + +.el_group { + padding-left:18px; + background-image:url(group.gif); + background-position:left center; + background-repeat:no-repeat; +} + +.el_bundle { + padding-left:18px; + background-image:url(bundle.gif); + background-position:left center; + background-repeat:no-repeat; +} + +.el_package { + padding-left:18px; + background-image:url(package.gif); + background-position:left center; + background-repeat:no-repeat; +} + +.el_class { + padding-left:18px; + background-image:url(class.gif); + background-position:left center; + background-repeat:no-repeat; +} + +.el_source { + padding-left:18px; + background-image:url(source.gif); + background-position:left center; + background-repeat:no-repeat; +} + +.el_method { + padding-left:18px; + background-image:url(method.gif); + background-position:left center; + background-repeat:no-repeat; +} + +.el_session { + padding-left:18px; + background-image:url(session.gif); + background-position:left center; + background-repeat:no-repeat; +} + +pre.source { + border:#d6d3ce 1px solid; + font-family:monospace; +} + +pre.source ol { + margin-bottom: 0px; + margin-top: 0px; +} + +pre.source li { + border-left: 1px solid #D6D3CE; + color: #A0A0A0; + padding-left: 0px; +} + +pre.source span.fc { + background-color:#ccffcc; +} + +pre.source span.nc { + background-color:#ffcccc; +} + +pre.source span.pc { + background-color:#ffffcc; +} + + +table.coverage { + empty-cells:show; + border-collapse:collapse; +} + +table.coverage thead { + background-color:#e0e0e0; +} + +table.coverage thead td { + white-space:nowrap; + padding:2px 8px 0px 8px; + border-bottom:#b0b0b0 1px solid; +} + +table.coverage thead td.ctr1 { + text-align:right; + padding-right:4px; + border-left:#cccccc 1px solid; +} + +table.coverage thead td.ctr2 { + text-align:right; + padding-left:4px; +} + +table.coverage tbody td { + vertical-align:top; + padding:2px 8px 2px 8px; + border-bottom:#d6d3ce 1px solid; +} + +table.coverage tbody tr:hover { + background: #f0f0d0 !important; +} + +table.coverage tbody td.ctr1 { + text-align:right; + padding-right:4px; + border-left:#e8e8e8 1px solid; +} + +table.coverage tbody td.ctr2 { + text-align:right; + padding-left:4px; +} + +table.coverage tfoot td { + padding:2px 8px 2px 8px; +} + +table.coverage tfoot td.ctr1 { + text-align:right; + padding-right:4px; + border-left:#e8e8e8 1px solid; +} + +table.coverage tfoot td.ctr2 { + text-align:right; + padding-left:4px; +} + +.footer { + margin-top:20px; + border-top:#d6d3ce 1px solid; + padding-top:2px; + font-size:8pt; + color:#a0a0a0; +} + +.footer a { + color:#a0a0a0; +} + +.right { + float:right; +} -- cgit v1.2.3 From edbcb26a37ac9456908fcedc2d314c1ab65b04ec Mon Sep 17 00:00:00 2001 From: "Marc R. Hoffmann" Date: Fri, 26 Oct 2018 22:39:45 +0200 Subject: Update FAQ (#778) * Interfaces can contain code nowadays * CLI is another way to trigger remote dumps * There is a runtime API for remote dumps --- org.jacoco.doc/docroot/doc/faq.html | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/org.jacoco.doc/docroot/doc/faq.html b/org.jacoco.doc/docroot/doc/faq.html index 0e910fb0..15be0a8b 100644 --- a/org.jacoco.doc/docroot/doc/faq.html +++ b/org.jacoco.doc/docroot/doc/faq.html @@ -99,22 +99,22 @@ ids for a detailed discussion.

        -

        Why are Java interface types not shown in the coverage reports?

        +

        Why are abstract methods not shown in coverage reports?

        - Java interface methods do not contain code, therefore code coverage cannot - be evaluated. Indeed code coverage is recorded for the implementation classes. - The same applies to abstract methods in abstract classes. + Abstract methods do not contain code, therefore code coverage cannot be + evaluated. Indeed code coverage is recorded for subclasses implementing these + methods. The same applies to non-default methods in interfaces.

        Can I collect coverage information without stopping the JVM?

        - Yes, there are two possible ways: The JaCoCo agent + Yes, there are three possible ways: The JaCoCo agent can be configured for remote control via TCP/IP sockets. This allows to collect execution data at any point in time from a running JVM. The - dump Ant task or the - dump Maven goal can be used to - request dumps. The remote control feature also allows you to reset execution - data. + dump Ant task, the + dump Maven goal and the + command line interface can be used to request dumps. + The remote control feature also allows you to reset execution data.

        Alternatively the JaCoCo agent can be configured to @@ -122,6 +122,10 @@ org.jacoco:type=Runtime provides operations to dump and reset execution data at any point in time.

        +

        + In addition JaCoCo provides a Java API + to directly access the runtime within the JVM executing the tests. +

        My code uses reflection. Why does it fail when I execute it with JaCoCo?

        -- cgit v1.2.3 From 40b9c345584948dae0d5b861478527e30b50cd26 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sat, 27 Oct 2018 21:30:16 +0200 Subject: Upgrade ASM to 7.0 for official support of Java 11 --- .travis.sh | 12 ++++-------- .travis.yml | 2 +- org.jacoco.build/pom.xml | 2 +- .../src/org/jacoco/core/internal/ContentTypeDetector.java | 4 ++-- .../src/org/jacoco/core/internal/instr/InstrSupport.java | 2 +- org.jacoco.doc/docroot/doc/changes.html | 8 ++++++++ org.jacoco.doc/docroot/doc/faq.html | 2 +- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/.travis.sh b/.travis.sh index 81fdf16f..dcd9d119 100755 --- a/.travis.sh +++ b/.travis.sh @@ -60,8 +60,8 @@ case "$JDK" in 10) install_jdk $JDK10_URL ;; -11-ea) - install_jdk $JDK11_EA_URL +11) + install_jdk $JDK11_URL ;; 12-ea) install_jdk $JDK12_EA_URL @@ -93,12 +93,8 @@ case "$JDK" in mvn -V -B -e verify -Djdk.version=${JDK} -Dbytecode.version=${JDK} -Decj=${ECJ:-} --toolchains=./.travis/travis-toolchains.xml \ --settings=./.travis/settings.xml ;; -10) - mvn -V -B -e verify -Dbytecode.version=10 \ - --settings=./.travis/settings.xml - ;; -11-ea) - mvn -V -B -e verify -Dbytecode.version=11 \ +10 | 11) + mvn -V -B -e verify -Dbytecode.version=${JDK} \ --settings=./.travis/settings.xml ;; 12-ea) diff --git a/.travis.yml b/.travis.yml index da301639..854f0cff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ env: ECJ=true - JDK=9 - JDK=10 - - JDK=11-ea + - JDK=11 - JDK=12-ea script: ./.travis.sh diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index f765fbfb..bcac8d66 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -138,7 +138,7 @@ ${jvm.args} - 6.2.1 + 7.0 1.7.1 2.0.28 4.8.2 diff --git a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java index 5ef3a9a0..07213656 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java @@ -85,9 +85,9 @@ public class ContentTypeDetector { case Opcodes.V9: case Opcodes.V10: case Opcodes.V11: - case Opcodes.V11 | Opcodes.V_PREVIEW_EXPERIMENTAL: + case Opcodes.V11 | Opcodes.V_PREVIEW: case Opcodes.V12: - case Opcodes.V12 | Opcodes.V_PREVIEW_EXPERIMENTAL: + case Opcodes.V12 | Opcodes.V_PREVIEW: return CLASSFILE; } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java index b1d48f7d..15f7ea1f 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java @@ -25,7 +25,7 @@ public final class InstrSupport { } /** ASM API version */ - public static final int ASM_API_VERSION = Opcodes.ASM7_EXPERIMENTAL; + public static final int ASM_API_VERSION = Opcodes.ASM7; // === Data Field === diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 94184856..bfe6d8c3 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -22,11 +22,19 @@

        New Features

          +
        • JaCoCo now officially supports Java 11 + (GitHub #760).
        • Branch added by the Kotlin compiler for "unsafe" cast operator is filtered out during generation of report (GitHub #761).
        +

        Non-functional Changes

        +
          +
        • JaCoCo now depends on ASM 7.0 + (GitHub #760).
        • +
        +

        Release 0.8.2 (2018/08/21)

        New Features

        diff --git a/org.jacoco.doc/docroot/doc/faq.html b/org.jacoco.doc/docroot/doc/faq.html index 15be0a8b..da5eab0a 100644 --- a/org.jacoco.doc/docroot/doc/faq.html +++ b/org.jacoco.doc/docroot/doc/faq.html @@ -45,7 +45,7 @@

        What Java versions are supported by JaCoCo?

        - JaCoCo supports Java class files from version 1.0 to 10. However the minimum + JaCoCo supports Java class files from version 1.0 to 11. However the minimum JRE version required by the JaCoCo runtime (e.g. the agent) and the JaCoCo tools is 1.5. Also note that class files under test from version 1.6 and above have to contain valid stackmap frames. -- cgit v1.2.3 From 0de0b1abb76affd5645b299d4488e9ef02f77be3 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sun, 4 Nov 2018 02:50:27 +0100 Subject: Add missing license headers to Groovy scripts --- org.jacoco.build/pom.xml | 1 + .../src/test/resources/verify-it.groovy | 13 ++++++++++++- .../src/test/resources/verify-offline.groovy | 13 ++++++++++++- org.jacoco.examples.test/src/test/resources/verify.groovy | 13 ++++++++++++- 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index bcac8d66..7dbb768f 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -556,6 +556,7 @@ + diff --git a/org.jacoco.examples.test/src/test/resources/verify-it.groovy b/org.jacoco.examples.test/src/test/resources/verify-it.groovy index 85ec2055..dc63310d 100644 --- a/org.jacoco.examples.test/src/test/resources/verify-it.groovy +++ b/org.jacoco.examples.test/src/test/resources/verify-it.groovy @@ -1,4 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Mirko Friedenhagen - initial API and implementation + * + *******************************************************************************/ File realBaseDir = new File(basedir, "../../../target/it-it/build"); assert new File(realBaseDir, "target/site/jacoco/index.html").exists(); assert new File(realBaseDir, "target/site/jacoco-it/index.html").exists(); -return true; \ No newline at end of file +return true; diff --git a/org.jacoco.examples.test/src/test/resources/verify-offline.groovy b/org.jacoco.examples.test/src/test/resources/verify-offline.groovy index 247fc4a5..bd1f34bf 100644 --- a/org.jacoco.examples.test/src/test/resources/verify-offline.groovy +++ b/org.jacoco.examples.test/src/test/resources/verify-offline.groovy @@ -1,5 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Mirko Friedenhagen - initial API and implementation + * + *******************************************************************************/ File realBaseDir = new File(basedir, "../../../target/it-offline/build"); assert new File(realBaseDir, "target/site/jacoco/index.html").exists(); assert !new File(realBaseDir, "target/site/jacoco-it/index.html").exists(); assert new File(realBaseDir, "build.log").getText().contains(":restore-instrumented-classes"); -return true; \ No newline at end of file +return true; diff --git a/org.jacoco.examples.test/src/test/resources/verify.groovy b/org.jacoco.examples.test/src/test/resources/verify.groovy index 4fa6fa01..6c4e95a2 100644 --- a/org.jacoco.examples.test/src/test/resources/verify.groovy +++ b/org.jacoco.examples.test/src/test/resources/verify.groovy @@ -1,4 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Mirko Friedenhagen - initial API and implementation + * + *******************************************************************************/ File realBaseDir = new File(basedir, "../../../target/it/build"); assert new File(realBaseDir, "target/site/jacoco/index.html").exists(); assert !new File(realBaseDir, "target/site/jacoco-it/index.html").exists(); -return true; \ No newline at end of file +return true; -- cgit v1.2.3 From 470a132fc8001a8c2f76bfe19dba5bc0366fd665 Mon Sep 17 00:00:00 2001 From: Andres Almiray Date: Wed, 7 Nov 2018 23:45:19 +0100 Subject: Add module with validation tests for Groovy (#733) --- org.jacoco.build/pom.xml | 1 + org.jacoco.core.test.validation.groovy/pom.xml | 74 ++++++++++++++++++++++ .../validation/groovy/GroovyDataClassTest.java | 30 +++++++++ .../groovy/targets/GroovyDataClassTarget.groovy | 30 +++++++++ org.jacoco.core.test.validation/pom.xml | 14 ++++ org.jacoco.doc/docroot/doc/build.html | 6 +- 6 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 org.jacoco.core.test.validation.groovy/pom.xml create mode 100644 org.jacoco.core.test.validation.groovy/src/org/jacoco/core/test/validation/groovy/GroovyDataClassTest.java create mode 100644 org.jacoco.core.test.validation.groovy/src/org/jacoco/core/test/validation/groovy/targets/GroovyDataClassTarget.groovy diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index 7dbb768f..4cb2f480 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -266,6 +266,7 @@ **/*.java **/*.kt + **/*.groovy **/*.properties diff --git a/org.jacoco.core.test.validation.groovy/pom.xml b/org.jacoco.core.test.validation.groovy/pom.xml new file mode 100644 index 00000000..58eec680 --- /dev/null +++ b/org.jacoco.core.test.validation.groovy/pom.xml @@ -0,0 +1,74 @@ + + + + 4.0.0 + + + org.jacoco + org.jacoco.core.test.validation + 0.8.3-SNAPSHOT + ../org.jacoco.core.test.validation + + + org.jacoco.core.test.validation.groovy + + JaCoCo :: Test :: Core :: Validation Groovy + + + 1.6.2 + 2.5.3 + + + + + ${project.groupId} + org.jacoco.core.test + ${project.version} + + + org.codehaus.groovy + groovy + ${groovy.version} + + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + ${gmaven.version} + + + compile + process-sources + + compile + + + + + ${groovy.targetBytecode} + + + ${project.build.sourceDirectory} + + **/*.groovy + + + + + + + + diff --git a/org.jacoco.core.test.validation.groovy/src/org/jacoco/core/test/validation/groovy/GroovyDataClassTest.java b/org.jacoco.core.test.validation.groovy/src/org/jacoco/core/test/validation/groovy/GroovyDataClassTest.java new file mode 100644 index 00000000..10f3d682 --- /dev/null +++ b/org.jacoco.core.test.validation.groovy/src/org/jacoco/core/test/validation/groovy/GroovyDataClassTest.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Andres Almiray - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.groovy; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.groovy.targets.GroovyDataClassTarget; +import org.junit.Test; + +/** + * Test of data classes. + */ +public class GroovyDataClassTest extends ValidationTestBase { + public GroovyDataClassTest() { + super(GroovyDataClassTarget.class); + } + + @Test + public void test_method_count() { + assertMethodCount(1); + } +} diff --git a/org.jacoco.core.test.validation.groovy/src/org/jacoco/core/test/validation/groovy/targets/GroovyDataClassTarget.groovy b/org.jacoco.core.test.validation.groovy/src/org/jacoco/core/test/validation/groovy/targets/GroovyDataClassTarget.groovy new file mode 100644 index 00000000..08044069 --- /dev/null +++ b/org.jacoco.core.test.validation.groovy/src/org/jacoco/core/test/validation/groovy/targets/GroovyDataClassTarget.groovy @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Andres Almiray - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.groovy.targets + +/* This annotation generates the following + * - a constructor that takes an int as argument + * - a suitable implementation of toString() + * - a suitable implementation of hashCode() + * - a suitable implementation of equals(Object) + * - a public method named canEqual(Object) + * - a getter & setter for the valRead property + */ +@groovy.transform.Canonical +class GroovyDataClassTarget { // assertEmpty() + + int valRead // assertEmpty() + + static void main(String[] args) { + new GroovyDataClassTarget() // assertFullyCovered() + } +} diff --git a/org.jacoco.core.test.validation/pom.xml b/org.jacoco.core.test.validation/pom.xml index 37da4a2f..04bd835b 100644 --- a/org.jacoco.core.test.validation/pom.xml +++ b/org.jacoco.core.test.validation/pom.xml @@ -31,6 +31,7 @@ true + ${maven.compiler.target} @@ -88,9 +89,13 @@ 7 + + 1.7 + ../org.jacoco.core.test.validation.kotlin ../org.jacoco.core.test.validation.java7 + ../org.jacoco.core.test.validation.groovy @@ -102,9 +107,13 @@ 7 + + 1.7 + ../org.jacoco.core.test.validation.kotlin ../org.jacoco.core.test.validation.java7 + ../org.jacoco.core.test.validation.groovy @@ -119,11 +128,13 @@ 1.8 + 1.8 ../org.jacoco.core.test.validation.kotlin ../org.jacoco.core.test.validation.java7 ../org.jacoco.core.test.validation.java8 + ../org.jacoco.core.test.validation.groovy @@ -145,6 +156,7 @@ ../org.jacoco.core.test.validation.kotlin ../org.jacoco.core.test.validation.java7 ../org.jacoco.core.test.validation.java8 + ../org.jacoco.core.test.validation.groovy @@ -166,6 +178,7 @@ ../org.jacoco.core.test.validation.kotlin ../org.jacoco.core.test.validation.java7 ../org.jacoco.core.test.validation.java8 + ../org.jacoco.core.test.validation.groovy @@ -187,6 +200,7 @@ ../org.jacoco.core.test.validation.kotlin ../org.jacoco.core.test.validation.java7 ../org.jacoco.core.test.validation.java8 + ../org.jacoco.core.test.validation.groovy diff --git a/org.jacoco.doc/docroot/doc/build.html b/org.jacoco.doc/docroot/doc/build.html index 692101e4..5764a3c9 100644 --- a/org.jacoco.doc/docroot/doc/build.html +++ b/org.jacoco.doc/docroot/doc/build.html @@ -117,7 +117,11 @@ org.jacoco.core.test.validation.java7 excluded from build - compiled into bytecode version 51 (Java 7) + compiled into bytecode version 51 (Java 7) + + + org.jacoco.core.test.validation.groovy + excluded from build org.jacoco.core.test.validation.kotlin -- cgit v1.2.3 From 4d4d02e6dbfb17f454bf4579ee13209e9f035154 Mon Sep 17 00:00:00 2001 From: "Marc R. Hoffmann" Date: Thu, 15 Nov 2018 00:39:53 +0100 Subject: Refactor coverage analysis package (#744) * Encapsulate insn/branch status tracking in Instruction * Move Instruction to the analysis package * Encapsulate Instruction building in new class InstructionsBuilder * Separate coverage calculation from filtering --- .../core/internal/analysis/InstructionTest.java | 173 +++++++++++ .../internal/analysis/InstructionsBuilderTest.java | 189 ++++++++++++ .../core/internal/analysis/MethodAnalyzerTest.java | 13 +- .../analysis/MethodCoverageCalculatorTest.java | 224 +++++++++++++++ .../jacoco/core/internal/flow/InstructionTest.java | 124 -------- .../jacoco/core/internal/flow/LabelInfoTest.java | 6 +- .../core/internal/analysis/ClassAnalyzer.java | 43 ++- .../jacoco/core/internal/analysis/Instruction.java | 207 ++++++++++++++ .../internal/analysis/InstructionsBuilder.java | 186 ++++++++++++ .../core/internal/analysis/MethodAnalyzer.java | 318 +++------------------ .../analysis/MethodCoverageCalculator.java | 178 ++++++++++++ .../org/jacoco/core/internal/flow/Instruction.java | 149 ---------- .../org/jacoco/core/internal/flow/LabelInfo.java | 1 + 13 files changed, 1237 insertions(+), 574 deletions(-) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionTest.java create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionsBuilderTest.java create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageCalculatorTest.java delete mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/flow/InstructionTest.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/Instruction.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/InstructionsBuilder.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageCalculator.java delete mode 100644 org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionTest.java new file mode 100644 index 00000000..ec740e80 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionTest.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.internal.analysis; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Before; +import org.junit.Test; + +/** + * Unit tests for {@link Instruction}. + */ +public class InstructionTest { + + private Instruction instruction; + + @Before + public void setup() { + instruction = new Instruction(123); + } + + @Test + public void getLine_should_return_line_number() { + assertEquals(123, instruction.getLine()); + } + + @Test + public void new_instance_should_have_no_coverage_and_no_branches() { + assertEquals(CounterImpl.COUNTER_1_0, + instruction.getInstructionCounter()); + assertEquals(CounterImpl.COUNTER_0_0, instruction.getBranchCounter()); + } + + @Test + public void addBranchWithInstruction_should_not_increment_branches_when_only_one_branch_is_added() { + instruction.addBranch(new Instruction(122), 0); + + assertEquals(CounterImpl.COUNTER_0_0, instruction.getBranchCounter()); + } + + @Test + public void addBranchWithInstruction_should_increment_branches_when_two_branches_are_added() { + instruction.addBranch(new Instruction(122), 0); + instruction.addBranch(new Instruction(123), 1); + + assertEquals(CounterImpl.getInstance(2, 0), + instruction.getBranchCounter()); + } + + @Test + public void addBranchWithInstruction_should_propagate_existing_coverage_status() { + final Instruction target = new Instruction(122); + target.addBranch(true, 0); + + instruction.addBranch(target, 0); + + assertEquals(CounterImpl.COUNTER_0_1, + instruction.getInstructionCounter()); + } + + @Test + public void addBranchWithProbe_should_increment_branches_when_covered() { + instruction.addBranch(true, 0); + instruction.addBranch(true, 1); + + assertEquals(CounterImpl.getInstance(0, 1), + instruction.getInstructionCounter()); + assertEquals(CounterImpl.getInstance(0, 2), + instruction.getBranchCounter()); + } + + @Test + public void addBranchWithProbe_should_increment_branches_when_not_covered() { + instruction.addBranch(false, 0); + instruction.addBranch(false, 1); + + assertEquals(CounterImpl.getInstance(1, 0), + instruction.getInstructionCounter()); + assertEquals(CounterImpl.getInstance(2, 0), + instruction.getBranchCounter()); + } + + @Test + public void addBranchWithProbe_should_increment_branches_when_partly_covered() { + instruction.addBranch(false, 0); + instruction.addBranch(true, 1); + + assertEquals(CounterImpl.getInstance(0, 1), + instruction.getInstructionCounter()); + assertEquals(CounterImpl.getInstance(1, 1), + instruction.getBranchCounter()); + } + + @Test + public void addBranchWithProbe_should_propagate_coverage_status_to_existing_predecessors() { + final Instruction i1 = new Instruction(124); + final Instruction i2 = new Instruction(125); + instruction.addBranch(i1, 3); + i1.addBranch(i2, 5); + + i2.addBranch(true, 8); + + assertEquals(CounterImpl.COUNTER_0_1, + instruction.getInstructionCounter()); + } + + @Test + public void addBranch_should_count_large_number_of_branches() { + for (int branch = 0; branch < 0x1000; branch++) { + instruction.addBranch(true, branch); + } + + assertEquals(CounterImpl.getInstance(0, 0x1000), + instruction.getBranchCounter()); + } + + @Test + public void addBranch_should_propagate_coverage_status_over_very_long_sequence() { + Instruction next = instruction; + for (int i = 0; i < 0x10000; i++) { + final Instruction insn = new Instruction(i); + next.addBranch(insn, 0); + next = insn; + } + next.addBranch(true, 0); + + assertEquals(CounterImpl.COUNTER_0_1, + instruction.getInstructionCounter()); + } + + @Test + public void merge_should_calculate_superset_of_covered_branches() { + final Instruction i1 = new Instruction(124); + i1.addBranch(false, 1); + i1.addBranch(false, 2); + i1.addBranch(true, 3); + i1.addBranch(true, 4); + final Instruction i2 = new Instruction(124); + i2.addBranch(false, 1); + i2.addBranch(true, 2); + i2.addBranch(false, 3); + i2.addBranch(true, 4); + + instruction = i1.merge(i2); + + assertEquals(CounterImpl.getInstance(1, 3), + instruction.getBranchCounter()); + } + + @Test + public void replaceBranches_should_calculate_coverage_on_new_branches() { + Instruction i1 = new Instruction(1); + Instruction i2 = new Instruction(2); + Instruction i3 = new Instruction(3); + i3.addBranch(true, 0); + + instruction = instruction.replaceBranches(Arrays.asList(i1, i2, i3)); + + assertEquals(CounterImpl.getInstance(2, 1), + instruction.getBranchCounter()); + } +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionsBuilderTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionsBuilderTest.java new file mode 100644 index 00000000..32dea10f --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionsBuilderTest.java @@ -0,0 +1,189 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.internal.analysis; + +import static org.junit.Assert.assertEquals; + +import java.util.Map; + +import org.jacoco.core.analysis.ISourceFileCoverage; +import org.jacoco.core.internal.flow.LabelInfo; +import org.junit.Before; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnNode; + +/** + * Unit tests for {@link InstructionsBuilder}. + */ +public class InstructionsBuilderTest { + + private InstructionsBuilder builder; + + @Before + public void setup() { + builder = new InstructionsBuilder(new boolean[] { false, true }); + } + + @Test + public void current_line_number_should_be_applied_to_instructions() { + InsnNode i1 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i1); + + builder.setCurrentLine(10); + InsnNode i2 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i2); + InsnNode i3 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i3); + + builder.setCurrentLine(20); + InsnNode i4 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i4); + + Map map = builder.getInstructions(); + assertEquals(ISourceFileCoverage.UNKNOWN_LINE, map.get(i1).getLine()); + assertEquals(10, map.get(i2).getLine()); + assertEquals(10, map.get(i3).getLine()); + assertEquals(20, map.get(i4).getLine()); + } + + @Test + public void null_probearray_should_not_mark_instruction_as_covered() { + builder = new InstructionsBuilder(null); + + InsnNode i1 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i1); + builder.addProbe(5, 0); + + Map map = builder.getInstructions(); + assertEquals(CounterImpl.COUNTER_1_0, + map.get(i1).getInstructionCounter()); + } + + @Test + public void unexecuted_probe_should_not_mark_instruction_as_covered() { + InsnNode i1 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i1); + builder.addProbe(0, 0); + + Map map = builder.getInstructions(); + assertEquals(CounterImpl.COUNTER_1_0, + map.get(i1).getInstructionCounter()); + } + + @Test + public void executed_probe_should_mark_instruction_as_covered() { + InsnNode i1 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i1); + builder.addProbe(1, 0); + + Map map = builder.getInstructions(); + assertEquals(CounterImpl.COUNTER_0_1, + map.get(i1).getInstructionCounter()); + } + + @Test + public void subsequent_instructions_should_be_linked_by_default() { + InsnNode i1 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i1); + + InsnNode i2 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i2); + + // mark i2 as covered + builder.addProbe(1, 0); + + // coverage should be propagated to i1 + Map map = builder.getInstructions(); + assertEquals(CounterImpl.COUNTER_0_1, + map.get(i1).getInstructionCounter()); + } + + @Test + public void subsequent_instructions_should_not_be_linked_when_noSuccessor_was_called() { + InsnNode i1 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i1); + builder.noSuccessor(); + + InsnNode i2 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i2); + + // mark i2 as covered + builder.addProbe(1, 0); + + // coverage should not be propagated to i1 + Map map = builder.getInstructions(); + assertEquals(CounterImpl.COUNTER_1_0, + map.get(i1).getInstructionCounter()); + } + + @Test + public void subsequent_instructions_should_be_linked_after_label_marked_as_successor() { + InsnNode i1 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i1); + + Label l = new Label(); + LabelInfo.setSuccessor(l); + builder.addLabel(l); + InsnNode i2 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i2); + + // mark i2 as covered + builder.addProbe(1, 0); + + // coverage should be propagated to i1 + Map map = builder.getInstructions(); + assertEquals(CounterImpl.COUNTER_0_1, + map.get(i1).getInstructionCounter()); + } + + @Test + public void subsequent_instructions_should_not_be_linked_after_label_not_marked_as_successor() { + InsnNode i1 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i1); + + builder.addLabel(new Label()); + InsnNode i2 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i2); + + // mark i2 as covered + builder.addProbe(1, 0); + + // coverage should not be propagated to i1 + Map map = builder.getInstructions(); + assertEquals(CounterImpl.COUNTER_1_0, + map.get(i1).getInstructionCounter()); + } + + @Test + public void jumps_should_propagate_coverage_status() { + InsnNode i1 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i1); + Label l2 = new Label(); + builder.addJump(l2, 0); + + builder.addLabel(l2); + InsnNode i2 = new InsnNode(Opcodes.NOP); + builder.addInstruction(i2); + + // mark i2 as covered + builder.addProbe(1, 0); + + // coverage should be propagated to i1 + Map map = builder.getInstructions(); + assertEquals(CounterImpl.COUNTER_0_1, + map.get(i1).getInstructionCounter()); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java index d0484093..3260ae1e 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java @@ -884,14 +884,21 @@ public class MethodAnalyzerTest implements IProbeIdGenerator { private void runMethodAnalzer(IFilter filter) { LabelFlowAnalyzer.markLabels(method); - final MethodAnalyzer analyzer = new MethodAnalyzer("doit", "()V", null, - probes, filter, new FilterContextMock()); + InstructionsBuilder builder = new InstructionsBuilder(probes); + final MethodAnalyzer analyzer = new MethodAnalyzer(builder); + final MethodProbesAdapter probesAdapter = new MethodProbesAdapter( analyzer, this); // note that CheckMethodAdapter verifies that this test does not violate // contracts of ASM API analyzer.accept(method, new CheckMethodAdapter(probesAdapter)); - result = analyzer.getCoverage(); + + MethodCoverageImpl mc = new MethodCoverageImpl("doit", "V()", null); + MethodCoverageCalculator mcc = new MethodCoverageCalculator( + builder.getInstructions()); + filter.filter(method, new FilterContextMock(), mcc); + mcc.calculate(mc); + result = mc; } private void assertLine(int nr, int insnMissed, int insnCovered, diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageCalculatorTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageCalculatorTest.java new file mode 100644 index 00000000..776dfb60 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageCalculatorTest.java @@ -0,0 +1,224 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.internal.analysis; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import org.jacoco.core.analysis.ISourceFileCoverage; +import org.junit.Before; +import org.junit.Test; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; + +/** + * Unit tests for {@link MethodCoverageCalculator}. + */ +public class MethodCoverageCalculatorTest { + + private Map instructions; + + // The purpose of this list is to link instruction nodes + private InsnList list; + + private MethodCoverageImpl coverage; + + @Before + public void setup() { + instructions = new HashMap(); + coverage = new MethodCoverageImpl("run", "()V", null); + list = new InsnList(); + } + + @Test + public void should_report_instructions() { + addInsn(1, true); + addInsn(2, true); + addInsn(2, false); + addInsn(3, false); + + MethodCoverageCalculator c = new MethodCoverageCalculator(instructions); + c.calculate(coverage); + + assertLine(1, 0, 1, 0, 0); + assertLine(2, 1, 1, 0, 0); + assertLine(3, 1, 0, 0, 0); + } + + @Test + public void should_report_instructions_with_branches() { + addInsn(1, false, false); + addInsn(2, false, false, true); + addInsn(3, false, true, true); + + MethodCoverageCalculator c = new MethodCoverageCalculator(instructions); + c.calculate(coverage); + + assertLine(1, 1, 0, 2, 0); + assertLine(2, 0, 1, 2, 1); + assertLine(3, 0, 1, 1, 2); + } + + @Test + public void should_ignore_single_instruction() { + addInsn(1, true); + InsnNode i1 = addInsn(1, false); + addInsn(2, true); + + MethodCoverageCalculator c = new MethodCoverageCalculator(instructions); + c.ignore(i1, i1); + c.calculate(coverage); + + assertLine(1, 0, 1, 0, 0); // only one instruction not filtered + assertLine(2, 0, 1, 0, 0); + } + + @Test + public void should_ignore_instruction_range() { + addInsn(1, true); + InsnNode i1 = addInsn(2, false); + addInsn(2, false); + addInsn(2, false); + addInsn(2, false); + InsnNode i2 = addInsn(2, false); + addInsn(3, true); + + MethodCoverageCalculator c = new MethodCoverageCalculator(instructions); + c.ignore(i1, i2); + c.calculate(coverage); + + assertLine(1, 0, 1, 0, 0); + assertLine(2, 0, 0, 0, 0); // all instructions filtered in line 2 + assertLine(3, 0, 1, 0, 0); + } + + @Test + public void should_merge_instructions() { + addInsn(1, true); + InsnNode i1 = addInsn(2, false, true); + InsnNode i2 = addInsn(2, true, false); + addInsn(3, true); + + MethodCoverageCalculator c = new MethodCoverageCalculator(instructions); + c.merge(i1, i2); + c.calculate(coverage); + + assertLine(1, 0, 1, 0, 0); + assertLine(2, 0, 1, 0, 2); // one fully covered instruction left + assertLine(3, 0, 1, 0, 0); + } + + @Test + public void should_merge_multiple_instructions() { + InsnNode i1 = addInsn(1, true, false, false); + InsnNode i2 = addInsn(1, false, true, false); + InsnNode i3 = addInsn(1, false, false, true); + + MethodCoverageCalculator c = new MethodCoverageCalculator(instructions); + c.merge(i1, i2); + c.merge(i2, i3); + c.calculate(coverage); + + assertLine(1, 0, 1, 0, 3); // one fully covered instruction left + } + + @Test + public void should_merge_instructions_redundant() { + addInsn(1, true); + InsnNode i1 = addInsn(2, false, true); + InsnNode i2 = addInsn(2, true, false); + addInsn(3, true); + + MethodCoverageCalculator c = new MethodCoverageCalculator(instructions); + c.merge(i1, i2); + c.merge(i2, i1); + c.calculate(coverage); + + assertLine(1, 0, 1, 0, 0); + assertLine(2, 0, 1, 0, 2); // one fully covered instruction left + assertLine(3, 0, 1, 0, 0); + } + + @Test + public void should_replace_branches() { + InsnNode i1 = addInsn(1); + InsnNode i2 = addInsn(2, true); + InsnNode i3 = addInsn(2, true); + InsnNode i4 = addInsn(2, false); + + MethodCoverageCalculator c = new MethodCoverageCalculator(instructions); + c.replaceBranches(i1, + new HashSet(Arrays.asList(i2, i3, i4))); + c.calculate(coverage); + + assertLine(1, 0, 1, 1, 2); // branches coverage status replaced + assertLine(2, 1, 2, 0, 0); // still in place + } + + @Test + public void should_replace_branches_with_merged_instructions() { + InsnNode i1 = addInsn(1, false, false, false); + InsnNode i2 = addInsn(2, true); + InsnNode i3 = addInsn(2, false); + InsnNode i4 = addInsn(2, false); + + MethodCoverageCalculator c = new MethodCoverageCalculator(instructions); + c.merge(i4, i3); + c.merge(i3, i2); + c.replaceBranches(i1, + new HashSet(Arrays.asList(i2, i3, i4))); + c.calculate(coverage); + + assertLine(1, 0, 1, 0, 3); + } + + @Test + public void should_work_without_lines() { + addInsn(ISourceFileCoverage.UNKNOWN_LINE, false); + addInsn(ISourceFileCoverage.UNKNOWN_LINE, false); + addInsn(ISourceFileCoverage.UNKNOWN_LINE, true); + + MethodCoverageCalculator c = new MethodCoverageCalculator(instructions); + c.calculate(coverage); + + assertEquals(ISourceFileCoverage.UNKNOWN_LINE, coverage.getFirstLine()); + assertEquals(ISourceFileCoverage.UNKNOWN_LINE, coverage.getLastLine()); + assertEquals(CounterImpl.getInstance(2, 1), + coverage.getInstructionCounter()); + } + + private void assertLine(int idx, int mi, int ci, int mb, int cb) { + assertEquals("instructions", CounterImpl.getInstance(mi, ci), + coverage.getLine(idx).getInstructionCounter()); + assertEquals("branches", CounterImpl.getInstance(mb, cb), + coverage.getLine(idx).getBranchCounter()); + } + + private InsnNode addInsn(int line, boolean... branches) { + Instruction i = new Instruction(line); + int idx = 0; + for (boolean covered : branches) { + i.addBranch(covered, idx++); + } + InsnNode node = new InsnNode(Opcodes.NOP); + list.add(node); + instructions.put(node, i); + return node; + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/flow/InstructionTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/flow/InstructionTest.java deleted file mode 100644 index 950827c1..00000000 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/flow/InstructionTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2018 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.core.internal.flow; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; - -import org.junit.Before; -import org.junit.Test; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.InsnNode; - -/** - * Unit tests for {@link Instruction}. - */ -public class InstructionTest { - - private Instruction instruction; - - @Before - public void setup() { - instruction = new Instruction(new InsnNode(Opcodes.NOP), 123); - } - - @Test - public void testInit() { - final InsnNode node = new InsnNode(Opcodes.NOP); - instruction = new Instruction(node, 123); - assertSame(node, instruction.getNode()); - assertEquals(123, instruction.getLine()); - assertEquals(0, instruction.getBranches()); - assertEquals(0, instruction.getCoveredBranches()); - } - - @Test - public void testAddBranch() { - instruction.addBranch(); - assertEquals(1, instruction.getBranches()); - instruction.addBranch(); - assertEquals(2, instruction.getBranches()); - instruction.addBranch(); - assertEquals(3, instruction.getBranches()); - assertEquals(0, instruction.getCoveredBranches()); - } - - @Test - public void testSetPredecessor() { - final Instruction predecessor = new Instruction( - new InsnNode(Opcodes.NOP), 122); - instruction.setPredecessor(predecessor, 0); - assertEquals(1, predecessor.getBranches()); - } - - @Test - public void setCovered_should_mark_branch_in_predecessor() { - final Instruction i = new Instruction(new InsnNode(Opcodes.NOP), 122); - i.setCovered(2); - assertEquals(1, i.getCoveredBranches()); - assertEquals("{2}", i.toString()); - - final Instruction s1 = new Instruction(new InsnNode(Opcodes.NOP), 123); - s1.setPredecessor(i, 1); - s1.setCovered(0); - assertEquals("{0}", s1.toString()); - assertEquals(1, s1.getCoveredBranches()); - assertEquals("{1, 2}", i.toString()); - assertEquals(2, i.getCoveredBranches()); - - final Instruction s2 = new Instruction(new InsnNode(Opcodes.NOP), 124); - s2.setPredecessor(i, 0); - s2.setCovered(1); - assertEquals("{0}", s1.toString()); - assertEquals(1, s2.getCoveredBranches()); - assertEquals("{0, 1, 2}", i.toString()); - assertEquals(3, i.getCoveredBranches()); - } - - @Test - public void should_use_BitSet_to_hold_information_about_branches_of_big_switches() { - for (int branch = 0; branch < 256; branch++) { - instruction.setCovered(branch); - } - assertEquals(256, instruction.getCoveredBranches()); - } - - @Test - public void merge_should_add_covered_branches_from_another_instruction() { - final Instruction i1 = new Instruction(new InsnNode(Opcodes.NOP), 123); - i1.setCovered(0); - final Instruction i2 = new Instruction(new InsnNode(Opcodes.NOP), 123); - i2.setCovered(1); - i1.merge(i2); - assertEquals("{0, 1}", i1.toString()); - assertEquals(2, i1.getCoveredBranches()); - assertEquals("{1}", i2.toString()); - } - - @Test - public void testSetCoveredOnLongSequence() { - final Instruction first = new Instruction(new InsnNode(Opcodes.NOP), 0); - Instruction next = first; - for (int i = 0; i < 0x10000; i++) { - final Instruction insn = new Instruction(new InsnNode(Opcodes.NOP), - i); - insn.setPredecessor(next, 0); - next = insn; - } - - // The implementation must not cause an StackOverflowError even on very - // long sequences: - next.setCovered(0); - assertEquals(1, first.getCoveredBranches()); - } - -} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/flow/LabelInfoTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/flow/LabelInfoTest.java index 85007950..1ed75724 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/flow/LabelInfoTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/flow/LabelInfoTest.java @@ -17,11 +17,10 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import org.jacoco.core.internal.analysis.Instruction; import org.junit.Before; import org.junit.Test; import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.InsnNode; /** * Unit tests for {@link LabelInfoTest}. @@ -161,8 +160,7 @@ public class LabelInfoTest { @Test public void testSetInstruction() { - final Instruction instruction = new Instruction( - new InsnNode(Opcodes.NOP), 123); + final Instruction instruction = new Instruction(123); LabelInfo.setInstruction(label, instruction); assertSame(instruction, LabelInfo.getInstruction(label)); } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java index e40b66dc..02bc380a 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java @@ -14,14 +14,16 @@ package org.jacoco.core.internal.analysis; import java.util.HashSet; import java.util.Set; -import org.jacoco.core.analysis.IMethodCoverage; import org.jacoco.core.internal.analysis.filter.Filters; +import org.jacoco.core.internal.analysis.filter.IFilter; import org.jacoco.core.internal.analysis.filter.IFilterContext; import org.jacoco.core.internal.flow.ClassProbesVisitor; import org.jacoco.core.internal.flow.MethodProbesVisitor; import org.jacoco.core.internal.instr.InstrSupport; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.tree.MethodNode; /** * Analyzes the structure of a class. @@ -29,6 +31,8 @@ import org.objectweb.asm.FieldVisitor; public class ClassAnalyzer extends ClassProbesVisitor implements IFilterContext { + private final IFilter filter = Filters.ALL; + private final ClassCoverageImpl coverage; private final boolean[] probes; private final StringPool stringPool; @@ -80,21 +84,38 @@ public class ClassAnalyzer extends ClassProbesVisitor InstrSupport.assertNotInstrumented(name, coverage.getName()); - return new MethodAnalyzer(stringPool.get(name), stringPool.get(desc), - stringPool.get(signature), probes, Filters.ALL, this) { + final InstructionsBuilder builder = new InstructionsBuilder(probes); + + return new MethodAnalyzer(builder) { + @Override - public void visitEnd() { - super.visitEnd(); - final IMethodCoverage methodCoverage = getCoverage(); - if (methodCoverage.getInstructionCounter() - .getTotalCount() > 0) { - // Only consider methods that actually contain code - coverage.addMethod(methodCoverage); - } + public void accept(final MethodNode methodNode, + final MethodVisitor methodVisitor) { + super.accept(methodNode, methodVisitor); + addMethodCoverage(stringPool.get(name), stringPool.get(desc), + stringPool.get(signature), builder, methodNode); } }; } + private void addMethodCoverage(final String name, final String desc, + final String signature, final InstructionsBuilder icc, + final MethodNode methodNode) { + final MethodCoverageCalculator mcc = new MethodCoverageCalculator( + icc.getInstructions()); + filter.filter(methodNode, this, mcc); + + final MethodCoverageImpl mc = new MethodCoverageImpl(name, desc, + signature); + mcc.calculate(mc); + + if (mc.getInstructionCounter().getTotalCount() > 0) { + // Only consider methods that actually contain code + coverage.addMethod(mc); + } + + } + @Override public FieldVisitor visitField(final int access, final String name, final String desc, final String signature, final Object value) { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/Instruction.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/Instruction.java new file mode 100644 index 00000000..ea6eb829 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/Instruction.java @@ -0,0 +1,207 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.internal.analysis; + +import java.util.BitSet; +import java.util.Collection; + +import org.jacoco.core.analysis.ICounter; + +/** + * Execution status of a single bytecode instruction internally used for + * coverage analysis. The execution status is recorded separately for each + * outgoing branch. Each instruction has at least one branch, for example in + * case of a simple sequence of instructions (by convention branch 0). Instances + * of this class are used in two steps: + * + *

        Step 1: Building the CFG

        + * + * For each bytecode instruction of a method a {@link Instruction} instance is + * created. In correspondence with the CFG these instances are linked with each + * other with the addBranch() methods. The executions status is + * either directly derived from a probe which has been inserted in the execution + * flow ({@link #addBranch(boolean, int)}) or indirectly propagated along the + * CFG edges ({@link #addBranch(Instruction, int)}). + * + *

        Step 2: Querying the Coverage Status

        + * + * After all instructions have been created and linked each instruction knows + * its execution status and can be queried with: + * + *
          + *
        • {@link #getLine()}
        • + *
        • {@link #getInstructionCounter()}
        • + *
        • {@link #getBranchCounter()}
        • + *
        + * + * For the purpose of filtering instructions can be combined to new + * instructions. Note that these methods create new {@link Instruction} + * instances and do not modify the existing ones. + * + *
          + *
        • {@link #merge(Instruction)}
        • + *
        • {@link #replaceBranches(Collection)}
        • + *
        + */ +public class Instruction { + + private final int line; + + private int branches; + + private final BitSet coveredBranches; + + private Instruction predecessor; + + private int predecessorBranch; + + /** + * New instruction at the given line. + * + * @param line + * source line this instruction belongs to + */ + public Instruction(final int line) { + this.line = line; + this.branches = 0; + this.coveredBranches = new BitSet(); + } + + /** + * Adds a branch to this instruction which execution status is indirectly + * derived from the execution status of the target instruction. In case the + * branch is covered the status is propagated also to the predecessors of + * this instruction. + * + * Note: This method is not idempotent and must be called exactly once for + * every branch. + * + * @param target + * target instruction of this branch + * @param branch + * branch identifier unique for this instruction + */ + public void addBranch(final Instruction target, final int branch) { + branches++; + target.predecessor = this; + target.predecessorBranch = branch; + if (!target.coveredBranches.isEmpty()) { + propagateExecutedBranch(this, branch); + } + } + + /** + * Adds a branch to this instruction which execution status is directly + * derived from a probe. In case the branch is covered the status is + * propagated also to the predecessors of this instruction. + * + * Note: This method is not idempotent and must be called exactly once for + * every branch. + * + * @param executed + * whether the corresponding probe has been executed + * @param branch + * branch identifier unique for this instruction + */ + public void addBranch(final boolean executed, final int branch) { + branches++; + if (executed) { + propagateExecutedBranch(this, branch); + } + } + + private static void propagateExecutedBranch(Instruction insn, int branch) { + // No recursion here, as there can be very long chains of instructions + while (insn != null) { + if (!insn.coveredBranches.isEmpty()) { + insn.coveredBranches.set(branch); + break; + } + insn.coveredBranches.set(branch); + branch = insn.predecessorBranch; + insn = insn.predecessor; + } + } + + /** + * Returns the source line this instruction belongs to. + * + * @return corresponding source line + */ + public int getLine() { + return line; + } + + /** + * Merges information about covered branches of this instruction with + * another instruction. + * + * @param other + * instruction to merge with + * @return new instance with merged branches + */ + public Instruction merge(final Instruction other) { + final Instruction result = new Instruction(this.line); + result.branches = this.branches; + result.coveredBranches.or(this.coveredBranches); + result.coveredBranches.or(other.coveredBranches); + return result; + } + + /** + * Creates a copy of this instruction where all outgoing branches are + * replaced with the given instructions. The coverage status of the new + * instruction is derived from the status of the given instructions. + * + * @param newBranches + * new branches to consider + * @return new instance with replaced branches + */ + public Instruction replaceBranches( + final Collection newBranches) { + final Instruction result = new Instruction(this.line); + result.branches = newBranches.size(); + int idx = 0; + for (final Instruction b : newBranches) { + if (!b.coveredBranches.isEmpty()) { + result.coveredBranches.set(idx++); + } + } + return result; + } + + /** + * Returns the instruction coverage counter of this instruction. It is + * always 1 instruction which is covered or not. + * + * @return the instruction coverage counter + */ + public ICounter getInstructionCounter() { + return coveredBranches.isEmpty() ? CounterImpl.COUNTER_1_0 + : CounterImpl.COUNTER_0_1; + } + + /** + * Returns the branch coverage counter of this instruction. Only + * instructions with at least 2 outgoing edges report branches. + * + * @return the branch coverage counter + */ + public ICounter getBranchCounter() { + if (branches < 2) { + return CounterImpl.COUNTER_0_0; + } + final int covered = coveredBranches.cardinality(); + return CounterImpl.getInstance(branches - covered, covered); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/InstructionsBuilder.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/InstructionsBuilder.java new file mode 100644 index 00000000..41c602ea --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/InstructionsBuilder.java @@ -0,0 +1,186 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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.core.internal.analysis; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.jacoco.core.analysis.ISourceNode; +import org.jacoco.core.internal.flow.LabelInfo; +import org.objectweb.asm.Label; +import org.objectweb.asm.tree.AbstractInsnNode; + +/** + * Stateful builder for the {@link Instruction}s of a method. All instructions + * of a method must be added in their original sequence along with additional + * information like line numbers. Afterwards the instructions can be obtained + * with the getInstructions() method. + */ +class InstructionsBuilder { + + /** Probe array of the class the analyzed method belongs to. */ + private final boolean[] probes; + + /** The line which belong to subsequently added instructions. */ + private int currentLine; + + /** The last instruction which has been added. */ + private Instruction currentInsn; + + /** + * All instructions of a method mapped from the ASM node to the + * corresponding {@link Instruction} instance. + */ + private final Map instructions; + + /** + * The labels which mark the subsequent instructions. + * + * Due to ASM issue #315745 there can be more than one label per instruction + */ + private final List
      +

      Fixed Bugs

      +
        +
      • Report code coverage correctly for Kotlin methods with default arguments + (GitHub #774).
      • +
      +

      Non-functional Changes

      • JaCoCo now depends on ASM 7.0 -- cgit v1.2.3 From 490939ef743d679990fbabc0dba33bb4bb37e302 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 10 Dec 2018 12:31:45 +0100 Subject: Add filter for instructions inlined by Kotlin compiler (#764) --- .../test/validation/kotlin/KotlinInlineTest.java | 26 +++ .../kotlin/targets/KotlinInlineTarget.kt | 36 ++++ .../core/internal/analysis/MethodAnalyzerTest.java | 3 + .../analysis/filter/FilterContextMock.java | 5 + .../analysis/filter/KotlinInlineFilterTest.java | 223 +++++++++++++++++++++ .../core/test/validation/ValidationTestBase.java | 10 + .../core/internal/analysis/ClassAnalyzer.java | 12 +- .../core/internal/analysis/filter/Filters.java | 33 +-- .../core/internal/analysis/filter/IFilter.java | 4 +- .../internal/analysis/filter/IFilterContext.java | 6 + .../analysis/filter/KotlinInlineFilter.java | 135 +++++++++++++ org.jacoco.doc/docroot/doc/changes.html | 3 + 12 files changed, 478 insertions(+), 18 deletions(-) create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinInlineTest.java create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinInlineTarget.kt create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilterTest.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinInlineTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinInlineTest.java new file mode 100644 index 00000000..0134d0d0 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinInlineTest.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.kotlin.targets.KotlinInlineTarget; + +/** + * Test of inline functions. + */ +public class KotlinInlineTest extends ValidationTestBase { + + public KotlinInlineTest() { + super(KotlinInlineTarget.class); + } + +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinInlineTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinInlineTarget.kt new file mode 100644 index 00000000..e1a8c425 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinInlineTarget.kt @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin.targets + +import org.jacoco.core.test.validation.targets.Stubs.nop +import org.jacoco.core.test.validation.targets.Stubs.t + +/** + * Test target for `inline` functions. + */ +object KotlinInlineTarget { + + inline fun inlined() { + nop() // assertNotCovered() + } + + @JvmStatic + fun main(args: Array) { + + inlined() // assertFullyCovered() + + /* Following inlined method for some reasons doesn't appear in SMAP: */ + assert(t()) // assertPartlyCovered(2, 2) + + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java index 65df61fa..873f7f0b 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java @@ -129,6 +129,9 @@ public class MethodAnalyzerTest implements IProbeIdGenerator { probes[0] = true; runMethodAnalzer(NOP_FILTER); + assertEquals(1002, result.getFirstLine()); + assertEquals(1002, result.getLastLine()); + assertLine(1001, 0, 0, 0, 0); assertLine(1002, 0, 1, 0, 0); } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java index 4be4a491..3724139c 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java @@ -23,6 +23,7 @@ public class FilterContextMock implements IFilterContext { public String superClassName = "java/lang/Object"; public Set classAnnotations = new HashSet(); public String sourceFileName = "Foo.java"; + public String sourceDebugExtension; public String getClassName() { return className; @@ -40,4 +41,8 @@ public class FilterContextMock implements IFilterContext { return sourceFileName; } + public String getSourceDebugExtension() { + return sourceDebugExtension; + } + } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilterTest.java new file mode 100644 index 00000000..9445615e --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilterTest.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.MethodNode; + +/** + * Unit tests for {@link KotlinInlineFilter}. + */ +public class KotlinInlineFilterTest extends FilterTestBase { + + private final KotlinInlineFilter filter = new KotlinInlineFilter(); + + private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "callsite", "()V", null, null); + + @Test + public void should_filter() { + context.sourceFileName = "callsite.kt"; + context.sourceDebugExtension = "" // + + "SMAP\n" // + + "callsite.kt\n" // OutputFileName=callsite.kt + + "Kotlin\n" // DefaultStratumId=Kotlin + + "*S Kotlin\n" // StratumID=Kotlin + + "*F\n" // FileSection + + "+ 1 callsite.kt\n" // FileID=1,FileName=callsite.kt + + "CallsiteKt\n" // + + "+ 2 a.kt\n" // FileID=2,FileName=a.kt + + "AKt\n" // + + "+ 3 b.kt\n" // FileID=3,FileName=b.kt + + "BKt\n" // + + "*L\n" // LineSection + + "1#1,8:1\n" // InputStartLine=1,LineFileID=1,RepeatCount=8,OutputStartLine=1 + + "2#2,2:9\n" // InputStartLine=2,LineFileID=2,RepeatCount=2,OutputStartLine=9 + + "2#3,2:11\n" // InputStartLine=2,LineFileID=3,RepeatCount=2,OutputStartLine=11 + + "*E\n"; // EndSection + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + + m.visitLineNumber(2, new Label()); + m.visitInsn(Opcodes.NOP); + + m.visitLineNumber(9, new Label()); + shouldIgnorePrevious(m); + m.visitMethodInsn(Opcodes.INVOKESTATIC, "Stubs", "nop", "()V", false); + shouldIgnorePrevious(m); + m.visitLineNumber(10, new Label()); + shouldIgnorePrevious(m); + m.visitInsn(Opcodes.NOP); + shouldIgnorePrevious(m); + + m.visitLineNumber(3, new Label()); + m.visitInsn(Opcodes.NOP); + + m.visitLineNumber(11, new Label()); + shouldIgnorePrevious(m); + m.visitMethodInsn(Opcodes.INVOKESTATIC, "Stubs", "nop", "()V", false); + shouldIgnorePrevious(m); + m.visitLineNumber(12, new Label()); + shouldIgnorePrevious(m); + m.visitInsn(Opcodes.NOP); + shouldIgnorePrevious(m); + + m.visitLineNumber(4, new Label()); + m.visitInsn(Opcodes.RETURN); + + filter.filter(m, context, output); + + assertIgnored(expectedRanges.toArray(new Range[0])); + + // should not reparse: + context.sourceDebugExtension = ""; + filter.filter(m, context, output); + } + + @Test + public void should_filter_when_in_same_file() { + context.sourceFileName = "callsite.kt"; + context.sourceDebugExtension = "" // + + "SMAP\n" // + + "callsite.kt\n" // OutputFileName=callsite.kt + + "Kotlin\n" // DefaultStratumId=Kotlin + + "*S Kotlin\n" // StratumID=Kotlin + + "*F\n" // FileSection + + "+ 1 callsite.kt\n" // FileID=1,FileName=callsite.kt + + "CallsiteKt\n" // + + "*L\n" // LineSection + + "1#1,33:1\n" // InputStartLine=1,LineFileID=1,RepeatCount=33,OutputStartLine=1 + + "22#1,2:34\n" // InputStartLine=22,LineFileID=1,RepeatCount=2,OutputStartLine=34 + + "*E\n"; // EndSection + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + + m.visitLineNumber(28, new Label()); + m.visitInsn(Opcodes.NOP); + + m.visitLineNumber(34, new Label()); + shouldIgnorePrevious(m); + m.visitMethodInsn(Opcodes.INVOKESTATIC, "Stubs", "nop", "()V", false); + shouldIgnorePrevious(m); + m.visitLineNumber(35, new Label()); + shouldIgnorePrevious(m); + m.visitInsn(Opcodes.NOP); + shouldIgnorePrevious(m); + + m.visitLineNumber(30, new Label()); + m.visitInsn(Opcodes.RETURN); + + filter.filter(m, context, output); + + assertIgnored(expectedRanges.toArray(new Range[0])); + } + + @Test + public void should_not_parse_SourceDebugExtension_attribute_when_no_kotlin_metadata_annotation() { + context.sourceDebugExtension = "SMAP"; + + m.visitLineNumber(1, new Label()); + m.visitInsn(Opcodes.RETURN); + + filter.filter(m, context, output); + + assertIgnored(); + } + + @Test + public void should_not_filter_when_no_SourceDebugExtension_attribute() { + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + + m.visitLineNumber(1, new Label()); + m.visitInsn(Opcodes.RETURN); + + filter.filter(m, context, output); + + assertIgnored(); + } + + @Test + public void should_throw_exception_when_SMAP_incomplete() { + context.sourceDebugExtension = "" // + + "SMAP\n"; + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + + try { + filter.filter(m, context, output); + fail("exception expected"); + } catch (final IllegalStateException e) { + assertEquals("Unexpected SMAP line: null", e.getMessage()); + } + } + + @Test + public void should_throw_exception_when_unexpected_FileInfo() { + context.sourceFileName = "callsite.kt"; + context.sourceDebugExtension = "" // + + "SMAP\n" // + + "callsite.kt\n" // + + "Kotlin\n" // + + "*S Kotlin\n" // + + "*F\n" // + + "xxx"; + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + + try { + filter.filter(m, context, output); + fail("exception expected"); + } catch (final IllegalStateException e) { + assertEquals("Unexpected SMAP line: xxx", e.getMessage()); + } + } + + @Test + public void should_throw_exception_when_unexpected_LineInfo() { + context.sourceFileName = "callsite.kt"; + context.sourceDebugExtension = "" // + + "SMAP\n" // + + "callsite.kt\n" // + + "Kotlin\n" // + + "*S Kotlin\n" // + + "*F\n" // + + "*L\n" // + + "xxx"; + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + + try { + filter.filter(m, context, output); + fail("exception expected"); + } catch (final IllegalStateException e) { + assertEquals("Unexpected SMAP line: xxx", e.getMessage()); + } + } + + private final List expectedRanges = new ArrayList(); + + private void shouldIgnorePrevious(final MethodNode m) { + expectedRanges.add( + new Range(m.instructions.getLast(), m.instructions.getLast())); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java index d8b5e727..4d93c28d 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/ValidationTestBase.java @@ -12,6 +12,7 @@ package org.jacoco.core.test.validation; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.lang.reflect.Method; @@ -113,6 +114,15 @@ public abstract class ValidationTestBase { } } + @Test + public void last_line_in_coverage_data_should_be_less_or_equal_to_number_of_lines_in_source_file() { + assertTrue(String.format( + "Last line in coverage data (%d) should be less or equal to number of lines in source file (%d)", + Integer.valueOf(source.getCoverage().getLastLine()), + Integer.valueOf(source.getLines().size())), + source.getCoverage().getLastLine() <= source.getLines().size()); + } + /* * Predefined assertion methods: */ diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java index 02bc380a..c584cacf 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java @@ -31,14 +31,16 @@ import org.objectweb.asm.tree.MethodNode; public class ClassAnalyzer extends ClassProbesVisitor implements IFilterContext { - private final IFilter filter = Filters.ALL; - private final ClassCoverageImpl coverage; private final boolean[] probes; private final StringPool stringPool; private final Set classAnnotations = new HashSet(); + private String sourceDebugExtension; + + private final IFilter filter; + /** * Creates a new analyzer that builds coverage data for a class. * @@ -54,6 +56,7 @@ public class ClassAnalyzer extends ClassProbesVisitor this.coverage = coverage; this.probes = probes; this.stringPool = stringPool; + this.filter = Filters.all(); } @Override @@ -75,6 +78,7 @@ public class ClassAnalyzer extends ClassProbesVisitor @Override public void visitSource(final String source, final String debug) { coverage.setSourceFileName(stringPool.get(source)); + sourceDebugExtension = debug; } @Override @@ -146,4 +150,8 @@ public class ClassAnalyzer extends ClassProbesVisitor return coverage.getSourceFileName(); } + public String getSourceDebugExtension() { + return sourceDebugExtension; + } + } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index 76b050f4..f7ffa98d 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -23,22 +23,27 @@ public final class Filters implements IFilter { */ public static final IFilter NONE = new Filters(); + private final IFilter[] filters; + /** - * Filter that combines all other filters. + * Creates filter that combines all other filters. + * + * @return filter that combines all other filters */ - public static final IFilter ALL = new Filters(new EnumFilter(), - new SyntheticFilter(), new SynchronizedFilter(), - new TryWithResourcesJavac11Filter(), - new TryWithResourcesJavacFilter(), new TryWithResourcesEcjFilter(), - new FinallyFilter(), new PrivateEmptyNoArgConstructorFilter(), - new StringSwitchJavacFilter(), new StringSwitchEcjFilter(), - new EnumEmptyConstructorFilter(), new AnnotationGeneratedFilter(), - new KotlinGeneratedFilter(), new KotlinLateinitFilter(), - new KotlinWhenFilter(), new KotlinWhenStringFilter(), - new KotlinUnsafeCastOperatorFilter(), - new KotlinDefaultArgumentsFilter()); - - private final IFilter[] filters; + public static IFilter all() { + return new Filters(new EnumFilter(), new SyntheticFilter(), + new SynchronizedFilter(), new TryWithResourcesJavac11Filter(), + new TryWithResourcesJavacFilter(), + new TryWithResourcesEcjFilter(), new FinallyFilter(), + new PrivateEmptyNoArgConstructorFilter(), + new StringSwitchJavacFilter(), new StringSwitchEcjFilter(), + new EnumEmptyConstructorFilter(), + new AnnotationGeneratedFilter(), new KotlinGeneratedFilter(), + new KotlinLateinitFilter(), new KotlinWhenFilter(), + new KotlinWhenStringFilter(), + new KotlinUnsafeCastOperatorFilter(), + new KotlinDefaultArgumentsFilter(), new KotlinInlineFilter()); + } private Filters(final IFilter... filters) { this.filters = filters; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java index 2c64da1e..97f870d7 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java @@ -14,8 +14,8 @@ package org.jacoco.core.internal.analysis.filter; import org.objectweb.asm.tree.MethodNode; /** - * Interface for filter implementations. Instances of filters are reused and so - * must be stateless. + * Interface for filter implementations. Instances of filters are created for + * analysis of each class and so can have per-class state. */ public interface IFilter { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java index 88c46483..0bc37535 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java @@ -39,4 +39,10 @@ public interface IFilterContext { */ String getSourceFileName(); + /** + * @return value of SourceDebugExtension attribute or null if + * not available + */ + String getSourceDebugExtension(); + } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java new file mode 100644 index 00000000..4f52dadc --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LineNumberNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Filters out instructions that were inlined by Kotlin compiler. + */ +public final class KotlinInlineFilter implements IFilter { + + private int firstGeneratedLineNumber = -1; + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + if (context.getSourceDebugExtension() == null) { + return; + } + + if (!KotlinGeneratedFilter.isKotlinClass(context)) { + return; + } + + if (firstGeneratedLineNumber == -1) { + firstGeneratedLineNumber = getFirstGeneratedLineNumber( + context.getSourceFileName(), + context.getSourceDebugExtension()); + } + + int line = 0; + for (AbstractInsnNode i = methodNode.instructions + .getFirst(); i != null; i = i.getNext()) { + if (AbstractInsnNode.LINE == i.getType()) { + line = ((LineNumberNode) i).line; + } + if (line >= firstGeneratedLineNumber) { + output.ignore(i, i); + } + } + } + + private static int getFirstGeneratedLineNumber(final String sourceFileName, + final String smap) { + try { + final BufferedReader br = new BufferedReader( + new StringReader(smap)); + expectLine(br, "SMAP"); + // OutputFileName + expectLine(br, sourceFileName); + // DefaultStratumId + expectLine(br, "Kotlin"); + // StratumSection + expectLine(br, "*S Kotlin"); + // FileSection + expectLine(br, "*F"); + int sourceFileId = -1; + String line; + while (!"*L".equals(line = br.readLine())) { + // AbsoluteFileName + br.readLine(); + + final Matcher m = FILE_INFO_PATTERN.matcher(line); + if (!m.matches()) { + throw new IllegalStateException( + "Unexpected SMAP line: " + line); + } + final String fileName = m.group(2); + if (fileName.equals(sourceFileName)) { + sourceFileId = Integer.parseInt(m.group(1)); + } + } + // LineSection + int min = Integer.MAX_VALUE; + while (!"*E".equals(line = br.readLine())) { + final Matcher m = LINE_INFO_PATTERN.matcher(line); + if (!m.matches()) { + throw new IllegalStateException( + "Unexpected SMAP line: " + line); + } + final int inputStartLine = Integer.parseInt(m.group(1)); + final int lineFileID = Integer + .parseInt(m.group(2).substring(1)); + final int outputStartLine = Integer.parseInt(m.group(4)); + if (sourceFileId == lineFileID + && inputStartLine == outputStartLine) { + continue; + } + min = Math.min(outputStartLine, min); + } + return min; + } catch (final IOException e) { + // Must not happen with StringReader + throw new AssertionError(e); + } + } + + private static void expectLine(final BufferedReader br, + final String expected) throws IOException { + final String line = br.readLine(); + if (!expected.equals(line)) { + throw new IllegalStateException("Unexpected SMAP line: " + line); + } + } + + private static final Pattern LINE_INFO_PATTERN = Pattern.compile("" // + + "([0-9]++)" // InputStartLine + + "(#[0-9]++)?+" // LineFileID + + "(,[0-9]++)?+" // RepeatCount + + ":([0-9]++)" // OutputStartLine + + "(,[0-9]++)?+" // OutputLineIncrement + ); + + private static final Pattern FILE_INFO_PATTERN = Pattern.compile("" // + + "\\+ ([0-9]++)" // FileID + + " (.++)" // FileName + ); + +} diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 48e03ec4..83195c93 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -27,6 +27,9 @@
      • Branch added by the Kotlin compiler for "unsafe" cast operator is filtered out during generation of report (GitHub #761).
      • +
      • Instructions inlined by Kotlin compiler are filtered out during generation + of report + (GitHub #764).

      Fixed Bugs

      -- cgit v1.2.3 From 529be6db01c2cc606bb4b4cdc2088cf0df724961 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 12 Dec 2018 11:01:34 +0100 Subject: Add unit tests for AbstractMatcher (#796) --- .../analysis/filter/AbstractMatcherTest.java | 265 +++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java new file mode 100644 index 00000000..69c520ff --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java @@ -0,0 +1,265 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +/** + * Unit tests for {@link AbstractMatcher}. + */ +public class AbstractMatcherTest { + + private final AbstractMatcher matcher = new AbstractMatcher() { + }; + + private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "method_name", "()V", null, null); + + @Test + public void skipNonOpcodes() { + m.visitFrame(Opcodes.F_FULL, 0, null, 0, null); + final Label label = new Label(); + m.visitLabel(label); + m.visitLineNumber(42, label); + m.visitInsn(Opcodes.NOP); + + // should skip all non opcodes + matcher.cursor = m.instructions.getFirst(); + matcher.skipNonOpcodes(); + assertSame(m.instructions.getLast(), matcher.cursor); + + // should not change cursor when it points on instruction with opcode + matcher.skipNonOpcodes(); + assertSame(m.instructions.getLast(), matcher.cursor); + + // should not do anything when cursor is null + matcher.cursor = null; + matcher.skipNonOpcodes(); + } + + @Test + public void nextIs() { + m.visitInsn(Opcodes.NOP); + m.visitInsn(Opcodes.NOP); + + // should set cursor to null when opcode mismatch + matcher.cursor = m.instructions.getFirst(); + matcher.nextIs(Opcodes.ATHROW); + assertNull(matcher.cursor); + + // should set cursor to next instruction when match + matcher.cursor = m.instructions.getFirst(); + matcher.nextIs(Opcodes.NOP); + assertSame(m.instructions.getLast(), matcher.cursor); + + // should not do anything when cursor is null + matcher.cursor = null; + matcher.nextIs(Opcodes.NOP); + } + + @Test + public void nextIsSwitch() { + // should set cursor to null when opcode mismatch + m.visitInsn(Opcodes.NOP); + m.visitInsn(Opcodes.NOP); + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsSwitch(); + assertNull(matcher.cursor); + + // should set cursor to next instruction when match + m.instructions.clear(); + m.visitInsn(Opcodes.NOP); + m.visitTableSwitchInsn(0, 0, new Label()); + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsSwitch(); + assertSame(m.instructions.getLast(), matcher.cursor); + + // should set cursor to next instruction when match + m.instructions.clear(); + m.visitInsn(Opcodes.NOP); + m.visitLookupSwitchInsn(new Label(), null, new Label[0]); + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsSwitch(); + assertSame(m.instructions.getLast(), matcher.cursor); + + // should not do anything when cursor is null + matcher.cursor = null; + matcher.nextIsSwitch(); + } + + @Test + public void nextIsVar() { + m.visitInsn(Opcodes.NOP); + m.visitVarInsn(Opcodes.ILOAD, 42); + + // should set cursor to null when opcode mismatch + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsVar(Opcodes.ALOAD, "name"); + assertNull(matcher.cursor); + + // should set cursor to next instruction when match + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsVar(Opcodes.ILOAD, "name"); + assertSame(m.instructions.getLast(), matcher.cursor); + + // should set cursor to null when var mismatch + matcher.cursor = m.instructions.getFirst(); + matcher.vars.put("name", new VarInsnNode(Opcodes.ILOAD, 13)); + matcher.nextIsVar(Opcodes.ILOAD, "name"); + assertNull(matcher.cursor); + + // should set cursor to next instruction when match + matcher.cursor = m.instructions.getFirst(); + matcher.vars.put("name", new VarInsnNode(Opcodes.ILOAD, 42)); + matcher.nextIsVar(Opcodes.ILOAD, "name"); + assertSame(m.instructions.getLast(), matcher.cursor); + + // should not do anything when cursor is null + matcher.cursor = null; + matcher.nextIsVar(Opcodes.ILOAD, "name"); + } + + @Test + public void nextIsInvokeStatic() { + m.visitInsn(Opcodes.NOP); + m.visitMethodInsn(Opcodes.INVOKESTATIC, "owner", "name", "()V", false); + + // should set cursor to null when owner mismatch + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsInvokeStatic("another_owner", "name"); + assertNull(matcher.cursor); + + // should set cursor to null when name mismatch + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsInvokeStatic("owner", "another_name"); + assertNull(matcher.cursor); + + // should set cursor to next instruction when match + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsInvokeStatic("owner", "name"); + assertSame(m.instructions.getLast(), matcher.cursor); + + // should not do anything when cursor is null + matcher.cursor = null; + matcher.nextIsInvokeStatic("owner", "name"); + } + + @Test + public void nextIsInvokeVirtual() { + m.visitInsn(Opcodes.NOP); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "owner", "name", "()V", false); + + // should set cursor to null when owner mismatch + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsInvokeVirtual("another_owner", "name"); + assertNull(matcher.cursor); + + // should set cursor to null when name mismatch + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsInvokeVirtual("owner", "another_name"); + assertNull(matcher.cursor); + + // should set cursor to next instruction when match + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsInvokeVirtual("owner", "name"); + assertSame(m.instructions.getLast(), matcher.cursor); + + // should not do anything when cursor is null + matcher.cursor = null; + matcher.nextIsInvokeVirtual("owner", "name"); + } + + @Test + public void nextIsInvokeSuper() { + m.visitInsn(Opcodes.NOP); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, "owner", "not_init", "()V", + false); + + // should set cursor to null when name mismatch + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsInvokeSuper("owner", "()V"); + assertNull(matcher.cursor); + + m.instructions.clear(); + m.visitInsn(Opcodes.NOP); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, "owner", "", "()V", + false); + + // should set cursor to null when owner mismatch + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsInvokeSuper("another_owner", "()V"); + assertNull(matcher.cursor); + + // should set cursor to null when descriptor mismatch + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsInvokeSuper("owner", "(I)V"); + assertNull(matcher.cursor); + + // should set cursor to next instruction when match + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsInvokeSuper("owner", "()V"); + assertSame(m.instructions.getLast(), matcher.cursor); + + // should not do anything when cursor is null + matcher.cursor = null; + matcher.nextIsInvokeSuper("owner", "()V"); + } + + @Test + public void nextIsNew() { + m.visitInsn(Opcodes.NOP); + m.visitTypeInsn(Opcodes.NEW, "descriptor"); + + // should set cursor to null when descriptor mismatch + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsNew("another_descriptor"); + assertNull(matcher.cursor); + + // should set cursor to next instruction when match + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsNew("descriptor"); + assertSame(m.instructions.getLast(), matcher.cursor); + + // should not do anything when cursor is null + matcher.cursor = null; + matcher.nextIsNew("descriptor"); + } + + @Test + public void firstIsALoad0() { + // should set cursor to null when opcode mismatch + m.visitInsn(Opcodes.NOP); + matcher.firstIsALoad0(m); + assertNull(matcher.cursor); + + // should set cursor to null when var mismatch + m.instructions.clear(); + m.visitVarInsn(Opcodes.ALOAD, 1); + matcher.firstIsALoad0(m); + assertNull(matcher.cursor); + + // should set cursor to first instruction when match + m.instructions.clear(); + m.visitVarInsn(Opcodes.ALOAD, 0); + matcher.firstIsALoad0(m); + assertSame(m.instructions.getLast(), matcher.cursor); + } + +} -- cgit v1.2.3 From 9ad5e6ca90822fc0f99fc2c1600d41d38ec69e47 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 14 Dec 2018 17:56:18 +0100 Subject: Fix filtering in case of inlining top level function into class in same file (#798) --- .../test/validation/kotlin/KotlinInlineTest.java | 4 +- .../kotlin/targets/KotlinInlineTarget.kt | 10 +++ .../analysis/filter/KotlinInlineFilterTest.java | 78 +++++++++++++++++++--- .../analysis/filter/KotlinInlineFilter.java | 10 ++- 4 files changed, 87 insertions(+), 15 deletions(-) diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinInlineTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinInlineTest.java index 0134d0d0..5d6fab7e 100644 --- a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinInlineTest.java +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinInlineTest.java @@ -12,7 +12,7 @@ package org.jacoco.core.test.validation.kotlin; import org.jacoco.core.test.validation.ValidationTestBase; -import org.jacoco.core.test.validation.kotlin.targets.KotlinInlineTarget; +import org.jacoco.core.test.validation.kotlin.targets.KotlinInlineTargetKt; /** * Test of inline functions. @@ -20,7 +20,7 @@ import org.jacoco.core.test.validation.kotlin.targets.KotlinInlineTarget; public class KotlinInlineTest extends ValidationTestBase { public KotlinInlineTest() { - super(KotlinInlineTarget.class); + super(KotlinInlineTargetKt.class); } } diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinInlineTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinInlineTarget.kt index e1a8c425..f65045a4 100644 --- a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinInlineTarget.kt +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinInlineTarget.kt @@ -17,6 +17,14 @@ import org.jacoco.core.test.validation.targets.Stubs.t /** * Test target for `inline` functions. */ +fun main(args: Array) { + KotlinInlineTarget.main(args) +} + +inline fun inlined_top_level() { + nop() // assertNotCovered() +} + object KotlinInlineTarget { inline fun inlined() { @@ -26,6 +34,8 @@ object KotlinInlineTarget { @JvmStatic fun main(args: Array) { + inlined_top_level() // assertFullyCovered() + inlined() // assertFullyCovered() /* Following inlined method for some reasons doesn't appear in SMAP: */ diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilterTest.java index 9445615e..e5cc845b 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilterTest.java @@ -92,37 +92,69 @@ public class KotlinInlineFilterTest extends FilterTestBase { filter.filter(m, context, output); } + /** + *
      +	 *     inline fun inlined_top_level() {
      +	 *       Stubs.nop()
      +	 *     }
      +	 *
      +	 *     class Callsite {
      +	 *       fun inlined() {
      +	 *           Stubs.nop()
      +	 *       }
      +	 *
      +	 *       fun callsite {
      +	 *         inlined_top_level()
      +	 *         inlined()
      +	 *       }
      +	 *     }
      +	 * 
      + */ @Test public void should_filter_when_in_same_file() { - context.sourceFileName = "callsite.kt"; + context.sourceFileName = "example.kt"; context.sourceDebugExtension = "" // + "SMAP\n" // - + "callsite.kt\n" // OutputFileName=callsite.kt + + "example.kt\n" // OutputFileName=example.kt + "Kotlin\n" // DefaultStratumId=Kotlin + "*S Kotlin\n" // StratumID=Kotlin + "*F\n" // FileSection - + "+ 1 callsite.kt\n" // FileID=1,FileName=callsite.kt - + "CallsiteKt\n" // + + "+ 1 example.kt\n" // FileID=1,FileName=example.kt + + "Callsite\n" // + + "+ 2 example.kt\n" // FileID=2,FileName=example.kt + + "ExampleKt\n" // + "*L\n" // LineSection - + "1#1,33:1\n" // InputStartLine=1,LineFileID=1,RepeatCount=33,OutputStartLine=1 - + "22#1,2:34\n" // InputStartLine=22,LineFileID=1,RepeatCount=2,OutputStartLine=34 + + "1#1,15:1\n" // InputStartLine=1,LineFileID=1,RepeatCount=10,OutputStartLine=1 + + "7#1,2:18\n" // InputStartLine=7,LineFileID=1,RepeatCount=2,OutputStartLine=18 + + "2#2,2:16\n" // InputStartLine=2,LineFileID=2,RepeatCount=2,OutputStartLine=16 + "*E\n"; // EndSection context.classAnnotations .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); - m.visitLineNumber(28, new Label()); + m.visitLineNumber(11, new Label()); m.visitInsn(Opcodes.NOP); + m.visitLineNumber(16, new Label()); + shouldIgnorePrevious(m); + m.visitMethodInsn(Opcodes.INVOKESTATIC, "Stubs", "nop", "()V", false); + shouldIgnorePrevious(m); + m.visitLineNumber(17, new Label()); + shouldIgnorePrevious(m); + m.visitInsn(Opcodes.NOP); + shouldIgnorePrevious(m); - m.visitLineNumber(34, new Label()); + m.visitLineNumber(12, new Label()); + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitVarInsn(Opcodes.ASTORE, 1); + m.visitLineNumber(18, new Label()); shouldIgnorePrevious(m); m.visitMethodInsn(Opcodes.INVOKESTATIC, "Stubs", "nop", "()V", false); shouldIgnorePrevious(m); - m.visitLineNumber(35, new Label()); + m.visitLineNumber(19, new Label()); shouldIgnorePrevious(m); m.visitInsn(Opcodes.NOP); shouldIgnorePrevious(m); - m.visitLineNumber(30, new Label()); + m.visitLineNumber(13, new Label()); m.visitInsn(Opcodes.RETURN); filter.filter(m, context, output); @@ -191,6 +223,30 @@ public class KotlinInlineFilterTest extends FilterTestBase { } } + @Test + public void should_throw_exception_when_no_SourceFileId_for_SourceFile() { + context.sourceFileName = "example.kt"; + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + context.sourceDebugExtension = "" // + + "SMAP\n" // + + "example.kt\n" // + + "Kotlin\n" // + + "*S Kotlin\n" // + + "*F\n" // + + "+ 1 another.kt\n" // + + "AnotherKt\n" // + + "*L\n" // + + "*E\n"; + + try { + filter.filter(m, context, output); + fail("exception expected"); + } catch (final IllegalStateException e) { + assertEquals("Unexpected SMAP FileSection", e.getMessage()); + } + } + @Test public void should_throw_exception_when_unexpected_LineInfo() { context.sourceFileName = "callsite.kt"; @@ -200,6 +256,8 @@ public class KotlinInlineFilterTest extends FilterTestBase { + "Kotlin\n" // + "*S Kotlin\n" // + "*F\n" // + + "+ 1 callsite.kt\n" // + + "Callsite\n" // + "*L\n" // + "xxx"; context.classAnnotations diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java index 4f52dadc..a809e232 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java @@ -14,6 +14,7 @@ package org.jacoco.core.internal.analysis.filter; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; +import java.util.BitSet; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -70,7 +71,7 @@ public final class KotlinInlineFilter implements IFilter { expectLine(br, "*S Kotlin"); // FileSection expectLine(br, "*F"); - int sourceFileId = -1; + final BitSet sourceFileIds = new BitSet(); String line; while (!"*L".equals(line = br.readLine())) { // AbsoluteFileName @@ -83,9 +84,12 @@ public final class KotlinInlineFilter implements IFilter { } final String fileName = m.group(2); if (fileName.equals(sourceFileName)) { - sourceFileId = Integer.parseInt(m.group(1)); + sourceFileIds.set(Integer.parseInt(m.group(1))); } } + if (sourceFileIds.isEmpty()) { + throw new IllegalStateException("Unexpected SMAP FileSection"); + } // LineSection int min = Integer.MAX_VALUE; while (!"*E".equals(line = br.readLine())) { @@ -98,7 +102,7 @@ public final class KotlinInlineFilter implements IFilter { final int lineFileID = Integer .parseInt(m.group(2).substring(1)); final int outputStartLine = Integer.parseInt(m.group(4)); - if (sourceFileId == lineFileID + if (sourceFileIds.get(lineFileID) && inputStartLine == outputStartLine) { continue; } -- cgit v1.2.3 From d919b8e8c1341c2713094efd539ff4b5a54b3598 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 21 Dec 2018 12:37:39 +0100 Subject: Add filter for Kotlin coroutines (#802) --- org.jacoco.core.test.validation.kotlin/pom.xml | 7 +- .../validation/kotlin/KotlinCoroutineTest.java | 26 ++++ .../kotlin/targets/KotlinCoroutineTarget.kt | 36 ++++++ .../analysis/filter/AbstractMatcherTest.java | 13 +- .../analysis/filter/KotlinCoroutineFilterTest.java | 135 +++++++++++++++++++++ .../internal/analysis/filter/AbstractMatcher.java | 11 +- .../core/internal/analysis/filter/Filters.java | 3 +- .../analysis/filter/KotlinCoroutineFilter.java | 125 +++++++++++++++++++ .../filter/KotlinUnsafeCastOperatorFilter.java | 2 +- .../internal/analysis/filter/KotlinWhenFilter.java | 2 +- org.jacoco.doc/docroot/doc/changes.html | 3 + 11 files changed, 349 insertions(+), 14 deletions(-) create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinCoroutineTest.java create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java diff --git a/org.jacoco.core.test.validation.kotlin/pom.xml b/org.jacoco.core.test.validation.kotlin/pom.xml index a50fe3f2..e461e246 100644 --- a/org.jacoco.core.test.validation.kotlin/pom.xml +++ b/org.jacoco.core.test.validation.kotlin/pom.xml @@ -25,7 +25,7 @@ 6 - 1.2.60 + 1.3.0 @@ -39,6 +39,11 @@ kotlin-stdlib ${kotlin.version} + + org.jetbrains.kotlinx + kotlinx-coroutines-core + 1.0.1 + diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinCoroutineTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinCoroutineTest.java new file mode 100644 index 00000000..65fa8f68 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinCoroutineTest.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.kotlin.targets.KotlinCoroutineTarget; + +/** + * Test of coroutines. + */ +public class KotlinCoroutineTest extends ValidationTestBase { + + public KotlinCoroutineTest() { + super(KotlinCoroutineTarget.class); + } + +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt new file mode 100644 index 00000000..0ef900fe --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin.targets + +import kotlinx.coroutines.runBlocking +import org.jacoco.core.test.validation.targets.Stubs.nop + +/** + * Test target for coroutines. + */ +object KotlinCoroutineTarget { + + suspend fun suspendingFunction() { + } + + @JvmStatic + fun main(args: Array) { + + runBlocking { // assertFullyCovered() + nop() // assertFullyCovered() + suspendingFunction() // assertFullyCovered() + nop() // assertFullyCovered() + } // assertFullyCovered() + + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java index 69c520ff..e89bd419 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java @@ -223,23 +223,28 @@ public class AbstractMatcherTest { } @Test - public void nextIsNew() { + public void nextIsType() { m.visitInsn(Opcodes.NOP); m.visitTypeInsn(Opcodes.NEW, "descriptor"); + // should set cursor to null when opcode mismatch + matcher.cursor = m.instructions.getFirst(); + matcher.nextIsType(Opcodes.CHECKCAST, "descriptor"); + assertNull(matcher.cursor); + // should set cursor to null when descriptor mismatch matcher.cursor = m.instructions.getFirst(); - matcher.nextIsNew("another_descriptor"); + matcher.nextIsType(Opcodes.NEW, "another_descriptor"); assertNull(matcher.cursor); // should set cursor to next instruction when match matcher.cursor = m.instructions.getFirst(); - matcher.nextIsNew("descriptor"); + matcher.nextIsType(Opcodes.NEW, "descriptor"); assertSame(m.instructions.getLast(), matcher.cursor); // should not do anything when cursor is null matcher.cursor = null; - matcher.nextIsNew("descriptor"); + matcher.nextIsType(Opcodes.NEW, "descriptor"); } @Test diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java new file mode 100644 index 00000000..13cdc397 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.MethodNode; + +/** + * Unit test for {@link KotlinCoroutineFilter}. + */ +public class KotlinCoroutineFilterTest extends FilterTestBase { + + private final IFilter filter = new KotlinCoroutineFilter(); + + private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "invokeSuspend", "(Ljava/lang/Object;)Ljava/lang/Object;", null, + null); + + /** + *
      +	 *     runBlocking {
      +	 *         nop()
      +	 *         suspendingFunction()
      +	 *         nop()
      +	 *     }
      +	 * 
      + */ + @Test + public void should_filter() { + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + + m.visitLabel(new Label()); + m.visitMethodInsn(Opcodes.INVOKESTATIC, + "kotlin/coroutines/intrinsics/IntrinsicsKt", + "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;", false); + m.visitVarInsn(Opcodes.ASTORE, 3); + + m.visitVarInsn(Opcodes.ALOAD, 0); + // line of "runBlocking" + m.visitFieldInsn(Opcodes.GETFIELD, "", "label", "I"); + final Label dflt = new Label(); + final Label state0 = new Label(); + final Label state1 = new Label(); + m.visitTableSwitchInsn(0, 1, dflt, state0, state1); + final Range range1 = new Range(); + range1.fromInclusive = m.instructions.getLast(); + + m.visitLabel(state0); + + { + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitInsn(Opcodes.DUP); + m.visitTypeInsn(Opcodes.INSTANCEOF, "kotlin/Result$Failure"); + Label label = new Label(); + m.visitJumpInsn(Opcodes.IFEQ, label); + m.visitTypeInsn(Opcodes.CHECKCAST, "kotlin/Result$Failure"); + m.visitFieldInsn(Opcodes.GETFIELD, "kotlin/Result$Failure", + "exception", "Ljava/lang/Throwable"); + m.visitInsn(Opcodes.ATHROW); + m.visitInsn(Opcodes.POP); + range1.toInclusive = m.instructions.getLast(); + m.visitLabel(label); + } + + // line before "suspendingFunction" + m.visitInsn(Opcodes.NOP); + + // line of "suspendingFunction" + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "", "suspendingFunction", + "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", false); + + m.visitInsn(Opcodes.DUP); + final Range range2 = new Range(); + range2.fromInclusive = m.instructions.getLast(); + m.visitVarInsn(Opcodes.ALOAD, 3); + final Label continuationLabelAfterLoadedResult = new Label(); + m.visitJumpInsn(Opcodes.IF_ACMPNE, continuationLabelAfterLoadedResult); + // line of "runBlocking" + m.visitVarInsn(Opcodes.ALOAD, 3); + m.visitInsn(Opcodes.ARETURN); + + m.visitLabel(state1); + + { + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitInsn(Opcodes.DUP); + m.visitTypeInsn(Opcodes.INSTANCEOF, "kotlin/Result$Failure"); + final Label label = new Label(); + m.visitJumpInsn(Opcodes.IFEQ, label); + m.visitTypeInsn(Opcodes.CHECKCAST, "kotlin/Result$Failure"); + m.visitFieldInsn(Opcodes.GETFIELD, "kotlin/Result$Failure", + "exception", "Ljava/lang/Throwable"); + m.visitInsn(Opcodes.ATHROW); + m.visitInsn(Opcodes.POP); + m.visitLabel(label); + } + m.visitVarInsn(Opcodes.ALOAD, 1); + range2.toInclusive = m.instructions.getLast(); + m.visitLabel(continuationLabelAfterLoadedResult); + + // line after "suspendingFunction" + m.visitInsn(Opcodes.NOP); + m.visitInsn(Opcodes.ARETURN); + + m.visitLabel(dflt); + final Range range0 = new Range(); + range0.fromInclusive = m.instructions.getLast(); + m.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException"); + m.visitInsn(Opcodes.DUP); + m.visitLdcInsn("call to 'resume' before 'invoke' with coroutine"); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, + "java/lang/IllegalStateException", "", + "(Ljava/lang/String;)V", false); + m.visitInsn(Opcodes.ATHROW); + range0.toInclusive = m.instructions.getLast(); + + filter.filter(m, context, output); + + assertIgnored(range0, range1, range2); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java index a4dd6208..2ae1499b 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java @@ -42,16 +42,15 @@ abstract class AbstractMatcher { } /** - * Moves {@link #cursor} to next instruction if it is NEW with - * given operand, otherwise sets it to null. + * Moves {@link #cursor} to next instruction if it is {@link TypeInsnNode} + * with given opcode and operand, otherwise sets it to null. */ - final void nextIsNew(final String desc) { - nextIs(Opcodes.NEW); + final void nextIsType(final int opcode, final String desc) { + nextIs(opcode); if (cursor == null) { return; } - final TypeInsnNode i = (TypeInsnNode) cursor; - if (desc.equals(i.desc)) { + if (((TypeInsnNode) cursor).desc.equals(desc)) { return; } cursor = null; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index f7ffa98d..a1116548 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -42,7 +42,8 @@ public final class Filters implements IFilter { new KotlinLateinitFilter(), new KotlinWhenFilter(), new KotlinWhenStringFilter(), new KotlinUnsafeCastOperatorFilter(), - new KotlinDefaultArgumentsFilter(), new KotlinInlineFilter()); + new KotlinDefaultArgumentsFilter(), new KotlinInlineFilter(), + new KotlinCoroutineFilter()); } private Filters(final IFilter... filters) { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java new file mode 100644 index 00000000..f2ecd340 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import java.util.ArrayList; +import java.util.List; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TableSwitchInsnNode; + +/** + * Filters branches that Kotlin compiler generates for coroutines. + */ +public final class KotlinCoroutineFilter implements IFilter { + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + + if (!KotlinGeneratedFilter.isKotlinClass(context)) { + return; + } + + if (!"invokeSuspend".equals(methodNode.name)) { + return; + } + + new Matcher().match(methodNode, output); + + } + + private static class Matcher extends AbstractMatcher { + private void match(final MethodNode methodNode, + final IFilterOutput output) { + cursor = methodNode.instructions.getFirst(); + nextIsInvokeStatic("kotlin/coroutines/intrinsics/IntrinsicsKt", + "getCOROUTINE_SUSPENDED"); + nextIsVar(Opcodes.ASTORE, "COROUTINE_SUSPENDED"); + nextIsVar(Opcodes.ALOAD, "this"); + nextIs(Opcodes.GETFIELD); + nextIs(Opcodes.TABLESWITCH); + if (cursor == null) { + return; + } + final TableSwitchInsnNode s = (TableSwitchInsnNode) cursor; + final List ignore = new ArrayList( + s.labels.size() * 2); + + nextIs(Opcodes.ALOAD); + nextIs(Opcodes.DUP); + nextIsType(Opcodes.INSTANCEOF, "kotlin/Result$Failure"); + nextIs(Opcodes.IFEQ); + nextIsType(Opcodes.CHECKCAST, "kotlin/Result$Failure"); + nextIs(Opcodes.GETFIELD); + nextIs(Opcodes.ATHROW); + nextIs(Opcodes.POP); + + if (cursor == null) { + return; + } + ignore.add(s); + ignore.add(cursor); + + for (AbstractInsnNode i = methodNode.instructions + .getFirst(); i != null; i = i.getNext()) { + cursor = i; + nextIsVar(Opcodes.ALOAD, "COROUTINE_SUSPENDED"); + nextIs(Opcodes.IF_ACMPNE); + nextIsVar(Opcodes.ALOAD, "COROUTINE_SUSPENDED"); + nextIs(Opcodes.ARETURN); + + nextIs(Opcodes.ALOAD); + nextIs(Opcodes.DUP); + nextIsType(Opcodes.INSTANCEOF, "kotlin/Result$Failure"); + nextIs(Opcodes.IFEQ); + nextIsType(Opcodes.CHECKCAST, "kotlin/Result$Failure"); + nextIs(Opcodes.GETFIELD); + nextIs(Opcodes.ATHROW); + nextIs(Opcodes.POP); + + nextIs(Opcodes.ALOAD); + if (cursor != null) { + ignore.add(i); + ignore.add(cursor); + } + } + + if (ignore.size() != s.labels.size() * 2) { + return; + } + + cursor = s.dflt; + nextIsType(Opcodes.NEW, "java/lang/IllegalStateException"); + nextIs(Opcodes.DUP); + nextIs(Opcodes.LDC); + if (!((LdcInsnNode) cursor).cst.equals( + "call to 'resume' before 'invoke' with coroutine")) { + return; + } + nextIsInvokeSuper("java/lang/IllegalStateException", + "(Ljava/lang/String;)V"); + nextIs(Opcodes.ATHROW); + if (cursor == null) { + return; + } + + output.ignore(s.dflt, cursor); + for (int i = 0; i < ignore.size(); i += 2) { + output.ignore(ignore.get(i), ignore.get(i + 1)); + } + } + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java index b65cac27..ed52aaf8 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java @@ -43,7 +43,7 @@ public final class KotlinUnsafeCastOperatorFilter implements IFilter { } cursor = start; - nextIsNew(KOTLIN_TYPE_CAST_EXCEPTION); + nextIsType(Opcodes.NEW, KOTLIN_TYPE_CAST_EXCEPTION); nextIs(Opcodes.DUP); nextIs(Opcodes.LDC); if (cursor == null) { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java index a39356f9..e9ffe045 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java @@ -50,7 +50,7 @@ public final class KotlinWhenFilter implements IFilter { } cursor = start; - nextIsNew(EXCEPTION); + nextIsType(Opcodes.NEW, EXCEPTION); nextIs(Opcodes.DUP); nextIsInvokeSuper(EXCEPTION, "()V"); nextIs(Opcodes.ATHROW); diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 83195c93..f50ea364 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -30,6 +30,9 @@
    • Instructions inlined by Kotlin compiler are filtered out during generation of report (GitHub #764).
    • +
    • Branches added by the Kotlin compiler for coroutines are filtered out + during generation of report + (GitHub #802).

    Fixed Bugs

    -- cgit v1.2.3 From ccad8eb36a13e9500a20da82cd5535a96c56e369 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sun, 23 Dec 2018 20:51:44 +0100 Subject: Show message in HTML report when source file can't be found (#801) --- org.jacoco.doc/docroot/doc/changes.html | 2 + .../report/internal/html/page/ClassPageTest.java | 71 ++++++++++++++++++++++ .../report/internal/html/page/ClassPage.java | 17 ++++++ 3 files changed, 90 insertions(+) diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index f50ea364..2da42cb5 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -33,6 +33,8 @@
  • Branches added by the Kotlin compiler for coroutines are filtered out during generation of report (GitHub #802).
  • +
  • HTML report shows message when source file can't be found + (GitHub #801).
  • Fixed Bugs

    diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/ClassPageTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/ClassPageTest.java index 5a296f4b..7126f93e 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/ClassPageTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/ClassPageTest.java @@ -18,6 +18,8 @@ import java.io.IOException; import org.jacoco.core.analysis.IClassCoverage; import org.jacoco.core.internal.analysis.ClassCoverageImpl; import org.jacoco.core.internal.analysis.MethodCoverageImpl; +import org.jacoco.report.internal.ReportOutputFolder; +import org.jacoco.report.internal.html.ILinkable; import org.junit.Before; import org.junit.Test; import org.w3c.dom.Document; @@ -47,6 +49,7 @@ public class ClassPageTest extends PageTestBase { page.render(); final Document doc = support.parse(output.getFile("Foo.html")); + assertEquals("", support.findStr(doc, "doc/body/p[1]")); assertEquals("el_method", support.findStr(doc, "/html/body/table[1]/tbody/tr[1]/td[1]/span/@class")); assertEquals("a()", support.findStr(doc, @@ -57,6 +60,74 @@ public class ClassPageTest extends PageTestBase { "/html/body/table[1]/tbody/tr[3]/td[1]/span")); } + @Test + public void should_not_generate_message_when_SourceFileName_not_present() + throws Exception { + page = new ClassPage(node, null, null, rootFolder, context); + page.render(); + + final Document doc = support.parse(output.getFile("Foo.html")); + assertEquals("", support.findStr(doc, "/html/body/p[1]")); + } + + @Test + public void should_generate_message_when_SourceFileName_present_but_no_SourceFilePage() + throws Exception { + node.setSourceFileName("Foo.java"); + + page = new ClassPage(node, null, null, rootFolder, context); + page.render(); + + final Document doc = support.parse(output.getFile("Foo.html")); + assertEquals( + "Source file \"org/jacoco/example/Foo.java\" was not found during generation of report.", + support.findStr(doc, "/html/body/p[1]")); + } + + @Test + public void should_generate_message_with_default_package_when_SourceFileName_present_but_no_SourceFilePage() + throws Exception { + node = new ClassCoverageImpl("Foo", 123, false); + node.addMethod(new MethodCoverageImpl("a", "()V", null)); + node.setSourceFileName("Foo.java"); + + page = new ClassPage(node, null, null, rootFolder, context); + page.render(); + + final Document doc = support.parse(output.getFile("Foo.html")); + assertEquals( + "Source file \"Foo.java\" was not found during generation of report.", + support.findStr(doc, "/html/body/p[1]")); + } + + @Test + public void should_not_generate_message_when_SourceFileName_and_SourceFilePage_present() + throws Exception { + node.setSourceFileName("Foo.java"); + + page = new ClassPage(node, null, new SourceLink(), rootFolder, context); + page.render(); + + final Document doc = support.parse(output.getFile("Foo.html")); + assertEquals("", support.findStr(doc, "/html/body/p[1]")); + } + + private class SourceLink implements ILinkable { + + public String getLink(final ReportOutputFolder base) { + return "Source.java.html"; + } + + public String getLinkLabel() { + return ""; + } + + public String getLinkStyle() { + return null; + } + + } + @Test public void testGetFileName() throws IOException { page = new ClassPage(node, null, null, rootFolder, context); diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/ClassPage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/ClassPage.java index 2fab2c21..2c35a11b 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/ClassPage.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/ClassPage.java @@ -16,6 +16,7 @@ import java.io.IOException; import org.jacoco.core.analysis.IClassCoverage; import org.jacoco.core.analysis.IMethodCoverage; import org.jacoco.report.internal.ReportOutputFolder; +import org.jacoco.report.internal.html.HTMLElement; import org.jacoco.report.internal.html.IHTMLReportContext; import org.jacoco.report.internal.html.ILinkable; @@ -80,4 +81,20 @@ public class ClassPage extends TablePage { getNode().getInterfaceNames()); } + @Override + protected void content(HTMLElement body) throws IOException { + if (getNode().getSourceFileName() != null && sourcePage == null) { + final String sourcePath; + if (getNode().getPackageName().length() != 0) { + sourcePath = getNode().getPackageName() + "/" + getNode().getSourceFileName(); + } else { + sourcePath = getNode().getSourceFileName(); + } + body.p().text("Source file \"" + sourcePath + + "\" was not found during generation of report."); + } + + super.content(body); + } + } -- cgit v1.2.3 From 3b8df21b64ec1e581c620b7a12483d7a6ee1655b Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 26 Dec 2018 07:43:03 +0100 Subject: Update filter for Kotlin coroutines that restore state (#803) --- .../kotlin/targets/KotlinCoroutineTarget.kt | 5 ++- .../analysis/filter/KotlinCoroutineFilterTest.java | 17 ++++--- .../internal/analysis/filter/AbstractMatcher.java | 10 +++++ .../analysis/filter/KotlinCoroutineFilter.java | 52 ++++++++++++++-------- org.jacoco.doc/docroot/doc/changes.html | 3 +- 5 files changed, 59 insertions(+), 28 deletions(-) diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt index 0ef900fe..2b2c2a0f 100644 --- a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt @@ -26,9 +26,10 @@ object KotlinCoroutineTarget { fun main(args: Array) { runBlocking { // assertFullyCovered() - nop() // assertFullyCovered() + val x = 42 + nop(x) // assertFullyCovered() suspendingFunction() // assertFullyCovered() - nop() // assertFullyCovered() + nop(x) // assertFullyCovered() } // assertFullyCovered() } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java index 13cdc397..cc93c377 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java @@ -31,9 +31,10 @@ public class KotlinCoroutineFilterTest extends FilterTestBase { /** *
     	 *     runBlocking {
    -	 *         nop()
    +	 *         val x = 42
    +	 *         nop(x)
     	 *         suspendingFunction()
    -	 *         nop()
    +	 *         nop(x)
     	 *     }
     	 * 
    */ @@ -46,11 +47,11 @@ public class KotlinCoroutineFilterTest extends FilterTestBase { m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/coroutines/intrinsics/IntrinsicsKt", "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;", false); - m.visitVarInsn(Opcodes.ASTORE, 3); + m.visitVarInsn(Opcodes.ASTORE, 4); m.visitVarInsn(Opcodes.ALOAD, 0); // line of "runBlocking" - m.visitFieldInsn(Opcodes.GETFIELD, "", "label", "I"); + m.visitFieldInsn(Opcodes.GETFIELD, "Target", "label", "I"); final Label dflt = new Label(); final Label state0 = new Label(); final Label state1 = new Label(); @@ -85,15 +86,19 @@ public class KotlinCoroutineFilterTest extends FilterTestBase { m.visitInsn(Opcodes.DUP); final Range range2 = new Range(); range2.fromInclusive = m.instructions.getLast(); - m.visitVarInsn(Opcodes.ALOAD, 3); + m.visitVarInsn(Opcodes.ALOAD, 4); final Label continuationLabelAfterLoadedResult = new Label(); m.visitJumpInsn(Opcodes.IF_ACMPNE, continuationLabelAfterLoadedResult); // line of "runBlocking" - m.visitVarInsn(Opcodes.ALOAD, 3); + m.visitVarInsn(Opcodes.ALOAD, 4); m.visitInsn(Opcodes.ARETURN); m.visitLabel(state1); + m.visitVarInsn(Opcodes.ALOAD, 0); + m.visitFieldInsn(Opcodes.GETFIELD, "Target", "I$0", "I"); + m.visitVarInsn(Opcodes.ISTORE, 3); + { m.visitVarInsn(Opcodes.ALOAD, 1); m.visitInsn(Opcodes.DUP); diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java index 2ae1499b..ca7fb9ac 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java @@ -158,11 +158,21 @@ abstract class AbstractMatcher { * {@link AbstractInsnNode#LABEL}, {@link AbstractInsnNode#LINE}. */ final void skipNonOpcodes() { + cursor = skipNonOpcodes(cursor); + } + + /** + * Returns first instruction from given and following it that is not + * {@link AbstractInsnNode#FRAME}, {@link AbstractInsnNode#LABEL}, + * {@link AbstractInsnNode#LINE}. + */ + static AbstractInsnNode skipNonOpcodes(AbstractInsnNode cursor) { while (cursor != null && (cursor.getType() == AbstractInsnNode.FRAME || cursor.getType() == AbstractInsnNode.LABEL || cursor.getType() == AbstractInsnNode.LINE)) { cursor = cursor.getNext(); } + return cursor; } } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java index f2ecd340..f1261b22 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java @@ -16,6 +16,7 @@ import java.util.List; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TableSwitchInsnNode; @@ -72,32 +73,45 @@ public final class KotlinCoroutineFilter implements IFilter { ignore.add(s); ignore.add(cursor); - for (AbstractInsnNode i = methodNode.instructions - .getFirst(); i != null; i = i.getNext()) { + int suspensionPoint = 1; + for (AbstractInsnNode i = cursor; i != null + && suspensionPoint < s.labels.size(); i = i.getNext()) { cursor = i; nextIsVar(Opcodes.ALOAD, "COROUTINE_SUSPENDED"); nextIs(Opcodes.IF_ACMPNE); + if (cursor == null) { + continue; + } + final AbstractInsnNode continuationAfterLoadedResult = skipNonOpcodes( + (((JumpInsnNode) cursor)).label); nextIsVar(Opcodes.ALOAD, "COROUTINE_SUSPENDED"); nextIs(Opcodes.ARETURN); - - nextIs(Opcodes.ALOAD); - nextIs(Opcodes.DUP); - nextIsType(Opcodes.INSTANCEOF, "kotlin/Result$Failure"); - nextIs(Opcodes.IFEQ); - nextIsType(Opcodes.CHECKCAST, "kotlin/Result$Failure"); - nextIs(Opcodes.GETFIELD); - nextIs(Opcodes.ATHROW); - nextIs(Opcodes.POP); - - nextIs(Opcodes.ALOAD); - if (cursor != null) { - ignore.add(i); - ignore.add(cursor); + if (cursor == null + || skipNonOpcodes(cursor.getNext()) != skipNonOpcodes( + s.labels.get(suspensionPoint))) { + continue; } - } - if (ignore.size() != s.labels.size() * 2) { - return; + for (AbstractInsnNode j = i; j != null; j = j.getNext()) { + cursor = j; + nextIs(Opcodes.ALOAD); + nextIs(Opcodes.DUP); + nextIsType(Opcodes.INSTANCEOF, "kotlin/Result$Failure"); + nextIs(Opcodes.IFEQ); + nextIsType(Opcodes.CHECKCAST, "kotlin/Result$Failure"); + nextIs(Opcodes.GETFIELD); + nextIs(Opcodes.ATHROW); + nextIs(Opcodes.POP); + + nextIs(Opcodes.ALOAD); + if (cursor != null && skipNonOpcodes(cursor + .getNext()) == continuationAfterLoadedResult) { + ignore.add(i); + ignore.add(cursor); + suspensionPoint++; + break; + } + } } cursor = s.dflt; diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 2da42cb5..2614497c 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -32,7 +32,8 @@ (GitHub #764).
  • Branches added by the Kotlin compiler for coroutines are filtered out during generation of report - (GitHub #802).
  • + (GitHub #802, + #803).
  • HTML report shows message when source file can't be found (GitHub #801).
  • -- cgit v1.2.3 From f93bf2cbce7253f670bc10aa10f95b7e831f9a53 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Thu, 27 Dec 2018 08:02:38 +0100 Subject: Reduce duplication of code (#808) --- .../core/internal/analysis/filter/KotlinWhenFilter.java | 13 +------------ .../analysis/filter/KotlinWhenStringFilter.java | 17 +++-------------- .../internal/analysis/filter/StringSwitchEcjFilter.java | 17 +++-------------- 3 files changed, 7 insertions(+), 40 deletions(-) diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java index e9ffe045..dff035cd 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java @@ -93,20 +93,9 @@ public final class KotlinWhenFilter implements IFilter { } final Set newTargets = new HashSet(); for (LabelNode label : labels) { - newTargets.add(instructionAfterLabel(label)); + newTargets.add(AbstractMatcher.skipNonOpcodes(label)); } output.replaceBranches(switchNode, newTargets); } - private static AbstractInsnNode instructionAfterLabel( - final LabelNode label) { - AbstractInsnNode i = label.getNext(); - while (i.getType() == AbstractInsnNode.FRAME - || i.getType() == AbstractInsnNode.LABEL - || i.getType() == AbstractInsnNode.LINE) { - i = i.getNext(); - } - return i; - } - } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java index b8694c24..895ba4e8 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java @@ -67,7 +67,7 @@ public final class KotlinWhenStringFilter implements IFilter { } final Set replacements = new HashSet(); - replacements.add(instructionAfterLabel(defaultLabel)); + replacements.add(skipNonOpcodes(defaultLabel)); for (int i = 0; i < hashCodes; i++) { while (true) { @@ -83,8 +83,8 @@ public final class KotlinWhenStringFilter implements IFilter { return; } - replacements.add(instructionAfterLabel( - ((JumpInsnNode) cursor).label)); + replacements + .add(skipNonOpcodes(((JumpInsnNode) cursor).label)); if (jump.label == defaultLabel) { // end of comparisons for same hashCode @@ -98,15 +98,4 @@ public final class KotlinWhenStringFilter implements IFilter { } } - private static AbstractInsnNode instructionAfterLabel( - final LabelNode label) { - AbstractInsnNode i = label.getNext(); - while (i.getType() == AbstractInsnNode.FRAME - || i.getType() == AbstractInsnNode.LABEL - || i.getType() == AbstractInsnNode.LINE) { - i = i.getNext(); - } - return i; - } - } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java index 6c52d3b9..caa66e72 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java @@ -67,7 +67,7 @@ public final class StringSwitchEcjFilter implements IFilter { } final Set replacements = new HashSet(); - replacements.add(instructionAfterLabel(defaultLabel)); + replacements.add(skipNonOpcodes(defaultLabel)); for (int i = 0; i < hashCodes; i++) { while (true) { @@ -80,8 +80,8 @@ public final class StringSwitchEcjFilter implements IFilter { return; } - replacements.add(instructionAfterLabel( - ((JumpInsnNode) cursor).label)); + replacements + .add(skipNonOpcodes(((JumpInsnNode) cursor).label)); if (cursor.getNext().getOpcode() == Opcodes.GOTO) { // end of comparisons for same hashCode @@ -99,15 +99,4 @@ public final class StringSwitchEcjFilter implements IFilter { } } - private static AbstractInsnNode instructionAfterLabel( - final LabelNode label) { - AbstractInsnNode i = label.getNext(); - while (i.getType() == AbstractInsnNode.FRAME - || i.getType() == AbstractInsnNode.LABEL - || i.getType() == AbstractInsnNode.LINE) { - i = i.getNext(); - } - return i; - } - } -- cgit v1.2.3 From fd90e3ee3404d4996f42fa95eef32c45464592bb Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 28 Dec 2018 00:11:45 +0100 Subject: synthetic methods that represent Kotlin suspend functions should not be ignored (#804) --- .../validation/kotlin/targets/KotlinCoroutineTarget.kt | 3 ++- .../internal/analysis/filter/SyntheticFilterTest.java | 15 +++++++++++++++ .../internal/analysis/filter/KotlinCoroutineFilter.java | 8 ++++++++ .../core/internal/analysis/filter/SyntheticFilter.java | 13 +++++++++---- org.jacoco.doc/docroot/doc/changes.html | 3 +++ 5 files changed, 37 insertions(+), 5 deletions(-) diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt index 2b2c2a0f..07e94bf5 100644 --- a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt @@ -19,7 +19,8 @@ import org.jacoco.core.test.validation.targets.Stubs.nop */ object KotlinCoroutineTarget { - suspend fun suspendingFunction() { + private suspend fun suspendingFunction() { + nop() // assertFullyCovered() } @JvmStatic diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java index 9b70b70a..d0bb2667 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java @@ -82,4 +82,19 @@ public class SyntheticFilterTest extends FilterTestBase { assertMethodIgnored(m); } + @Test + public void should_not_filter_synthetic_methods_whose_last_argument_is_kotlin_coroutine_continuation() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, + Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC, "example", + "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", null, + null); + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + m.visitInsn(Opcodes.NOP); + + filter.filter(m, context, output); + + assertIgnored(); + } + } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java index f1261b22..d9944bf5 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.List; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LdcInsnNode; @@ -26,6 +27,13 @@ import org.objectweb.asm.tree.TableSwitchInsnNode; */ public final class KotlinCoroutineFilter implements IFilter { + static boolean isLastArgumentContinuation(final MethodNode methodNode) { + final Type methodType = Type.getMethodType(methodNode.desc); + final int lastArgument = methodType.getArgumentTypes().length - 1; + return lastArgument >= 0 && "kotlin.coroutines.Continuation".equals( + methodType.getArgumentTypes()[lastArgument].getClassName()); + } + public void filter(final MethodNode methodNode, final IFilterContext context, final IFilterOutput output) { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java index 5dfeecf5..34a66b18 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java @@ -29,10 +29,15 @@ public final class SyntheticFilter implements IFilter { return; } - if (KotlinDefaultArgumentsFilter - .isDefaultArgumentsMethodName(methodNode.name) - && KotlinGeneratedFilter.isKotlinClass(context)) { - return; + if (KotlinGeneratedFilter.isKotlinClass(context)) { + if (KotlinDefaultArgumentsFilter + .isDefaultArgumentsMethodName(methodNode.name)) { + return; + } + + if (KotlinCoroutineFilter.isLastArgumentContinuation(methodNode)) { + return; + } } output.ignore(methodNode.instructions.getFirst(), diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 2614497c..379a6b33 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -42,6 +42,9 @@
    • Report code coverage correctly for Kotlin methods with default arguments (GitHub #774).
    • +
    • synthetic methods that represent Kotlin suspend + functions should not be ignored + (GitHub #804).

    Non-functional Changes

    -- cgit v1.2.3 From 9c45dab3e9d9ed888481005095b30d3e5b55b338 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sun, 30 Dec 2018 09:17:58 +0100 Subject: Update filter for Kotlin suspending functions (#809) --- .../kotlin/targets/KotlinCoroutineTarget.kt | 7 +- .../analysis/filter/KotlinCoroutineFilterTest.java | 164 ++++++++++++++++++++- .../analysis/filter/KotlinCoroutineFilter.java | 65 +++++++- org.jacoco.doc/docroot/doc/changes.html | 7 +- 4 files changed, 227 insertions(+), 16 deletions(-) diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt index 07e94bf5..2ce21621 100644 --- a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt @@ -19,7 +19,12 @@ import org.jacoco.core.test.validation.targets.Stubs.nop */ object KotlinCoroutineTarget { - private suspend fun suspendingFunction() { + private suspend fun suspendingFunction() { // assertEmpty() + anotherSuspendingFunction() // assertFullyCovered() + nop() // assertFullyCovered() + } // assertFullyCovered() + + private suspend fun anotherSuspendingFunction() { nop() // assertFullyCovered() } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java index cc93c377..7405f7c2 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java @@ -24,10 +24,6 @@ public class KotlinCoroutineFilterTest extends FilterTestBase { private final IFilter filter = new KotlinCoroutineFilter(); - private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, - "invokeSuspend", "(Ljava/lang/Object;)Ljava/lang/Object;", null, - null); - /** *
     	 *     runBlocking {
    @@ -39,11 +35,16 @@ public class KotlinCoroutineFilterTest extends FilterTestBase {
     	 * 
    */ @Test - public void should_filter() { + public void should_filter_suspending_lambdas() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "invokeSuspend", "(Ljava/lang/Object;)Ljava/lang/Object;", null, + null); context.classAnnotations .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); m.visitLabel(new Label()); + final Range range1 = new Range(); + range1.fromInclusive = m.instructions.getLast(); m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/coroutines/intrinsics/IntrinsicsKt", "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;", false); @@ -56,8 +57,6 @@ public class KotlinCoroutineFilterTest extends FilterTestBase { final Label state0 = new Label(); final Label state1 = new Label(); m.visitTableSwitchInsn(0, 1, dflt, state0, state1); - final Range range1 = new Range(); - range1.fromInclusive = m.instructions.getLast(); m.visitLabel(state0); @@ -137,4 +136,155 @@ public class KotlinCoroutineFilterTest extends FilterTestBase { assertIgnored(range0, range1, range2); } + /** + *
    +	 *     suspend fun example() {
    +	 *         suspendingFunction()
    +	 *         nop()
    +	 *     }
    +	 * 
    + */ + @Test + public void should_filter_suspending_functions() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, + Opcodes.ACC_STATIC, "example", + "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", null, + null); + context.classAnnotations + .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC); + + final int continuationArgumentIndex = 0; + final int continuationIndex = 2; + + m.visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex); + final Range range1 = new Range(); + range1.fromInclusive = m.instructions.getLast(); + m.visitTypeInsn(Opcodes.INSTANCEOF, "ExampleKt$example$1"); + final Label createStateInstance = new Label(); + m.visitJumpInsn(Opcodes.IFEQ, createStateInstance); + + m.visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex); + m.visitTypeInsn(Opcodes.CHECKCAST, "ExampleKt$example$1"); + m.visitVarInsn(Opcodes.ASTORE, continuationIndex); + + m.visitVarInsn(Opcodes.ALOAD, continuationIndex); + m.visitFieldInsn(Opcodes.GETFIELD, "ExampleKt$example$1", "label", "I"); + + m.visitLdcInsn(Integer.valueOf(Integer.MIN_VALUE)); + m.visitInsn(Opcodes.IAND); + m.visitJumpInsn(Opcodes.IFEQ, createStateInstance); + + m.visitVarInsn(Opcodes.ALOAD, continuationIndex); + m.visitInsn(Opcodes.DUP); + m.visitFieldInsn(Opcodes.GETFIELD, "ExampleKt$example$1", "label", "I"); + + m.visitLdcInsn(Integer.valueOf(Integer.MIN_VALUE)); + m.visitInsn(Opcodes.ISUB); + m.visitFieldInsn(Opcodes.PUTFIELD, "ExampleKt$example$1", "label", "I"); + + final Label afterCoroutineStateCreated = new Label(); + m.visitJumpInsn(Opcodes.GOTO, afterCoroutineStateCreated); + + m.visitLabel(createStateInstance); + + m.visitTypeInsn(Opcodes.NEW, "ExampleKt$example$1"); + m.visitInsn(Opcodes.DUP); + m.visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, "ExampleKt$example$1", + "", "(Lkotlin/coroutines/Continuation;)V", false); + + m.visitVarInsn(Opcodes.ASTORE, continuationIndex); + + m.visitLabel(afterCoroutineStateCreated); + + m.visitVarInsn(Opcodes.ALOAD, continuationIndex); + m.visitFieldInsn(Opcodes.GETFIELD, "ExampleKt$example$1", "result", + "Ljava/lang/Object;"); + m.visitVarInsn(Opcodes.ASTORE, 1); + + m.visitMethodInsn(Opcodes.INVOKESTATIC, + "kotlin/coroutines/intrinsics/IntrinsicsKt", + "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;", false); + + // line of "fun" + m.visitVarInsn(Opcodes.ASTORE, 3); + + m.visitVarInsn(Opcodes.ALOAD, continuationIndex); + m.visitFieldInsn(Opcodes.GETFIELD, "ExampleKt$example$1", "label", "I"); + final Label dflt = new Label(); + final Label state0 = new Label(); + final Label state1 = new Label(); + m.visitTableSwitchInsn(0, 1, dflt, state0, state1); + + m.visitLabel(state0); + + { + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitInsn(Opcodes.DUP); + m.visitTypeInsn(Opcodes.INSTANCEOF, "kotlin/Result$Failure"); + Label label = new Label(); + m.visitJumpInsn(Opcodes.IFEQ, label); + m.visitTypeInsn(Opcodes.CHECKCAST, "kotlin/Result$Failure"); + m.visitFieldInsn(Opcodes.GETFIELD, "kotlin/Result$Failure", + "exception", "Ljava/lang/Throwable"); + m.visitInsn(Opcodes.ATHROW); + m.visitInsn(Opcodes.POP); + range1.toInclusive = m.instructions.getLast(); + m.visitLabel(label); + } + + // line of "suspendingFunction" + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "", "suspendingFunction", + "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", false); + + m.visitInsn(Opcodes.DUP); + final Range range2 = new Range(); + range2.fromInclusive = m.instructions.getLast(); + m.visitVarInsn(Opcodes.ALOAD, 3); + final Label continuationLabelAfterLoadedResult = new Label(); + m.visitJumpInsn(Opcodes.IF_ACMPNE, continuationLabelAfterLoadedResult); + // line of "fun" + m.visitVarInsn(Opcodes.ALOAD, 3); + m.visitInsn(Opcodes.ARETURN); + + m.visitLabel(state1); + + { + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitInsn(Opcodes.DUP); + m.visitTypeInsn(Opcodes.INSTANCEOF, "kotlin/Result$Failure"); + final Label label = new Label(); + m.visitJumpInsn(Opcodes.IFEQ, label); + m.visitTypeInsn(Opcodes.CHECKCAST, "kotlin/Result$Failure"); + m.visitFieldInsn(Opcodes.GETFIELD, "kotlin/Result$Failure", + "exception", "Ljava/lang/Throwable"); + m.visitInsn(Opcodes.ATHROW); + m.visitInsn(Opcodes.POP); + m.visitLabel(label); + } + m.visitVarInsn(Opcodes.ALOAD, 1); + range2.toInclusive = m.instructions.getLast(); + m.visitLabel(continuationLabelAfterLoadedResult); + + // line after "suspendingFunction" + m.visitInsn(Opcodes.NOP); + m.visitInsn(Opcodes.ARETURN); + + m.visitLabel(dflt); + final Range range0 = new Range(); + range0.fromInclusive = m.instructions.getLast(); + m.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException"); + m.visitInsn(Opcodes.DUP); + m.visitLdcInsn("call to 'resume' before 'invoke' with coroutine"); + m.visitMethodInsn(Opcodes.INVOKESPECIAL, + "java/lang/IllegalStateException", "", + "(Ljava/lang/String;)V", false); + m.visitInsn(Opcodes.ATHROW); + range0.toInclusive = m.instructions.getLast(); + + filter.filter(m, context, output); + + assertIgnored(range0, range1, range2); + } + } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java index d9944bf5..51943ef9 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java @@ -41,10 +41,6 @@ public final class KotlinCoroutineFilter implements IFilter { return; } - if (!"invokeSuspend".equals(methodNode.name)) { - return; - } - new Matcher().match(methodNode, output); } @@ -55,6 +51,16 @@ public final class KotlinCoroutineFilter implements IFilter { cursor = methodNode.instructions.getFirst(); nextIsInvokeStatic("kotlin/coroutines/intrinsics/IntrinsicsKt", "getCOROUTINE_SUSPENDED"); + + if (cursor == null) { + cursor = skipNonOpcodes(methodNode.instructions.getFirst()); + + nextIsCreateStateInstance(); + + nextIsInvokeStatic("kotlin/coroutines/intrinsics/IntrinsicsKt", + "getCOROUTINE_SUSPENDED"); + } + nextIsVar(Opcodes.ASTORE, "COROUTINE_SUSPENDED"); nextIsVar(Opcodes.ALOAD, "this"); nextIs(Opcodes.GETFIELD); @@ -78,7 +84,7 @@ public final class KotlinCoroutineFilter implements IFilter { if (cursor == null) { return; } - ignore.add(s); + ignore.add(methodNode.instructions.getFirst()); ignore.add(cursor); int suspensionPoint = 1; @@ -142,6 +148,55 @@ public final class KotlinCoroutineFilter implements IFilter { output.ignore(ignore.get(i), ignore.get(i + 1)); } } + + private void nextIsCreateStateInstance() { + nextIs(Opcodes.INSTANCEOF); + + nextIs(Opcodes.IFEQ); + if (cursor == null) { + return; + } + final AbstractInsnNode createStateInstance = skipNonOpcodes( + ((JumpInsnNode) cursor).label); + + nextIs(Opcodes.ALOAD); + nextIs(Opcodes.CHECKCAST); + nextIs(Opcodes.ASTORE); + + nextIs(Opcodes.ALOAD); + nextIs(Opcodes.GETFIELD); + + nextIs(Opcodes.LDC); + nextIs(Opcodes.IAND); + nextIs(Opcodes.IFEQ); + if (cursor == null || skipNonOpcodes( + ((JumpInsnNode) cursor).label) != createStateInstance) { + return; + } + + nextIs(Opcodes.ALOAD); + nextIs(Opcodes.DUP); + nextIs(Opcodes.GETFIELD); + + nextIs(Opcodes.LDC); + nextIs(Opcodes.ISUB); + nextIs(Opcodes.PUTFIELD); + + nextIs(Opcodes.GOTO); + if (cursor == null) { + return; + } + final AbstractInsnNode afterCoroutineStateCreated = skipNonOpcodes( + ((JumpInsnNode) cursor).label); + + if (skipNonOpcodes(cursor.getNext()) != createStateInstance) { + return; + } + + cursor = afterCoroutineStateCreated; + nextIs(Opcodes.GETFIELD); + nextIs(Opcodes.ASTORE); + } } } diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 379a6b33..59de7915 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -30,10 +30,11 @@
  • Instructions inlined by Kotlin compiler are filtered out during generation of report (GitHub #764).
  • -
  • Branches added by the Kotlin compiler for coroutines are filtered out - during generation of report +
  • Branches added by the Kotlin compiler for suspending lambdas and functions + are filtered out during generation of report (GitHub #802, - #803).
  • + #803, + #809).
  • HTML report shows message when source file can't be found (GitHub #801).
  • -- cgit v1.2.3 From 3718bd939efb0bb0d7b8729b1f05aac65b4333d6 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sun, 6 Jan 2019 05:47:31 +0100 Subject: Fix typo --- .../src/org/jacoco/report/internal/html/page/PackagePageTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/PackagePageTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/PackagePageTest.java index 2a0fd275..e7d1ed7c 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/PackagePageTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/PackagePageTest.java @@ -30,7 +30,7 @@ import org.junit.Test; import org.w3c.dom.Document; /** - * Unit tests for {@link PackageSourcePage}. + * Unit tests for {@link PackagePage}. */ public class PackagePageTest extends PageTestBase { -- cgit v1.2.3 From c7d70c7b0be325e84b9c98203e3e99946ac8bfcd Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Sun, 6 Jan 2019 13:42:49 +0100 Subject: Show messages in HTML report when class has no debug information (#818) --- org.jacoco.doc/docroot/doc/changes.html | 2 ++ .../report/internal/html/page/ClassPageTest.java | 29 +++++++++++++++++++--- .../report/internal/html/page/ClassPage.java | 16 +++++++++--- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 59de7915..36acc8b6 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -37,6 +37,8 @@ #809).
  • HTML report shows message when source file can't be found (GitHub #801).
  • +
  • HTML report shows message when class has no debug information + (GitHub #818).
  • Fixed Bugs

    diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/ClassPageTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/ClassPageTest.java index 7126f93e..b174fb29 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/ClassPageTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/ClassPageTest.java @@ -17,6 +17,7 @@ import java.io.IOException; import org.jacoco.core.analysis.IClassCoverage; import org.jacoco.core.internal.analysis.ClassCoverageImpl; +import org.jacoco.core.internal.analysis.CounterImpl; import org.jacoco.core.internal.analysis.MethodCoverageImpl; import org.jacoco.report.internal.ReportOutputFolder; import org.jacoco.report.internal.html.ILinkable; @@ -37,8 +38,10 @@ public class ClassPageTest extends PageTestBase { @Override public void setup() throws Exception { super.setup(); + final MethodCoverageImpl m = new MethodCoverageImpl("a", "()V", null); + m.increment(CounterImpl.COUNTER_1_0, CounterImpl.COUNTER_0_0, 42); node = new ClassCoverageImpl("org/jacoco/example/Foo", 123, false); - node.addMethod(new MethodCoverageImpl("a", "()V", null)); + node.addMethod(m); node.addMethod(new MethodCoverageImpl("b", "()V", null)); node.addMethod(new MethodCoverageImpl("c", "()V", null)); } @@ -61,13 +64,15 @@ public class ClassPageTest extends PageTestBase { } @Test - public void should_not_generate_message_when_SourceFileName_not_present() + public void should_generate_message_when_SourceFileName_not_present() throws Exception { page = new ClassPage(node, null, null, rootFolder, context); page.render(); final Document doc = support.parse(output.getFile("Foo.html")); - assertEquals("", support.findStr(doc, "/html/body/p[1]")); + assertEquals( + "Class files must be compiled with debug information to link with source files.", + support.findStr(doc, "/html/body/p[1]")); } @Test @@ -87,8 +92,10 @@ public class ClassPageTest extends PageTestBase { @Test public void should_generate_message_with_default_package_when_SourceFileName_present_but_no_SourceFilePage() throws Exception { + final MethodCoverageImpl m = new MethodCoverageImpl("a", "()V", null); + m.increment(CounterImpl.COUNTER_1_0, CounterImpl.COUNTER_0_0, 42); node = new ClassCoverageImpl("Foo", 123, false); - node.addMethod(new MethodCoverageImpl("a", "()V", null)); + node.addMethod(m); node.setSourceFileName("Foo.java"); page = new ClassPage(node, null, null, rootFolder, context); @@ -112,6 +119,20 @@ public class ClassPageTest extends PageTestBase { assertEquals("", support.findStr(doc, "/html/body/p[1]")); } + @Test + public void should_generate_message_when_no_lines() throws Exception { + node = new ClassCoverageImpl("Foo", 123, false); + node.addMethod(new MethodCoverageImpl("m", "()V", null)); + + page = new ClassPage(node, null, new SourceLink(), rootFolder, context); + page.render(); + + final Document doc = support.parse(output.getFile("Foo.html")); + assertEquals( + "Class files must be compiled with debug information to show line coverage.", + support.findStr(doc, "/html/body/p[1]")); + } + private class SourceLink implements ILinkable { public String getLink(final ReportOutputFolder base) { diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/ClassPage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/ClassPage.java index 2c35a11b..f297daa4 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/ClassPage.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/ClassPage.java @@ -83,12 +83,22 @@ public class ClassPage extends TablePage { @Override protected void content(HTMLElement body) throws IOException { - if (getNode().getSourceFileName() != null && sourcePage == null) { + if (getNode().getLineCounter().getTotalCount() == 0) { + body.p().text( + "Class files must be compiled with debug information to show line coverage."); + } + + final String sourceFileName = getNode().getSourceFileName(); + if (sourceFileName == null) { + body.p().text( + "Class files must be compiled with debug information to link with source files."); + + } else if (sourcePage == null) { final String sourcePath; if (getNode().getPackageName().length() != 0) { - sourcePath = getNode().getPackageName() + "/" + getNode().getSourceFileName(); + sourcePath = getNode().getPackageName() + "/" + sourceFileName; } else { - sourcePath = getNode().getSourceFileName(); + sourcePath = sourceFileName; } body.p().text("Source file \"" + sourcePath + "\" was not found during generation of report."); -- cgit v1.2.3 From abb6f9a3f84f58405840866af8319442ad5e8129 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Sun, 6 Jan 2019 15:12:05 +0100 Subject: Show message in HTML report when analyzed class does not match executed (#819) --- org.jacoco.doc/docroot/doc/changes.html | 2 ++ .../jacoco/report/internal/html/page/ClassPageTest.java | 14 ++++++++++++++ .../org/jacoco/report/internal/html/page/ClassPage.java | 5 +++++ 3 files changed, 21 insertions(+) diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 36acc8b6..9b84b4f5 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -39,6 +39,8 @@ (GitHub #801).
  • HTML report shows message when class has no debug information (GitHub #818).
  • +
  • HTML report shows message when analyzed class does not match executed + (GitHub #819).
  • Fixed Bugs

    diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/ClassPageTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/ClassPageTest.java index b174fb29..5d45daaa 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/ClassPageTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/ClassPageTest.java @@ -133,6 +133,20 @@ public class ClassPageTest extends PageTestBase { support.findStr(doc, "/html/body/p[1]")); } + @Test + public void should_generate_message_when_class_id_mismatch() + throws Exception { + node = new ClassCoverageImpl("Foo", 123, true); + node.addMethod(new MethodCoverageImpl("m", "()V", null)); + + page = new ClassPage(node, null, new SourceLink(), rootFolder, context); + page.render(); + + final Document doc = support.parse(output.getFile("Foo.html")); + assertEquals("A different version of class was executed at runtime.", + support.findStr(doc, "/html/body/p[1]")); + } + private class SourceLink implements ILinkable { public String getLink(final ReportOutputFolder base) { diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/ClassPage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/ClassPage.java index f297daa4..10f1f82a 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/ClassPage.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/ClassPage.java @@ -83,6 +83,11 @@ public class ClassPage extends TablePage { @Override protected void content(HTMLElement body) throws IOException { + if (getNode().isNoMatch()) { + body.p().text( + "A different version of class was executed at runtime."); + } + if (getNode().getLineCounter().getTotalCount() == 0) { body.p().text( "Class files must be compiled with debug information to show line coverage."); -- cgit v1.2.3 From 514a27db58feed4c15d9655e733da7ed221c6ea4 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sun, 6 Jan 2019 16:35:53 +0100 Subject: Fix typo IStructureVisitor has been replaced by ICoverageVisitor in version 0.5.0 --- org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java index a44afb78..2b240ecf 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java @@ -95,7 +95,7 @@ public class CoverageBuilder implements ICoverageVisitor { return result; } - // === IStructureVisitor === + // === ICoverageVisitor === public void visitCoverage(final IClassCoverage coverage) { // Only consider classes that actually contain code: -- cgit v1.2.3 From e6414191630a30f6f90ea12c755b54f423c15f0b Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sun, 6 Jan 2019 18:43:45 +0100 Subject: Add validation test for Kotlin safe call operator It can be fully covered without any filters. --- .../kotlin/KotlinSafeCallOperatorTest.java | 26 +++++++++++++++++++ .../kotlin/targets/KotlinSafeCallOperatorTarget.kt | 29 ++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinSafeCallOperatorTest.java create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinSafeCallOperatorTarget.kt diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinSafeCallOperatorTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinSafeCallOperatorTest.java new file mode 100644 index 00000000..e4e45557 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinSafeCallOperatorTest.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.kotlin.targets.KotlinSafeCallOperatorTarget; + +/** + * Test of safe call operator. + */ +public class KotlinSafeCallOperatorTest extends ValidationTestBase { + + public KotlinSafeCallOperatorTest() { + super(KotlinSafeCallOperatorTarget.class); + } + +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinSafeCallOperatorTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinSafeCallOperatorTarget.kt new file mode 100644 index 00000000..c620cac0 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinSafeCallOperatorTarget.kt @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin.targets + +/** + * Test target for safe call operator. + */ +object KotlinSafeCallOperatorTarget { + + private fun example(x: String?): Int? { + return x?.length // assertFullyCovered(0, 2) + } + + @JvmStatic + fun main(args: Array) { + example("") + example(null) + } + +} -- cgit v1.2.3 From 07474471a5274b71ae3a98e54d2aa0cdacd7c612 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sun, 6 Jan 2019 19:05:03 +0100 Subject: Add validation test for Kotlin elvis operator It can be fully covered without any filters. --- .../validation/kotlin/KotlinElvisOperatorTest.java | 26 +++++++++++++++++++ .../kotlin/targets/KotlinElvisOperatorTarget.kt | 29 ++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinElvisOperatorTest.java create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinElvisOperatorTarget.kt diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinElvisOperatorTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinElvisOperatorTest.java new file mode 100644 index 00000000..d1a6ead4 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinElvisOperatorTest.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.kotlin.targets.KotlinElvisOperatorTarget; + +/** + * Test of elvis operator. + */ +public class KotlinElvisOperatorTest extends ValidationTestBase { + + public KotlinElvisOperatorTest() { + super(KotlinElvisOperatorTarget.class); + } + +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinElvisOperatorTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinElvisOperatorTarget.kt new file mode 100644 index 00000000..b088daf7 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinElvisOperatorTarget.kt @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin.targets + +/** + * Test target for elvis operator. + */ +object KotlinElvisOperatorTarget { + + private fun example(x: String?): String { + return x ?: "" // assertFullyCovered(0, 2) + } + + @JvmStatic + fun main(args: Array) { + example("") + example(null) + } + +} -- cgit v1.2.3 From 34afa221fa3102427b04ca44ef827c4ddff2cd0f Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sun, 6 Jan 2019 19:18:50 +0100 Subject: Add validation test for Kotlin "safe" cast operator It can be fully covered without any filters. --- .../test/validation/kotlin/KotlinSafeCastTest.java | 27 ++++++++++++++++++++ .../kotlin/targets/KotlinSafeCastTarget.kt | 29 ++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinSafeCastTest.java create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinSafeCastTarget.kt diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinSafeCastTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinSafeCastTest.java new file mode 100644 index 00000000..0773b777 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinSafeCastTest.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.kotlin.targets.KotlinElvisOperatorTarget; +import org.jacoco.core.test.validation.kotlin.targets.KotlinSafeCastTarget; + +/** + * Test of "safe" cast operator. + */ +public class KotlinSafeCastTest extends ValidationTestBase { + + public KotlinSafeCastTest() { + super(KotlinSafeCastTarget.class); + } + +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinSafeCastTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinSafeCastTarget.kt new file mode 100644 index 00000000..1b0c200d --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinSafeCastTarget.kt @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin.targets + +/** + * Test target for "safe" cast operator. + */ +object KotlinSafeCastTarget { + + private fun example(x: Any?): String? { + return x as? String // assertFullyCovered(0, 2) + } + + @JvmStatic + fun main(args: Array) { + example("") + example(1) + } + +} -- cgit v1.2.3 From 2458e8a4e467a5afc376b56a4e487ac54de0158e Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Tue, 8 Jan 2019 19:56:54 +0100 Subject: Extend filtering by annotation name to ones that simply contain Generated (#822) --- .../analysis/filter/AnnotationGeneratedFilterTest.java | 15 +++++++++++++++ .../analysis/filter/AnnotationGeneratedFilter.java | 9 +++++---- org.jacoco.doc/docroot/doc/changes.html | 4 ++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java index 26070e49..caa894d1 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java @@ -66,6 +66,21 @@ public class AnnotationGeneratedFilterTest extends FilterTestBase { assertMethodIgnored(m); } + @Test + public void should_filter_classes_annotated_with_runtime_visible_org_apache_avro_specific_AvroGenerated() { + final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "readExternal", "()V", null, null); + + m.visitInsn(Opcodes.NOP); + + context.classAnnotations + .add("Lorg/apache/avro/specific/AvroGenerated;"); + + filter.filter(m, context, output); + + assertMethodIgnored(m); + } + @Test public void should_filter_when_annotation_is_inner() { final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java index aae93f69..00492029 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java @@ -20,7 +20,7 @@ import org.objectweb.asm.tree.MethodNode; * Filters classes and methods annotated with * {@link java.lang.annotation.RetentionPolicy#RUNTIME runtime visible} and * {@link java.lang.annotation.RetentionPolicy#CLASS invisible} annotation whose - * simple name is Generated. + * simple name contains Generated. */ public final class AnnotationGeneratedFilter implements IFilter { @@ -44,9 +44,10 @@ public final class AnnotationGeneratedFilter implements IFilter { } private static boolean matches(final String annotation) { - return "Generated;".equals( - annotation.substring(Math.max(annotation.lastIndexOf('/'), - annotation.lastIndexOf('$')) + 1)); + final String name = annotation + .substring(Math.max(annotation.lastIndexOf('/'), + annotation.lastIndexOf('$')) + 1); + return name.contains("Generated"); } private static boolean presentIn(final List annotations) { diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 9b84b4f5..58d87c84 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -35,6 +35,10 @@ (GitHub #802, #803, #809). +
  • Classes and methods annotated with runtime visible and invisible annotation + whose simple name contains "Generated" (previously equality was required) + are filtered out during generation of report + (GitHub #822).
  • HTML report shows message when source file can't be found (GitHub #801).
  • HTML report shows message when class has no debug information -- cgit v1.2.3 From 45efe1ec7a8f182e5d80a89ce306f8958b047140 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Tue, 8 Jan 2019 20:47:27 +0100 Subject: Add filter for Kotlin not-null assertion operator (#815) --- .../kotlin/KotlinNotNullOperatorTest.java | 26 ++++++++++ .../kotlin/targets/KotlinNotNullOperatorTarget.kt | 32 ++++++++++++ .../filter/KotlinNotNullOperatorFilterTest.java | 59 ++++++++++++++++++++++ .../core/internal/analysis/filter/Filters.java | 1 + .../filter/KotlinNotNullOperatorFilter.java | 48 ++++++++++++++++++ org.jacoco.doc/docroot/doc/changes.html | 3 ++ 6 files changed, 169 insertions(+) create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinNotNullOperatorTest.java create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinNotNullOperatorTarget.kt create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilterTest.java create mode 100644 org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinNotNullOperatorTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinNotNullOperatorTest.java new file mode 100644 index 00000000..d2fb7162 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinNotNullOperatorTest.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.kotlin.targets.KotlinNotNullOperatorTarget; + +/** + * Test of not-null assertion operator. + */ +public class KotlinNotNullOperatorTest extends ValidationTestBase { + + public KotlinNotNullOperatorTest() { + super(KotlinNotNullOperatorTarget.class); + } + +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinNotNullOperatorTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinNotNullOperatorTarget.kt new file mode 100644 index 00000000..23681de4 --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinNotNullOperatorTarget.kt @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin.targets + +/** + * Test target for not-null assertion operator. + */ +object KotlinNotNullOperatorTarget { + + private fun example(x: String?): Int { + return x!!.length // assertFullyCovered() + } + + @JvmStatic + fun main(args: Array) { + example("") + try { + example(null) + } catch (e: NullPointerException) { + } + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilterTest.java new file mode 100644 index 00000000..4e40caed --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilterTest.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import org.jacoco.core.internal.instr.InstrSupport; +import org.junit.Test; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.MethodNode; + +/** + * Unit tests for {@link KotlinNotNullOperatorFilter}. + */ +public class KotlinNotNullOperatorFilterTest extends FilterTestBase { + + private final KotlinNotNullOperatorFilter filter = new KotlinNotNullOperatorFilter(); + + private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0, + "example", "()V", null, null); + + /** + *
    +	 *     return x!!.length
    +	 * 
    + */ + @Test + public void should_filter() { + m.visitVarInsn(Opcodes.ALOAD, 1); + m.visitInsn(Opcodes.DUP); + + final Range range = new Range(); + final Label label = new Label(); + m.visitJumpInsn(Opcodes.IFNONNULL, label); + range.fromInclusive = m.instructions.getLast(); + // no line number here and hence no probe + m.visitMethodInsn(Opcodes.INVOKESTATIC, + "kotlin/jvm/internal/Intrinsics", "throwNpe", "()V", false); + range.toInclusive = m.instructions.getLast(); + + m.visitLabel(label); + m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "length", + "()I", false); + m.visitInsn(Opcodes.IRETURN); + + filter.filter(m, context, output); + + assertIgnored(range); + } + +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java index a1116548..2f071942 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java @@ -42,6 +42,7 @@ public final class Filters implements IFilter { new KotlinLateinitFilter(), new KotlinWhenFilter(), new KotlinWhenStringFilter(), new KotlinUnsafeCastOperatorFilter(), + new KotlinNotNullOperatorFilter(), new KotlinDefaultArgumentsFilter(), new KotlinInlineFilter(), new KotlinCoroutineFilter()); } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java new file mode 100644 index 00000000..2a96bfb9 --- /dev/null +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.analysis.filter; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; + +/** + * Filters branch in bytecode that Kotlin compiler generates for not-null + * assertion operator. + */ +public final class KotlinNotNullOperatorFilter implements IFilter { + + public void filter(final MethodNode methodNode, + final IFilterContext context, final IFilterOutput output) { + final Matcher matcher = new Matcher(); + for (AbstractInsnNode i = methodNode.instructions + .getFirst(); i != null; i = i.getNext()) { + matcher.match(i, output); + } + } + + private static class Matcher extends AbstractMatcher { + public void match(final AbstractInsnNode start, + final IFilterOutput output) { + if (Opcodes.IFNONNULL != start.getOpcode()) { + return; + } + cursor = start; + nextIsInvokeStatic("kotlin/jvm/internal/Intrinsics", "throwNpe"); + if (cursor == null) { + return; + } + output.ignore(start, cursor); + } + } + +} diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 58d87c84..cc483851 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -27,6 +27,9 @@
  • Branch added by the Kotlin compiler for "unsafe" cast operator is filtered out during generation of report (GitHub #761).
  • +
  • Branch added by the Kotlin compiler for not-null assertion operator is + filtered out during generation of report + (GitHub #815).
  • Instructions inlined by Kotlin compiler are filtered out during generation of report (GitHub #764).
  • -- cgit v1.2.3 From 234a28d07f62be922df9e56dfde854bd3fb1d8dc Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 9 Jan 2019 11:31:08 +0100 Subject: Replace all remaining uses of Opcodes.ASM6 in tests on Opcodes.ASM7 --- .../src/org/jacoco/cli/internal/commands/InstrumentTest.java | 3 ++- .../org/jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/InstrumentTest.java b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/InstrumentTest.java index 40a3918f..20f61e71 100644 --- a/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/InstrumentTest.java +++ b/org.jacoco.cli.test/src/org/jacoco/cli/internal/commands/InstrumentTest.java @@ -26,6 +26,7 @@ import java.util.HashSet; import java.util.Set; import org.jacoco.cli.internal.CommandTestBase; +import org.jacoco.core.internal.instr.InstrSupport; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -137,7 +138,7 @@ public class InstrumentTest extends CommandTestBase { ClassReader reader = new ClassReader(in); in.close(); final Set fields = new HashSet(); - reader.accept(new ClassVisitor(Opcodes.ASM6) { + reader.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION) { @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java index b83782c9..8f29d19b 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java @@ -296,7 +296,7 @@ public class ProbeArrayStrategyFactoryTest { private final List methods = new ArrayList(); ClassVisitorMock() { - super(Opcodes.ASM6); + super(InstrSupport.ASM_API_VERSION); } @Override @@ -313,7 +313,7 @@ public class ProbeArrayStrategyFactoryTest { String signature, String[] exceptions) { final AddedMethod m = new AddedMethod(access, name, desc); methods.add(m); - return new MethodVisitor(Opcodes.ASM6) { + return new MethodVisitor(InstrSupport.ASM_API_VERSION) { @Override public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { -- cgit v1.2.3 From 0a6bf71575171332d155703ed3a6fc33b279078c Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Wed, 9 Jan 2019 13:24:53 +0100 Subject: Make unit tests realistic (#824) Probe 2 is executed when probe 0 or probe 1 is executed. --- .../src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java index 873f7f0b..287b02a1 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java @@ -325,22 +325,24 @@ public class MethodAnalyzerTest implements IProbeIdGenerator { public void if_branch_merge_should_show_partial_branch_coverage_when_probe_for_first_branch_is_executed() { createIfBranchMerge(); probes[0] = true; + probes[2] = true; runMethodAnalzer(); assertLine(1001, 0, 2, 1, 1); assertLine(1002, 1, 0, 0, 0); - assertLine(1003, 1, 0, 0, 0); + assertLine(1003, 0, 1, 0, 0); } @Test public void if_branch_merge_should_show_partial_branch_coverage_when_probe_for_second_branch_is_executed() { createIfBranchMerge(); probes[1] = true; + probes[2] = true; runMethodAnalzer(); assertLine(1001, 0, 2, 1, 1); assertLine(1002, 0, 1, 0, 0); - assertLine(1003, 1, 0, 0, 0); + assertLine(1003, 0, 1, 0, 0); } @Test -- cgit v1.2.3 From bf8a1161bd9285b0997ea84ede1fa25abc6b71b2 Mon Sep 17 00:00:00 2001 From: Sylwester Lachiewicz Date: Wed, 9 Jan 2019 14:31:39 +0100 Subject: Upgrade maven-plugin-plugin to 3.6.0 and maven-shade-plugin to 3.2.1 (#820) --- org.jacoco.build/pom.xml | 55 ++------------------------------- org.jacoco.core.test.validation/pom.xml | 9 ------ 2 files changed, 2 insertions(+), 62 deletions(-) diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index 4cb2f480..b7529999 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -364,7 +364,7 @@ org.apache.maven.plugins maven-plugin-plugin - 3.5 + 3.6.0 org.apache.maven.plugins @@ -389,7 +389,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.1.0 + 3.2.1 org.apache.maven.plugins @@ -734,57 +734,6 @@ - - - - java10-bytecode - - - bytecode.version - 10 - - - - 9 - 9 - - - - - java11-bytecode - - - bytecode.version - 11 - - - - 9 - 9 - - - - - java12-bytecode - - - bytecode.version - 12 - - - - 9 - 9 - - - ecj diff --git a/org.jacoco.core.test.validation/pom.xml b/org.jacoco.core.test.validation/pom.xml index 04bd835b..650d5870 100644 --- a/org.jacoco.core.test.validation/pom.xml +++ b/org.jacoco.core.test.validation/pom.xml @@ -148,9 +148,6 @@ 1.8 - - 10 - 10 ../org.jacoco.core.test.validation.kotlin @@ -170,9 +167,6 @@ 1.8 - - 11 - 11 ../org.jacoco.core.test.validation.kotlin @@ -192,9 +186,6 @@ 1.8 - - 12 - 12 ../org.jacoco.core.test.validation.kotlin -- cgit v1.2.3 From 77b7667190c9534cea6fd72064b2d70270e53354 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Wed, 9 Jan 2019 22:41:45 +0100 Subject: Get rid of warnings about shading ASM "module-info.class" (#826) --- org.jacoco.agent.rt/pom.xml | 8 ++++++++ org.jacoco.ant/pom.xml | 8 ++++++++ org.jacoco.cli/pom.xml | 6 ++++++ 3 files changed, 22 insertions(+) diff --git a/org.jacoco.agent.rt/pom.xml b/org.jacoco.agent.rt/pom.xml index baf36e62..40f7e72d 100644 --- a/org.jacoco.agent.rt/pom.xml +++ b/org.jacoco.agent.rt/pom.xml @@ -68,6 +68,14 @@ ${jacoco.runtime.package.name}.asm + + + org.ow2.asm:* + + module-info.class + + + diff --git a/org.jacoco.ant/pom.xml b/org.jacoco.ant/pom.xml index 4d3a5849..cf7d4a3f 100644 --- a/org.jacoco.ant/pom.xml +++ b/org.jacoco.ant/pom.xml @@ -67,6 +67,14 @@ org.jacoco.asm + + + org.ow2.asm:* + + module-info.class + + + diff --git a/org.jacoco.cli/pom.xml b/org.jacoco.cli/pom.xml index cb27c8bf..3a759819 100644 --- a/org.jacoco.cli/pom.xml +++ b/org.jacoco.cli/pom.xml @@ -108,6 +108,12 @@ **/Messages_*.properties + + org.ow2.asm:* + + module-info.class + + -- cgit v1.2.3 From db5fefeb4c45b22c67b5a14a7fdf945050a2a6bf Mon Sep 17 00:00:00 2001 From: Sylwester Lachiewicz Date: Thu, 10 Jan 2019 09:44:31 +0100 Subject: Require at least Maven 3.0 for jacoco-maven-plugin (#821) --- jacoco-maven-plugin.test/it/it-check-fails-halt/pom.xml | 6 ++---- jacoco-maven-plugin.test/it/it-check-fails-no-halt/pom.xml | 6 ++---- jacoco-maven-plugin.test/it/it-check-passes/pom.xml | 9 +++------ jacoco-maven-plugin.test/it/it-dump/pom.xml | 6 ++---- jacoco-maven-plugin.test/it/it-java9/pom.xml | 6 ++---- jacoco-maven-plugin/pom.xml | 4 ++-- jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java | 12 +++--------- jacoco-maven-plugin/src/org/jacoco/maven/MergeMojo.java | 5 +---- org.jacoco.doc/docroot/doc/changes.html | 2 ++ org.jacoco.doc/docroot/doc/maven.html | 2 +- org.jacoco.examples/build/pom-it.xml | 6 ++---- org.jacoco.examples/build/pom-offline.xml | 6 ++---- org.jacoco.examples/build/pom.xml | 6 ++---- 13 files changed, 26 insertions(+), 50 deletions(-) diff --git a/jacoco-maven-plugin.test/it/it-check-fails-halt/pom.xml b/jacoco-maven-plugin.test/it/it-check-fails-halt/pom.xml index 176e5ffc..a4183ab8 100644 --- a/jacoco-maven-plugin.test/it/it-check-fails-halt/pom.xml +++ b/jacoco-maven-plugin.test/it/it-check-fails-halt/pom.xml @@ -40,15 +40,13 @@ - - + CLASS Example - - + METHOD MISSEDCOUNT 0 diff --git a/jacoco-maven-plugin.test/it/it-check-fails-no-halt/pom.xml b/jacoco-maven-plugin.test/it/it-check-fails-no-halt/pom.xml index 3cafa0f8..636bf77e 100644 --- a/jacoco-maven-plugin.test/it/it-check-fails-no-halt/pom.xml +++ b/jacoco-maven-plugin.test/it/it-check-fails-no-halt/pom.xml @@ -41,12 +41,10 @@ false - - + BUNDLE - - + METHOD MISSEDCOUNT 0 diff --git a/jacoco-maven-plugin.test/it/it-check-passes/pom.xml b/jacoco-maven-plugin.test/it/it-check-passes/pom.xml index 80195ced..4004a14c 100644 --- a/jacoco-maven-plugin.test/it/it-check-passes/pom.xml +++ b/jacoco-maven-plugin.test/it/it-check-passes/pom.xml @@ -40,18 +40,15 @@ - - + BUNDLE - - + INSTRUCTION COVEREDRATIO 0.90 - - + CLASS MISSEDCOUNT 0 diff --git a/jacoco-maven-plugin.test/it/it-dump/pom.xml b/jacoco-maven-plugin.test/it/it-dump/pom.xml index 8e209914..d4e8403f 100644 --- a/jacoco-maven-plugin.test/it/it-dump/pom.xml +++ b/jacoco-maven-plugin.test/it/it-dump/pom.xml @@ -50,12 +50,10 @@ - - + BUNDLE - - + CLASS COVEREDCOUNT 1 diff --git a/jacoco-maven-plugin.test/it/it-java9/pom.xml b/jacoco-maven-plugin.test/it/it-java9/pom.xml index 77503567..a52a28a4 100644 --- a/jacoco-maven-plugin.test/it/it-java9/pom.xml +++ b/jacoco-maven-plugin.test/it/it-java9/pom.xml @@ -49,11 +49,9 @@ - - + - - + INSTRUCTION COVEREDCOUNT 8 diff --git a/jacoco-maven-plugin/pom.xml b/jacoco-maven-plugin/pom.xml index f3819f0f..f048f402 100644 --- a/jacoco-maven-plugin/pom.xml +++ b/jacoco-maven-plugin/pom.xml @@ -27,7 +27,7 @@ The JaCoCo Maven Plugin provides the JaCoCo runtime agent to your tests and allows basic report creation. - 2.2.1 + 3.0 @@ -54,7 +54,7 @@ org.apache.maven - maven-project + maven-core ${project.prerequisites.maven} diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java index 6b37a6b4..ad021b37 100644 --- a/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java +++ b/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java @@ -64,12 +64,6 @@ public class CheckMojo extends AbstractJacocoMojo implements IViolationsOutput { * * *

    - * Note that you must use implementation hints for - * rule and limit when using Maven 2, with Maven 3 you do - * not need to specify the attributes. - *

    - * - *

    * This example requires an overall instruction coverage of 80% and no class * must be missed: *

    @@ -77,15 +71,15 @@ public class CheckMojo extends AbstractJacocoMojo implements IViolationsOutput { *
     	 * {@code
     	 * 
    -	 *   
    +	 *   
     	 *     BUNDLE
     	 *     
    -	 *       
    +	 *       
     	 *         INSTRUCTION
     	 *         COVEREDRATIO
     	 *         0.80
     	 *       
    -	 *       
    +	 *       
     	 *         CLASS
     	 *         MISSEDCOUNT
     	 *         0
    diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/MergeMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/MergeMojo.java
    index 8b882e08..bbac299d 100644
    --- a/jacoco-maven-plugin/src/org/jacoco/maven/MergeMojo.java
    +++ b/jacoco-maven-plugin/src/org/jacoco/maven/MergeMojo.java
    @@ -43,13 +43,10 @@ public class MergeMojo extends AbstractJacocoMojo {
     	/**
     	 * This mojo accepts any number of execution data file sets.
     	 * 
    -	 * Note that you need an implementation hint on fileset
    -	 * with Maven 2 (not needed with Maven 3):
    -	 * 
     	 * 
     	 * 
     	 * <fileSets>
    -	 *   <fileSet implementation="org.apache.maven.shared.model.fileset.FileSet">
    +	 *   <fileSet>
     	 *     <directory>${project.build.directory}</directory>
     	 *     <includes>
     	 *       <include>*.exec</include>
    diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html
    index cc483851..9b535b0f 100644
    --- a/org.jacoco.doc/docroot/doc/changes.html
    +++ b/org.jacoco.doc/docroot/doc/changes.html
    @@ -22,6 +22,8 @@
     
     

    New Features

      +
    • jacoco-maven-plugin now requires at least Maven 3.0 + (GitHub #821).
    • JaCoCo now officially supports Java 11 (GitHub #760).
    • Branch added by the Kotlin compiler for "unsafe" cast operator is filtered diff --git a/org.jacoco.doc/docroot/doc/maven.html b/org.jacoco.doc/docroot/doc/maven.html index 0546c1bc..5284978e 100644 --- a/org.jacoco.doc/docroot/doc/maven.html +++ b/org.jacoco.doc/docroot/doc/maven.html @@ -73,7 +73,7 @@

        -
      • Maven 2.1.0 or higher and
      • +
      • Maven 3.0 or higher and
      • Java 1.5 or higher (for both, the Maven runtime and the test executor).
      diff --git a/org.jacoco.examples/build/pom-it.xml b/org.jacoco.examples/build/pom-it.xml index 91886d8b..3ead2da3 100644 --- a/org.jacoco.examples/build/pom-it.xml +++ b/org.jacoco.examples/build/pom-it.xml @@ -74,12 +74,10 @@ - - + BUNDLE - - + COMPLEXITY COVEREDRATIO 0.60 diff --git a/org.jacoco.examples/build/pom-offline.xml b/org.jacoco.examples/build/pom-offline.xml index 0763f4a4..a972d234 100644 --- a/org.jacoco.examples/build/pom-offline.xml +++ b/org.jacoco.examples/build/pom-offline.xml @@ -75,12 +75,10 @@ - - + BUNDLE - - + COMPLEXITY COVEREDRATIO 0.60 diff --git a/org.jacoco.examples/build/pom.xml b/org.jacoco.examples/build/pom.xml index 26c6033d..fa257c26 100644 --- a/org.jacoco.examples/build/pom.xml +++ b/org.jacoco.examples/build/pom.xml @@ -62,12 +62,10 @@ - - + BUNDLE - - + COMPLEXITY COVEREDRATIO 0.60 -- cgit v1.2.3 From ee1324d7dd35de7781a452932fa4701d2f410c3f Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Thu, 10 Jan 2019 22:06:42 +0100 Subject: Remove misleading parameters of jacoco-maven-plugin goals (#827) --- .../src/org/jacoco/maven/AbstractAgentMojo.java | 30 +++++++++++++----- .../src/org/jacoco/maven/AbstractJacocoMojo.java | 36 ---------------------- .../src/org/jacoco/maven/CheckMojo.java | 17 ++++++++-- .../src/org/jacoco/maven/InstrumentMojo.java | 17 +++++++++- org.jacoco.doc/docroot/doc/changes.html | 5 +++ 5 files changed, 58 insertions(+), 47 deletions(-) diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/AbstractAgentMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/AbstractAgentMojo.java index 1d3f34e6..cc85b7f7 100644 --- a/jacoco-maven-plugin/src/org/jacoco/maven/AbstractAgentMojo.java +++ b/jacoco-maven-plugin/src/org/jacoco/maven/AbstractAgentMojo.java @@ -12,6 +12,7 @@ package org.jacoco.maven; import java.io.File; +import java.util.List; import java.util.Map; import java.util.Properties; @@ -57,6 +58,21 @@ public abstract class AbstractAgentMojo extends AbstractJacocoMojo { */ @Parameter(property = "jacoco.append") Boolean append; + + /** + * A list of class names to include in instrumentation. May use wildcard + * characters (* and ?). When not specified everything will be included. + */ + @Parameter + private List includes; + + /** + * A list of class names to exclude from instrumentation. May use wildcard + * characters (* and ?). When not specified nothing will be excluded. + */ + @Parameter + private List excludes; + /** * A list of class loader names, that should be excluded from execution * analysis. The list entries are separated by a colon (:) and may use @@ -168,15 +184,13 @@ public abstract class AbstractAgentMojo extends AbstractJacocoMojo { if (append != null) { agentOptions.setAppend(append.booleanValue()); } - if (getIncludes() != null && !getIncludes().isEmpty()) { - final String agentIncludes = StringUtils.join(getIncludes() - .iterator(), ":"); - agentOptions.setIncludes(agentIncludes); + if (includes != null && !includes.isEmpty()) { + agentOptions + .setIncludes(StringUtils.join(includes.iterator(), ":")); } - if (getExcludes() != null && !getExcludes().isEmpty()) { - final String agentExcludes = StringUtils.join(getExcludes() - .iterator(), ":"); - agentOptions.setExcludes(agentExcludes); + if (excludes != null && !excludes.isEmpty()) { + agentOptions + .setExcludes(StringUtils.join(excludes.iterator(), ":")); } if (exclClassLoaders != null) { agentOptions.setExclClassloader(exclClassLoaders); diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/AbstractJacocoMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/AbstractJacocoMojo.java index d1612ab6..3ed86ec0 100644 --- a/jacoco-maven-plugin/src/org/jacoco/maven/AbstractJacocoMojo.java +++ b/jacoco-maven-plugin/src/org/jacoco/maven/AbstractJacocoMojo.java @@ -11,8 +11,6 @@ *******************************************************************************/ package org.jacoco.maven; -import java.util.List; - import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -30,22 +28,6 @@ public abstract class AbstractJacocoMojo extends AbstractMojo { @Parameter(property = "project", readonly = true) private MavenProject project; - /** - * A list of class files to include in instrumentation/analysis/reports. May - * use wildcard characters (* and ?). When not specified everything will be - * included. - */ - @Parameter - private List includes; - - /** - * A list of class files to exclude from instrumentation/analysis/reports. - * May use wildcard characters (* and ?). When not specified nothing will be - * excluded. - */ - @Parameter - private List excludes; - /** * Flag used to suppress execution. */ @@ -90,22 +72,4 @@ public abstract class AbstractJacocoMojo extends AbstractMojo { return project; } - /** - * Returns the list of class files to include. - * - * @return class files to include, may contain wildcard characters - */ - protected List getIncludes() { - return includes; - } - - /** - * Returns the list of class files to exclude. - * - * @return class files to exclude, may contain wildcard characters - */ - protected List getExcludes() { - return excludes; - } - } diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java index ad021b37..3b46f8ed 100644 --- a/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java +++ b/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java @@ -128,6 +128,20 @@ public class CheckMojo extends AbstractJacocoMojo implements IViolationsOutput { @Parameter(defaultValue = "${project.build.directory}/jacoco.exec") private File dataFile; + /** + * A list of class files to include into analysis. May use wildcard + * characters (* and ?). When not specified everything will be included. + */ + @Parameter + private List includes; + + /** + * A list of class files to exclude from analysis. May use wildcard + * characters (* and ?). When not specified nothing will be excluded. + */ + @Parameter + private List excludes; + private boolean violations; private boolean canCheckCoverage() { @@ -169,8 +183,7 @@ public class CheckMojo extends AbstractJacocoMojo implements IViolationsOutput { try { final IReportVisitor visitor = support.initRootVisitor(); support.loadExecutionData(dataFile); - support.processProject(visitor, getProject(), this.getIncludes(), - this.getExcludes()); + support.processProject(visitor, getProject(), includes, excludes); visitor.visitEnd(); } catch (final IOException e) { throw new MojoExecutionException( diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/InstrumentMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/InstrumentMojo.java index c74cf6bb..df31b930 100644 --- a/jacoco-maven-plugin/src/org/jacoco/maven/InstrumentMojo.java +++ b/jacoco-maven-plugin/src/org/jacoco/maven/InstrumentMojo.java @@ -23,6 +23,7 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.IOUtil; import org.jacoco.core.instr.Instrumenter; @@ -44,6 +45,20 @@ import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator; @Mojo(name = "instrument", defaultPhase = LifecyclePhase.PROCESS_CLASSES, threadSafe = true) public class InstrumentMojo extends AbstractJacocoMojo { + /** + * A list of class files to include in instrumentation. May use wildcard + * characters (* and ?). When not specified everything will be included. + */ + @Parameter + private List includes; + + /** + * A list of class files to exclude from instrumentation. May use wildcard + * characters (* and ?). When not specified nothing will be excluded. + */ + @Parameter + private List excludes; + @Override public void executeMojo() throws MojoExecutionException, MojoFailureException { @@ -61,7 +76,7 @@ public class InstrumentMojo extends AbstractJacocoMojo { final List fileNames; try { - fileNames = new FileFilter(this.getIncludes(), this.getExcludes()) + fileNames = new FileFilter(includes, excludes) .getFileNames(classesDir); } catch (final IOException e1) { throw new MojoExecutionException( diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 9b535b0f..c2cd337e 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -59,6 +59,11 @@
    • synthetic methods that represent Kotlin suspend functions should not be ignored (GitHub #804).
    • +
    • Removed misleading parameters includes and + excludes from dump, merge and + restore-instrumented-classes goals of jacoco-maven-plugin, + because they have no effect + (GitHub #827).

    Non-functional Changes

    -- cgit v1.2.3 From 9a4fa06206e83324b92177e08180d530a0c92b25 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sat, 12 Jan 2019 19:50:40 +0100 Subject: Remove unused maven-plugin-tools-javadoc taglets --- jacoco-maven-plugin/pom.xml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/jacoco-maven-plugin/pom.xml b/jacoco-maven-plugin/pom.xml index f048f402..2165e9aa 100644 --- a/jacoco-maven-plugin/pom.xml +++ b/jacoco-maven-plugin/pom.xml @@ -111,19 +111,6 @@ - - org.apache.maven.plugins - maven-javadoc-plugin - - - - org.apache.maven.plugin-tools - maven-plugin-tools-javadoc - 2.8 - - - - org.apache.maven.plugins maven-plugin-plugin -- cgit v1.2.3 From 317da27c487349ae7d5e6993e97f1d0d8ff7959e Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Sat, 12 Jan 2019 21:44:15 +0100 Subject: Configure exec-maven-plugin to use selected JDK toolchain (#830) --- org.jacoco.cli/pom.xml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/org.jacoco.cli/pom.xml b/org.jacoco.cli/pom.xml index 3a759819..82aa79b5 100644 --- a/org.jacoco.cli/pom.xml +++ b/org.jacoco.cli/pom.xml @@ -49,11 +49,15 @@ package - java + exec - org.jacoco.cli.internal.XmlDocumentation + jdk + java + -cp + + org.jacoco.cli.internal.XmlDocumentation ${project.build.directory}/generated-documentation/cli.xml @@ -119,6 +123,6 @@ - + -- cgit v1.2.3 From b307a3352ba806e93cb371e1dac21fbb9548e10c Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 16 Jan 2019 21:20:48 +0100 Subject: Fix typo --- .../src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java index 6d31358f..6f4cfc60 100644 --- a/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java +++ b/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java @@ -114,7 +114,7 @@ public class ModifiedSystemClassRuntime extends AbstractRuntime { * @return new runtime instance * * @throws ClassNotFoundException - * id the given class can not be found + * if the given class can not be found */ public static IRuntime createFor(final Instrumentation inst, final String className, final String accessFieldName) -- cgit v1.2.3 From 0152b7a08014c1dbc72404ce4bbf3194cbc5a0ac Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Thu, 17 Jan 2019 19:49:47 +0100 Subject: Improve wording (#832) --- org.jacoco.doc/docroot/doc/changes.html | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index c2cd337e..b174728b 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -40,9 +40,10 @@ (GitHub #802, #803, #809). -
  • Classes and methods annotated with runtime visible and invisible annotation - whose simple name contains "Generated" (previously equality was required) - are filtered out during generation of report +
  • Classes and methods annotated by annotation whose retention policy is + runtime or class and whose simple name contains + "Generated" (previously equality was required) are filtered out during + generation of report (GitHub #822).
  • HTML report shows message when source file can't be found (GitHub #801).
  • @@ -111,9 +112,9 @@ generation of report (GitHub #737, #746). -
  • Classes and methods annotated with runtime visible and invisible annotation - whose simple name is Generated are filtered out during - generation of report +
  • Classes and methods annotated with annotation whose retention policy + is runtime or class and whose simple name + is Generated are filtered out during generation of report (GitHub #731).
  • Maven goal report-aggregate now also considers dependencies specified using version range. Idea and implementation by Lukas Krejc -- cgit v1.2.3 From 13f29eb797d32338fb073bef8cc37b4e1dbde9f1 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Fri, 18 Jan 2019 18:25:51 +0100 Subject: Preserve empty class and sourcefile nodes in XML report (#817) --- .../src/org/jacoco/maven/ReportSupport.java | 6 +- org.jacoco.ant/src/org/jacoco/ant/ReportTask.java | 3 +- .../jacoco/core/analysis/CoverageBuilderTest.java | 10 +-- .../internal/analysis/ClassCoverageImplTest.java | 2 +- .../org/jacoco/core/analysis/CoverageBuilder.java | 30 ++++----- .../org/jacoco/core/analysis/CoverageNodeImpl.java | 4 ++ .../org/jacoco/core/analysis/ICoverageNode.java | 9 ++- .../core/internal/analysis/ClassAnalyzer.java | 2 +- .../core/internal/analysis/ClassCoverageImpl.java | 6 +- org.jacoco.doc/docroot/doc/changes.html | 2 + .../jacoco/report/ReportStructureTestDriver.java | 29 ++++++-- .../org/jacoco/report/csv/CSVFormatterTest.java | 6 +- .../org/jacoco/report/csv/CSVGroupHandlerTest.java | 2 + .../org/jacoco/report/html/HTMLFormatterTest.java | 20 ++++++ .../report/internal/html/page/BundlePageTest.java | 77 ++++++++++++++++++++++ .../report/internal/html/page/PackagePageTest.java | 58 +++++++++++++--- .../internal/html/page/PackageSourcePageTest.java | 34 +++++++++- .../org/jacoco/report/xml/XMLFormatterTest.java | 24 +++++++ .../src/org/jacoco/report/csv/CSVGroupHandler.java | 4 +- .../report/internal/html/page/BundlePage.java | 3 + .../report/internal/html/page/PackagePage.java | 3 + .../internal/html/page/PackageSourcePage.java | 3 + 22 files changed, 284 insertions(+), 53 deletions(-) create mode 100644 org.jacoco.report.test/src/org/jacoco/report/internal/html/page/BundlePageTest.java diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/ReportSupport.java b/jacoco-maven-plugin/src/org/jacoco/maven/ReportSupport.java index b66d6886..b582d8d9 100644 --- a/jacoco-maven-plugin/src/org/jacoco/maven/ReportSupport.java +++ b/jacoco-maven-plugin/src/org/jacoco/maven/ReportSupport.java @@ -222,9 +222,9 @@ final class ReportSupport { c.getName())); } } - if (bundle.getClassCounter().getTotalCount() > 0 - && bundle.getLineCounter().getTotalCount() == 0) { - log.warn("To enable source code annotation class files have to be compiled with debug information."); + if (!bundle.isEmpty() && bundle.getLineCounter().getTotalCount() == 0) { + log.warn( + "To enable source code annotation class files have to be compiled with debug information."); } } diff --git a/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java b/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java index 8ed7b8c6..e981b38a 100644 --- a/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java +++ b/org.jacoco.ant/src/org/jacoco/ant/ReportTask.java @@ -593,8 +593,7 @@ public class ReportTask extends Task { } private void checkForMissingDebugInformation(final ICoverageNode node) { - if (node.getClassCounter().getTotalCount() > 0 - && node.getLineCounter().getTotalCount() == 0) { + if (!node.isEmpty() && node.getLineCounter().getTotalCount() == 0) { log(format( "To enable source code annotation class files for bundle '%s' have to be compiled with debug information.", node.getName()), Project.MSG_WARN); diff --git a/org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageBuilderTest.java b/org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageBuilderTest.java index a4a38954..40c35e8f 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageBuilderTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/analysis/CoverageBuilderTest.java @@ -13,7 +13,6 @@ package org.jacoco.core.analysis; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.Collection; @@ -106,13 +105,10 @@ public class CoverageBuilderTest { } @Test - public void testIgnoreClassesWithoutCode() { - final MethodCoverageImpl method = new MethodCoverageImpl("doit", "()V", - null); - addClass(123L, false, "Sample", null, method); + public void should_not_ignore_empty_classes() { + addClass(123L, false, "Empty", null); - final Collection classes = coverageBuilder.getClasses(); - assertTrue(classes.isEmpty()); + assertEquals(1, coverageBuilder.getClasses().size()); } @Test(expected = IllegalStateException.class) diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java index b219a878..57d281b3 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java @@ -93,7 +93,7 @@ public class ClassCoverageImplTest { assertEquals(CounterImpl.COUNTER_0_0, node.getInstructionCounter()); assertEquals(CounterImpl.COUNTER_0_0, node.getBranchCounter()); assertEquals(CounterImpl.COUNTER_0_0, node.getMethodCounter()); - assertEquals(CounterImpl.COUNTER_1_0, node.getClassCounter()); + assertEquals(CounterImpl.COUNTER_0_0, node.getClassCounter()); } @Test diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java index 2b240ecf..3c21d244 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java @@ -98,23 +98,19 @@ public class CoverageBuilder implements ICoverageVisitor { // === ICoverageVisitor === public void visitCoverage(final IClassCoverage coverage) { - // Only consider classes that actually contain code: - if (coverage.getInstructionCounter().getTotalCount() > 0) { - final String name = coverage.getName(); - final IClassCoverage dup = classes.put(name, coverage); - if (dup != null) { - if (dup.getId() != coverage.getId()) { - throw new IllegalStateException( - "Can't add different class with same name: " - + name); - } - } else { - final String source = coverage.getSourceFileName(); - if (source != null) { - final SourceFileCoverageImpl sourceFile = getSourceFile( - source, coverage.getPackageName()); - sourceFile.increment(coverage); - } + final String name = coverage.getName(); + final IClassCoverage dup = classes.put(name, coverage); + if (dup != null) { + if (dup.getId() != coverage.getId()) { + throw new IllegalStateException( + "Can't add different class with same name: " + name); + } + } else { + final String source = coverage.getSourceFileName(); + if (source != null) { + final SourceFileCoverageImpl sourceFile = getSourceFile(source, + coverage.getPackageName()); + sourceFile.increment(coverage); } } } diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java index c1bcb26a..450a9a21 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java @@ -143,6 +143,10 @@ public class CoverageNodeImpl implements ICoverageNode { throw new AssertionError(entity); } + public boolean isEmpty() { + return getInstructionCounter().getTotalCount() == 0; + } + public ICoverageNode getPlainCopy() { final CoverageNodeImpl copy = new CoverageNodeImpl(elementType, name); copy.instructionCounter = CounterImpl.getInstance(instructionCounter); diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java index f7605278..a43747c2 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java @@ -131,6 +131,13 @@ public interface ICoverageNode { */ ICounter getCounter(CounterEntity entity); + /** + * Checks whether this is an empty node. + * + * @return true if this node does not contain instructions + */ + boolean isEmpty(); + /** * Creates a plain copy of this node. While {@link ICoverageNode} * implementations may contain heavy data structures, the copy returned by @@ -141,4 +148,4 @@ public interface ICoverageNode { */ ICoverageNode getPlainCopy(); -} \ No newline at end of file +} diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java index c584cacf..f65bcf93 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java @@ -113,7 +113,7 @@ public class ClassAnalyzer extends ClassProbesVisitor signature); mcc.calculate(mc); - if (mc.getInstructionCounter().getTotalCount() > 0) { + if (!mc.isEmpty()) { // Only consider methods that actually contain code coverage.addMethod(mc); } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java index cb45604c..04bc81dc 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java @@ -47,7 +47,6 @@ public class ClassCoverageImpl extends SourceNodeImpl implements IClassCoverage this.id = id; this.noMatch = noMatch; this.methods = new ArrayList(); - this.classCounter = CounterImpl.COUNTER_1_0; } /** @@ -59,10 +58,11 @@ public class ClassCoverageImpl extends SourceNodeImpl implements IClassCoverage public void addMethod(final IMethodCoverage method) { this.methods.add(method); increment(method); - // As class is considered as covered when at least one method is - // covered: + // Class is considered as covered when at least one method is covered: if (methodCounter.getCoveredCount() > 0) { this.classCounter = CounterImpl.COUNTER_0_1; + } else { + this.classCounter = CounterImpl.COUNTER_1_0; } } diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index b174728b..e15e653f 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -51,6 +51,8 @@ (GitHub #818).
  • HTML report shows message when analyzed class does not match executed (GitHub #819).
  • +
  • Empty class and sourcefile nodes are preserved and available in XML report + (GitHub #817).
  • Fixed Bugs

    diff --git a/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java b/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java index 203028fc..9ac87f38 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java +++ b/org.jacoco.report.test/src/org/jacoco/report/ReportStructureTestDriver.java @@ -13,6 +13,8 @@ package org.jacoco.report; import java.io.IOException; import java.io.Reader; +import java.io.StringReader; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -45,7 +47,7 @@ public class ReportStructureTestDriver { public Reader getSourceFile(String packageName, String fileName) throws IOException { - return null; + return new StringReader(""); } public int getTabWidth() { @@ -84,11 +86,30 @@ public class ReportStructureTestDriver { sourceFileCoverageImpl.increment(classCoverage); sourceFileCoverage = sourceFileCoverageImpl; + final ClassCoverageImpl emptyClassInNonEmptyPackage = new ClassCoverageImpl( + "org/jacoco/example/Empty", 0, false); + emptyClassInNonEmptyPackage.setSourceFileName("Empty.java"); + final SourceFileCoverageImpl emptySourceInNonEmptyPackage = new SourceFileCoverageImpl( + "Empty.java", "org/jacoco/example"); + + final ClassCoverageImpl emptyClassInEmptyPackage = new ClassCoverageImpl( + "empty/Empty", 0, false); + emptyClassInEmptyPackage.setSourceFileName("Empty.java"); + final SourceFileCoverageImpl emptySourceInEmptyPackage = new SourceFileCoverageImpl( + "Empty.java", "empty"); + final PackageCoverageImpl emptyPackage = new PackageCoverageImpl( + "empty", + Collections. singletonList( + emptyClassInEmptyPackage), + Collections. singletonList( + emptySourceInEmptyPackage)); + packageCoverage = new PackageCoverageImpl("org/jacoco/example", - Collections.singleton(classCoverage), - Collections.singleton(sourceFileCoverage)); + Arrays.asList(classCoverage, emptyClassInNonEmptyPackage), + Arrays.asList(sourceFileCoverage, + emptySourceInNonEmptyPackage)); bundleCoverage = new BundleCoverageImpl("bundle", - Collections.singleton(packageCoverage)); + Arrays.asList(packageCoverage, emptyPackage)); } public void sendNestedGroups(IReportVisitor reportVisitor) diff --git a/org.jacoco.report.test/src/org/jacoco/report/csv/CSVFormatterTest.java b/org.jacoco.report.test/src/org/jacoco/report/csv/CSVFormatterTest.java index ac0e61d9..949ff0c1 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/csv/CSVFormatterTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/csv/CSVFormatterTest.java @@ -64,6 +64,7 @@ public class CSVFormatterTest { assertEquals( "group/bundle,org.jacoco.example,FooClass,10,15,1,2,0,3,1,2,0,1", lines.get(1)); + assertEquals(2, lines.size()); } @Test @@ -77,6 +78,7 @@ public class CSVFormatterTest { assertEquals( "report/bundle,org.jacoco.example,FooClass,10,15,1,2,0,3,1,2,0,1", lines.get(2)); + assertEquals(3, lines.size()); } @Test @@ -84,9 +86,9 @@ public class CSVFormatterTest { driver.sendBundle(visitor); final List lines = getLines(); assertEquals(HEADER, lines.get(0)); - assertEquals( - "bundle,org.jacoco.example,FooClass,10,15,1,2,0,3,1,2,0,1", + assertEquals("bundle,org.jacoco.example,FooClass,10,15,1,2,0,3,1,2,0,1", lines.get(1)); + assertEquals(2, lines.size()); } @Test diff --git a/org.jacoco.report.test/src/org/jacoco/report/csv/CSVGroupHandlerTest.java b/org.jacoco.report.test/src/org/jacoco/report/csv/CSVGroupHandlerTest.java index 03174067..b323f6dd 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/csv/CSVGroupHandlerTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/csv/CSVGroupHandlerTest.java @@ -51,6 +51,7 @@ public class CSVGroupHandlerTest { assertEquals( "bundle,org.jacoco.example,FooClass,10,15,1,2,0,3,1,2,0,1", reader.readLine()); + assertEquals("no more lines expected", null, reader.readLine()); } @Test @@ -61,6 +62,7 @@ public class CSVGroupHandlerTest { assertEquals( "group/bundle,org.jacoco.example,FooClass,10,15,1,2,0,3,1,2,0,1", reader.readLine()); + assertEquals("no more lines expected", null, reader.readLine()); } private BufferedReader getResultReader() { diff --git a/org.jacoco.report.test/src/org/jacoco/report/html/HTMLFormatterTest.java b/org.jacoco.report.test/src/org/jacoco/report/html/HTMLFormatterTest.java index b1c03ff2..e4fe16fd 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/html/HTMLFormatterTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/html/HTMLFormatterTest.java @@ -65,16 +65,36 @@ public class HTMLFormatterTest { driver.sendGroup(formatter.createVisitor(output)); output.assertFile("index.html"); output.assertFile("bundle/index.html"); + output.assertFile("bundle/org.jacoco.example/index.html"); + output.assertFile("bundle/org.jacoco.example/index.source.html"); output.assertFile("bundle/org.jacoco.example/FooClass.html"); + output.assertFile("bundle/org.jacoco.example/FooClass.java.html"); + output.assertNoFile("bundle/org.jacoco.example/Empty.html"); + output.assertNoFile("bundle/org.jacoco.example/Empty.java.html"); + + output.assertNoFile("bundle/empty/index.html"); + output.assertNoFile("bundle/empty/index.source.html"); + output.assertNoFile("bundle/empty/Empty.html"); + output.assertNoFile("bundle/empty/Empty.java.html"); } @Test public void testStructureWithBundleOnly() throws IOException { driver.sendBundle(formatter.createVisitor(output)); output.assertFile("index.html"); + output.assertFile("org.jacoco.example/index.html"); + output.assertFile("org.jacoco.example/index.source.html"); output.assertFile("org.jacoco.example/FooClass.html"); + output.assertFile("org.jacoco.example/FooClass.java.html"); + output.assertNoFile("org.jacoco.example/Empty.html"); + output.assertNoFile("org.jacoco.example/Empty.java.html"); + + output.assertNoFile("empty/index.html"); + output.assertNoFile("empty/index.source.html"); + output.assertNoFile("empty/Empty.html"); + output.assertNoFile("empty/Empty.java.html"); } @Test diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/BundlePageTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/BundlePageTest.java new file mode 100644 index 00000000..8de70f44 --- /dev/null +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/BundlePageTest.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2009, 2018 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.report.internal.html.page; + +import org.jacoco.core.analysis.IBundleCoverage; +import org.jacoco.core.analysis.IClassCoverage; +import org.jacoco.core.analysis.IPackageCoverage; +import org.jacoco.core.analysis.ISourceFileCoverage; +import org.jacoco.core.internal.analysis.BundleCoverageImpl; +import org.jacoco.core.internal.analysis.ClassCoverageImpl; +import org.jacoco.core.internal.analysis.CounterImpl; +import org.jacoco.core.internal.analysis.MethodCoverageImpl; +import org.jacoco.core.internal.analysis.PackageCoverageImpl; +import org.junit.Before; +import org.junit.Test; +import org.w3c.dom.Document; + +import java.util.Arrays; +import java.util.Collections; + +import static org.junit.Assert.assertEquals; + +/** + * Unit tests for {@link BundlePage}. + */ +public class BundlePageTest extends PageTestBase { + + @Before + @Override + public void setup() throws Exception { + super.setup(); + } + + @Test + public void should_render_non_empty_packages() throws Exception { + final ClassCoverageImpl classCoverage = new ClassCoverageImpl( + "example/Class", 0, false); + final MethodCoverageImpl methodCoverage = new MethodCoverageImpl("m", + "()V", null); + methodCoverage.increment(CounterImpl.COUNTER_1_0, + CounterImpl.COUNTER_0_0, 42); + classCoverage.addMethod(methodCoverage); + final IPackageCoverage nonEmptyPackage = new PackageCoverageImpl( + "example", + Collections. singleton(classCoverage), + Collections. emptySet()); + + final IPackageCoverage emptyPackage = new PackageCoverageImpl("empty", + Collections. emptySet(), + Collections. emptySet()); + + final IBundleCoverage node = new BundleCoverageImpl("bundle", + Arrays.asList(nonEmptyPackage, emptyPackage)); + + final BundlePage page = new BundlePage(node, null, null, rootFolder, + context); + page.render(); + + final Document doc = support.parse(output.getFile("index.html")); + assertEquals("el_package", support.findStr(doc, + "/html/body/table[1]/tbody/tr[1]/td[1]/a/@class")); + assertEquals("example", support.findStr(doc, + "/html/body/table[1]/tbody/tr[1]/td[1]/a")); + assertEquals("1", + support.findStr(doc, "count(/html/body/table[1]/tbody/tr)")); + } + +} diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/PackagePageTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/PackagePageTest.java index e7d1ed7c..ded93ab0 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/PackagePageTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/PackagePageTest.java @@ -22,6 +22,8 @@ import org.jacoco.core.analysis.IClassCoverage; import org.jacoco.core.analysis.IPackageCoverage; import org.jacoco.core.analysis.ISourceFileCoverage; import org.jacoco.core.internal.analysis.ClassCoverageImpl; +import org.jacoco.core.internal.analysis.CounterImpl; +import org.jacoco.core.internal.analysis.MethodCoverageImpl; import org.jacoco.core.internal.analysis.PackageCoverageImpl; import org.jacoco.core.internal.analysis.SourceFileCoverageImpl; import org.jacoco.report.ISourceFileLocator; @@ -56,16 +58,49 @@ public class PackagePageTest extends PageTestBase { }; } + @Test + public void should_render_non_empty_classes() throws Exception { + final ClassCoverageImpl nonEmptyClass = new ClassCoverageImpl( + "example/NonEmptyClass", 0, false); + final MethodCoverageImpl nonEmptyMethod = new MethodCoverageImpl("m", + "()V", null); + nonEmptyMethod.increment(CounterImpl.COUNTER_1_0, + CounterImpl.COUNTER_0_0, 42); + nonEmptyClass.addMethod(nonEmptyMethod); + final ClassCoverageImpl emptyClass = new ClassCoverageImpl( + "example/EmptyClass", 0, false); + + node = new PackageCoverageImpl("example", + Arrays. asList(emptyClass, nonEmptyClass), + Collections. emptySet()); + + page = new PackagePage(node, null, sourceLocator, rootFolder, context); + page.render(); + + final Document doc = support.parse(output.getFile("index.html")); + assertEquals("NonEmptyClass", support.findStr(doc, + "/html/body/table[1]/tbody/tr[1]/td[1]/a")); + assertEquals("1", + support.findStr(doc, "count(/html/body/table[1]/tbody/tr)")); + } + @Test public void testContentsWithSource() throws Exception { - IClassCoverage class1 = new ClassCoverageImpl( + ClassCoverageImpl class1 = new ClassCoverageImpl( "org/jacoco/example/Foo1", 0x1000, false); - IClassCoverage class2 = new ClassCoverageImpl( + MethodCoverageImpl method1 = new MethodCoverageImpl("m", "()V", null); + method1.increment(CounterImpl.COUNTER_1_0, CounterImpl.COUNTER_0_0, 42); + class1.addMethod(method1); + ClassCoverageImpl class2 = new ClassCoverageImpl( "org/jacoco/example/Foo2", 0x2000, false); + MethodCoverageImpl method2 = new MethodCoverageImpl("m", "()V", null); + method2.increment(CounterImpl.COUNTER_1_0, CounterImpl.COUNTER_0_0, 42); + class2.addMethod(method2); ISourceFileCoverage src1 = new SourceFileCoverageImpl("Src1.java", "org/jacoco/example"); - node = new PackageCoverageImpl("org/jacoco/example", Arrays.asList( - class1, class2), Arrays.asList(src1)); + node = new PackageCoverageImpl("org/jacoco/example", + Arrays. asList(class1, class2), + Arrays.asList(src1)); page = new PackagePage(node, null, sourceLocator, rootFolder, context); page.render(); @@ -93,12 +128,19 @@ public class PackagePageTest extends PageTestBase { @Test public void testContentsNoSource() throws Exception { - IClassCoverage class1 = new ClassCoverageImpl( + ClassCoverageImpl class1 = new ClassCoverageImpl( "org/jacoco/example/Foo1", 0x1000, false); - IClassCoverage class2 = new ClassCoverageImpl( + MethodCoverageImpl method1 = new MethodCoverageImpl("m", "()V", null); + method1.increment(CounterImpl.COUNTER_1_0, CounterImpl.COUNTER_0_0, 42); + class1.addMethod(method1); + ClassCoverageImpl class2 = new ClassCoverageImpl( "org/jacoco/example/Foo2", 0x2000, false); - node = new PackageCoverageImpl("org/jacoco/example", Arrays.asList( - class1, class2), Collections. emptyList()); + MethodCoverageImpl method2 = new MethodCoverageImpl("m", "()V", null); + method2.increment(CounterImpl.COUNTER_1_0, CounterImpl.COUNTER_0_0, 42); + class2.addMethod(method2); + node = new PackageCoverageImpl("org/jacoco/example", + Arrays. asList(class1, class2), + Collections. emptyList()); page = new PackagePage(node, null, sourceLocator, rootFolder, context); page.render(); diff --git a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/PackageSourcePageTest.java b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/PackageSourcePageTest.java index c39a4982..873da822 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/PackageSourcePageTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/internal/html/page/PackageSourcePageTest.java @@ -24,6 +24,7 @@ import java.util.Collections; import org.jacoco.core.analysis.IClassCoverage; import org.jacoco.core.analysis.ISourceFileCoverage; +import org.jacoco.core.internal.analysis.CounterImpl; import org.jacoco.core.internal.analysis.PackageCoverageImpl; import org.jacoco.core.internal.analysis.SourceFileCoverageImpl; import org.jacoco.report.ISourceFileLocator; @@ -48,12 +49,16 @@ public class PackageSourcePageTest extends PageTestBase { @Override public void setup() throws Exception { super.setup(); - ISourceFileCoverage src1 = new SourceFileCoverageImpl("Src1.java", + SourceFileCoverageImpl src1 = new SourceFileCoverageImpl("Src1.java", "org/jacoco/example"); - ISourceFileCoverage src2 = new SourceFileCoverageImpl("Src2.java", + src1.increment(CounterImpl.COUNTER_1_0, + CounterImpl.COUNTER_0_0, 1); + SourceFileCoverageImpl src2 = new SourceFileCoverageImpl("Src2.java", "org/jacoco/example"); + src2.increment(CounterImpl.COUNTER_1_0, + CounterImpl.COUNTER_0_0, 1); node = new PackageCoverageImpl("org/jacoco/example", - Collections. emptyList(), Arrays.asList(src1, + Collections. emptyList(), Arrays.asList(src1, src2)); sourceLocator = new ISourceFileLocator() { @@ -108,6 +113,29 @@ public class PackageSourcePageTest extends PageTestBase { "/html/body/table[1]/tbody/tr[2]/td[1]/span")); } + @Test + public void should_render_non_empty_sources() throws Exception { + final ISourceFileCoverage emptySource = new SourceFileCoverageImpl( + "Empty.java", "example"); + final SourceFileCoverageImpl nonEmptySource = new SourceFileCoverageImpl( + "NonEmpty.java", "example"); + nonEmptySource.increment(CounterImpl.COUNTER_1_0, + CounterImpl.COUNTER_0_0, 1); + node = new PackageCoverageImpl("example", + Collections. emptyList(), + Arrays.asList(emptySource, nonEmptySource)); + + page = new PackageSourcePage(node, null, sourceLocator, rootFolder, + context, packagePageLink); + page.render(); + + final Document doc = support.parse(output.getFile("index.source.html")); + assertEquals("NonEmpty.java", support.findStr(doc, + "/html/body/table[1]/tbody/tr[1]/td[1]/span")); + assertEquals("1", + support.findStr(doc, "count(/html/body/table[1]/tbody/tr)")); + } + @Test public void testGetSourceFilePages() throws Exception { page = new PackageSourcePage(node, null, sourceLocator, rootFolder, diff --git a/org.jacoco.report.test/src/org/jacoco/report/xml/XMLFormatterTest.java b/org.jacoco.report.test/src/org/jacoco/report/xml/XMLFormatterTest.java index 57552ce8..3afb4e3c 100644 --- a/org.jacoco.report.test/src/org/jacoco/report/xml/XMLFormatterTest.java +++ b/org.jacoco.report.test/src/org/jacoco/report/xml/XMLFormatterTest.java @@ -134,9 +134,15 @@ public class XMLFormatterTest { visitor.visitInfo(infos, data); driver.sendBundle(visitor); assertPathMatches("bundle", "/report/@name"); + + assertPathMatches("2", "count(/report/package)"); assertPathMatches("org/jacoco/example", "/report/package/@name"); + + assertPathMatches("3", "count(/report/package/class)"); assertPathMatches("org/jacoco/example/FooClass", "/report/package/class/@name"); + + assertPathMatches("1", "count(/report/package/class/method)"); assertPathMatches("fooMethod", "/report/package/class/method/@name"); assertPathMatches("1", "count(/report/counter[@type='INSTRUCTION'])"); @@ -163,6 +169,9 @@ public class XMLFormatterTest { assertPathMatches("0", "report/counter[@type='CLASS']/@missed"); assertPathMatches("1", "report/counter[@type='CLASS']/@covered"); + assertPathMatches("2", + "count(report/package[@name='org/jacoco/example']/sourcefile)"); + assertPathMatches("3", "count(report/package/sourcefile/line)"); assertPathMatches("1", "report/package/sourcefile[@name='FooClass.java']/line[1]/@nr"); assertPathMatches("3", @@ -176,6 +185,21 @@ public class XMLFormatterTest { "report/package/sourcefile[@name='FooClass.java']/line[3]/@nr"); assertPathMatches("4", "report/package/sourcefile[@name='FooClass.java']/line[3]/@mi"); + + assertPathMatches("0", "count(/report/package[@name='empty']/counter)"); + + assertPathMatches("1", "count(/report/package[@name='empty']/class)"); + assertPathMatches("empty/Empty", + "/report/package[@name='empty']/class/@name"); + assertPathMatches("0", + "count(report/package[@name='empty']/class/*)"); + + assertPathMatches("1", + "count(/report/package[@name='empty']/sourcefile)"); + assertPathMatches("Empty.java", + "report/package[@name='empty']/sourcefile/@name"); + assertPathMatches("0", + "count(report/package[@name='empty']/sourcefile/*)"); } @Test diff --git a/org.jacoco.report/src/org/jacoco/report/csv/CSVGroupHandler.java b/org.jacoco.report/src/org/jacoco/report/csv/CSVGroupHandler.java index 0f50ffe0..7b95af5c 100644 --- a/org.jacoco.report/src/org/jacoco/report/csv/CSVGroupHandler.java +++ b/org.jacoco.report/src/org/jacoco/report/csv/CSVGroupHandler.java @@ -43,7 +43,9 @@ class CSVGroupHandler implements IReportGroupVisitor { for (final IPackageCoverage p : bundle.getPackages()) { final String packageName = p.getName(); for (final IClassCoverage c : p.getClasses()) { - writer.writeRow(name, packageName, c); + if (!c.isEmpty()) { + writer.writeRow(name, packageName, c); + } } } } diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/BundlePage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/BundlePage.java index 3189faa1..e12226c0 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/BundlePage.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/BundlePage.java @@ -62,6 +62,9 @@ public class BundlePage extends TablePage { private void renderPackages() throws IOException { for (final IPackageCoverage p : bundle.getPackages()) { + if (p.isEmpty()) { + continue; + } final String packagename = p.getName(); final String foldername = packagename.length() == 0 ? "default" : packagename.replace('/', '.'); diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/PackagePage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/PackagePage.java index f473850a..10b2c461 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/PackagePage.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/PackagePage.java @@ -65,6 +65,9 @@ public class PackagePage extends TablePage { private void renderClasses() throws IOException { for (final IClassCoverage c : getNode().getClasses()) { + if (c.isEmpty()) { + continue; + } final ILinkable sourceFilePage = packageSourcePage .getSourceFilePage(c.getSourceFileName()); final ClassPage page = new ClassPage(c, this, sourceFilePage, diff --git a/org.jacoco.report/src/org/jacoco/report/internal/html/page/PackageSourcePage.java b/org.jacoco.report/src/org/jacoco/report/internal/html/page/PackageSourcePage.java index cfe7f792..11d6dfbe 100644 --- a/org.jacoco.report/src/org/jacoco/report/internal/html/page/PackageSourcePage.java +++ b/org.jacoco.report/src/org/jacoco/report/internal/html/page/PackageSourcePage.java @@ -79,6 +79,9 @@ public class PackageSourcePage extends TablePage { private final void renderSourceFilePages() throws IOException { final String packagename = getNode().getName(); for (final ISourceFileCoverage s : getNode().getSourceFiles()) { + if (s.isEmpty()) { + continue; + } final String sourcename = s.getName(); final Reader reader = locator .getSourceFile(packagename, sourcename); -- cgit v1.2.3 From 519226e7259c0dd36a59c53de9989d99521cc7e9 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Sat, 19 Jan 2019 05:04:28 +0100 Subject: Happy New Year 2019! --- LICENSE.md | 2 +- jacoco-maven-plugin.test/it/it-check-fails-halt/pom.xml | 2 +- .../it/it-check-fails-halt/src/main/java/Example.java | 2 +- .../it/it-check-fails-halt/src/test/java/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-check-fails-halt/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-check-fails-no-halt/pom.xml | 2 +- .../it/it-check-fails-no-halt/src/main/java/Example.java | 2 +- .../it/it-check-fails-no-halt/src/test/java/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-check-fails-no-halt/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-check-passes/pom.xml | 2 +- .../it/it-check-passes/src/main/java/Example.java | 2 +- .../it/it-check-passes/src/test/java/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-check-passes/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-customize-agent/pom.xml | 2 +- .../it/it-customize-agent/src/main/java/Example.java | 2 +- .../it/it-customize-agent/src/test/java/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-customize-agent/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-dump/pom.xml | 2 +- jacoco-maven-plugin.test/it/it-dump/src/main/java/Server.java | 2 +- jacoco-maven-plugin.test/it/it-dump/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-includes-excludes/pom.xml | 2 +- .../src/main/java/org/project/DatabaseUtil.java | 2 +- .../it/it-includes-excludes/src/main/java/org/project/FileUtil.java | 2 +- .../it/it-includes-excludes/src/main/java/org/project/TestUtil.java | 2 +- .../src/test/java/org/project/TestDatabaseUtil.java | 2 +- jacoco-maven-plugin.test/it/it-includes-excludes/verify.bsh | 2 +- .../it/it-java9-offline-instrumentation/pom.xml | 2 +- .../it-java9-offline-instrumentation/src/main/java/module-info.java | 2 +- .../src/main/java/org/example/Example.java | 2 +- .../src/test/java/org/example/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-java9/pom.xml | 2 +- jacoco-maven-plugin.test/it/it-java9/src/main/java/Example.java | 2 +- jacoco-maven-plugin.test/it/it-java9/src/test/java/ExampleTest.java | 2 +- .../it/it-merge-passes/it-merge-passes-merge/pom.xml | 4 ++-- .../it/it-merge-passes/it-merge-passes-project1/pom.xml | 2 +- .../it-merge-passes-project1/src/main/java/Example.java | 2 +- .../it-merge-passes-project1/src/test/java/ExampleTest.java | 2 +- .../it/it-merge-passes/it-merge-passes-project2/pom.xml | 2 +- .../it-merge-passes-project2/src/main/java/Example.java | 2 +- .../it-merge-passes-project2/src/test/java/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-merge-passes/pom.xml | 2 +- jacoco-maven-plugin.test/it/it-merge-passes/verify.bsh | 4 ++-- .../it/it-multi-module/child-jar-without-sources/pom.xml | 2 +- jacoco-maven-plugin.test/it/it-multi-module/child/pom.xml | 2 +- .../it/it-multi-module/child/src/main/java/Example.java | 2 +- .../it/it-multi-module/child/src/main/java/somepackage/Example.java | 2 +- .../it/it-multi-module/child/src/test/java/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-multi-module/pom.xml | 2 +- jacoco-maven-plugin.test/it/it-multi-module/skip-child/pom.xml | 2 +- .../it/it-multi-module/skip-child/src/test/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-multi-module/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-multiple-executions/pom.xml | 2 +- .../it/it-multiple-executions/src/main/java/Example.java | 2 +- .../it/it-multiple-executions/src/test/java/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-multiple-executions/verify.bsh | 2 +- .../it-offline-instrumentation/child-without-main-classes/pom.xml | 2 +- .../child-without-main-classes/src/test/java/ExampleTest.java | 2 +- .../it/it-offline-instrumentation/child/pom.xml | 2 +- .../child/src/main/java/DoNotInstrument.java | 2 +- .../it/it-offline-instrumentation/child/src/main/java/Example.java | 2 +- .../it-offline-instrumentation/child/src/test/java/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-offline-instrumentation/pom.xml | 2 +- jacoco-maven-plugin.test/it/it-offline-instrumentation/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-prepend-property-skip/pom.xml | 2 +- .../it/it-prepend-property-skip/src/test/java/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-prepend-property/pom.xml | 2 +- jacoco-maven-plugin.test/it/it-prepend-property/verify.bsh | 2 +- .../it/it-report-aggregate-customization/child1/pom.xml | 2 +- .../child1/src/main/java/package1/Example1.java | 2 +- .../child1/src/test/java/package1/Example1Test.java | 2 +- .../it/it-report-aggregate-customization/child2/pom.xml | 2 +- .../child2/src/main/java/package2/Example2.java | 2 +- .../child2/src/test/java/package2/Example2Test.java | 2 +- .../it/it-report-aggregate-customization/pom.xml | 2 +- .../it/it-report-aggregate-customization/report/pom.xml | 2 +- .../it/it-report-aggregate-customization/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-report-aggregate/child1-test/pom.xml | 2 +- .../child1-test/src/test/java/package1/Example1bTest.java | 2 +- jacoco-maven-plugin.test/it/it-report-aggregate/child1/pom.xml | 2 +- .../child1/src/main/java/package1/Example1a.java | 2 +- .../child1/src/main/java/package1/Example1b.java | 2 +- .../child1/src/test/java/package1/Example1aTest.java | 2 +- jacoco-maven-plugin.test/it/it-report-aggregate/child2/pom.xml | 2 +- .../it-report-aggregate/child2/src/main/java/package2/Example2.java | 2 +- .../child2/src/test/java/package2/Example2Test.java | 2 +- jacoco-maven-plugin.test/it/it-report-aggregate/child2v2/pom.xml | 2 +- .../child2v2/src/main/java/package2/Example2.java | 2 +- .../child2v2/src/test/java/package2/Example2Test.java | 2 +- jacoco-maven-plugin.test/it/it-report-aggregate/pom.xml | 2 +- jacoco-maven-plugin.test/it/it-report-aggregate/report/pom.xml | 2 +- .../report/src/test/java/packagereport/ReportTest.java | 2 +- jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-report-nomatch/pom.xml | 2 +- .../it/it-report-nomatch/src/main/java/Example.java | 2 +- jacoco-maven-plugin.test/it/it-report-nomatch/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-report-unreadable-dump/pom.xml | 2 +- jacoco-maven-plugin.test/it/it-report-unreadable-dump/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-report-without-debug/pom.xml | 2 +- .../it/it-report-without-debug/src/main/java/Example.java | 2 +- .../it/it-report-without-debug/src/test/java/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-report-without-debug/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-report-without-dump/pom.xml | 2 +- jacoco-maven-plugin.test/it/it-report-without-dump/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-site-failsafe/pom.xml | 2 +- .../it/it-site-failsafe/src/main/java/Example.java | 2 +- .../it/it-site-failsafe/src/test/java/ExampleIT.java | 2 +- .../it/it-site-failsafe/src/test/java/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-site-failsafe/verify.bsh | 2 +- jacoco-maven-plugin.test/it/it-site/pom.xml | 2 +- jacoco-maven-plugin.test/it/it-site/src/main/java/Example.java | 2 +- jacoco-maven-plugin.test/it/it-site/src/test/java/ExampleTest.java | 2 +- jacoco-maven-plugin.test/it/it-site/verify.bsh | 2 +- jacoco-maven-plugin.test/it/settings.xml | 2 +- jacoco-maven-plugin.test/it/setup-parent/pom.xml | 2 +- jacoco-maven-plugin.test/pom.xml | 2 +- jacoco-maven-plugin/META-INF/m2e/lifecycle-mapping-metadata.xml | 2 +- jacoco-maven-plugin/pom.xml | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/AbstractAgentMojo.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/AbstractJacocoMojo.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/AbstractReportMojo.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/AgentITMojo.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/AgentMojo.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/DumpMojo.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/FileFilter.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/InstrumentMojo.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/MergeMojo.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/ReportAggregateMojo.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/ReportITMojo.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/ReportMojo.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/ReportSupport.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/RestoreMojo.java | 2 +- jacoco-maven-plugin/src/org/jacoco/maven/RuleConfiguration.java | 2 +- jacoco/assembly.xml | 2 +- jacoco/pom.xml | 2 +- org.jacoco.agent.rt.test/pom.xml | 2 +- .../src/org/jacoco/agent/rt/internal/AgentTest.java | 2 +- .../src/org/jacoco/agent/rt/internal/ClassFileDumperTest.java | 2 +- .../src/org/jacoco/agent/rt/internal/ConfigLoaderTest.java | 2 +- .../src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java | 2 +- .../src/org/jacoco/agent/rt/internal/ExceptionRecorder.java | 2 +- .../src/org/jacoco/agent/rt/internal/output/ExecutorTestBase.java | 2 +- .../src/org/jacoco/agent/rt/internal/output/FileOutputTest.java | 2 +- .../src/org/jacoco/agent/rt/internal/output/MockServerSocket.java | 2 +- .../org/jacoco/agent/rt/internal/output/MockServerSocketTest.java | 2 +- .../org/jacoco/agent/rt/internal/output/MockSocketConnection.java | 2 +- .../jacoco/agent/rt/internal/output/MockSocketConnectionTest.java | 2 +- .../org/jacoco/agent/rt/internal/output/TcpClientOutputTest.java | 2 +- .../src/org/jacoco/agent/rt/internal/output/TcpConnectionTest.java | 2 +- .../org/jacoco/agent/rt/internal/output/TcpServerOutputTest.java | 2 +- org.jacoco.agent.rt/pom.xml | 2 +- org.jacoco.agent.rt/src/com/vladium/emma/rt/RT.java | 2 +- org.jacoco.agent.rt/src/com/vladium/emma/rt/package-info.java | 4 ++-- org.jacoco.agent.rt/src/org/jacoco/agent/rt/IAgent.java | 2 +- org.jacoco.agent.rt/src/org/jacoco/agent/rt/RT.java | 2 +- org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Agent.java | 2 +- .../src/org/jacoco/agent/rt/internal/ClassFileDumper.java | 2 +- .../src/org/jacoco/agent/rt/internal/ConfigLoader.java | 2 +- .../src/org/jacoco/agent/rt/internal/CoverageTransformer.java | 2 +- .../src/org/jacoco/agent/rt/internal/IExceptionLogger.java | 2 +- .../src/org/jacoco/agent/rt/internal/JmxRegistration.java | 2 +- org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Offline.java | 2 +- org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/PreMain.java | 2 +- .../src/org/jacoco/agent/rt/internal/output/FileOutput.java | 2 +- .../src/org/jacoco/agent/rt/internal/output/IAgentOutput.java | 2 +- .../src/org/jacoco/agent/rt/internal/output/NoneOutput.java | 2 +- .../src/org/jacoco/agent/rt/internal/output/TcpClientOutput.java | 2 +- .../src/org/jacoco/agent/rt/internal/output/TcpConnection.java | 2 +- .../src/org/jacoco/agent/rt/internal/output/TcpServerOutput.java | 2 +- org.jacoco.agent.rt/src/org/jacoco/agent/rt/package-info.java | 4 ++-- org.jacoco.agent.test/pom.xml | 2 +- org.jacoco.agent.test/src/org/jacoco/agent/AgentJarTest.java | 2 +- org.jacoco.agent/pom.xml | 2 +- org.jacoco.agent/src/org/jacoco/agent/AgentJar.java | 2 +- org.jacoco.agent/src/org/jacoco/agent/package-info.java | 4 ++-- org.jacoco.ant.test/pom.xml | 2 +- org.jacoco.ant.test/src/TestTargetInDefault.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/AgentTaskTest.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/AgentTaskTest.xml | 4 ++-- org.jacoco.ant.test/src/org/jacoco/ant/AntFilesLocatorTest.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/AntResourcesLocatorTest.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/CoverageTaskTest.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/CoverageTaskTest.xml | 4 ++-- org.jacoco.ant.test/src/org/jacoco/ant/CreateExecFiles.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/DumpExecClassNames.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/DumpTaskTest.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/DumpTaskTest.xml | 4 ++-- org.jacoco.ant.test/src/org/jacoco/ant/DumpTaskWithServerTest.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/DumpTaskWithServerTest.xml | 4 ++-- org.jacoco.ant.test/src/org/jacoco/ant/InstrumentTaskTest.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/InstrumentTaskTest.xml | 4 ++-- org.jacoco.ant.test/src/org/jacoco/ant/MergeTaskTest.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/MergeTaskTest.xml | 4 ++-- org.jacoco.ant.test/src/org/jacoco/ant/RemoveDebugInfos.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/ReportTaskLocaleTest.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/ReportTaskTest.java | 2 +- org.jacoco.ant.test/src/org/jacoco/ant/ReportTaskTest.xml | 4 ++-- org.jacoco.ant.test/src/org/jacoco/ant/TestTarget.java | 2 +- org.jacoco.ant/pom.xml | 2 +- org.jacoco.ant/src/org/jacoco/ant/AbstractCoverageTask.java | 2 +- org.jacoco.ant/src/org/jacoco/ant/AgentTask.java | 2 +- org.jacoco.ant/src/org/jacoco/ant/AntFilesLocator.java | 2 +- org.jacoco.ant/src/org/jacoco/ant/AntResourcesLocator.java | 2 +- org.jacoco.ant/src/org/jacoco/ant/CoverageTask.java | 2 +- org.jacoco.ant/src/org/jacoco/ant/DumpTask.java | 2 +- org.jacoco.ant/src/org/jacoco/ant/InstrumentTask.java | 2 +- org.jacoco.ant/src/org/jacoco/ant/MergeTask.java | 2 +- org.jacoco.ant/src/org/jacoco/ant/ReportTask.java | 2 +- org.jacoco.ant/src/org/jacoco/ant/antlib.xml | 4 ++-- org.jacoco.build/pom.xml | 6 +++--- org.jacoco.cli.test/pom.xml | 2 +- .../src/org/jacoco/cli/internal/CommandTestBase.java | 2 +- org.jacoco.cli.test/src/org/jacoco/cli/internal/MainTest.java | 2 +- .../src/org/jacoco/cli/internal/XmlDocumentationTest.java | 2 +- .../src/org/jacoco/cli/internal/commands/ClassInfoTest.java | 2 +- .../src/org/jacoco/cli/internal/commands/DumpTest.java | 2 +- .../src/org/jacoco/cli/internal/commands/ExecInfoTest.java | 2 +- .../src/org/jacoco/cli/internal/commands/InstrumentTest.java | 2 +- .../src/org/jacoco/cli/internal/commands/MergeTest.java | 2 +- .../src/org/jacoco/cli/internal/commands/ReportTest.java | 2 +- .../src/org/jacoco/cli/internal/commands/VersionTest.java | 2 +- org.jacoco.cli/pom.xml | 2 +- org.jacoco.cli/src/org/jacoco/cli/internal/Command.java | 2 +- org.jacoco.cli/src/org/jacoco/cli/internal/CommandHandler.java | 2 +- org.jacoco.cli/src/org/jacoco/cli/internal/CommandParser.java | 2 +- org.jacoco.cli/src/org/jacoco/cli/internal/Main.java | 2 +- org.jacoco.cli/src/org/jacoco/cli/internal/XmlDocumentation.java | 2 +- .../src/org/jacoco/cli/internal/commands/AllCommands.java | 2 +- org.jacoco.cli/src/org/jacoco/cli/internal/commands/ClassInfo.java | 2 +- org.jacoco.cli/src/org/jacoco/cli/internal/commands/Dump.java | 2 +- org.jacoco.cli/src/org/jacoco/cli/internal/commands/ExecInfo.java | 2 +- org.jacoco.cli/src/org/jacoco/cli/internal/commands/Instrument.java | 2 +- org.jacoco.cli/src/org/jacoco/cli/internal/commands/Merge.java | 2 +- org.jacoco.cli/src/org/jacoco/cli/internal/commands/Report.java | 2 +- org.jacoco.cli/src/org/jacoco/cli/internal/commands/Version.java | 2 +- org.jacoco.core.test.validation.groovy/pom.xml | 2 +- .../org/jacoco/core/test/validation/groovy/GroovyDataClassTest.java | 2 +- .../test/validation/groovy/targets/GroovyDataClassTarget.groovy | 2 +- org.jacoco.core.test.validation.java5/pom.xml | 2 +- .../jacoco/core/test/validation/java5/AnnotationGeneratedTest.java | 2 +- .../core/test/validation/java5/AnnotationInitializerTest.java | 2 +- .../org/jacoco/core/test/validation/java5/BadCycleClassTest.java | 2 +- .../jacoco/core/test/validation/java5/BooleanExpressionsTest.java | 2 +- .../org/jacoco/core/test/validation/java5/ClassInitializerTest.java | 2 +- .../src/org/jacoco/core/test/validation/java5/ConstructorsTest.java | 2 +- .../java5/ControlStructureBeforeSuperConstructorTest.java | 2 +- .../jacoco/core/test/validation/java5/ControlStructuresTest.java | 2 +- .../jacoco/core/test/validation/java5/CyclomaticComplexityTest.java | 2 +- .../org/jacoco/core/test/validation/java5/EnumConstructorTest.java | 2 +- .../jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java | 2 +- .../src/org/jacoco/core/test/validation/java5/EnumSwitchTest.java | 2 +- .../src/org/jacoco/core/test/validation/java5/ExceptionsTest.java | 2 +- .../jacoco/core/test/validation/java5/ExplicitInitialFrameTest.java | 2 +- .../validation/java5/FieldInitializationInTwoConstructorsTest.java | 2 +- .../src/org/jacoco/core/test/validation/java5/FinallyTest.java | 2 +- .../src/org/jacoco/core/test/validation/java5/FramesTest.java | 2 +- .../core/test/validation/java5/ImplicitFieldInitializationTest.java | 2 +- .../core/test/validation/java5/InterfaceClassInitializerTest.java | 2 +- .../jacoco/core/test/validation/java5/StructuredLockingTest.java | 2 +- .../src/org/jacoco/core/test/validation/java5/SynchronizedTest.java | 2 +- .../src/org/jacoco/core/test/validation/java5/SyntheticTest.java | 2 +- .../test/validation/java5/targets/AnnotationGeneratedTarget.java | 2 +- .../test/validation/java5/targets/AnnotationInitializerTarget.java | 2 +- .../core/test/validation/java5/targets/BadCycleClassTarget.java | 2 +- .../test/validation/java5/targets/BooleanExpressionsTarget.java | 2 +- .../core/test/validation/java5/targets/ClassInitializerTarget.java | 2 +- .../core/test/validation/java5/targets/ConstructorsTarget.java | 2 +- .../java5/targets/ControlStructureBeforeSuperConstructorTarget.java | 2 +- .../core/test/validation/java5/targets/ControlStructuresTarget.java | 2 +- .../core/test/validation/java5/targets/EnumConstructorTarget.java | 2 +- .../test/validation/java5/targets/EnumImplicitMethodsTarget.java | 2 +- .../jacoco/core/test/validation/java5/targets/EnumSwitchTarget.java | 2 +- .../jacoco/core/test/validation/java5/targets/ExceptionsTarget.java | 2 +- .../test/validation/java5/targets/ExplicitInitialFrameTarget.java | 2 +- .../java5/targets/FieldInitializationInTwoConstructorsTarget.java | 2 +- .../jacoco/core/test/validation/java5/targets/FinallyTarget.java | 2 +- .../validation/java5/targets/ImplicitFieldInitializationTarget.java | 2 +- .../validation/java5/targets/InterfaceClassInitializerTarget.java | 2 +- .../core/test/validation/java5/targets/StructuredLockingTarget.java | 2 +- .../core/test/validation/java5/targets/SynchronizedTarget.java | 2 +- .../jacoco/core/test/validation/java5/targets/SyntheticTarget.java | 2 +- org.jacoco.core.test.validation.java7/pom.xml | 2 +- .../src/org/jacoco/core/test/validation/java7/StringSwitchTest.java | 2 +- .../org/jacoco/core/test/validation/java7/TryWithResourcesTest.java | 2 +- .../core/test/validation/java7/targets/StringSwitchTarget.java | 2 +- .../core/test/validation/java7/targets/TryWithResourcesTarget.java | 2 +- org.jacoco.core.test.validation.java8/pom.xml | 2 +- .../core/test/validation/java8/AnnotationOnLocalVariableTest.java | 2 +- .../jacoco/core/test/validation/java8/BadCycleInterfaceTest.java | 2 +- .../core/test/validation/java8/BootstrapMethodReferenceTest.java | 2 +- .../core/test/validation/java8/InterfaceDefaultMethodsTest.java | 2 +- .../core/test/validation/java8/InterfaceOnlyDefaultMethodsTest.java | 2 +- .../jacoco/core/test/validation/java8/LambdaExpressionsTest.java | 2 +- .../jacoco/core/test/validation/java8/LambdaInInterfaceTest.java | 2 +- .../validation/java8/targets/AnnotationOnLocalVariableTarget.java | 2 +- .../core/test/validation/java8/targets/BadCycleInterfaceTarget.java | 2 +- .../validation/java8/targets/InterfaceDefaultMethodsTarget.java | 2 +- .../validation/java8/targets/InterfaceOnlyDefaultMethodsTarget.java | 2 +- .../core/test/validation/java8/targets/LambdaExpressionsTarget.java | 2 +- .../core/test/validation/java8/targets/LambdaInInterfaceTarget.java | 2 +- org.jacoco.core.test.validation.kotlin/pom.xml | 2 +- .../org/jacoco/core/test/validation/kotlin/KotlinCoroutineTest.java | 2 +- .../org/jacoco/core/test/validation/kotlin/KotlinDataClassTest.java | 2 +- .../core/test/validation/kotlin/KotlinDefaultArgumentsTest.java | 2 +- .../jacoco/core/test/validation/kotlin/KotlinElvisOperatorTest.java | 2 +- .../org/jacoco/core/test/validation/kotlin/KotlinInlineTest.java | 2 +- .../org/jacoco/core/test/validation/kotlin/KotlinLateinitTest.java | 2 +- .../core/test/validation/kotlin/KotlinNotNullOperatorTest.java | 2 +- .../core/test/validation/kotlin/KotlinSafeCallOperatorTest.java | 2 +- .../org/jacoco/core/test/validation/kotlin/KotlinSafeCastTest.java | 2 +- .../core/test/validation/kotlin/KotlinTopLevelFunctionTest.java | 2 +- .../core/test/validation/kotlin/KotlinUnsafeCastOperatorTest.java | 2 +- .../core/test/validation/kotlin/KotlinWhenExpressionTest.java | 2 +- .../core/test/validation/kotlin/targets/KotlinCoroutineTarget.kt | 2 +- .../core/test/validation/kotlin/targets/KotlinDataClassTarget.kt | 2 +- .../test/validation/kotlin/targets/KotlinDefaultArgumentsTarget.kt | 2 +- .../test/validation/kotlin/targets/KotlinElvisOperatorTarget.kt | 2 +- .../core/test/validation/kotlin/targets/KotlinInlineTarget.kt | 2 +- .../core/test/validation/kotlin/targets/KotlinLateinitTarget.kt | 2 +- .../test/validation/kotlin/targets/KotlinNotNullOperatorTarget.kt | 2 +- .../test/validation/kotlin/targets/KotlinSafeCallOperatorTarget.kt | 2 +- .../core/test/validation/kotlin/targets/KotlinSafeCastTarget.kt | 2 +- .../test/validation/kotlin/targets/KotlinTopLevelFunctionTarget.kt | 2 +- .../validation/kotlin/targets/KotlinUnsafeCastOperatorTarget.kt | 2 +- .../test/validation/kotlin/targets/KotlinWhenExpressionTarget.kt | 2 +- org.jacoco.core.test.validation/pom.xml | 2 +- org.jacoco.core.test/pom.xml | 2 +- org.jacoco.core.test/src/org/jacoco/core/JaCoCoTest.java | 2 +- org.jacoco.core.test/src/org/jacoco/core/analysis/AnalyzerTest.java | 2 +- .../src/org/jacoco/core/analysis/CounterComparatorTest.java | 2 +- .../src/org/jacoco/core/analysis/CoverageBuilderTest.java | 2 +- .../src/org/jacoco/core/analysis/CoverageNodeImplTest.java | 2 +- .../src/org/jacoco/core/analysis/NodeComparatorTest.java | 2 +- .../src/org/jacoco/core/data/ExecutionDataReaderWriterTest.java | 2 +- .../src/org/jacoco/core/data/ExecutionDataStoreTest.java | 2 +- .../src/org/jacoco/core/data/ExecutionDataTest.java | 2 +- .../jacoco/core/data/IncompatibleExecDataVersionExceptionTest.java | 2 +- .../src/org/jacoco/core/data/SessionInfoStoreTest.java | 2 +- org.jacoco.core.test/src/org/jacoco/core/data/SessionInfoTest.java | 2 +- .../src/org/jacoco/core/instr/ClassFileVersionsTest.java | 2 +- .../src/org/jacoco/core/instr/InstrumenterTest.java | 2 +- org.jacoco.core.test/src/org/jacoco/core/instr/MethodRecorder.java | 2 +- .../src/org/jacoco/core/instr/ResizeInstructionsTest.java | 2 +- .../src/org/jacoco/core/internal/ContentTypeDetectorTest.java | 2 +- .../src/org/jacoco/core/internal/Pack200StreamsTest.java | 2 +- .../org/jacoco/core/internal/analysis/BundleCoverageImplTest.java | 2 +- .../src/org/jacoco/core/internal/analysis/ClassAnalyzerTest.java | 2 +- .../org/jacoco/core/internal/analysis/ClassCoverageImplTest.java | 2 +- .../src/org/jacoco/core/internal/analysis/CounterImplTest.java | 2 +- .../src/org/jacoco/core/internal/analysis/InstructionTest.java | 2 +- .../org/jacoco/core/internal/analysis/InstructionsBuilderTest.java | 2 +- .../src/org/jacoco/core/internal/analysis/LineImplTest.java | 2 +- .../src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java | 2 +- .../jacoco/core/internal/analysis/MethodCoverageCalculatorTest.java | 2 +- .../org/jacoco/core/internal/analysis/MethodCoverageImplTest.java | 2 +- .../src/org/jacoco/core/internal/analysis/PackageCoverageTest.java | 2 +- .../jacoco/core/internal/analysis/SourceFileCoverageImplTest.java | 2 +- .../src/org/jacoco/core/internal/analysis/SourceNodeImplTest.java | 2 +- .../src/org/jacoco/core/internal/analysis/StringPoolTest.java | 2 +- .../jacoco/core/internal/analysis/filter/AbstractMatcherTest.java | 2 +- .../internal/analysis/filter/AnnotationGeneratedFilterTest.java | 2 +- .../internal/analysis/filter/EnumEmptyConstructorFilterTest.java | 2 +- .../org/jacoco/core/internal/analysis/filter/EnumFilterTest.java | 2 +- .../org/jacoco/core/internal/analysis/filter/FilterContextMock.java | 2 +- .../org/jacoco/core/internal/analysis/filter/FilterTestBase.java | 2 +- .../org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java | 2 +- .../core/internal/analysis/filter/KotlinCoroutineFilterTest.java | 2 +- .../internal/analysis/filter/KotlinDefaultArgumentsFilterTest.java | 2 +- .../core/internal/analysis/filter/KotlinGeneratedFilterTest.java | 2 +- .../core/internal/analysis/filter/KotlinInlineFilterTest.java | 2 +- .../core/internal/analysis/filter/KotlinLateinitFilterTest.java | 2 +- .../internal/analysis/filter/KotlinNotNullOperatorFilterTest.java | 2 +- .../analysis/filter/KotlinUnsafeCastOperatorFilterTest.java | 2 +- .../jacoco/core/internal/analysis/filter/KotlinWhenFilterTest.java | 2 +- .../core/internal/analysis/filter/KotlinWhenStringFilterTest.java | 2 +- .../analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java | 2 +- .../core/internal/analysis/filter/StringSwitchEcjFilterTest.java | 2 +- .../core/internal/analysis/filter/StringSwitchJavacFilterTest.java | 2 +- .../core/internal/analysis/filter/SynchronizedFilterTest.java | 2 +- .../jacoco/core/internal/analysis/filter/SyntheticFilterTest.java | 2 +- .../internal/analysis/filter/TryWithResourcesEcjFilterTest.java | 2 +- .../internal/analysis/filter/TryWithResourcesJavac11FilterTest.java | 2 +- .../internal/analysis/filter/TryWithResourcesJavacFilterTest.java | 2 +- .../src/org/jacoco/core/internal/data/CRC64Test.java | 2 +- .../org/jacoco/core/internal/data/CompactDataInputOutputTest.java | 2 +- .../src/org/jacoco/core/internal/flow/ClassProbesAdapterTest.java | 2 +- .../src/org/jacoco/core/internal/flow/FrameSnapshotTest.java | 2 +- .../src/org/jacoco/core/internal/flow/LabelFlowAnalyzerTest.java | 2 +- .../src/org/jacoco/core/internal/flow/LabelInfoTest.java | 2 +- .../src/org/jacoco/core/internal/flow/MethodProbesAdapterTest.java | 2 +- .../src/org/jacoco/core/internal/flow/MethodSanitizerTest.java | 2 +- .../src/org/jacoco/core/internal/instr/ClassInstrumenterTest.java | 2 +- .../jacoco/core/internal/instr/DuplicateFrameEliminatorTest.java | 2 +- .../src/org/jacoco/core/internal/instr/InstrSupportTest.java | 2 +- .../src/org/jacoco/core/internal/instr/MethodInstrumenterTest.java | 2 +- .../jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java | 2 +- .../src/org/jacoco/core/internal/instr/ProbeCounterTest.java | 2 +- .../src/org/jacoco/core/internal/instr/ProbeInserterTest.java | 2 +- .../src/org/jacoco/core/internal/instr/SignatureRemoverTest.java | 2 +- .../src/org/jacoco/core/runtime/AgentOptionsTest.java | 2 +- .../src/org/jacoco/core/runtime/CommandLineSupportTest.java | 2 +- .../src/org/jacoco/core/runtime/LoggerRuntimeTest.java | 2 +- .../src/org/jacoco/core/runtime/ModifiedSystemClassRuntimeTest.java | 2 +- .../core/runtime/OfflineInstrumentationAccessGeneratorTest.java | 2 +- .../src/org/jacoco/core/runtime/RemoteControlReaderWriterTest.java | 2 +- .../src/org/jacoco/core/runtime/RuntimeDataTest.java | 2 +- .../src/org/jacoco/core/runtime/RuntimeTestBase.java | 2 +- .../src/org/jacoco/core/runtime/SystemPropertiesRuntimeTest.java | 2 +- org.jacoco.core.test/src/org/jacoco/core/runtime/TestStorage.java | 4 ++-- .../src/org/jacoco/core/runtime/URLStreamHandlerRuntimeTest.java | 2 +- .../src/org/jacoco/core/runtime/WildcardMatcherTest.java | 2 +- .../src/org/jacoco/core/test/InstrumentingLoader.java | 2 +- org.jacoco.core.test/src/org/jacoco/core/test/TargetLoader.java | 2 +- .../src/org/jacoco/core/test/perf/AnalysisTimeScenario.java | 2 +- .../org/jacoco/core/test/perf/ExecuteInstrumentedCodeScenario.java | 2 +- org.jacoco.core.test/src/org/jacoco/core/test/perf/IPerfOutput.java | 2 +- .../src/org/jacoco/core/test/perf/IPerfScenario.java | 2 +- .../src/org/jacoco/core/test/perf/InstrumentationSizeSzenario.java | 2 +- .../src/org/jacoco/core/test/perf/InstrumentationTimeScenario.java | 2 +- .../src/org/jacoco/core/test/perf/PerfOutputWriter.java | 2 +- .../src/org/jacoco/core/test/perf/PerformanceSuite.java | 2 +- .../src/org/jacoco/core/test/perf/TimedScenario.java | 2 +- .../src/org/jacoco/core/test/perf/targets/Target01.java | 2 +- .../src/org/jacoco/core/test/perf/targets/Target02.java | 2 +- .../src/org/jacoco/core/test/perf/targets/Target03.java | 2 +- .../src/org/jacoco/core/test/validation/Compiler.java | 2 +- .../src/org/jacoco/core/test/validation/JavaVersion.java | 2 +- .../src/org/jacoco/core/test/validation/JavaVersionTest.java | 2 +- .../src/org/jacoco/core/test/validation/Source.java | 2 +- .../src/org/jacoco/core/test/validation/SourceTest.java | 2 +- .../src/org/jacoco/core/test/validation/StatementExecutor.java | 2 +- .../src/org/jacoco/core/test/validation/StatementExecutorTest.java | 2 +- .../src/org/jacoco/core/test/validation/StatementParser.java | 2 +- .../src/org/jacoco/core/test/validation/StatementParserTest.java | 2 +- .../src/org/jacoco/core/test/validation/ValidationTestBase.java | 2 +- .../src/org/jacoco/core/test/validation/targets/Stubs.java | 2 +- .../src/org/jacoco/core/tools/ExecDumpClientTest.java | 2 +- .../src/org/jacoco/core/tools/ExecFileLoaderTest.java | 2 +- org.jacoco.core/pom.xml | 2 +- org.jacoco.core/src/org/jacoco/core/JaCoCo.java | 2 +- org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java | 2 +- org.jacoco.core/src/org/jacoco/core/analysis/CounterComparator.java | 2 +- org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java | 2 +- org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java | 2 +- org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java | 4 ++-- org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java | 4 ++-- org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java | 2 +- org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java | 2 +- org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java | 2 +- org.jacoco.core/src/org/jacoco/core/analysis/ILine.java | 2 +- org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java | 4 ++-- org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java | 4 ++-- .../src/org/jacoco/core/analysis/ISourceFileCoverage.java | 4 ++-- org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java | 2 +- org.jacoco.core/src/org/jacoco/core/analysis/NodeComparator.java | 2 +- org.jacoco.core/src/org/jacoco/core/analysis/package-info.java | 4 ++-- org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java | 2 +- org.jacoco.core/src/org/jacoco/core/data/ExecutionDataReader.java | 2 +- org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java | 2 +- org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java | 2 +- org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java | 2 +- org.jacoco.core/src/org/jacoco/core/data/ISessionInfoVisitor.java | 2 +- .../org/jacoco/core/data/IncompatibleExecDataVersionException.java | 4 ++-- org.jacoco.core/src/org/jacoco/core/data/SessionInfo.java | 2 +- org.jacoco.core/src/org/jacoco/core/data/SessionInfoStore.java | 2 +- org.jacoco.core/src/org/jacoco/core/data/package-info.java | 4 ++-- org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java | 2 +- org.jacoco.core/src/org/jacoco/core/instr/package-info.java | 4 ++-- .../src/org/jacoco/core/internal/ContentTypeDetector.java | 2 +- org.jacoco.core/src/org/jacoco/core/internal/InputStreams.java | 2 +- org.jacoco.core/src/org/jacoco/core/internal/Pack200Streams.java | 2 +- .../src/org/jacoco/core/internal/analysis/BundleCoverageImpl.java | 2 +- .../src/org/jacoco/core/internal/analysis/ClassAnalyzer.java | 2 +- .../src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java | 2 +- .../src/org/jacoco/core/internal/analysis/CounterImpl.java | 2 +- .../src/org/jacoco/core/internal/analysis/Instruction.java | 2 +- .../src/org/jacoco/core/internal/analysis/InstructionsBuilder.java | 2 +- org.jacoco.core/src/org/jacoco/core/internal/analysis/LineImpl.java | 2 +- .../src/org/jacoco/core/internal/analysis/MethodAnalyzer.java | 2 +- .../org/jacoco/core/internal/analysis/MethodCoverageCalculator.java | 2 +- .../src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java | 2 +- .../src/org/jacoco/core/internal/analysis/PackageCoverageImpl.java | 2 +- .../org/jacoco/core/internal/analysis/SourceFileCoverageImpl.java | 2 +- .../src/org/jacoco/core/internal/analysis/SourceNodeImpl.java | 2 +- .../src/org/jacoco/core/internal/analysis/StringPool.java | 2 +- .../org/jacoco/core/internal/analysis/filter/AbstractMatcher.java | 2 +- .../core/internal/analysis/filter/AnnotationGeneratedFilter.java | 2 +- .../core/internal/analysis/filter/EnumEmptyConstructorFilter.java | 2 +- .../src/org/jacoco/core/internal/analysis/filter/EnumFilter.java | 2 +- .../src/org/jacoco/core/internal/analysis/filter/Filters.java | 2 +- .../src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java | 2 +- .../src/org/jacoco/core/internal/analysis/filter/IFilter.java | 2 +- .../org/jacoco/core/internal/analysis/filter/IFilterContext.java | 2 +- .../src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java | 2 +- .../jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java | 2 +- .../core/internal/analysis/filter/KotlinDefaultArgumentsFilter.java | 2 +- .../jacoco/core/internal/analysis/filter/KotlinGeneratedFilter.java | 2 +- .../jacoco/core/internal/analysis/filter/KotlinInlineFilter.java | 2 +- .../jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java | 2 +- .../core/internal/analysis/filter/KotlinNotNullOperatorFilter.java | 2 +- .../internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java | 2 +- .../org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java | 2 +- .../core/internal/analysis/filter/KotlinWhenStringFilter.java | 2 +- .../analysis/filter/PrivateEmptyNoArgConstructorFilter.java | 2 +- .../jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java | 2 +- .../core/internal/analysis/filter/StringSwitchJavacFilter.java | 2 +- .../jacoco/core/internal/analysis/filter/SynchronizedFilter.java | 2 +- .../org/jacoco/core/internal/analysis/filter/SyntheticFilter.java | 2 +- .../core/internal/analysis/filter/TryWithResourcesEcjFilter.java | 2 +- .../internal/analysis/filter/TryWithResourcesJavac11Filter.java | 2 +- .../core/internal/analysis/filter/TryWithResourcesJavacFilter.java | 2 +- org.jacoco.core/src/org/jacoco/core/internal/data/CRC64.java | 2 +- .../src/org/jacoco/core/internal/data/CompactDataInput.java | 2 +- .../src/org/jacoco/core/internal/data/CompactDataOutput.java | 2 +- .../src/org/jacoco/core/internal/flow/ClassProbesAdapter.java | 2 +- .../src/org/jacoco/core/internal/flow/ClassProbesVisitor.java | 2 +- .../src/org/jacoco/core/internal/flow/FrameSnapshot.java | 2 +- org.jacoco.core/src/org/jacoco/core/internal/flow/IFrame.java | 2 +- .../src/org/jacoco/core/internal/flow/IProbeIdGenerator.java | 2 +- .../src/org/jacoco/core/internal/flow/LabelFlowAnalyzer.java | 2 +- org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java | 2 +- .../src/org/jacoco/core/internal/flow/MethodProbesAdapter.java | 2 +- .../src/org/jacoco/core/internal/flow/MethodProbesVisitor.java | 2 +- .../src/org/jacoco/core/internal/flow/MethodSanitizer.java | 2 +- .../jacoco/core/internal/instr/ClassFieldProbeArrayStrategy.java | 2 +- .../src/org/jacoco/core/internal/instr/ClassInstrumenter.java | 2 +- .../org/jacoco/core/internal/instr/DuplicateFrameEliminator.java | 2 +- .../src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java | 2 +- .../src/org/jacoco/core/internal/instr/IProbeInserter.java | 2 +- .../src/org/jacoco/core/internal/instr/InstrSupport.java | 2 +- .../core/internal/instr/InterfaceFieldProbeArrayStrategy.java | 2 +- .../src/org/jacoco/core/internal/instr/LocalProbeArrayStrategy.java | 4 ++-- .../src/org/jacoco/core/internal/instr/MethodInstrumenter.java | 2 +- .../src/org/jacoco/core/internal/instr/NoneProbeArrayStrategy.java | 4 ++-- .../org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java | 2 +- .../src/org/jacoco/core/internal/instr/ProbeCounter.java | 2 +- .../src/org/jacoco/core/internal/instr/ProbeInserter.java | 2 +- .../src/org/jacoco/core/internal/instr/SignatureRemover.java | 2 +- org.jacoco.core/src/org/jacoco/core/package-info.java | 4 ++-- org.jacoco.core/src/org/jacoco/core/runtime/AbstractRuntime.java | 2 +- org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java | 2 +- org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java | 2 +- .../org/jacoco/core/runtime/IExecutionDataAccessorGenerator.java | 2 +- .../src/org/jacoco/core/runtime/IRemoteCommandVisitor.java | 2 +- org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java | 2 +- org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java | 2 +- .../src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java | 2 +- .../jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java | 2 +- .../src/org/jacoco/core/runtime/RemoteControlReader.java | 2 +- .../src/org/jacoco/core/runtime/RemoteControlWriter.java | 2 +- org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java | 2 +- .../src/org/jacoco/core/runtime/SystemPropertiesRuntime.java | 2 +- .../src/org/jacoco/core/runtime/URLStreamHandlerRuntime.java | 2 +- org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java | 2 +- org.jacoco.core/src/org/jacoco/core/runtime/package-info.java | 4 ++-- org.jacoco.core/src/org/jacoco/core/tools/ExecDumpClient.java | 2 +- org.jacoco.core/src/org/jacoco/core/tools/ExecFileLoader.java | 2 +- org.jacoco.core/src/org/jacoco/core/tools/package-info.java | 4 ++-- org.jacoco.doc/pom.xml | 2 +- org.jacoco.examples.test/pom.xml | 2 +- org.jacoco.examples.test/src/org/jacoco/examples/ClassInfoTest.java | 2 +- org.jacoco.examples.test/src/org/jacoco/examples/ConsoleOutput.java | 2 +- .../src/org/jacoco/examples/CoreTutorialTest.java | 2 +- org.jacoco.examples.test/src/org/jacoco/examples/ExecDumpTest.java | 2 +- .../src/org/jacoco/examples/MBeanClientTest.java | 2 +- org.jacoco.examples.test/src/test/resources/verify-it.groovy | 2 +- org.jacoco.examples.test/src/test/resources/verify-offline.groovy | 2 +- org.jacoco.examples.test/src/test/resources/verify.groovy | 2 +- org.jacoco.examples/assembly.xml | 2 +- org.jacoco.examples/build/build-offline.xml | 4 ++-- org.jacoco.examples/build/build.xml | 4 ++-- org.jacoco.examples/build/pom-it.xml | 2 +- org.jacoco.examples/build/pom-offline.xml | 2 +- org.jacoco.examples/build/pom.xml | 2 +- .../build/src/main/java/org/jacoco/examples/expressions/Add.java | 2 +- .../build/src/main/java/org/jacoco/examples/expressions/Const.java | 2 +- .../build/src/main/java/org/jacoco/examples/expressions/Div.java | 2 +- .../src/main/java/org/jacoco/examples/expressions/IExpression.java | 2 +- .../build/src/main/java/org/jacoco/examples/expressions/Mul.java | 2 +- .../build/src/main/java/org/jacoco/examples/expressions/Sub.java | 2 +- .../src/main/java/org/jacoco/examples/parser/ExpressionParser.java | 2 +- .../build/src/main/java/org/jacoco/examples/parser/Main.java | 2 +- .../test/java/org/jacoco/examples/parser/ExpressionParserIT.java | 2 +- .../test/java/org/jacoco/examples/parser/ExpressionParserTest.java | 2 +- org.jacoco.examples/pom.xml | 2 +- org.jacoco.examples/src/org/jacoco/examples/ClassInfo.java | 2 +- org.jacoco.examples/src/org/jacoco/examples/CoreTutorial.java | 2 +- org.jacoco.examples/src/org/jacoco/examples/ExecDump.java | 2 +- .../src/org/jacoco/examples/ExecutionDataClient.java | 2 +- .../src/org/jacoco/examples/ExecutionDataServer.java | 2 +- org.jacoco.examples/src/org/jacoco/examples/MBeanClient.java | 2 +- org.jacoco.examples/src/org/jacoco/examples/ReportGenerator.java | 2 +- org.jacoco.report.test/pom.xml | 2 +- .../src/org/jacoco/report/DirectorySourceFileLocatorTest.java | 2 +- .../src/org/jacoco/report/FileMultiReportOutputTest.java | 2 +- .../src/org/jacoco/report/InputStreamSourceFileLocatorTest.java | 2 +- org.jacoco.report.test/src/org/jacoco/report/JavaNamesTest.java | 2 +- .../src/org/jacoco/report/MemoryMultiReportOutput.java | 2 +- org.jacoco.report.test/src/org/jacoco/report/MemoryOutput.java | 2 +- .../src/org/jacoco/report/MultiReportVisitorTest.java | 2 +- .../src/org/jacoco/report/MultiSourceFileLocatorTest.java | 2 +- .../src/org/jacoco/report/ReportStructureTestDriver.java | 2 +- .../src/org/jacoco/report/ZipMultiReportOutputTest.java | 2 +- .../src/org/jacoco/report/check/BundleCheckerTest.java | 2 +- org.jacoco.report.test/src/org/jacoco/report/check/LimitTest.java | 2 +- org.jacoco.report.test/src/org/jacoco/report/check/RuleTest.java | 2 +- .../src/org/jacoco/report/check/RulesCheckerTest.java | 2 +- .../src/org/jacoco/report/csv/CSVFormatterTest.java | 2 +- .../src/org/jacoco/report/csv/CSVGroupHandlerTest.java | 2 +- .../src/org/jacoco/report/csv/ClassRowWriterTest.java | 2 +- .../src/org/jacoco/report/csv/DelimitedWriterTest.java | 2 +- .../src/org/jacoco/report/html/HTMLFormatterTest.java | 2 +- .../src/org/jacoco/report/internal/NormalizedFileNamesTest.java | 2 +- .../src/org/jacoco/report/internal/ReportOutputFolderTest.java | 2 +- .../src/org/jacoco/report/internal/html/HTMLElementTest.java | 2 +- .../src/org/jacoco/report/internal/html/HTMLSupport.java | 2 +- .../src/org/jacoco/report/internal/html/LinkableStub.java | 2 +- .../src/org/jacoco/report/internal/html/page/BundlePageTest.java | 2 +- .../src/org/jacoco/report/internal/html/page/ClassPageTest.java | 2 +- .../src/org/jacoco/report/internal/html/page/MethodItemTest.java | 2 +- .../src/org/jacoco/report/internal/html/page/NodePageTest.java | 2 +- .../src/org/jacoco/report/internal/html/page/PackagePageTest.java | 2 +- .../org/jacoco/report/internal/html/page/PackageSourcePageTest.java | 2 +- .../src/org/jacoco/report/internal/html/page/PageTestBase.java | 2 +- .../src/org/jacoco/report/internal/html/page/ReportPageTest.java | 2 +- .../src/org/jacoco/report/internal/html/page/SessionsPageTest.java | 2 +- .../org/jacoco/report/internal/html/page/SourceFilePageTest.java | 2 +- .../org/jacoco/report/internal/html/page/SourceHighlighterTest.java | 2 +- .../org/jacoco/report/internal/html/resources/ResourcesTest.java | 2 +- .../src/org/jacoco/report/internal/html/resources/StylesTest.java | 2 +- .../src/org/jacoco/report/internal/html/table/BarColumnTest.java | 2 +- .../org/jacoco/report/internal/html/table/CounterColumnTest.java | 2 +- .../src/org/jacoco/report/internal/html/table/LabelColumnTest.java | 2 +- .../org/jacoco/report/internal/html/table/PercentageColumnTest.java | 2 +- .../src/org/jacoco/report/internal/html/table/SortIndexTest.java | 2 +- .../src/org/jacoco/report/internal/html/table/TableTest.java | 2 +- .../src/org/jacoco/report/internal/xml/LocalEntityResolver.java | 2 +- .../src/org/jacoco/report/internal/xml/XMLElementTest.java | 2 +- .../src/org/jacoco/report/internal/xml/XMLGroupVisitorTest.java | 2 +- .../src/org/jacoco/report/internal/xml/XMLSupport.java | 2 +- .../src/org/jacoco/report/xml/XMLFormatterTest.java | 2 +- org.jacoco.report/pom.xml | 2 +- .../src/org/jacoco/report/DirectorySourceFileLocator.java | 2 +- org.jacoco.report/src/org/jacoco/report/FileMultiReportOutput.java | 2 +- org.jacoco.report/src/org/jacoco/report/ILanguageNames.java | 2 +- org.jacoco.report/src/org/jacoco/report/IMultiReportOutput.java | 2 +- org.jacoco.report/src/org/jacoco/report/IReportGroupVisitor.java | 2 +- org.jacoco.report/src/org/jacoco/report/IReportVisitor.java | 2 +- org.jacoco.report/src/org/jacoco/report/ISourceFileLocator.java | 2 +- .../src/org/jacoco/report/InputStreamSourceFileLocator.java | 2 +- org.jacoco.report/src/org/jacoco/report/JavaNames.java | 2 +- org.jacoco.report/src/org/jacoco/report/MultiReportVisitor.java | 2 +- org.jacoco.report/src/org/jacoco/report/MultiSourceFileLocator.java | 2 +- org.jacoco.report/src/org/jacoco/report/ZipMultiReportOutput.java | 2 +- org.jacoco.report/src/org/jacoco/report/check/BundleChecker.java | 2 +- .../src/org/jacoco/report/check/IViolationsOutput.java | 2 +- org.jacoco.report/src/org/jacoco/report/check/Limit.java | 2 +- org.jacoco.report/src/org/jacoco/report/check/Rule.java | 2 +- org.jacoco.report/src/org/jacoco/report/check/RulesChecker.java | 2 +- org.jacoco.report/src/org/jacoco/report/check/package-info.java | 4 ++-- org.jacoco.report/src/org/jacoco/report/csv/CSVFormatter.java | 2 +- org.jacoco.report/src/org/jacoco/report/csv/CSVGroupHandler.java | 2 +- org.jacoco.report/src/org/jacoco/report/csv/ClassRowWriter.java | 2 +- org.jacoco.report/src/org/jacoco/report/csv/DelimitedWriter.java | 2 +- org.jacoco.report/src/org/jacoco/report/csv/package-info.java | 4 ++-- org.jacoco.report/src/org/jacoco/report/html/HTMLFormatter.java | 2 +- org.jacoco.report/src/org/jacoco/report/html/package-info.java | 4 ++-- .../src/org/jacoco/report/internal/AbstractGroupVisitor.java | 2 +- .../src/org/jacoco/report/internal/NormalizedFileNames.java | 2 +- .../src/org/jacoco/report/internal/ReportOutputFolder.java | 2 +- .../src/org/jacoco/report/internal/html/HTMLElement.java | 2 +- .../src/org/jacoco/report/internal/html/HTMLGroupVisitor.java | 2 +- .../src/org/jacoco/report/internal/html/IHTMLReportContext.java | 4 ++-- .../src/org/jacoco/report/internal/html/ILinkable.java | 2 +- .../src/org/jacoco/report/internal/html/index/ElementIndex.java | 2 +- .../src/org/jacoco/report/internal/html/index/IIndexUpdate.java | 2 +- .../src/org/jacoco/report/internal/html/index/package-info.java | 4 ++-- .../src/org/jacoco/report/internal/html/page/BundlePage.java | 2 +- .../src/org/jacoco/report/internal/html/page/ClassPage.java | 2 +- .../src/org/jacoco/report/internal/html/page/GroupPage.java | 2 +- .../src/org/jacoco/report/internal/html/page/MethodItem.java | 2 +- .../src/org/jacoco/report/internal/html/page/NodePage.java | 2 +- .../src/org/jacoco/report/internal/html/page/PackagePage.java | 2 +- .../src/org/jacoco/report/internal/html/page/PackageSourcePage.java | 2 +- .../src/org/jacoco/report/internal/html/page/ReportPage.java | 2 +- .../src/org/jacoco/report/internal/html/page/SessionsPage.java | 2 +- .../src/org/jacoco/report/internal/html/page/SourceFileItem.java | 2 +- .../src/org/jacoco/report/internal/html/page/SourceFilePage.java | 2 +- .../src/org/jacoco/report/internal/html/page/SourceHighlighter.java | 2 +- .../src/org/jacoco/report/internal/html/page/TablePage.java | 2 +- .../src/org/jacoco/report/internal/html/resources/Resources.java | 2 +- .../src/org/jacoco/report/internal/html/resources/Styles.java | 2 +- .../src/org/jacoco/report/internal/html/resources/package-info.java | 4 ++-- .../src/org/jacoco/report/internal/html/table/BarColumn.java | 2 +- .../src/org/jacoco/report/internal/html/table/CounterColumn.java | 2 +- .../src/org/jacoco/report/internal/html/table/IColumnRenderer.java | 2 +- .../src/org/jacoco/report/internal/html/table/ITableItem.java | 2 +- .../src/org/jacoco/report/internal/html/table/LabelColumn.java | 2 +- .../src/org/jacoco/report/internal/html/table/PercentageColumn.java | 2 +- .../src/org/jacoco/report/internal/html/table/SortIndex.java | 2 +- .../src/org/jacoco/report/internal/html/table/Table.java | 2 +- .../org/jacoco/report/internal/html/table/TableItemComparator.java | 4 ++-- .../src/org/jacoco/report/internal/html/table/package-info.java | 4 ++-- .../src/org/jacoco/report/internal/xml/ReportElement.java | 2 +- .../src/org/jacoco/report/internal/xml/XMLCoverageWriter.java | 2 +- .../src/org/jacoco/report/internal/xml/XMLElement.java | 2 +- .../src/org/jacoco/report/internal/xml/XMLGroupVisitor.java | 2 +- org.jacoco.report/src/org/jacoco/report/package-info.java | 4 ++-- org.jacoco.report/src/org/jacoco/report/xml/XMLFormatter.java | 2 +- org.jacoco.report/src/org/jacoco/report/xml/package-info.java | 4 ++-- org.jacoco.report/src/org/jacoco/report/xml/report.dtd | 4 ++-- org.jacoco.tests/pom.xml | 2 +- 712 files changed, 755 insertions(+), 755 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index a53f7c98..2bb435eb 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ License ======= -Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors +Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors The JaCoCo Java Code Coverage Library and all included documentation is made available by Mountainminds GmbH & Co. KG, Munich. Except indicated below, the diff --git a/jacoco-maven-plugin.test/it/it-check-fails-halt/pom.xml b/jacoco-maven-plugin.test/it/it-check-fails-halt/pom.xml index a4183ab8..ad27b9a8 100644 --- a/jacoco-maven-plugin.test/it/it-check-fails-halt/pom.xml +++ b/jacoco-maven-plugin.test/it/it-check-fails-halt/pom.xml @@ -1,6 +1,6 @@ - \ No newline at end of file + diff --git a/org.jacoco.tests/pom.xml b/org.jacoco.tests/pom.xml index b47f60bd..7a4c9751 100644 --- a/org.jacoco.tests/pom.xml +++ b/org.jacoco.tests/pom.xml @@ -1,6 +1,6 @@ - 7.0 + 7.1 1.7.1 2.0.28 4.8.2 diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java index f9cf3c13..d679cdbb 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java @@ -71,10 +71,42 @@ public class InstrSupportTest { } @Test - public void getVersionMajor_should_return_major_version_number() { - final byte[] bytes = new byte[] { (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, - (byte) 0xBE, /* minor */ 0x00, 0x03, /* major */ 0x00, 0x2D }; - assertEquals(45, InstrSupport.getVersionMajor(bytes)); + public void getMajorVersion_should_read_unsigned_two_bytes_at_offset_6() { + final byte[] bytes = new byte[] { // + (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE, // magic + (byte) 0xFF, (byte) 0xFF, // minor_version + (byte) 0x80, (byte) 0x12 // major_version + }; + + assertEquals(32786, InstrSupport.getMajorVersion(bytes)); + } + + @Test + public void setMajorVersion_should_write_unsigned_two_bytes_at_offset_6() { + final byte[] bytes = new byte[8]; + + InstrSupport.setMajorVersion(32786, bytes); + + assertArrayEquals( + new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // magic + (byte) 0x00, (byte) 0x00, // minor_version + (byte) 0x80, (byte) 0x12 // major_version + }, bytes); + } + + @Test + public void getMajorVersion_should_read_major_version_from_ClassReader_at_offset_relative_to_constant_pool() { + final byte[] bytes = new byte[] { // + (byte) 0xFF, // before class bytes + (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE, // magic + 0x00, 0x03, // minor_version + (byte) 0x80, 0x12, // major_version + 0x00, 0x02, // constant_pool_count + 0x01, 0x00, 0x00 // constant_pool + }; + + assertEquals(32786, + InstrSupport.getMajorVersion(new ClassReader(bytes, 1, -1))); } @Test 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 79748c10..561b09cb 100644 --- a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java +++ b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java @@ -81,7 +81,7 @@ public class Instrumenter { }; final IProbeArrayStrategy strategy = ProbeArrayStrategyFactory .createFor(classId, reader, accessorGenerator); - final int version = InstrSupport.getVersionMajor(source); + final int version = InstrSupport.getMajorVersion(reader); final ClassVisitor visitor = new ClassProbesAdapter( new ClassInstrumenter(strategy, writer), InstrSupport.needsFrames(version)); diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java index 99e00270..1e438958 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java @@ -158,18 +158,52 @@ public final class InstrSupport { */ static final int CLINIT_ACC = Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC; - private static final int MAJOR_VERSION_INDEX = 6; + /** + * Gets major version number from given bytes of class (unsigned two bytes + * at offset 6). + * + * @param b + * bytes of class + * @return major version of bytecode + * @see Java + * Virtual Machine Specification ยง4 The class File Format + * @see #setMajorVersion(int, byte[]) + * @see #getMajorVersion(ClassReader) + */ + public static int getMajorVersion(final byte[] b) { + return ((b[6] & 0xFF) << 8) | (b[7] & 0xFF); + } /** - * Gets major of bytecode version number from given bytes of class. + * Sets major version number in given bytes of class (unsigned two bytes at + * offset 6). * + * @param majorVersion + * major version of bytecode to set * @param b * bytes of class - * @return version of bytecode + * @see #getMajorVersion(byte[]) + */ + public static void setMajorVersion(final int majorVersion, final byte[] b) { + b[6] = (byte) (majorVersion >>> 8); + b[7] = (byte) majorVersion; + } + + /** + * Gets major version number from given {@link ClassReader}. + * + * @param reader + * reader to get information about the class + * @return major version of bytecode + * @see ClassReader#ClassReader(byte[], int, int) + * @see #getMajorVersion(byte[]) */ - public static int getVersionMajor(final byte[] b) { - return (short) (((b[MAJOR_VERSION_INDEX] & 0xFF) << 8) - | (b[MAJOR_VERSION_INDEX + 1] & 0xFF)); + public static int getMajorVersion(final ClassReader reader) { + // relative to the beginning of constant pool because ASM provides API + // to construct ClassReader which reads from the middle of array + final int firstConstantPoolEntryOffset = reader.getItem(1) - 1; + return reader.readUnsignedShort(firstConstantPoolEntryOffset - 4); } /** @@ -237,15 +271,13 @@ public final class InstrSupport { * @return {@link ClassReader} */ public static ClassReader classReaderFor(final byte[] b) { - final byte[] originalVersion = new byte[] { b[4], b[5], b[6], b[7] }; - if (getVersionMajor(b) == Opcodes.V12 + 1) { - b[4] = (byte) (Opcodes.V12 >>> 24); - b[5] = (byte) (Opcodes.V12 >>> 16); - b[6] = (byte) (Opcodes.V12 >>> 8); - b[7] = (byte) Opcodes.V12; + final int originalVersion = getMajorVersion(b); + if (originalVersion == Opcodes.V12 + 1) { + // temporarily downgrade version to bypass check in ASM + setMajorVersion(Opcodes.V12, b); } final ClassReader classReader = new ClassReader(b); - System.arraycopy(originalVersion, 0, b, 4, originalVersion.length); + setMajorVersion(originalVersion, b); return classReader; } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java index 72c8dd68..d5756b7f 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java @@ -43,7 +43,7 @@ public final class ProbeArrayStrategyFactory { final IExecutionDataAccessorGenerator accessorGenerator) { final String className = reader.getClassName(); - final int version = InstrSupport.getVersionMajor(reader.b); + final int version = InstrSupport.getMajorVersion(reader); if (isInterfaceOrModule(reader)) { final ProbeCounter counter = getProbeCounter(reader); diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 15250c84..71faf94f 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -30,6 +30,13 @@ (GitHub #849). +

    Fixed bugs

    +
      +
    • Fixed incorrect update of frames caused by bug in ASM library in case of + arrays with more than 7 dimensions + (GitHub #839).
    • +
    +

    API Changes

    • Methods Instrumenter.instrument(org.objectweb.asm.ClassReader) @@ -38,6 +45,12 @@ (GitHub #850).
    +

    Non-functional Changes

    +
      +
    • JaCoCo now depends on ASM 7.1 + (GitHub #851).
    • +
    +

    Release 0.8.3 (2019/01/23)

    New Features

    -- cgit v1.2.3 From 375a3dc9b5660047f352480d784fe071437154b8 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 8 Mar 2019 11:45:56 +0100 Subject: Remove redundant parentheses --- .../org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java index e2bed498..8f20e849 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java @@ -91,7 +91,7 @@ public final class KotlinCoroutineFilter implements IFilter { continue; } final AbstractInsnNode continuationAfterLoadedResult = skipNonOpcodes( - (((JumpInsnNode) cursor)).label); + ((JumpInsnNode) cursor).label); nextIsVar(Opcodes.ALOAD, "COROUTINE_SUSPENDED"); nextIs(Opcodes.ARETURN); if (cursor == null -- cgit v1.2.3 From 23d835d5eb0f62a7ff036c5e74d933f0de407e7c Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Fri, 8 Mar 2019 19:19:13 +0100 Subject: Method `needsFrames` should also consider high byte of version (#854) --- .../src/org/jacoco/core/internal/instr/InstrSupportTest.java | 2 ++ org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java index d679cdbb..8345ac1b 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/InstrSupportTest.java @@ -128,6 +128,8 @@ public class InstrSupportTest { assertTrue(InstrSupport.needsFrames(Opcodes.V11)); assertTrue(InstrSupport.needsFrames(Opcodes.V12)); assertTrue(InstrSupport.needsFrames(Opcodes.V12 + 1)); + + assertTrue(InstrSupport.needsFrames(0x0100)); } @Test diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java index 1e438958..85e83a3a 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java @@ -215,7 +215,7 @@ public final class InstrSupport { */ public static boolean needsFrames(final int version) { // consider major version only (due to 1.1 anomaly) - return (version & 0xff) >= Opcodes.V1_6; + return (version & 0xFFFF) >= Opcodes.V1_6; } /** -- cgit v1.2.3 From 4e2385364ab4b02487e96bcaea0d7774b2f039cc Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Sat, 9 Mar 2019 00:36:35 +0100 Subject: Add unit test for NoneProbeArrayStrategy (#855) --- .../internal/instr/NoneProbeArrayStrategyTest.java | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 org.jacoco.core.test/src/org/jacoco/core/internal/instr/NoneProbeArrayStrategyTest.java diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/NoneProbeArrayStrategyTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/NoneProbeArrayStrategyTest.java new file mode 100644 index 00000000..0c21f02c --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/NoneProbeArrayStrategyTest.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2009, 2019 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.internal.instr; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.objectweb.asm.tree.ClassNode; + +/** + * Unit tests for {@link NoneProbeArrayStrategy}. + */ +public class NoneProbeArrayStrategyTest { + + private NoneProbeArrayStrategy strategy; + + @Before + public void setup() { + strategy = new NoneProbeArrayStrategy(); + } + + @Test(expected = UnsupportedOperationException.class) + public void storeInstance_should_throw_UnsupportedOperationException() { + strategy.storeInstance(null, false, 0); + } + + @Test + public void addMembers_should_not_add_members() { + final ClassNode c = new ClassNode(); + strategy.addMembers(c, 0); + + assertEquals(0, c.methods.size()); + assertEquals(0, c.fields.size()); + } + +} -- cgit v1.2.3 From 771812b48fe8542b89ea66e82ca4b391a130c2b2 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Sat, 9 Mar 2019 08:10:32 +0000 Subject: Fix unlikely yet theoretically possible NPE (#853) --- .../jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java index 8f20e849..2e381325 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java @@ -120,6 +120,9 @@ public final class KotlinCoroutineFilter implements IFilter { nextIsType(Opcodes.NEW, "java/lang/IllegalStateException"); nextIs(Opcodes.DUP); nextIs(Opcodes.LDC); + if (cursor == null) { + return; + } if (!((LdcInsnNode) cursor).cst.equals( "call to 'resume' before 'invoke' with coroutine")) { return; -- cgit v1.2.3 From 795c8f9e3b2e7e7abe3f4342bbd4a1dd31530325 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Thu, 14 Mar 2019 13:54:13 +0100 Subject: `nextIsInvokeStatic` and `nextIsInvokeVirtual` should check method descriptor (#857) --- .../analysis/filter/AbstractMatcherTest.java | 72 ++++------------------ .../analysis/filter/KotlinCoroutineFilterTest.java | 4 +- .../analysis/filter/KotlinLateinitFilterTest.java | 2 +- .../internal/analysis/filter/AbstractMatcher.java | 44 +++---------- .../filter/EnumEmptyConstructorFilter.java | 3 +- .../analysis/filter/KotlinCoroutineFilter.java | 16 +++-- .../analysis/filter/KotlinLateinitFilter.java | 7 +-- .../filter/KotlinNotNullOperatorFilter.java | 3 +- .../filter/KotlinUnsafeCastOperatorFilter.java | 4 +- .../internal/analysis/filter/KotlinWhenFilter.java | 2 +- .../analysis/filter/KotlinWhenStringFilter.java | 6 +- .../filter/PrivateEmptyNoArgConstructorFilter.java | 3 +- .../analysis/filter/StringSwitchEcjFilter.java | 6 +- .../analysis/filter/StringSwitchJavacFilter.java | 6 +- .../analysis/filter/TryWithResourcesEcjFilter.java | 3 +- .../filter/TryWithResourcesJavac11Filter.java | 3 +- .../filter/TryWithResourcesJavacFilter.java | 3 +- 17 files changed, 62 insertions(+), 125 deletions(-) diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java index 56199bf5..f659632d 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java @@ -137,89 +137,41 @@ public class AbstractMatcherTest { } @Test - public void nextIsInvokeStatic() { - m.visitInsn(Opcodes.NOP); - m.visitMethodInsn(Opcodes.INVOKESTATIC, "owner", "name", "()V", false); - - // should set cursor to null when owner mismatch - matcher.cursor = m.instructions.getFirst(); - matcher.nextIsInvokeStatic("another_owner", "name"); - assertNull(matcher.cursor); - - // should set cursor to null when name mismatch - matcher.cursor = m.instructions.getFirst(); - matcher.nextIsInvokeStatic("owner", "another_name"); - assertNull(matcher.cursor); - - // should set cursor to next instruction when match - matcher.cursor = m.instructions.getFirst(); - matcher.nextIsInvokeStatic("owner", "name"); - assertSame(m.instructions.getLast(), matcher.cursor); - - // should not do anything when cursor is null - matcher.cursor = null; - matcher.nextIsInvokeStatic("owner", "name"); - } - - @Test - public void nextIsInvokeVirtual() { + public void nextIsInvoke() { m.visitInsn(Opcodes.NOP); m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "owner", "name", "()V", false); - // should set cursor to null when owner mismatch + // should set cursor to null when opcode mismatch matcher.cursor = m.instructions.getFirst(); - matcher.nextIsInvokeVirtual("another_owner", "name"); + matcher.nextIsInvoke(Opcodes.INVOKESTATIC, "owner", "name", "()V"); assertNull(matcher.cursor); - // should set cursor to null when name mismatch + // should set cursor to null when owner mismatch matcher.cursor = m.instructions.getFirst(); - matcher.nextIsInvokeVirtual("owner", "another_name"); + matcher.nextIsInvoke(Opcodes.INVOKEVIRTUAL, "another_owner", "name", + "()V"); assertNull(matcher.cursor); - // should set cursor to next instruction when match - matcher.cursor = m.instructions.getFirst(); - matcher.nextIsInvokeVirtual("owner", "name"); - assertSame(m.instructions.getLast(), matcher.cursor); - - // should not do anything when cursor is null - matcher.cursor = null; - matcher.nextIsInvokeVirtual("owner", "name"); - } - - @Test - public void nextIsInvokeSuper() { - m.visitInsn(Opcodes.NOP); - m.visitMethodInsn(Opcodes.INVOKESPECIAL, "owner", "not_init", "()V", - false); - // should set cursor to null when name mismatch matcher.cursor = m.instructions.getFirst(); - matcher.nextIsInvokeSuper("owner", "()V"); - assertNull(matcher.cursor); - - m.instructions.clear(); - m.visitInsn(Opcodes.NOP); - m.visitMethodInsn(Opcodes.INVOKESPECIAL, "owner", "", "()V", - false); - - // should set cursor to null when owner mismatch - matcher.cursor = m.instructions.getFirst(); - matcher.nextIsInvokeSuper("another_owner", "()V"); + matcher.nextIsInvoke(Opcodes.INVOKEVIRTUAL, "owner", "another_name", + "()V"); assertNull(matcher.cursor); // should set cursor to null when descriptor mismatch matcher.cursor = m.instructions.getFirst(); - matcher.nextIsInvokeSuper("owner", "(I)V"); + matcher.nextIsInvoke(Opcodes.INVOKEVIRTUAL, "owner", "name", + "(Lanother_descriptor;)V"); assertNull(matcher.cursor); // should set cursor to next instruction when match matcher.cursor = m.instructions.getFirst(); - matcher.nextIsInvokeSuper("owner", "()V"); + matcher.nextIsInvoke(Opcodes.INVOKEVIRTUAL, "owner", "name", "()V"); assertSame(m.instructions.getLast(), matcher.cursor); // should not do anything when cursor is null matcher.cursor = null; - matcher.nextIsInvokeSuper("owner", "()V"); + matcher.nextIsInvoke(Opcodes.INVOKEVIRTUAL, "owner", "name", "()V"); } @Test diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java index b5b06743..127ae309 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java @@ -53,7 +53,7 @@ public class KotlinCoroutineFilterTest extends FilterTestBase { { m.visitVarInsn(Opcodes.ALOAD, 1); m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/ResultKt", - "throwOnFailure", "", false); + "throwOnFailure", "(Ljava/lang/Object;)V", false); range1.toInclusive = m.instructions.getLast(); } @@ -83,7 +83,7 @@ public class KotlinCoroutineFilterTest extends FilterTestBase { { m.visitVarInsn(Opcodes.ALOAD, 1); m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/ResultKt", - "throwOnFailure", "", false); + "throwOnFailure", "(Ljava/lang/Object;)V", false); } m.visitVarInsn(Opcodes.ALOAD, 1); range2.toInclusive = m.instructions.getLast(); diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java index 5b5f3285..c9e34bab 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java @@ -47,7 +47,7 @@ public class KotlinLateinitFilterTest extends FilterTestBase { m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/jvm/internal/Intrinsics", "throwUninitializedPropertyAccessException", - "Ljava/lang/String;", false); + "(Ljava/lang/String;)V", false); final AbstractInsnNode expectedTo = m.instructions.getLast(); m.visitLabel(l2); m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java index c27c4e92..38860a83 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java @@ -57,49 +57,19 @@ abstract class AbstractMatcher { } /** - * Moves {@link #cursor} to next instruction if it is - * INVOKESPECIAL <init> with given owner and descriptor, - * otherwise sets it to null. - */ - final void nextIsInvokeSuper(final String owner, final String desc) { - nextIs(Opcodes.INVOKESPECIAL); - MethodInsnNode m = (MethodInsnNode) cursor; - if (m != null && owner.equals(m.owner) && "".equals(m.name) - && desc.equals(m.desc)) { - return; - } - cursor = null; - } - - /** - * Moves {@link #cursor} to next instruction if it is - * INVOKEVIRTUAL with given owner and name, otherwise sets it - * to null. - */ - final void nextIsInvokeVirtual(final String owner, final String name) { - nextIs(Opcodes.INVOKEVIRTUAL); - if (cursor == null) { - return; - } - final MethodInsnNode m = (MethodInsnNode) cursor; - if (owner.equals(m.owner) && name.equals(m.name)) { - return; - } - cursor = null; - } - - /** - * Moves {@link #cursor} to next instruction if it is - * INVOKESTATIC with given owner and name, otherwise sets it to + * Moves {@link #cursor} to next instruction if it is {@link MethodInsnNode} + * with given opcode, owner, name and descriptor, otherwise sets it to * null. */ - final void nextIsInvokeStatic(final String owner, final String name) { - nextIs(Opcodes.INVOKESTATIC); + final void nextIsInvoke(final int opcode, final String owner, + final String name, final String descriptor) { + nextIs(opcode); if (cursor == null) { return; } final MethodInsnNode m = (MethodInsnNode) cursor; - if (owner.equals(m.owner) && name.equals(m.name)) { + if (owner.equals(m.owner) && name.equals(m.name) + && descriptor.equals(m.desc)) { return; } cursor = null; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java index 8b7096a9..4a39d1e8 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java @@ -51,7 +51,8 @@ public final class EnumEmptyConstructorFilter implements IFilter { firstIsALoad0(methodNode); nextIs(Opcodes.ALOAD); nextIs(Opcodes.ILOAD); - nextIsInvokeSuper(ENUM_TYPE, CONSTRUCTOR_DESC); + nextIsInvoke(Opcodes.INVOKESPECIAL, ENUM_TYPE, CONSTRUCTOR_NAME, + CONSTRUCTOR_DESC); nextIs(Opcodes.RETURN); return cursor != null; } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java index 2e381325..66d450a3 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java @@ -49,16 +49,18 @@ public final class KotlinCoroutineFilter implements IFilter { private void match(final MethodNode methodNode, final IFilterOutput output) { cursor = methodNode.instructions.getFirst(); - nextIsInvokeStatic("kotlin/coroutines/intrinsics/IntrinsicsKt", - "getCOROUTINE_SUSPENDED"); + nextIsInvoke(Opcodes.INVOKESTATIC, + "kotlin/coroutines/intrinsics/IntrinsicsKt", + "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;"); if (cursor == null) { cursor = skipNonOpcodes(methodNode.instructions.getFirst()); nextIsCreateStateInstance(); - nextIsInvokeStatic("kotlin/coroutines/intrinsics/IntrinsicsKt", - "getCOROUTINE_SUSPENDED"); + nextIsInvoke(Opcodes.INVOKESTATIC, + "kotlin/coroutines/intrinsics/IntrinsicsKt", + "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;"); } nextIsVar(Opcodes.ASTORE, "COROUTINE_SUSPENDED"); @@ -127,7 +129,8 @@ public final class KotlinCoroutineFilter implements IFilter { "call to 'resume' before 'invoke' with coroutine")) { return; } - nextIsInvokeSuper("java/lang/IllegalStateException", + nextIsInvoke(Opcodes.INVOKESPECIAL, + "java/lang/IllegalStateException", "", "(Ljava/lang/String;)V"); nextIs(Opcodes.ATHROW); if (cursor == null) { @@ -142,7 +145,8 @@ public final class KotlinCoroutineFilter implements IFilter { private void nextIsThrowOnFailure() { final AbstractInsnNode c = cursor; - nextIsInvokeStatic("kotlin/ResultKt", "throwOnFailure"); + nextIsInvoke(Opcodes.INVOKESTATIC, "kotlin/ResultKt", + "throwOnFailure", "(Ljava/lang/Object;)V"); if (cursor == null) { cursor = c; // Before resolution of diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java index 44805984..12fe926c 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java @@ -21,9 +21,6 @@ import org.objectweb.asm.tree.MethodNode; */ public class KotlinLateinitFilter implements IFilter { - private final static String OWNER = "kotlin/jvm/internal/Intrinsics"; - private final static String NAME = "throwUninitializedPropertyAccessException"; - public void filter(final MethodNode methodNode, final IFilterContext context, final IFilterOutput output) { final Matcher matcher = new Matcher(); @@ -43,7 +40,9 @@ public class KotlinLateinitFilter implements IFilter { cursor = start; nextIs(Opcodes.LDC); - nextIsInvokeStatic(OWNER, NAME); + nextIsInvoke(Opcodes.INVOKESTATIC, "kotlin/jvm/internal/Intrinsics", + "throwUninitializedPropertyAccessException", + "(Ljava/lang/String;)V"); if (cursor != null) { output.ignore(start, cursor); diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java index a5a1b5d5..4dd223a3 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java @@ -37,7 +37,8 @@ public final class KotlinNotNullOperatorFilter implements IFilter { return; } cursor = start; - nextIsInvokeStatic("kotlin/jvm/internal/Intrinsics", "throwNpe"); + nextIsInvoke(Opcodes.INVOKESTATIC, "kotlin/jvm/internal/Intrinsics", + "throwNpe", "()V"); if (cursor == null) { return; } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java index 97b6835f..c298e945 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java @@ -54,8 +54,8 @@ public final class KotlinUnsafeCastOperatorFilter implements IFilter { .startsWith("null cannot be cast to non-null type"))) { return; } - nextIsInvokeSuper(KOTLIN_TYPE_CAST_EXCEPTION, - "(Ljava/lang/String;)V"); + nextIsInvoke(Opcodes.INVOKESPECIAL, KOTLIN_TYPE_CAST_EXCEPTION, + "", "(Ljava/lang/String;)V"); nextIs(Opcodes.ATHROW); if (cursor == null) { return; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java index 54931669..a229aa04 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java @@ -52,7 +52,7 @@ public final class KotlinWhenFilter implements IFilter { nextIsType(Opcodes.NEW, EXCEPTION); nextIs(Opcodes.DUP); - nextIsInvokeSuper(EXCEPTION, "()V"); + nextIsInvoke(Opcodes.INVOKESPECIAL, EXCEPTION, "", "()V"); nextIs(Opcodes.ATHROW); for (AbstractInsnNode i = cursor; i != null; i = i.getPrevious()) { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java index 497b4b52..fcccb550 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java @@ -46,7 +46,8 @@ public final class KotlinWhenStringFilter implements IFilter { return; } cursor = start; - nextIsInvokeVirtual("java/lang/String", "hashCode"); + nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", + "()I"); nextIsSwitch(); if (cursor == null) { return; @@ -73,7 +74,8 @@ public final class KotlinWhenStringFilter implements IFilter { while (true) { nextIsVar(Opcodes.ALOAD, "s"); nextIs(Opcodes.LDC); - nextIsInvokeVirtual("java/lang/String", "equals"); + nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/String", + "equals", "(Ljava/lang/Object;)Z"); // jump to next comparison or default case nextIs(Opcodes.IFEQ); final JumpInsnNode jump = (JumpInsnNode) cursor; diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java index 5406aa36..236ef712 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java @@ -37,7 +37,8 @@ public final class PrivateEmptyNoArgConstructorFilter implements IFilter { private boolean match(final MethodNode methodNode, final String superClassName) { firstIsALoad0(methodNode); - nextIsInvokeSuper(superClassName, CONSTRUCTOR_DESC); + nextIsInvoke(Opcodes.INVOKESPECIAL, superClassName, + CONSTRUCTOR_NAME, CONSTRUCTOR_DESC); nextIs(Opcodes.RETURN); return cursor != null; } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java index b0306662..e0aba35d 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java @@ -46,7 +46,8 @@ public final class StringSwitchEcjFilter implements IFilter { return; } cursor = start; - nextIsInvokeVirtual("java/lang/String", "hashCode"); + nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", + "()I"); nextIsSwitch(); if (cursor == null) { return; @@ -73,7 +74,8 @@ public final class StringSwitchEcjFilter implements IFilter { while (true) { nextIsVar(Opcodes.ALOAD, "s"); nextIs(Opcodes.LDC); - nextIsInvokeVirtual("java/lang/String", "equals"); + nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/String", + "equals", "(Ljava/lang/Object;)Z"); // jump to case nextIs(Opcodes.IFNE); if (cursor == null) { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java index 36421ee4..3033d9bc 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java @@ -68,12 +68,14 @@ public final class StringSwitchJavacFilter implements IFilter { // Even if expression is not a variable, its result will be // precomputed before the previous two instructions: nextIsVar(Opcodes.ALOAD, "s"); - nextIsInvokeVirtual("java/lang/String", "hashCode"); + nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode", + "()I"); next(); while (true) { nextIsVar(Opcodes.ALOAD, "s"); nextIs(Opcodes.LDC); - nextIsInvokeVirtual("java/lang/String", "equals"); + nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/String", + "equals", "(Ljava/lang/Object;)Z"); // jump to next comparison or second switch nextIs(Opcodes.IFEQ); // ICONST, BIPUSH or SIPUSH diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java index 158799f6..94dea561 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java @@ -200,7 +200,8 @@ public final class TryWithResourcesEcjFilter implements IFilter { // "primaryExc.addSuppressed(suppressedExc)" nextIsVar(Opcodes.ALOAD, "primaryExc"); nextIsVar(Opcodes.ALOAD, suppressedExc); - nextIsInvokeVirtual("java/lang/Throwable", "addSuppressed"); + nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", + "addSuppressed", "(Ljava/lang/Throwable;)V"); nextIsLabel(endLabel); return cursor != null; } diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java index 464031a5..7a20f74f 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java @@ -77,7 +77,8 @@ public final class TryWithResourcesJavac11Filter implements IFilter { nextIsVar(Opcodes.ASTORE, "t"); nextIsVar(Opcodes.ALOAD, "primaryExc"); nextIsVar(Opcodes.ALOAD, "t"); - nextIsInvokeVirtual("java/lang/Throwable", "addSuppressed"); // primaryExc.addSuppressed(t) + nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", + "addSuppressed", "(Ljava/lang/Throwable;)V"); // primaryExc.addSuppressed(t) nextIsVar(Opcodes.ALOAD, "primaryExc"); nextIs(Opcodes.ATHROW); if (cursor == null) { diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java index e6762d6b..23ecb0e6 100644 --- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java +++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java @@ -216,7 +216,8 @@ public final class TryWithResourcesJavacFilter implements IFilter { // "primaryExc.addSuppressed(t)" nextIsVar(Opcodes.ALOAD, "primaryExc"); nextIsVar(Opcodes.ALOAD, ctx + "t"); - nextIsInvokeVirtual("java/lang/Throwable", "addSuppressed"); + nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", + "addSuppressed", "(Ljava/lang/Throwable;)V"); nextIs(Opcodes.GOTO); // "r.close()" nextIsClose(); -- cgit v1.2.3 From 1db0792e87fa1e0549523c50e9d40a8e257cf74e Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov <138671+Godin@users.noreply.github.com> Date: Sat, 16 Mar 2019 23:46:38 +0100 Subject: module-info.class should be excluded from analysis (#859) --- .../src/org/jacoco/core/analysis/AnalyzerTest.java | 14 ++++++++++++++ org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java | 3 +++ org.jacoco.doc/docroot/doc/changes.html | 4 ++++ 3 files changed, 21 insertions(+) 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 6f8fee9c..1e95a5d1 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 @@ -76,6 +76,20 @@ public class AnalyzerTest { analyzer = new Analyzer(executionData, new EmptyStructureVisitor()); } + @Test + public void should_ignore_module_info() throws Exception { + final ClassWriter cw = new ClassWriter(0); + cw.visit(Opcodes.V9, Opcodes.ACC_MODULE, "module-info", null, null, + null); + cw.visitModule("module", 0, null).visitEnd(); + cw.visitEnd(); + final byte[] bytes = cw.toByteArray(); + + analyzer.analyzeClass(bytes, ""); + + assertTrue(classes.isEmpty()); + } + @Test public void should_ignore_synthetic_classes() throws Exception { final ClassWriter cw = new ClassWriter(0); 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 b46f1bbc..76b7be3c 100644 --- a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java +++ b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java @@ -104,6 +104,9 @@ public class Analyzer { private void analyzeClass(final byte[] source) { final long classId = CRC64.classId(source); final ClassReader reader = InstrSupport.classReaderFor(source); + if ((reader.getAccess() & Opcodes.ACC_MODULE) != 0) { + return; + } if ((reader.getAccess() & Opcodes.ACC_SYNTHETIC) != 0) { return; } diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 71faf94f..fa81f09d 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -35,6 +35,10 @@
  • Fixed incorrect update of frames caused by bug in ASM library in case of arrays with more than 7 dimensions (GitHub #839).
  • +
  • Fixed regression, which was introduced in 0.8.3 - + module-info.class should be excluded from analysis to not cause + IllegalStateException + (GitHub #859).
  • API Changes

    -- cgit v1.2.3 From 05dbc8ced954faf00a8d31d31776ad13a846bb93 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 22 Mar 2019 15:34:02 +0100 Subject: Upgrade maven-javadoc-plugin to 3.0.1 --- org.jacoco.build/pom.xml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index afb76b1e..7548b27d 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -347,19 +347,15 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + + 3.0.1 true false - - - - commons-lang - commons-lang - 2.6 - - org.apache.maven.plugins -- cgit v1.2.3 From 78f60007dcd40c9b6c79cbcde8a5ffb72c87410b Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 22 Mar 2019 16:29:47 +0100 Subject: Build with JDK 13 EA in Travis --- .travis.sh | 8 ++++++++ .travis.yml | 1 + org.jacoco.build/pom.xml | 16 ++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/.travis.sh b/.travis.sh index dcd9d119..cb2022cf 100755 --- a/.travis.sh +++ b/.travis.sh @@ -66,6 +66,9 @@ case "$JDK" in 12-ea) install_jdk $JDK12_EA_URL ;; +13-ea) + install_jdk $JDK13_EA_URL + ;; esac # Do not use "~/.mavenrc" set by Travis (https://github.com/travis-ci/travis-ci/issues/3893), @@ -101,6 +104,11 @@ case "$JDK" in mvn -V -B -e verify -Dbytecode.version=12 \ --settings=./.travis/settings.xml ;; +13-ea) + mvn -V -B -e verify -Dbytecode.version=13 \ + --projects \!org.jacoco.core.test.validation.groovy \ + --settings=./.travis/settings.xml + ;; *) echo "Incorrect JDK [$JDK]" exit 1; diff --git a/.travis.yml b/.travis.yml index 854f0cff..19eb8d3f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,5 +27,6 @@ env: - JDK=10 - JDK=11 - JDK=12-ea + - JDK=13-ea script: ./.travis.sh diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index 7548b27d..6726a10c 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -361,6 +361,14 @@ org.apache.maven.plugins maven-plugin-plugin 3.6.0 + + + + org.ow2.asm + asm + 7.1 + + org.apache.maven.plugins @@ -386,6 +394,14 @@ org.apache.maven.plugins maven-shade-plugin 3.2.1 + + + + org.ow2.asm + asm + 7.1 + + org.apache.maven.plugins -- cgit v1.2.3 From e03e5bd026e7b89de1f9a5745483b4a052a59dd5 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 22 Mar 2019 17:09:46 +0100 Subject: Happy birthday JDK 12! --- .travis.sh | 10 +++------- .travis.yml | 2 +- org.jacoco.doc/docroot/doc/changes.html | 1 + org.jacoco.doc/docroot/doc/faq.html | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.travis.sh b/.travis.sh index cb2022cf..58892364 100755 --- a/.travis.sh +++ b/.travis.sh @@ -63,8 +63,8 @@ case "$JDK" in 11) install_jdk $JDK11_URL ;; -12-ea) - install_jdk $JDK12_EA_URL +12) + install_jdk $JDK12_URL ;; 13-ea) install_jdk $JDK13_EA_URL @@ -96,14 +96,10 @@ case "$JDK" in mvn -V -B -e verify -Djdk.version=${JDK} -Dbytecode.version=${JDK} -Decj=${ECJ:-} --toolchains=./.travis/travis-toolchains.xml \ --settings=./.travis/settings.xml ;; -10 | 11) +10 | 11 | 12) mvn -V -B -e verify -Dbytecode.version=${JDK} \ --settings=./.travis/settings.xml ;; -12-ea) - mvn -V -B -e verify -Dbytecode.version=12 \ - --settings=./.travis/settings.xml - ;; 13-ea) mvn -V -B -e verify -Dbytecode.version=13 \ --projects \!org.jacoco.core.test.validation.groovy \ diff --git a/.travis.yml b/.travis.yml index 19eb8d3f..239d3b2a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ env: - JDK=9 - JDK=10 - JDK=11 - - JDK=12-ea + - JDK=12 - JDK=13-ea script: ./.travis.sh diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index fa81f09d..f16d09af 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -22,6 +22,7 @@

    New Features

      +
    • JaCoCo now officially supports Java 12
    • Instrumentation does not add synthetic field to Java 11+ class files, however still adds synthetic method (GitHub #845).
    • diff --git a/org.jacoco.doc/docroot/doc/faq.html b/org.jacoco.doc/docroot/doc/faq.html index da5eab0a..2e48734e 100644 --- a/org.jacoco.doc/docroot/doc/faq.html +++ b/org.jacoco.doc/docroot/doc/faq.html @@ -45,7 +45,7 @@

      What Java versions are supported by JaCoCo?

      - JaCoCo supports Java class files from version 1.0 to 11. However the minimum + JaCoCo supports Java class files from version 1.0 to 12. However the minimum JRE version required by the JaCoCo runtime (e.g. the agent) and the JaCoCo tools is 1.5. Also note that class files under test from version 1.6 and above have to contain valid stackmap frames. -- cgit v1.2.3 From a7b061c84cf0c6ee3fe46b381f191e72c55a0a9f Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 17 Apr 2019 14:03:00 +0200 Subject: Add validation test for Kotlin callable references --- .../kotlin/KotlinCallableReferenceTest.java | 26 ++++++++++++++++++ .../targets/KotlinCallableReferenceTarget.kt | 32 ++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinCallableReferenceTest.java create mode 100644 org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCallableReferenceTarget.kt diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinCallableReferenceTest.java b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinCallableReferenceTest.java new file mode 100644 index 00000000..321c717e --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/KotlinCallableReferenceTest.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2009, 2019 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.kotlin.targets.KotlinCallableReferenceTarget; + +/** + * Test of callable references. + */ +public class KotlinCallableReferenceTest extends ValidationTestBase { + + public KotlinCallableReferenceTest() { + super(KotlinCallableReferenceTarget.class); + } + +} diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCallableReferenceTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCallableReferenceTarget.kt new file mode 100644 index 00000000..fb032b4e --- /dev/null +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCallableReferenceTarget.kt @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2009, 2019 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: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.kotlin.targets + +import org.jacoco.core.test.validation.targets.Stubs.nop + +/** + * Test target for callable references. + */ +object KotlinCallableReferenceTarget { + + @JvmStatic + fun main(args: Array) { + + /* + anonymous class generated for callable reference is not marked as synthetic + https://youtrack.jetbrains.com/issue/KT-28453 + */ + nop(::main) // assertPartlyCovered(0, 0) + + } + +} -- cgit v1.2.3 From d3c47652b89267709aae04bec66a68bdf6df9670 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 17 Apr 2019 14:42:02 +0200 Subject: Upgrade Kotlin to 1.3.30 --- org.jacoco.core.test.validation.kotlin/pom.xml | 2 +- .../test/validation/kotlin/targets/KotlinCallableReferenceTarget.kt | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/org.jacoco.core.test.validation.kotlin/pom.xml b/org.jacoco.core.test.validation.kotlin/pom.xml index 99411f93..91071b5c 100644 --- a/org.jacoco.core.test.validation.kotlin/pom.xml +++ b/org.jacoco.core.test.validation.kotlin/pom.xml @@ -25,7 +25,7 @@ 6 - 1.3.0 + 1.3.30 diff --git a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCallableReferenceTarget.kt b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCallableReferenceTarget.kt index fb032b4e..b0240674 100644 --- a/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCallableReferenceTarget.kt +++ b/org.jacoco.core.test.validation.kotlin/src/org/jacoco/core/test/validation/kotlin/targets/KotlinCallableReferenceTarget.kt @@ -22,10 +22,11 @@ object KotlinCallableReferenceTarget { fun main(args: Array) { /* - anonymous class generated for callable reference is not marked as synthetic + Since Kotlin 1.3.30 + anonymous class generated for callable reference is marked as synthetic https://youtrack.jetbrains.com/issue/KT-28453 */ - nop(::main) // assertPartlyCovered(0, 0) + nop(::main) // assertFullyCovered(0, 0) } -- cgit v1.2.3 From 6d5731aa67725ad0a0510740bbd3611502a94105 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Fri, 3 May 2019 20:07:55 +0200 Subject: Upgrade Kotlin to 1.3.31 --- org.jacoco.core.test.validation.kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jacoco.core.test.validation.kotlin/pom.xml b/org.jacoco.core.test.validation.kotlin/pom.xml index 91071b5c..02debabe 100644 --- a/org.jacoco.core.test.validation.kotlin/pom.xml +++ b/org.jacoco.core.test.validation.kotlin/pom.xml @@ -25,7 +25,7 @@ 6 - 1.3.30 + 1.3.31 -- cgit v1.2.3 From 723a1acc6b4ab23556554568025c97c69035b120 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Wed, 8 May 2019 22:47:39 +0200 Subject: Prepare release 0.8.4 --- jacoco-maven-plugin.test/pom.xml | 2 +- jacoco-maven-plugin/pom.xml | 2 +- jacoco/pom.xml | 2 +- org.jacoco.agent.rt.test/pom.xml | 2 +- org.jacoco.agent.rt/pom.xml | 2 +- org.jacoco.agent.test/pom.xml | 2 +- org.jacoco.agent/pom.xml | 2 +- org.jacoco.ant.test/pom.xml | 2 +- org.jacoco.ant/pom.xml | 2 +- org.jacoco.build/pom.xml | 2 +- org.jacoco.cli.test/pom.xml | 2 +- org.jacoco.cli/pom.xml | 2 +- org.jacoco.core.test.validation.groovy/pom.xml | 2 +- org.jacoco.core.test.validation.java5/pom.xml | 2 +- org.jacoco.core.test.validation.java7/pom.xml | 2 +- org.jacoco.core.test.validation.java8/pom.xml | 2 +- org.jacoco.core.test.validation.kotlin/pom.xml | 2 +- org.jacoco.core.test.validation/pom.xml | 2 +- org.jacoco.core.test/pom.xml | 2 +- org.jacoco.core/pom.xml | 2 +- org.jacoco.doc/docroot/doc/changes.html | 2 +- org.jacoco.doc/pom.xml | 2 +- org.jacoco.examples.test/pom.xml | 2 +- org.jacoco.examples/pom.xml | 2 +- org.jacoco.report.test/pom.xml | 2 +- org.jacoco.report/pom.xml | 2 +- org.jacoco.tests/pom.xml | 2 +- pom.xml | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/jacoco-maven-plugin.test/pom.xml b/jacoco-maven-plugin.test/pom.xml index 7f08fe15..9325c374 100644 --- a/jacoco-maven-plugin.test/pom.xml +++ b/jacoco-maven-plugin.test/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.tests - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.tests diff --git a/jacoco-maven-plugin/pom.xml b/jacoco-maven-plugin/pom.xml index 6be21c8e..c19312cb 100644 --- a/jacoco-maven-plugin/pom.xml +++ b/jacoco-maven-plugin/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.build - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.build diff --git a/jacoco/pom.xml b/jacoco/pom.xml index d716ef86..9afefc04 100644 --- a/jacoco/pom.xml +++ b/jacoco/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.build diff --git a/org.jacoco.agent.rt.test/pom.xml b/org.jacoco.agent.rt.test/pom.xml index fcea3480..5394ee73 100644 --- a/org.jacoco.agent.rt.test/pom.xml +++ b/org.jacoco.agent.rt.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.tests diff --git a/org.jacoco.agent.rt/pom.xml b/org.jacoco.agent.rt/pom.xml index 29d6ae3f..605f4491 100644 --- a/org.jacoco.agent.rt/pom.xml +++ b/org.jacoco.agent.rt/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.build diff --git a/org.jacoco.agent.test/pom.xml b/org.jacoco.agent.test/pom.xml index 2e494374..da758be0 100644 --- a/org.jacoco.agent.test/pom.xml +++ b/org.jacoco.agent.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.tests diff --git a/org.jacoco.agent/pom.xml b/org.jacoco.agent/pom.xml index 1c898698..ac18ecad 100644 --- a/org.jacoco.agent/pom.xml +++ b/org.jacoco.agent/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.build diff --git a/org.jacoco.ant.test/pom.xml b/org.jacoco.ant.test/pom.xml index fd732a13..6686ae23 100644 --- a/org.jacoco.ant.test/pom.xml +++ b/org.jacoco.ant.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.tests diff --git a/org.jacoco.ant/pom.xml b/org.jacoco.ant/pom.xml index 7a9d08c6..cba37bd6 100644 --- a/org.jacoco.ant/pom.xml +++ b/org.jacoco.ant/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.build diff --git a/org.jacoco.build/pom.xml b/org.jacoco.build/pom.xml index 6726a10c..18ac6a5b 100644 --- a/org.jacoco.build/pom.xml +++ b/org.jacoco.build/pom.xml @@ -14,7 +14,7 @@ org.jacoco org.jacoco.build - 0.8.4-SNAPSHOT + 0.8.4 pom JaCoCo diff --git a/org.jacoco.cli.test/pom.xml b/org.jacoco.cli.test/pom.xml index 0a01a18f..fc6356db 100644 --- a/org.jacoco.cli.test/pom.xml +++ b/org.jacoco.cli.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.tests diff --git a/org.jacoco.cli/pom.xml b/org.jacoco.cli/pom.xml index cd602b1f..1b975fe4 100644 --- a/org.jacoco.cli/pom.xml +++ b/org.jacoco.cli/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.build diff --git a/org.jacoco.core.test.validation.groovy/pom.xml b/org.jacoco.core.test.validation.groovy/pom.xml index ec98b4bf..a30cb442 100644 --- a/org.jacoco.core.test.validation.groovy/pom.xml +++ b/org.jacoco.core.test.validation.groovy/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.core.test.validation - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.core.test.validation diff --git a/org.jacoco.core.test.validation.java5/pom.xml b/org.jacoco.core.test.validation.java5/pom.xml index dfd090cd..4591189a 100644 --- a/org.jacoco.core.test.validation.java5/pom.xml +++ b/org.jacoco.core.test.validation.java5/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.core.test.validation - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.core.test.validation diff --git a/org.jacoco.core.test.validation.java7/pom.xml b/org.jacoco.core.test.validation.java7/pom.xml index a63e652f..3f58d8b9 100644 --- a/org.jacoco.core.test.validation.java7/pom.xml +++ b/org.jacoco.core.test.validation.java7/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.core.test.validation - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.core.test.validation diff --git a/org.jacoco.core.test.validation.java8/pom.xml b/org.jacoco.core.test.validation.java8/pom.xml index 3bdeed46..5edd498e 100644 --- a/org.jacoco.core.test.validation.java8/pom.xml +++ b/org.jacoco.core.test.validation.java8/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.core.test.validation - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.core.test.validation diff --git a/org.jacoco.core.test.validation.kotlin/pom.xml b/org.jacoco.core.test.validation.kotlin/pom.xml index 02debabe..0541e005 100644 --- a/org.jacoco.core.test.validation.kotlin/pom.xml +++ b/org.jacoco.core.test.validation.kotlin/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.core.test.validation - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.core.test.validation diff --git a/org.jacoco.core.test.validation/pom.xml b/org.jacoco.core.test.validation/pom.xml index 2bb14a2d..7d9abf3c 100644 --- a/org.jacoco.core.test.validation/pom.xml +++ b/org.jacoco.core.test.validation/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.tests - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.tests diff --git a/org.jacoco.core.test/pom.xml b/org.jacoco.core.test/pom.xml index e24e2c66..843ebc86 100644 --- a/org.jacoco.core.test/pom.xml +++ b/org.jacoco.core.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.tests diff --git a/org.jacoco.core/pom.xml b/org.jacoco.core/pom.xml index e08174a4..0bb5b2b8 100644 --- a/org.jacoco.core/pom.xml +++ b/org.jacoco.core/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.build diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index f16d09af..1dfa98d9 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -18,7 +18,7 @@

      Change History

      -

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

      +

      Release 0.8.4 (2019/05/08)

      New Features

        diff --git a/org.jacoco.doc/pom.xml b/org.jacoco.doc/pom.xml index add88361..740b0ca4 100644 --- a/org.jacoco.doc/pom.xml +++ b/org.jacoco.doc/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.build diff --git a/org.jacoco.examples.test/pom.xml b/org.jacoco.examples.test/pom.xml index f3e87121..73358642 100644 --- a/org.jacoco.examples.test/pom.xml +++ b/org.jacoco.examples.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.tests diff --git a/org.jacoco.examples/pom.xml b/org.jacoco.examples/pom.xml index 5884bd3d..f942c770 100644 --- a/org.jacoco.examples/pom.xml +++ b/org.jacoco.examples/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.build diff --git a/org.jacoco.report.test/pom.xml b/org.jacoco.report.test/pom.xml index 16de1b70..64c0cfa0 100644 --- a/org.jacoco.report.test/pom.xml +++ b/org.jacoco.report.test/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.tests - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.tests diff --git a/org.jacoco.report/pom.xml b/org.jacoco.report/pom.xml index 3eb185de..9b834523 100644 --- a/org.jacoco.report/pom.xml +++ b/org.jacoco.report/pom.xml @@ -15,7 +15,7 @@ org.jacoco org.jacoco.build - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.build diff --git a/org.jacoco.tests/pom.xml b/org.jacoco.tests/pom.xml index f926c446..3efa06c9 100644 --- a/org.jacoco.tests/pom.xml +++ b/org.jacoco.tests/pom.xml @@ -16,7 +16,7 @@ org.jacoco org.jacoco.build - 0.8.4-SNAPSHOT + 0.8.4 ../org.jacoco.build diff --git a/pom.xml b/pom.xml index 3b30ac38..08fc6691 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.jacoco root - 0.8.4-SNAPSHOT + 0.8.4 pom -- cgit v1.2.3