diff options
Diffstat (limited to 'org.jacoco.core.test.validation.java5')
45 files changed, 3080 insertions, 0 deletions
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..4591189a --- /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, 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 +--> +<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.4</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/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..c56e6125 --- /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, 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.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/AnnotationInitializerTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationInitializerTest.java new file mode 100644 index 00000000..01a721f5 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/AnnotationInitializerTest.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * 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.java5; + +import static org.junit.Assert.assertEquals; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.AnnotationInitializerTarget; + +/** + * 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); + } + +} 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..cb6758bd --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BadCycleClassTest.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * 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.java5; + +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 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", + "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..366730e4 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/BooleanExpressionsTest.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: + * Marc R. Hoffmann - 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.BooleanExpressionsTarget; + +/** + * Tests of basic Java boolean expressions. + */ +public class BooleanExpressionsTest extends ValidationTestBase { + + public BooleanExpressionsTest() { + super(BooleanExpressionsTarget.class); + } + +} 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..cefd5bb2 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ClassInitializerTest.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: + * Marc R. Hoffmann - 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.ClassInitializerTarget; + +/** + * Tests of static initializer in classes. + */ +public class ClassInitializerTest extends ValidationTestBase { + + public ClassInitializerTest() { + super(ClassInitializerTarget.class); + } + +} 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..674b3df6 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ConstructorsTest.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * 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.java5; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.ConstructorsTarget; + +/** + * Tests for different constructors. Private empty constructors without + * arguments are filtered. + */ +public class ConstructorsTest extends ValidationTestBase { + + public ConstructorsTest() { + super(ConstructorsTarget.class); + } + +} 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..5381ae2f --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructureBeforeSuperConstructorTest.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * 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: + * Marc R. Hoffmann - 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.ControlStructureBeforeSuperConstructorTarget; + +/** + * Test of probes before the super constructor call. + */ +public class ControlStructureBeforeSuperConstructorTest + extends ValidationTestBase { + + public ControlStructureBeforeSuperConstructorTest() { + super(ControlStructureBeforeSuperConstructorTarget.class); + } + +} 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..350bbe03 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ControlStructuresTest.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: + * Marc R. Hoffmann - 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.ControlStructuresTarget; + +/** + * Tests of basic Java control structures. + */ +public class ControlStructuresTest extends ValidationTestBase { + + public ControlStructuresTest() { + super(ControlStructuresTarget.class); + } + +} 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..6bc16140 --- /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, 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: + * 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<? 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/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..f11a8b46 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumConstructorTest.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.java5; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.EnumConstructorTarget; + +/** + * Test of filtering of enum constructors. + */ +public class EnumConstructorTest extends ValidationTestBase { + + public EnumConstructorTest() { + super(EnumConstructorTarget.class); + } + +} 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..2653606c --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumImplicitMethodsTest.java @@ -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.java5; + +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 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 new file mode 100644 index 00000000..920c39a7 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/EnumSwitchTest.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * 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.java5; + +import org.jacoco.core.test.validation.Source.Line; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.EnumSwitchTarget; + +/** + * 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); + } + + 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 + assertPartlyCovered(line, 0, 2); + } else { + 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 new file mode 100644 index 00000000..5e0b78c0 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExceptionsTest.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * 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: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.java5; + +import org.jacoco.core.test.validation.Source.Line; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.ExceptionsTarget; + +/** + * Tests of exception based control flow. + */ +public class ExceptionsTest extends ValidationTestBase { + + public ExceptionsTest() { + super(ExceptionsTarget.class); + } + + public void assertCatchNoException(final Line line) { + if (isJDKCompiler) { + assertNotCovered(line); + } else { + assertPartlyCovered(line); + } + } + + public void assertCatchBlockEndNoException(final Line line) { + if (isJDKCompiler) { + assertFullyCovered(line); + } else { + assertEmpty(line); + } + } + + public void assertCatchImplicitException(final Line line) { + if (isJDKCompiler) { + assertFullyCovered(line); + } else { + assertPartlyCovered(line); + } + } + + public void assertCatchBlockEndImplicitException(final Line line) { + if (isJDKCompiler) { + assertNotCovered(line); + } else { + assertEmpty(line); + } + } + + public void assertFinally(final Line line) { + if (isJDKCompiler) { + assertEmpty(line); + } else { + assertFullyCovered(line); + } + } + + 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 new file mode 100644 index 00000000..8b645412 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ExplicitInitialFrameTest.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: + * Marc R. Hoffmann - 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.ExplicitInitialFrameTarget; + +/** + * Test for a methods having a explicit initial frame. + */ +public class ExplicitInitialFrameTest extends ValidationTestBase { + + public ExplicitInitialFrameTest() { + super(ExplicitInitialFrameTarget.class); + } + +} 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..069e35b2 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FieldInitializationInTwoConstructorsTest.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * 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: + * Marc R. Hoffmann - 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.FieldInitializationInTwoConstructorsTarget; + +/** + * Test of field initialization in two constructors. + */ +public class FieldInitializationInTwoConstructorsTest + extends ValidationTestBase { + + public FieldInitializationInTwoConstructorsTest() { + super(FieldInitializationInTwoConstructorsTarget.class); + } + +} 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..91a81247 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FinallyTest.java @@ -0,0 +1,230 @@ +/******************************************************************************* + * 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.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.internal.instr.InstrSupport; +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.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 { + + private Map<Integer, String> tags; + + public FinallyTest() { + super(FinallyTarget.class); + } + + @Before + @Override + public void setup() throws Exception { + super.setup(); + tags = new HashMap<Integer, String>(); + } + + public void assertFinally(final Line line) { + if (isJDKCompiler) { + assertEmpty(line); + } else { + assertFullyCovered(line); + } + } + + 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); + } + } + + public void assertTwoRegionsReturn1(final Line line) { + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { + // https://bugs.openjdk.java.net/browse/JDK-7008643 + assertEmpty(line); + } else { + assertFullyCovered(line); + } + } + + public void assertTwoRegionsReturn2(final Line line) { + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { + // https://bugs.openjdk.java.net/browse/JDK-7008643 + assertEmpty(line); + } else { + assertNotCovered(line); + } + } + + public void assertEmptyTry1(final Line line) { + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { + // compiler bug fixed in javac >= 1.8: + assertPartlyCovered(line); + } else { + assertFullyCovered(line); + } + } + + public void assertEmptyTry2(final Line line) { + if (isJDKCompiler && JAVA_VERSION.isBefore("1.8")) { + // compiler bug fixed in javac >= 1.8: + assertFullyCovered(line); + } else { + assertEmpty(line); + } + } + + public void assertAlwaysCompletesAbruptly0(final Line line) { + if (isJDKCompiler) { + // uncovered case: + assertEmpty(line); + } else { + assertPartlyCovered(line); + } + } + + 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. + */ + private void gotos() throws IOException { + + 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, getTagsWithGotos()); + } + + private Set<String> getTagsWithGotos() throws IOException { + final Set<String> gotoTags = new HashSet<String>(); + + byte[] b = TargetLoader.getClassDataAsBytes(FinallyTarget.class); + + final ClassNode classNode = new ClassNode(); + InstrSupport.classReaderFor(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/FramesTest.java b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FramesTest.java new file mode 100644 index 00000000..88e39039 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/FramesTest.java @@ -0,0 +1,170 @@ +/******************************************************************************* + * 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: + * 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.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) { + ClassReader rc = InstrSupport.classReaderFor(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..b46e9c22 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/ImplicitFieldInitializationTest.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: + * Marc R. Hoffmann - 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.ImplicitFieldInitializationTarget; + +/** + * Test of a implicit field initialization. + */ +public class ImplicitFieldInitializationTest extends ValidationTestBase { + + public ImplicitFieldInitializationTest() { + super(ImplicitFieldInitializationTarget.class); + } + +} 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..ed4843b1 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/InterfaceClassInitializerTest.java @@ -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: + * Marc R. Hoffmann - 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.InterfaceClassInitializerTarget; + +/** + * 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); + } + +} 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..7e13e651 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/StructuredLockingTest.java @@ -0,0 +1,196 @@ +/******************************************************************************* + * 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: + * 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.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.StructuredLockingTarget; +import org.junit.Test; +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 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"); + + ClassNode cn = new ClassNode(); + InstrSupport.classReaderFor(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/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..e4a841d8 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SynchronizedTest.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * 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.java5; + +import org.jacoco.core.test.validation.Source.Line; +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.SynchronizedTarget; + +/** + * Test of filtering of a bytecode that is generated for a synchronized + * statement. + */ +public class SynchronizedTest extends ValidationTestBase { + + public SynchronizedTest() { + super(SynchronizedTarget.class); + } + + public void assertMonitorEnterImplicitException(final Line line) { + if (isJDKCompiler) { + assertFullyCovered(line); + } else { + assertPartlyCovered(line); + } + } + + public void assertMonitorExit(final Line line) { + if (isJDKCompiler) { + // without filter next line covered partly: + assertFullyCovered(line); + } else { + assertEmpty(line); + } + } + + public void assertMonitorExitImplicitException(final Line line) { + if (isJDKCompiler) { + // without filter next line covered partly: + assertNotCovered(line); + } else { + 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 new file mode 100644 index 00000000..ce690bfc --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/SyntheticTest.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * 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.java5; + +import org.jacoco.core.test.validation.ValidationTestBase; +import org.jacoco.core.test.validation.java5.targets.SyntheticTarget; + +/** + * Test of filtering of synthetic methods. + */ +public class SyntheticTest extends ValidationTestBase { + + public SyntheticTest() { + super(SyntheticTarget.class); + } + + public void test_method_count() { + assertMethodCount(5); + } + +} 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..7effe60c --- /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, 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.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.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..841f0961 --- /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, 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.java5.targets; + +/** + * This test target is an annotation with an initializer. + */ +public @interface AnnotationInitializerTarget { + + Object CONST = new Object(); // assertFullyCovered() + + 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 new file mode 100644 index 00000000..c37fa8aa --- /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, 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.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"); // assertFullyCovered() + } + + public Child() { + Stubs.logEvent("childinit"); // assertFullyCovered() + } + + void someMethod() { + Stubs.logEvent("childsomeMethod"); // assertFullyCovered() + } + + } + + 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..6015ceac --- /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, 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: + * 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); // assertPartlyCovered(1, 1) + + /* 2. Boolean comparison result (both cases) */ + for (int i = 0; i < 2; i++) { + nop(i < 1); // assertFullyCovered(0, 2) + } + + /* 3. And */ + if (f() & f()) { // assertFullyCovered(1, 1) + nop(); + } + if (f() & t()) { // assertFullyCovered(1, 1) + nop(); + } + if (t() & f()) { // assertFullyCovered(1, 1) + nop(); + } + if (t() & t()) { // assertFullyCovered(1, 1) + nop(); + } + + /* 4. Conditional And */ + if (f() && f()) { // assertPartlyCovered(3, 1) + nop(); + } + if (f() && t()) { // assertPartlyCovered(3, 1) + nop(); + } + if (t() && f()) { // assertFullyCovered(2, 2) + nop(); + } + if (t() && t()) { // assertFullyCovered(2, 2) + nop(); + } + + /* 5. Or */ + if (f() | f()) { // assertFullyCovered(1, 1) + nop(); + } + if (f() | t()) { // assertFullyCovered(1, 1) + nop(); + } + if (t() | f()) { // assertFullyCovered(1, 1) + nop(); + } + if (t() | t()) { // assertFullyCovered(1, 1) + nop(); + } + + /* 6. Conditional Or */ + if (f() || f()) { // assertFullyCovered(2, 2) + nop(); + } + if (f() || t()) { // assertFullyCovered(2, 2) + nop(); + } + if (t() || f()) { // assertPartlyCovered(3, 1) + nop(); + } + if (t() || t()) { // assertPartlyCovered(3, 1) + nop(); + } + + /* 7. Exclusive Or */ + if (f() ^ f()) { // assertFullyCovered(1, 1) + nop(); + } + if (f() ^ t()) { // assertFullyCovered(1, 1) + nop(); + } + if (t() ^ f()) { // assertFullyCovered(1, 1) + nop(); + } + if (t() ^ t()) { // assertFullyCovered(1, 1) + nop(); + } + + /* 8. Conditional Operator */ + nop(t() ? i1() : i2()); // assertPartlyCovered(1, 1) + nop(f() ? i1() : i2()); // assertPartlyCovered(1, 1) + + /* 9. Not (one case) */ + nop(!t()); // assertPartlyCovered(1, 1) + nop(!f()); // assertPartlyCovered(1, 1) + + /* 10. Not (both cases) */ + for (boolean b : new boolean[] { true, false }) { + 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 new file mode 100644 index 00000000..5b1f5543 --- /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, 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: + * 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; // assertEmpty() + + public static final String CONST2 = "Hello"; // assertEmpty() + + /* These fields are initialized within <clinit> */ + + public static final int CONST3 = i1(); // assertFullyCovered() + + public static final Object CONST4 = new Object(); // assertFullyCovered() + + public static int field1 = 3; // assertFullyCovered() + + public static String field2 = "Hello"; // assertFullyCovered() + + public static int field3 = i1(); // assertFullyCovered() + + public static Object field4 = new Object(); // assertFullyCovered() + + static { + Stubs.nop(); // assertFullyCovered() + } + + 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..f818440e --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ConstructorsTarget.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * 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.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target calls different constructors. + */ +public class ConstructorsTarget { + + /* not filtered because not private: */ + ConstructorsTarget() { // assertFullyCovered() + } + + /* not filtered because has argument: */ + private ConstructorsTarget(Object arg) { // assertFullyCovered() + } + + private static class Super extends ConstructorsTarget { + private Super() { + /* + * not filtered because not empty - prepares arguments for super + * constructor: + */ + super(null); // assertFullyCovered() + } + } + + private class 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() + } + } + + private static class InnerStatic { + @SuppressWarnings("unused") + private final Object field = this; + + /* + * not filtered because not empty - contains initialization of a field: + */ + private InnerStatic() { // assertFullyCovered() + } + } + + /* + * not filtered because default constructor for not private inner classes is + * not private: + */ + public static class PublicDefault { // assertFullyCovered() + } + + static class PackageLocalDefault { // assertFullyCovered() + } + + private static class PrivateDefault { // assertEmpty() + } + + private static class PrivateNonEmptyNoArg { + private PrivateNonEmptyNoArg() { + nop(); // assertFullyCovered() + } + } + + private static class PrivateEmptyNoArg { + private PrivateEmptyNoArg() { // assertEmpty() + } // assertEmpty() + } + + 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..3af40473 --- /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, 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: + * 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()); // assertPartlyCovered(3, 1) + } + + 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..571adca1 --- /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, 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: + * 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(); // assertFullyCovered() + + } + + private static void missedIfBlock() { + + if (f()) { // assertFullyCovered(1, 1) + nop(); // assertNotCovered() + } else { + nop(); // assertFullyCovered() + } + + } + + private static void executedIfBlock() { + + if (t()) { // assertFullyCovered(1, 1) + nop(); // assertFullyCovered() + } else { + nop(); // assertNotCovered() + } + + } + + private static void missedWhileBlock() { + + while (f()) { // assertFullyCovered(1, 1) + nop(); // assertNotCovered() + } + + } + + private static void alwaysExecutedWhileBlock() { + + while (t()) { // assertFullyCovered(1, 1) + if (t()) { + break; + } + } + + } + + private static void executedWhileBlock() { + + int i = 0; + while (i++ < 3) { // assertFullyCovered(0, 2) + nop(); // assertFullyCovered() + } + + } + + private static void executedDoWhileBlock() { + + do { + nop(); // assertFullyCovered() + } while (f()); // assertFullyCovered(1, 1) + + } + + private static void missedForBlock() { + + for (nop(); f(); nop()) { // assertPartlyCovered(1, 1) + nop(); // assertNotCovered() + } + + } + + private static void executedForBlock() { + + for (int j = 0; j < 1; j++) { // assertFullyCovered(0, 2) + nop(); // assertFullyCovered() + } + + } + + private static void missedForEachBlock() { + + for (Object o : Collections.emptyList()) { // assertPartlyCovered(1, 1) + nop(o); // assertNotCovered() + } + + } + + private static void executedForEachBlock() { + + for (Object o : Collections.singleton(new Object())) { // assertFullyCovered(0,2) + nop(o); // assertFullyCovered() + } + + } + + private static void tableSwitchWithHit() { + + switch (i2()) { // assertFullyCovered(3, 1) + case 1: + nop(); // assertNotCovered() + break; + case 2: + nop(); // assertFullyCovered() + break; + case 3: + nop(); // assertNotCovered() + break; + default: + nop(); // assertNotCovered() + break; + } + + } + + private static void continuedTableSwitchWithHit() { + + switch (i2()) { // assertFullyCovered(3, 1) + case 1: + nop(); // assertNotCovered() + case 2: + nop(); // assertFullyCovered() + case 3: + nop(); // assertFullyCovered() + default: + nop(); // assertFullyCovered() + } + + } + + private static void tableSwitchWithoutHit() { + + switch (i2()) { // assertFullyCovered(3, 1) + case 3: + nop(); // assertNotCovered() + break; + case 4: + nop(); // assertNotCovered() + break; + case 5: + nop(); // assertNotCovered() + break; + default: + nop(); // assertFullyCovered() + break; + } + + } + + private static void lookupSwitchWithHit() { + + switch (i2()) { // assertFullyCovered(3, 1) + case -123: + nop(); // assertNotCovered() + break; + case 2: + nop(); // assertFullyCovered() + break; + case 456: + nop(); // assertNotCovered() + break; + default: + nop(); // assertNotCovered() + break; + } + + } + + private static void continuedLookupSwitchWithHit() { + + switch (i2()) { // assertFullyCovered(3, 1) + case -123: + nop(); // assertNotCovered() + case 2: + nop(); // assertFullyCovered() + case 456: + nop(); // assertFullyCovered() + default: + nop(); // assertFullyCovered() + } + + } + + private static void lookupSwitchWithoutHit() { + + switch (i2()) { // assertFullyCovered(3, 1) + case -123: + nop(); // assertNotCovered() + break; + case 456: + nop(); // assertNotCovered() + break; + case 789: + nop(); // assertNotCovered() + break; + default: + nop(); // assertFullyCovered() + break; + } + + } + + private static void breakStatement() { + + while (true) { + if (t()) { + break; // assertFullyCovered() + } + nop(); // assertNotCovered() + } + + } + + private static void continueStatement() { + + for (int j = 0; j < 1; j++) { + if (t()) { + continue; // assertFullyCovered() + } + nop(); // assertNotCovered() + } + + } + + private static void conditionalReturn() { + + if (t()) { + return; // assertFullyCovered() + } + nop(); // assertNotCovered() + + } + + private static void implicitReturn() { + + } // assertFullyCovered() + + private static void explicitReturn() { + + return; // assertFullyCovered() + + } // 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 new file mode 100644 index 00000000..5b526b94 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/EnumConstructorTarget.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * 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.java5.targets; + +import static org.jacoco.core.test.validation.targets.Stubs.nop; + +/** + * This test target is an enum constructor. + */ +public class EnumConstructorTarget { + + /* + * 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(); // assertNotCovered() + } + } + + /* Explicit empty constructor should be filtered: */ + private enum ExplicitEmptyConstructor { + ; + + ExplicitEmptyConstructor() { + /* without filter next line is not covered: */ + } // assertEmpty() + + ExplicitEmptyConstructor(Object p) { + } // assertNotCovered() + } + + 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..687bc4ec --- /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, 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.java5.targets; + +import org.jacoco.core.test.validation.targets.Stubs; + +public enum EnumImplicitMethodsTarget { // assertFullyCovered() + + CONST(Stubs.f() ? new Object() : new Object()); // assertPartlyCovered(1, 1) + + static { + } // 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. + */ + EnumImplicitMethodsTarget(Object o) { // assertFullyCovered() + } // assertFullyCovered() + + /** + * 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() { + } // assertNotCovered() + + /** + * 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) { + } // 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 new file mode 100644 index 00000000..51ca47e4 --- /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, 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.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) { // assertSwitch() + 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..efac5a69 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/ExceptionsTarget.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * 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: + * 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) { + } + } + + /** + * 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(); // 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(); // assertFullyCovered() + ex(); // assertNotCovered() + nop(); // assertNotCovered() + } + + private static void explicitException() { + nop(); // assertFullyCovered() + throw new StubException(); // assertFullyCovered() + } + + private static void noExceptionTryCatch() { + nop(); // assertFullyCovered() + try { + nop(); // assertFullyCovered() + } catch (StubException e) { // assertCatchNoException() + nop(); // assertNotCovered() + } // assertCatchBlockEndNoException() + } // assertFullyCovered() + + private static void implicitExceptionTryCatch() { + nop(); // assertFullyCovered() + try { + 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()) { // assertFullyCovered(1, 1) + return; + } + try { + ex(); // assertNotCovered() + } catch (StubException e) { + nop(); // assertFullyCovered() + } + } + + private static void explicitExceptionTryCatch() { + nop(); // assertFullyCovered() + try { + nop(); // assertFullyCovered() + throw new StubException(); // assertFullyCovered() + } catch (StubException e) { // assertFullyCovered() + nop(); // assertFullyCovered() + } // assertEmpty() + } // assertFullyCovered() + + private static void noExceptionFinally() { + nop(); // assertFullyCovered() + try { + nop(); // assertFullyCovered() + } finally { // assertFinally() + nop(); // assertFullyCovered() + } // assertEmpty() + } // assertFullyCovered() + + private static void implicitExceptionFinally() { + nop(); // assertFullyCovered() + try { + nop(); // assertFullyCovered() + ex(); // assertNotCovered() + nop(); // assertNotCovered() + } finally { // assertFinallyImplicitException() + nop(); // assertFullyCovered() + } // assertEmpty() + } // assertNotCovered() + + private static void explicitExceptionFinally() { + nop(); // assertFullyCovered() + try { + 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 new file mode 100644 index 00000000..475de0a4 --- /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, 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: + * 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(); // 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 new file mode 100644 index 00000000..b79b9224 --- /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, 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: + * 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; // assertPartlyCovered() + + int field2 = 123; // assertPartlyCovered() + + public FieldInitializationInTwoConstructorsTarget() { + } // assertFullyCovered() + + public FieldInitializationInTwoConstructorsTarget(String arg) { + } // 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 new file mode 100644 index 00000000..66aeabec --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/FinallyTarget.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * 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.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 { + + /** + * <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 { // assertFinally() tag("example.0") + if (in != null) { // assertFullyCovered(0, 2) + nop(); // assertFullyCovered() tag("example.2") + } // assertEmpty() + } // assertEmpty() + } + + private static Object open(boolean t) { + ex(t); + 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. + * <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>. + */ + private static void breakStatement() { + for (int i = 0; i < 1; i++) { // tag("breakStatement.for") + try { + if (f()) { + break; // assertEmpty() tag("breakStatement") + } + } finally { + nop("finally"); // assertFullyCovered() tag("breakStatement.1") + } // assertEmpty() tag("breakStatement.2") + } + } + + private static void catchNotExecuted() { + try { + nop("try"); + } 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) { // 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()) { // assertFullyCovered(1, 1) + nop(); // assertFullyCovered() + return; // assertTwoRegionsReturn1() + } else { + nop(); // assertNotCovered() + return; // assertTwoRegionsReturn2() + } + } finally { // assertEmpty() + nop(); // assertTwoRegions1() + } // assertEmpty() + } + + private static void nested() { + try { + nop(); + } 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 { // assertEmpty() + nop(); // assertEmptyTry1() + } // assertEmptyTry2() tag("emptyTry.2") + } + + @SuppressWarnings("finally") + private static void alwaysCompletesAbruptly() { + try { + nop(); + } finally { // assertAlwaysCompletesAbruptly0()tag("alwaysCompletesAbruptly.0") + return; // assertAlwaysCompletesAbruptly1() + } // assertEmpty() + } + + 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..46433454 --- /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, 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: + * 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 { // assertFullyCovered() + + Object field1; // assertEmpty() + + Object field2 = this; // assertFullyCovered() + + int field3; // assertEmpty() + + 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 new file mode 100644 index 00000000..81bcda82 --- /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, 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: + * 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; // assertEmpty() + + static final String CONST2 = "const"; // assertEmpty() + + /* These fields are initialized within <clinit> */ + + static final int CONST3 = i1(); // assertFullyCovered() + + static final Object CONST4 = new Object(); // assertFullyCovered() + +} 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..76b57f93 --- /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, 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: + * 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..b9b9ce66 --- /dev/null +++ b/org.jacoco.core.test.validation.java5/src/org/jacoco/core/test/validation/java5/targets/SynchronizedTarget.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * 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.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(); // 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) { // assertFullyCovered() + throw new StubException(); // assertFullyCovered() + } // assertEmpty() + } + + private static void implicitException() { + synchronized (lock) { // assertMonitorEnterImplicitException() + ex(); // assertNotCovered() + } // assertMonitorExitImplicitException() + } + + 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..efede92d --- /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, 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.java5.targets; + +/** + * This test target results in synthetic methods. + */ +public class SyntheticTarget { // assertEmpty() + + private static int counter; // assertEmpty() + + /** + * {@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. + */ + private SyntheticTarget() { + } + + static class Inner extends SyntheticTarget { // assertEmpty() + + 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(); + } + +} |