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