blob: 8777c9ba176e83eeeb4ce6f01a2e07da29c3d016 [file] [log] [blame]
/*******************************************************************************
* 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.flow;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.objectweb.asm.Opcodes.*;
import org.junit.Before;
import org.junit.Test;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
/**
* Unit tests for {@link LabelFlowAnalyzer}.
*/
public class LabelFlowAnalyzerTest {
private LabelFlowAnalyzer analyzer;
private Label label;
@Before
public void setup() {
analyzer = new LabelFlowAnalyzer();
label = new Label();
}
@Test
public void testInit() {
assertFalse(analyzer.successor);
assertTrue(analyzer.first);
assertNull(analyzer.lineStart);
}
@Test
public void testFlowScenario01() {
assertFalse(LabelInfo.isMultiTarget(label));
assertFalse(LabelInfo.isSuccessor(label));
}
@Test
public void testFlowScenario02() {
analyzer.visitJumpInsn(GOTO, label);
assertFalse(LabelInfo.isMultiTarget(label));
assertFalse(LabelInfo.isSuccessor(label));
}
@Test
public void testFlowScenario03() {
analyzer.visitInsn(RETURN);
analyzer.visitLabel(label);
assertFalse(LabelInfo.isMultiTarget(label));
assertFalse(LabelInfo.isSuccessor(label));
}
@Test
public void testFlowScenario04() {
analyzer.visitLabel(label);
assertFalse(LabelInfo.isMultiTarget(label));
assertFalse(LabelInfo.isSuccessor(label));
}
@Test
public void testFlowScenario05() {
analyzer.visitLabel(label);
analyzer.visitJumpInsn(GOTO, label);
assertTrue(LabelInfo.isMultiTarget(label));
assertFalse(LabelInfo.isSuccessor(label));
}
@Test
public void testFlowScenario06() {
analyzer.visitJumpInsn(IFEQ, label);
analyzer.visitLabel(label);
assertTrue(LabelInfo.isMultiTarget(label));
assertTrue(LabelInfo.isSuccessor(label));
}
@Test
public void testFlowScenario07() {
analyzer.visitJumpInsn(IFEQ, label);
analyzer.visitJumpInsn(GOTO, label);
assertTrue(LabelInfo.isMultiTarget(label));
assertFalse(LabelInfo.isSuccessor(label));
}
@Test
public void testFlowScenario08() {
analyzer.visitJumpInsn(IFEQ, label);
analyzer.visitJumpInsn(IFGT, label);
analyzer.visitLabel(label);
assertTrue(LabelInfo.isMultiTarget(label));
assertTrue(LabelInfo.isSuccessor(label));
}
@Test
public void testFlowScenario09() {
analyzer.visitInsn(Opcodes.NOP);
analyzer.visitLabel(label);
analyzer.visitLabel(label);
assertFalse(LabelInfo.isMultiTarget(label));
assertTrue(LabelInfo.isSuccessor(label));
}
@Test
public void testFlowScenario10() {
analyzer.visitTryCatchBlock(new Label(), new Label(), label,
"java/lang/Exception");
analyzer.visitJumpInsn(GOTO, label);
assertTrue(LabelInfo.isMultiTarget(label));
assertFalse(LabelInfo.isSuccessor(label));
}
@Test
public void testFlowScenario11() {
// Even if the same label is referenced multiple times but from the same
// source instruction this is only counted as one target.
analyzer.visitLookupSwitchInsn(label, new int[] { 0, 1 }, new Label[] {
label, label });
assertFalse(LabelInfo.isMultiTarget(label));
assertFalse(LabelInfo.isSuccessor(label));
}
@Test
public void testFlowScenario12() {
// Even if the same label is referenced multiple times but from the same
// source instruction this is only counted as one target.
analyzer.visitTableSwitchInsn(0, 1, label, new Label[] { label, label });
assertFalse(LabelInfo.isMultiTarget(label));
assertFalse(LabelInfo.isSuccessor(label));
}
@Test
public void testInsn() {
testInsn(NOP, true);
testInsn(ACONST_NULL, true);
testInsn(ICONST_M1, true);
testInsn(ICONST_0, true);
testInsn(ICONST_1, true);
testInsn(ICONST_2, true);
testInsn(ICONST_3, true);
testInsn(ICONST_4, true);
testInsn(ICONST_5, true);
testInsn(LCONST_0, true);
testInsn(LCONST_1, true);
testInsn(FCONST_0, true);
testInsn(FCONST_1, true);
testInsn(FCONST_2, true);
testInsn(DCONST_0, true);
testInsn(DCONST_1, true);
testInsn(IALOAD, true);
testInsn(LALOAD, true);
testInsn(FALOAD, true);
testInsn(DALOAD, true);
testInsn(AALOAD, true);
testInsn(BALOAD, true);
testInsn(CALOAD, true);
testInsn(SALOAD, true);
testInsn(IASTORE, true);
testInsn(LASTORE, true);
testInsn(FASTORE, true);
testInsn(DASTORE, true);
testInsn(AASTORE, true);
testInsn(BASTORE, true);
testInsn(CASTORE, true);
testInsn(SASTORE, true);
testInsn(POP, true);
testInsn(POP2, true);
testInsn(DUP, true);
testInsn(DUP_X1, true);
testInsn(DUP_X2, true);
testInsn(DUP2, true);
testInsn(DUP2_X1, true);
testInsn(DUP2_X2, true);
testInsn(SWAP, true);
testInsn(IADD, true);
testInsn(LADD, true);
testInsn(FADD, true);
testInsn(DADD, true);
testInsn(ISUB, true);
testInsn(LSUB, true);
testInsn(FSUB, true);
testInsn(DSUB, true);
testInsn(IMUL, true);
testInsn(LMUL, true);
testInsn(FMUL, true);
testInsn(DMUL, true);
testInsn(IDIV, true);
testInsn(LDIV, true);
testInsn(FDIV, true);
testInsn(DDIV, true);
testInsn(IREM, true);
testInsn(LREM, true);
testInsn(FREM, true);
testInsn(DREM, true);
testInsn(INEG, true);
testInsn(LNEG, true);
testInsn(FNEG, true);
testInsn(DNEG, true);
testInsn(ISHL, true);
testInsn(LSHL, true);
testInsn(ISHR, true);
testInsn(LSHR, true);
testInsn(IUSHR, true);
testInsn(LUSHR, true);
testInsn(IAND, true);
testInsn(LAND, true);
testInsn(IOR, true);
testInsn(LOR, true);
testInsn(IXOR, true);
testInsn(LXOR, true);
testInsn(I2L, true);
testInsn(I2F, true);
testInsn(I2D, true);
testInsn(L2I, true);
testInsn(L2F, true);
testInsn(L2D, true);
testInsn(F2I, true);
testInsn(F2L, true);
testInsn(F2D, true);
testInsn(D2I, true);
testInsn(D2L, true);
testInsn(D2F, true);
testInsn(I2B, true);
testInsn(I2C, true);
testInsn(I2S, true);
testInsn(LCMP, true);
testInsn(FCMPL, true);
testInsn(FCMPG, true);
testInsn(DCMPL, true);
testInsn(DCMPG, true);
testInsn(IRETURN, false);
testInsn(LRETURN, false);
testInsn(FRETURN, false);
testInsn(DRETURN, false);
testInsn(ARETURN, false);
testInsn(RETURN, false);
testInsn(ARRAYLENGTH, true);
testInsn(ATHROW, false);
testInsn(MONITORENTER, true);
testInsn(MONITOREXIT, true);
}
private void testInsn(int opcode, boolean expected) {
// ensure the flags are actually set:
analyzer.successor = !expected;
analyzer.first = true;
analyzer.visitInsn(opcode);
assertTrue(expected == analyzer.successor);
assertFalse(analyzer.first);
}
@Test(expected = AssertionError.class)
public void testVisitInsnNegative() {
analyzer.visitInsn(RET);
}
@Test
public void testIntInsn() {
analyzer.visitIntInsn(BIPUSH, 0);
assertTrue(analyzer.successor);
assertFalse(analyzer.first);
}
@Test
public void testVarInsn() {
analyzer.visitVarInsn(ILOAD, 0);
assertTrue(analyzer.successor);
assertFalse(analyzer.first);
}
@Test
public void testTypeInsn() {
analyzer.visitTypeInsn(NEW, "java/lang/String");
assertTrue(analyzer.successor);
assertFalse(analyzer.first);
}
@Test
public void testFieldInsn() {
analyzer.successor = false;
analyzer.visitFieldInsn(GETFIELD, "Foo", "name", "Ljava/lang/String;");
assertTrue(analyzer.successor);
assertFalse(analyzer.first);
}
@Test
public void testLineNumber() {
analyzer.visitLineNumber(42, label);
assertSame(label, analyzer.lineStart);
}
@Test
public void testMethodInsn() {
analyzer.visitLineNumber(42, label);
analyzer.visitMethodInsn(INVOKEVIRTUAL, "Foo", "doit", "()V", false);
assertTrue(analyzer.successor);
assertFalse(analyzer.first);
assertTrue(LabelInfo.isMethodInvocationLine(label));
}
@Test
public void testInvokeDynamicInsn() {
analyzer.visitLineNumber(42, label);
analyzer.visitInvokeDynamicInsn("foo", "()V", null);
assertTrue(analyzer.successor);
assertFalse(analyzer.first);
assertTrue(LabelInfo.isMethodInvocationLine(label));
}
@Test
public void testJumpInsn() {
testJumpInsn(IFEQ, true);
testJumpInsn(IFNE, true);
testJumpInsn(IFLT, true);
testJumpInsn(IFGE, true);
testJumpInsn(IFGT, true);
testJumpInsn(IFLE, true);
testJumpInsn(IF_ICMPEQ, true);
testJumpInsn(IF_ICMPNE, true);
testJumpInsn(IF_ICMPLT, true);
testJumpInsn(IF_ICMPGE, true);
testJumpInsn(IF_ICMPGT, true);
testJumpInsn(IF_ICMPLE, true);
testJumpInsn(IF_ACMPEQ, true);
testJumpInsn(IF_ACMPNE, true);
testJumpInsn(GOTO, false);
testJumpInsn(IFNULL, true);
testJumpInsn(IFNONNULL, true);
}
private void testJumpInsn(int opcode, boolean expected) {
// ensure the flags are actually set:
analyzer.successor = !expected;
analyzer.first = true;
analyzer.visitJumpInsn(opcode, label);
assertTrue(expected == analyzer.successor);
assertFalse(analyzer.first);
}
@Test(expected = AssertionError.class)
public void testVisitJumpInsnNegative() {
analyzer.visitJumpInsn(JSR, label);
}
@Test
public void testLdcInsn() {
analyzer.visitLdcInsn("Foo");
assertTrue(analyzer.successor);
assertFalse(analyzer.first);
}
@Test
public void testIincInsn() {
analyzer.visitIincInsn(0, 1);
assertTrue(analyzer.successor);
assertFalse(analyzer.first);
}
@Test
public void testTableSwitchInsn() {
analyzer.visitTableSwitchInsn(0, 0, label, new Label[] { label });
assertFalse(analyzer.successor);
assertFalse(analyzer.first);
}
@Test
public void testLookupSwitchInsn() {
analyzer.visitLookupSwitchInsn(label, new int[] { 0 },
new Label[] { label });
assertFalse(analyzer.successor);
assertFalse(analyzer.first);
}
@Test
public void testMultiANewArrayInsn() {
analyzer.visitMultiANewArrayInsn("java/lang/String", 3);
assertTrue(analyzer.successor);
assertFalse(analyzer.first);
}
}