diff options
author | Evgeny Mandrikov <Godin@users.noreply.github.com> | 2016-08-16 04:06:56 +0200 |
---|---|---|
committer | Marc R. Hoffmann <hoffmann@mountainminds.com> | 2016-08-16 04:06:56 +0200 |
commit | 28a112ca6c6f46cd385f00aa932ec0e334e045a7 (patch) | |
tree | 9d92399e1a2e797a87d560e49fc092e0017a113d /org.jacoco.core.test | |
parent | c6f2b6b7e887eb645b8aba928ff0134cfe66ec28 (diff) | |
download | platform_external_jacoco-28a112ca6c6f46cd385f00aa932ec0e334e045a7.tar.gz platform_external_jacoco-28a112ca6c6f46cd385f00aa932ec0e334e045a7.tar.bz2 platform_external_jacoco-28a112ca6c6f46cd385f00aa932ec0e334e045a7.zip |
Do not violate JVMS regarding initialization of final fields (#434)
Without this change instrumented classes can't pass checks
and cause IllegalAccessError starting from OpenJDK 9 EA b127
(see https://bugs.openjdk.java.net/browse/JDK-8157181).
Diffstat (limited to 'org.jacoco.core.test')
14 files changed, 530 insertions, 50 deletions
diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BadCycleInterfaceTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BadCycleInterfaceTest.java new file mode 100644 index 00000000..1b76d98d --- /dev/null +++ b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BadCycleInterfaceTest.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.BadCycleInterface; +import org.junit.Test; + +/** + * Test of "bad cycles" with interfaces. + */ +public class BadCycleInterfaceTest extends BadCycleTestBase { + + public BadCycleInterfaceTest() throws Exception { + super("src-java8", BadCycleInterface.class); + } + + @Test + public void test() throws Exception { + loader.loadClass(BadCycleInterface.Child.class.getName()) + .getMethod("childStaticMethod").invoke(null); + + analyze(BadCycleInterface.Child.class); + + if (System.getProperty("java.version").startsWith("9-ea")) { + // JDK-9042842 + assertLine("2", ICounter.NOT_COVERED); + } else { + assertLine("2", ICounter.FULLY_COVERED); + } + assertLine("4", ICounter.FULLY_COVERED); + } + +} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java index 405c4cff..66c3843d 100644 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java +++ b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceDefaultMethodsTest.java @@ -16,7 +16,7 @@ import org.jacoco.core.test.validation.targets.InterfaceDefaultMethodsTarget; import org.junit.Test; /** - * Tests of static initializer in interfaces. + * Tests of static initializer and default methods in interfaces. */ public class InterfaceDefaultMethodsTest extends ValidationTestBase { diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java new file mode 100644 index 00000000..24553d70 --- /dev/null +++ b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/InterfaceOnlyDefaultMethodsTest.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.InterfaceOnlyDefaultMethodsTarget; +import org.junit.Test; + +/** + * Tests of default methods in interfaces. + */ +public class InterfaceOnlyDefaultMethodsTest extends ValidationTestBase { + + public InterfaceOnlyDefaultMethodsTest() { + super("src-java8", InterfaceOnlyDefaultMethodsTarget.class); + } + + @Override + protected void run(final Class<?> targetClass) throws Exception { + loader.add(InterfaceOnlyDefaultMethodsTarget.Impl.class).newInstance(); + } + + @Test + public void testCoverageResult() { + assertLine("m1", ICounter.FULLY_COVERED); + assertLine("m2", ICounter.NOT_COVERED); + } + +} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/BadCycleInterface.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/BadCycleInterface.java new file mode 100644 index 00000000..c2b1519f --- /dev/null +++ b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/BadCycleInterface.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.targets; + +public class BadCycleInterface { + + public interface Base { + static final Object BASE_CONST = new Child() { + { + Stubs.nop("base clinit"); // $line-1$ + } + }.childDefaultMethod(); + + default void baseDefaultMethod() { + } + } + + public interface Child extends Base { + static final Object CHILD_CONST = new Object() { + { + Stubs.nop("child clinit"); // $line-3$ + } + }; + + default Object childDefaultMethod() { + Stubs.nop("child default method"); // $line-2$ + return null; + } + + static void childStaticMethod() { + Stubs.nop("child static method"); // $line-4$ + } + } + + public static void main(String[] args) { + Child.childStaticMethod(); + } + +} diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java index 65028b99..4bd91b39 100644 --- a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java +++ b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceDefaultMethodsTarget.java @@ -14,7 +14,7 @@ package org.jacoco.core.test.validation.targets; import static org.jacoco.core.test.validation.targets.Stubs.i1; /** - * This test target is an interface with a class initializer. + * This test target is an interface with a class initializer and default methods. */ public interface InterfaceDefaultMethodsTarget { diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java new file mode 100644 index 00000000..a27409e9 --- /dev/null +++ b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/targets/InterfaceOnlyDefaultMethodsTarget.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.targets; + +/** + * This test target is an interface with only default methods. + */ +public interface InterfaceOnlyDefaultMethodsTarget { + + // no <clinit>, only default methods: + + default void m1() { + return; // $line-m1$ + } + + default void m2() { + return; // $line-m2$ + } + + public class Impl implements InterfaceOnlyDefaultMethodsTarget { + + public Impl() { + m1(); + } + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ClassInstrumenterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ClassInstrumenterTest.java index 428ba653..5d417712 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ClassInstrumenterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ClassInstrumenterTest.java @@ -62,7 +62,7 @@ public class ClassInstrumenterTest implements IProbeArrayStrategy { // === IProbeArrayStrategy === - public int storeInstance(MethodVisitor mv, int variable) { + public int storeInstance(MethodVisitor mv, boolean clinit, int variable) { return 0; } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java index c8da6d6d..3ecbd3ad 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactoryTest.java @@ -14,7 +14,10 @@ package org.jacoco.core.internal.instr; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; import org.jacoco.core.runtime.IExecutionDataAccessorGenerator; import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator; @@ -98,9 +101,8 @@ public class ProbeArrayStrategyFactoryTest { assertDataField(InstrSupport.DATAFIELD_ACC); assertInitMethod(true); - final ClassVisitorMock cv = new ClassVisitorMock(); - strategy.storeInstance(cv.visitMethod(0, null, null, null, null), 0); - assertFalse(cv.interfaceMethod); + strategy.storeInstance(cv.visitMethod(0, null, null, null, null), false, + 0); } @Test @@ -119,21 +121,21 @@ public class ProbeArrayStrategyFactoryTest { @Test(expected = UnsupportedOperationException.class) public void testEmptyInterface7StoreInstance() { - IProbeArrayStrategy strategy = test(Opcodes.V1_7, - Opcodes.ACC_INTERFACE, false, false); - strategy.storeInstance(null, 0); + IProbeArrayStrategy strategy = test(Opcodes.V1_7, Opcodes.ACC_INTERFACE, + false, false); + strategy.storeInstance(null, false, 0); } @Test public void testInterface8() { + cv.isInterface = true; final IProbeArrayStrategy strategy = test(Opcodes.V1_8, Opcodes.ACC_INTERFACE, false, true); assertDataField(InstrSupport.DATAFIELD_INTF_ACC); - assertInitMethod(true); + assertInitAndClinitMethods(); - final ClassVisitorMock cv = new ClassVisitorMock(); - strategy.storeInstance(cv.visitMethod(0, null, null, null, null), 0); - assertTrue(cv.interfaceMethod); + strategy.storeInstance(cv.visitMethod(0, null, null, null, null), false, + 0); } @Test @@ -143,6 +145,13 @@ public class ProbeArrayStrategyFactoryTest { assertNoInitMethod(); } + @Test(expected = UnsupportedOperationException.class) + public void testEmptyInterface8StoreInstance() { + final IProbeArrayStrategy strategy = test(Opcodes.V1_8, + Opcodes.ACC_INTERFACE, false, false); + strategy.storeInstance(null, false, 0); + } + @Test public void testClinitInterface8() { test(Opcodes.V1_8, Opcodes.ACC_INTERFACE, true, false); @@ -150,6 +159,18 @@ public class ProbeArrayStrategyFactoryTest { assertNoInitMethod(); } + @Test + public void testClinitAndMethodsInterface8() { + cv.isInterface = true; + final IProbeArrayStrategy strategy = test(Opcodes.V1_8, + Opcodes.ACC_INTERFACE, true, true); + assertDataField(InstrSupport.DATAFIELD_INTF_ACC); + assertInitAndClinitMethods(); + + strategy.storeInstance(cv.visitMethod(0, "<clinit>", null, null, null), + true, 0); + } + private IProbeArrayStrategy test(int version, int access, boolean clinit, boolean method) { ClassWriter writer = new ClassWriter(0); @@ -179,16 +200,40 @@ public class ProbeArrayStrategyFactoryTest { return strategy; } + private static class AddedMethod { + private final int access; + private final String name; + private final String desc; + private boolean frames; + + AddedMethod(int access, String name, String desc) { + this.access = access; + this.name = name; + this.desc = desc; + } + + void assertInitMethod(boolean frames) { + assertEquals(InstrSupport.INITMETHOD_NAME, name); + assertEquals(InstrSupport.INITMETHOD_DESC, desc); + assertEquals(InstrSupport.INITMETHOD_ACC, access); + assertEquals(Boolean.valueOf(frames), Boolean.valueOf(frames)); + } + + void assertClinit() { + assertEquals(InstrSupport.CLINIT_NAME, name); + assertEquals(InstrSupport.CLINIT_DESC, desc); + assertEquals(InstrSupport.CLINIT_ACC, access); + assertEquals(Boolean.valueOf(false), Boolean.valueOf(frames)); + } + } + private static class ClassVisitorMock extends ClassVisitor { + private boolean isInterface; + private int fieldAccess; private String fieldName; - - private int methodAccess; - private String methodName; - - private boolean frames; - private boolean interfaceMethod; + private final List<AddedMethod> methods = new ArrayList<AddedMethod>(); ClassVisitorMock() { super(Opcodes.ASM5); @@ -206,20 +251,51 @@ public class ProbeArrayStrategyFactoryTest { @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - assertNull(methodName); - methodAccess = access; - methodName = name; + final AddedMethod m = new AddedMethod(access, name, desc); + methods.add(m); return new MethodVisitor(Opcodes.ASM5) { @Override public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { - frames = true; + m.frames = true; + } + + @Override + public void visitFieldInsn(int opcode, String owner, + String name, String desc) { + assertEquals(InstrSupport.DATAFIELD_NAME, name); + assertEquals(InstrSupport.DATAFIELD_DESC, desc); + + if (opcode == Opcodes.GETSTATIC) { + assertEquals(InstrSupport.INITMETHOD_NAME, + methods.get(methods.size() - 1).name); + } else if (opcode == Opcodes.PUTSTATIC) { + if (isInterface) { + assertEquals(InstrSupport.CLINIT_NAME, + methods.get(methods.size() - 1).name); + } else { + assertEquals(InstrSupport.INITMETHOD_NAME, + methods.get(methods.size() - 1).name); + } + } else { + fail(); + } } @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { - interfaceMethod = itf; + if ("getProbes".equals(name)) { + // method's owner is not interface: + assertFalse(itf); + return; + } + assertEquals(itf, isInterface); + + assertEquals(Opcodes.INVOKESTATIC, opcode); + assertEquals("Foo", owner); + assertEquals(InstrSupport.INITMETHOD_NAME, name); + assertEquals(InstrSupport.INITMETHOD_DESC, desc); } }; } @@ -235,13 +311,18 @@ public class ProbeArrayStrategyFactoryTest { } void assertInitMethod(boolean frames) { - assertEquals(InstrSupport.INITMETHOD_NAME, cv.methodName); - assertEquals(InstrSupport.INITMETHOD_ACC, cv.methodAccess); - assertEquals(Boolean.valueOf(frames), Boolean.valueOf(cv.frames)); + assertEquals(cv.methods.size(), 1); + cv.methods.get(0).assertInitMethod(frames); + } + + void assertInitAndClinitMethods() { + assertEquals(2, cv.methods.size()); + cv.methods.get(0).assertInitMethod(true); + cv.methods.get(1).assertClinit(); } void assertNoInitMethod() { - assertNull(cv.methodName); + assertEquals(0, cv.methods.size()); } } diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeInserterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeInserterTest.java index 6f2d7ec4..6a2f9c69 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeInserterTest.java +++ b/org.jacoco.core.test/src/org/jacoco/core/internal/instr/ProbeInserterTest.java @@ -39,9 +39,8 @@ public class ProbeInserterTest { expected = new MethodRecorder(); expectedVisitor = expected.getVisitor(); arrayStrategy = new IProbeArrayStrategy() { - - public int storeInstance(MethodVisitor mv, int variable) { - mv.visitLdcInsn("init"); + public int storeInstance(MethodVisitor mv, boolean clinit, int variable) { + mv.visitLdcInsn(clinit ? "clinit" : "init"); return 5; } @@ -57,7 +56,7 @@ public class ProbeInserterTest { @Test public void testVariableStatic() { - ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "()V", + ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "m", "()V", actualVisitor, arrayStrategy); pi.insertProbe(0); @@ -69,7 +68,7 @@ public class ProbeInserterTest { @Test public void testVariableNonStatic() { - ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor, + ProbeInserter pi = new ProbeInserter(0, "m", "()V", actualVisitor, arrayStrategy); pi.insertProbe(0); @@ -81,7 +80,7 @@ public class ProbeInserterTest { @Test public void testVariableNonStatic_IZObject() { - ProbeInserter pi = new ProbeInserter(0, "(IZLjava/lang/Object;)V", + ProbeInserter pi = new ProbeInserter(0, "m", "(IZLjava/lang/Object;)V", actualVisitor, arrayStrategy); pi.insertProbe(0); @@ -93,7 +92,7 @@ public class ProbeInserterTest { @Test public void testVariableNonStatic_JD() { - ProbeInserter pi = new ProbeInserter(0, "(JD)V", actualVisitor, + ProbeInserter pi = new ProbeInserter(0, "m", "(JD)V", actualVisitor, arrayStrategy); pi.insertProbe(0); @@ -105,7 +104,7 @@ public class ProbeInserterTest { @Test public void testVisitCode() { - ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor, + ProbeInserter pi = new ProbeInserter(0, "m", "()V", actualVisitor, arrayStrategy); pi.visitCode(); @@ -113,8 +112,17 @@ public class ProbeInserterTest { } @Test + public void testVisitClinit() { + ProbeInserter pi = new ProbeInserter(0, "<clinit>", "()V", + actualVisitor, arrayStrategy); + pi.visitCode(); + + expectedVisitor.visitLdcInsn("clinit"); + } + + @Test public void testVisitVarIns() { - ProbeInserter pi = new ProbeInserter(0, "(II)V", actualVisitor, + ProbeInserter pi = new ProbeInserter(0, "m", "(II)V", actualVisitor, arrayStrategy); pi.visitVarInsn(Opcodes.ALOAD, 0); @@ -135,7 +143,7 @@ public class ProbeInserterTest { @Test public void testVisitIincInsn() { - ProbeInserter pi = new ProbeInserter(0, "(II)V", actualVisitor, + ProbeInserter pi = new ProbeInserter(0, "m", "(II)V", actualVisitor, arrayStrategy); pi.visitIincInsn(0, 100); pi.visitIincInsn(1, 101); @@ -155,7 +163,7 @@ public class ProbeInserterTest { @Test public void testVisitLocalVariable() { - ProbeInserter pi = new ProbeInserter(0, "(II)V", actualVisitor, + ProbeInserter pi = new ProbeInserter(0, "m", "(II)V", actualVisitor, arrayStrategy); pi.visitLocalVariable(null, null, null, null, null, 0); @@ -176,7 +184,7 @@ public class ProbeInserterTest { @Test public void testVisitMaxs1() { - ProbeInserter pi = new ProbeInserter(0, "(II)V", actualVisitor, + ProbeInserter pi = new ProbeInserter(0, "m", "(II)V", actualVisitor, arrayStrategy); pi.visitCode(); pi.visitMaxs(0, 8); @@ -187,7 +195,7 @@ public class ProbeInserterTest { @Test public void testVisitMaxs2() { - ProbeInserter pi = new ProbeInserter(0, "(II)V", actualVisitor, + ProbeInserter pi = new ProbeInserter(0, "m", "(II)V", actualVisitor, arrayStrategy); pi.visitCode(); pi.visitMaxs(10, 8); @@ -198,7 +206,7 @@ public class ProbeInserterTest { @Test public void testVisitFrame() { - ProbeInserter pi = new ProbeInserter(0, "(J)V", actualVisitor, + ProbeInserter pi = new ProbeInserter(0, "m", "(J)V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_NEW, 3, new Object[] { "Foo", Opcodes.LONG, @@ -210,7 +218,7 @@ public class ProbeInserterTest { @Test public void testVisitFrameNoLocals() { - ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "()V", + ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "m", "()V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 0, new Object[0]); @@ -221,7 +229,7 @@ public class ProbeInserterTest { @Test public void testVisitFrameProbeAt0() { - ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "()V", + ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "m", "()V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_NEW, 2, new Object[] { Opcodes.DOUBLE, "Foo" }, @@ -233,7 +241,7 @@ public class ProbeInserterTest { @Test public void testFillOneWord() { - ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "(I)V", + ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "m", "(I)V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 0, new Object[] {}); @@ -245,7 +253,7 @@ public class ProbeInserterTest { @Test public void testFillTwoWord() { - ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "(J)V", + ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "m", "(J)V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 0, new Object[] {}); @@ -257,7 +265,7 @@ public class ProbeInserterTest { @Test public void testFillPartly() { - ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "(DIJ)V", + ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "m", "(DIJ)V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_NEW, 1, new Object[] { Opcodes.DOUBLE }, 0, @@ -271,7 +279,7 @@ public class ProbeInserterTest { @Test(expected = IllegalArgumentException.class) public void testVisitFrame_invalidType() { - ProbeInserter pi = new ProbeInserter(0, "()V", actualVisitor, + ProbeInserter pi = new ProbeInserter(0, "m", "()V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_SAME, 0, null, 0, null); } diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/InstrumentingLoader.java b/org.jacoco.core.test/src/org/jacoco/core/test/InstrumentingLoader.java new file mode 100644 index 00000000..99bbaedb --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/InstrumentingLoader.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms 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; + +import java.io.IOException; +import java.io.InputStream; + +import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.data.SessionInfoStore; +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.RuntimeData; +import org.jacoco.core.runtime.SystemPropertiesRuntime; + +public final class InstrumentingLoader extends ClassLoader { + + private final RuntimeData data; + private final IRuntime runtime; + + public InstrumentingLoader() throws Exception { + data = new RuntimeData(); + runtime = new SystemPropertiesRuntime(); + runtime.startup(data); + } + + @Override + protected synchronized Class<?> loadClass(String name, boolean resolve) + throws ClassNotFoundException { + if (name.startsWith("org.jacoco.core.test.validation.targets.")) { + final byte[] bytes; + try { + bytes = getClassBytes(name); + } catch (IOException e) { + throw new ClassNotFoundException("Unable to load", e); + } + final byte[] instrumented; + try { + instrumented = new Instrumenter(runtime).instrument(bytes, + name); + } catch (IOException e) { + throw new ClassNotFoundException("Unable to instrument", e); + } + final Class<?> c = defineClass(name, instrumented, 0, + instrumented.length); + if (resolve) { + resolveClass(c); + } + return c; + } + return super.loadClass(name, resolve); + } + + public byte[] getClassBytes(String name) throws IOException { + final String resource = "/" + name.replace('.', '/') + ".class"; + final InputStream in = getClass().getResourceAsStream(resource); + return TargetLoader.getClassDataAsBytes(in); + } + + public ExecutionDataStore collect() { + final ExecutionDataStore store = new ExecutionDataStore(); + data.collect(store, new SessionInfoStore(), false); + runtime.shutdown(); + return store; + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/TargetLoader.java b/org.jacoco.core.test/src/org/jacoco/core/test/TargetLoader.java index 00bab63e..de54015f 100644 --- a/org.jacoco.core.test/src/org/jacoco/core/test/TargetLoader.java +++ b/org.jacoco.core.test/src/org/jacoco/core/test/TargetLoader.java @@ -58,7 +58,11 @@ public class TargetLoader extends ClassLoader { } public static byte[] getClassDataAsBytes(Class<?> clazz) throws IOException { - InputStream in = getClassData(clazz); + return getClassDataAsBytes(getClassData(clazz)); + } + + public static byte[] getClassDataAsBytes(InputStream in) throws + IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] buffer = new byte[0x100]; int len; diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/BadCycleClassTest.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/BadCycleClassTest.java new file mode 100644 index 00000000..47820e68 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/BadCycleClassTest.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.test.validation.targets.BadCycleClass; +import org.junit.Test; + +/** + * Test of "bad cycles" with classes. + */ +public class BadCycleClassTest extends BadCycleTestBase { + + public BadCycleClassTest() throws Exception { + super(BadCycleClass.class); + } + + @Test + public void test() throws Exception { + loader.loadClass(BadCycleClass.Child.class.getName()).newInstance(); + + analyze(BadCycleClass.Child.class); + assertLine("1", ICounter.FULLY_COVERED); + assertLine("2", ICounter.FULLY_COVERED); + assertLine("3", ICounter.FULLY_COVERED); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/BadCycleTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/BadCycleTestBase.java new file mode 100644 index 00000000..dd7b4992 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/BadCycleTestBase.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import static org.junit.Assert.assertEquals; + +import java.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.ISourceFileCoverage; +import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.test.InstrumentingLoader; + +class BadCycleTestBase extends ValidationTestBase { + + protected final InstrumentingLoader loader = new InstrumentingLoader(); + + BadCycleTestBase(final Class<?> target) throws Exception { + super(target); + } + + BadCycleTestBase(final String srcFolder, final Class<?> target) + throws Exception { + super(srcFolder, target); + } + + @Override + public final void setup() throws Exception { + // nop + } + + @Override + protected final void run(Class<?> targetClass) throws Exception { + // nop + } + + final void analyze(Class<?> cls) throws IOException { + final byte[] bytes = loader.getClassBytes(cls.getName()); + final ExecutionDataStore store = loader.collect(); + + final CoverageBuilder builder = new CoverageBuilder(); + final Analyzer analyzer = new Analyzer(store, builder); + analyzer.analyzeClass(bytes, "TestTarget"); + final Collection<IClassCoverage> classes = builder.getClasses(); + assertEquals(1, classes.size(), 0.0); + classCoverage = classes.iterator().next(); + final Collection<ISourceFileCoverage> files = builder.getSourceFiles(); + assertEquals(1, files.size(), 0.0); + sourceCoverage = files.iterator().next(); + + source = Source.getSourceFor(srcFolder, target); + } + +} diff --git a/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/BadCycleClass.java b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/BadCycleClass.java new file mode 100644 index 00000000..44e40cd1 --- /dev/null +++ b/org.jacoco.core.test/src/org/jacoco/core/test/validation/targets/BadCycleClass.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation.targets; + +public class BadCycleClass { + + public static class Base { + static final Child b = new Child(); + + static { + b.someMethod(); + } + } + + public static class Child extends Base { + + static { + Stubs.nop("child clinit"); // $line-3$ + } + + public Child() { + Stubs.nop("child init"); // $line-1$ + } + + void someMethod() { + Stubs.nop("child someMethod"); // $line-2$ + } + + } + + public static void main(String[] args) { + new Child(); + } + +} |