| /******************************************************************************* |
| * 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); |
| } |
| |
| } |