/******************************************************************************* * Copyright (c) 2009, 2017 Mountainminds GmbH & Co. KG and Contributors * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Marc R. Hoffmann - initial API and implementation * *******************************************************************************/ package org.jacoco.core.internal.instr; import static org.junit.Assert.assertEquals; import org.jacoco.core.instr.MethodRecorder; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * Unit tests for {@link ProbeInserter}. */ public class ProbeInserterTest { private MethodRecorder actual, expected; private MethodVisitor actualVisitor, expectedVisitor; private IProbeArrayStrategy arrayStrategy; @Before public void setup() { actual = new MethodRecorder(); actualVisitor = actual.getVisitor(); expected = new MethodRecorder(); expectedVisitor = expected.getVisitor(); arrayStrategy = new IProbeArrayStrategy() { public int storeInstance(MethodVisitor mv, boolean clinit, int variable) { mv.visitLdcInsn(clinit ? "clinit" : "init"); return 5; } public void addMembers(ClassVisitor delegate, int probeCount) { } }; } @After public void verify() { assertEquals(expected, actual); } @Test public void testVariableStatic() { ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "m", "()V", actualVisitor, arrayStrategy); pi.insertProbe(0); expectedVisitor.visitVarInsn(Opcodes.ALOAD, 0); expectedVisitor.visitInsn(Opcodes.ICONST_0); expectedVisitor.visitInsn(Opcodes.ICONST_1); expectedVisitor.visitInsn(Opcodes.BASTORE); } @Test public void testVariableNonStatic() { ProbeInserter pi = new ProbeInserter(0, "m", "()V", actualVisitor, arrayStrategy); pi.insertProbe(0); expectedVisitor.visitVarInsn(Opcodes.ALOAD, 1); expectedVisitor.visitInsn(Opcodes.ICONST_0); expectedVisitor.visitInsn(Opcodes.ICONST_1); expectedVisitor.visitInsn(Opcodes.BASTORE); } @Test public void testVariableNonStatic_IZObject() { ProbeInserter pi = new ProbeInserter(0, "m", "(IZLjava/lang/Object;)V", actualVisitor, arrayStrategy); pi.insertProbe(0); expectedVisitor.visitVarInsn(Opcodes.ALOAD, 4); expectedVisitor.visitInsn(Opcodes.ICONST_0); expectedVisitor.visitInsn(Opcodes.ICONST_1); expectedVisitor.visitInsn(Opcodes.BASTORE); } @Test public void testVariableNonStatic_JD() { ProbeInserter pi = new ProbeInserter(0, "m", "(JD)V", actualVisitor, arrayStrategy); pi.insertProbe(0); expectedVisitor.visitVarInsn(Opcodes.ALOAD, 5); expectedVisitor.visitInsn(Opcodes.ICONST_0); expectedVisitor.visitInsn(Opcodes.ICONST_1); expectedVisitor.visitInsn(Opcodes.BASTORE); } @Test public void testVisitCode() { ProbeInserter pi = new ProbeInserter(0, "m", "()V", actualVisitor, arrayStrategy); pi.visitCode(); expectedVisitor.visitLdcInsn("init"); } @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, "m", "(II)V", actualVisitor, arrayStrategy); pi.visitVarInsn(Opcodes.ALOAD, 0); pi.visitVarInsn(Opcodes.ILOAD, 1); pi.visitVarInsn(Opcodes.ILOAD, 2); pi.visitVarInsn(Opcodes.ISTORE, 3); pi.visitVarInsn(Opcodes.FSTORE, 4); // Argument variables stay at the same position: expectedVisitor.visitVarInsn(Opcodes.ALOAD, 0); expectedVisitor.visitVarInsn(Opcodes.ILOAD, 1); expectedVisitor.visitVarInsn(Opcodes.ILOAD, 2); // Local variables are shifted by one: expectedVisitor.visitVarInsn(Opcodes.ISTORE, 4); expectedVisitor.visitVarInsn(Opcodes.FSTORE, 5); } @Test public void testVisitIincInsn() { ProbeInserter pi = new ProbeInserter(0, "m", "(II)V", actualVisitor, arrayStrategy); pi.visitIincInsn(0, 100); pi.visitIincInsn(1, 101); pi.visitIincInsn(2, 102); pi.visitIincInsn(3, 103); pi.visitIincInsn(4, 104); // Argument variables stay at the same position: expectedVisitor.visitIincInsn(0, 100); expectedVisitor.visitIincInsn(1, 101); expectedVisitor.visitIincInsn(2, 102); // Local variables are shifted by one: expectedVisitor.visitIincInsn(4, 103); expectedVisitor.visitIincInsn(5, 104); } @Test public void testVisitLocalVariable() { ProbeInserter pi = new ProbeInserter(0, "m", "(II)V", actualVisitor, arrayStrategy); pi.visitLocalVariable(null, null, null, null, null, 0); pi.visitLocalVariable(null, null, null, null, null, 1); pi.visitLocalVariable(null, null, null, null, null, 2); pi.visitLocalVariable(null, null, null, null, null, 3); pi.visitLocalVariable(null, null, null, null, null, 4); // Argument variables stay at the same position: expectedVisitor.visitLocalVariable(null, null, null, null, null, 0); expectedVisitor.visitLocalVariable(null, null, null, null, null, 1); expectedVisitor.visitLocalVariable(null, null, null, null, null, 2); // Local variables are shifted by one: expectedVisitor.visitLocalVariable(null, null, null, null, null, 4); expectedVisitor.visitLocalVariable(null, null, null, null, null, 5); } @Test public void testVisitMaxs1() { ProbeInserter pi = new ProbeInserter(0, "m", "(II)V", actualVisitor, arrayStrategy); pi.visitCode(); pi.visitMaxs(0, 8); expectedVisitor.visitLdcInsn("init"); expectedVisitor.visitMaxs(5, 9); } @Test public void testVisitMaxs2() { ProbeInserter pi = new ProbeInserter(0, "m", "(II)V", actualVisitor, arrayStrategy); pi.visitCode(); pi.visitMaxs(10, 8); expectedVisitor.visitLdcInsn("init"); expectedVisitor.visitMaxs(13, 9); } @Test public void testVisitFrame() { ProbeInserter pi = new ProbeInserter(0, "m", "(J)V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_NEW, 3, new Object[] { "Foo", Opcodes.LONG, "java/lang/String" }, 0, new Object[0]); expectedVisitor.visitFrame(Opcodes.F_NEW, 4, new Object[] { "Foo", Opcodes.LONG, "[Z", "java/lang/String" }, 0, new Object[0]); } @Test public void testVisitFrameNoLocals() { ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "m", "()V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 0, new Object[0]); expectedVisitor.visitFrame(Opcodes.F_NEW, 1, new Object[] { "[Z" }, 0, new Object[0]); } @Test public void testVisitFrameProbeAt0() { ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "m", "()V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_NEW, 2, new Object[] { Opcodes.DOUBLE, "Foo" }, 0, new Object[0]); expectedVisitor.visitFrame(Opcodes.F_NEW, 3, new Object[] { "[Z", Opcodes.DOUBLE, "Foo" }, 0, new Object[0]); } @Test public void testFillOneWord() { ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "m", "(I)V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 0, new Object[] {}); // The locals in this frame are filled with TOP up to the probe variable expectedVisitor.visitFrame(Opcodes.F_NEW, 2, new Object[] { Opcodes.TOP, "[Z", }, 0, new Object[] {}); } @Test public void testFillTwoWord() { ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "m", "(J)V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 0, new Object[] {}); // The locals in this frame are filled with TOP up to the probe variable expectedVisitor.visitFrame(Opcodes.F_NEW, 3, new Object[] { Opcodes.TOP, Opcodes.TOP, "[Z", }, 0, new Object[] {}); } @Test public void testFillPartly() { ProbeInserter pi = new ProbeInserter(Opcodes.ACC_STATIC, "m", "(DIJ)V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_NEW, 1, new Object[] { Opcodes.DOUBLE }, 0, new Object[] {}); // The locals in this frame are filled with TOP up to the probe variable expectedVisitor.visitFrame(Opcodes.F_NEW, 5, new Object[] { Opcodes.DOUBLE, Opcodes.TOP, Opcodes.TOP, Opcodes.TOP, "[Z", }, 0, new Object[] {}); } @Test(expected = IllegalArgumentException.class) public void testVisitFrame_invalidType() { ProbeInserter pi = new ProbeInserter(0, "m", "()V", actualVisitor, arrayStrategy); pi.visitFrame(Opcodes.F_SAME, 0, null, 0, null); } }