| /******************************************************************************* |
| * 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.analysis; |
| |
| import static org.junit.Assert.assertEquals; |
| |
| import java.util.ArrayList; |
| |
| import org.jacoco.core.analysis.ILine; |
| import org.jacoco.core.analysis.IMethodCoverage; |
| import org.jacoco.core.internal.analysis.filter.Filters; |
| import org.jacoco.core.internal.analysis.filter.IFilter; |
| import org.jacoco.core.internal.analysis.filter.IFilterOutput; |
| import org.jacoco.core.internal.flow.IProbeIdGenerator; |
| import org.jacoco.core.internal.flow.LabelFlowAnalyzer; |
| import org.jacoco.core.internal.flow.MethodProbesAdapter; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.objectweb.asm.Label; |
| import org.objectweb.asm.Opcodes; |
| import org.objectweb.asm.tree.AbstractInsnNode; |
| import org.objectweb.asm.tree.MethodNode; |
| import org.objectweb.asm.tree.TryCatchBlockNode; |
| import org.objectweb.asm.util.CheckMethodAdapter; |
| |
| /** |
| * Unit tests for {@link MethodAnalyzer}. |
| */ |
| public class MethodAnalyzerTest implements IProbeIdGenerator { |
| |
| private int nextProbeId; |
| |
| private boolean[] probes; |
| |
| private MethodNode method; |
| |
| private IMethodCoverage result; |
| |
| @Before |
| public void setup() { |
| nextProbeId = 0; |
| method = new MethodNode(); |
| method.tryCatchBlocks = new ArrayList<TryCatchBlockNode>(); |
| probes = new boolean[32]; |
| } |
| |
| public int nextId() { |
| return nextProbeId++; |
| } |
| |
| // === Scenario: linear Sequence without branches === |
| |
| private void createLinearSequence() { |
| final Label l0 = new Label(); |
| method.visitLabel(l0); |
| method.visitLineNumber(1001, l0); |
| method.visitInsn(Opcodes.NOP); |
| final Label l1 = new Label(); |
| method.visitLabel(l1); |
| method.visitLineNumber(1002, l1); |
| method.visitInsn(Opcodes.RETURN); |
| } |
| |
| @Test |
| public void testLinearSequenceNotCovered1() { |
| createLinearSequence(); |
| runMethodAnalzer(); |
| assertEquals(1, nextProbeId); |
| |
| assertLine(1001, 1, 0, 0, 0); |
| assertLine(1002, 1, 0, 0, 0); |
| } |
| |
| @Test |
| public void testLinearSequenceNotCovered2() { |
| createLinearSequence(); |
| probes = null; |
| runMethodAnalzer(); |
| assertEquals(1, nextProbeId); |
| |
| assertLine(1001, 1, 0, 0, 0); |
| assertLine(1002, 1, 0, 0, 0); |
| } |
| |
| @Test |
| public void testLinearSequenceCovered() { |
| createLinearSequence(); |
| probes[0] = true; |
| runMethodAnalzer(); |
| |
| assertLine(1001, 0, 1, 0, 0); |
| assertLine(1002, 0, 1, 0, 0); |
| } |
| |
| // === Scenario: simple if branch === |
| |
| private void createIfBranch() { |
| final Label l0 = new Label(); |
| method.visitLabel(l0); |
| method.visitLineNumber(1001, l0); |
| method.visitVarInsn(Opcodes.ILOAD, 1); |
| Label l1 = new Label(); |
| method.visitJumpInsn(Opcodes.IFEQ, l1); |
| final Label l2 = new Label(); |
| method.visitLabel(l2); |
| method.visitLineNumber(1002, l2); |
| method.visitLdcInsn("a"); |
| method.visitInsn(Opcodes.ARETURN); |
| method.visitLabel(l1); |
| method.visitLineNumber(1003, l1); |
| method.visitLdcInsn("b"); |
| method.visitInsn(Opcodes.ARETURN); |
| } |
| |
| @Test |
| public void testIfBranchNotCovered() { |
| createIfBranch(); |
| runMethodAnalzer(); |
| assertEquals(2, nextProbeId); |
| |
| assertLine(1001, 2, 0, 2, 0); |
| assertLine(1002, 2, 0, 0, 0); |
| assertLine(1003, 2, 0, 0, 0); |
| } |
| |
| @Test |
| public void testIfBranchCovered1() { |
| createIfBranch(); |
| probes[0] = true; |
| runMethodAnalzer(); |
| |
| assertLine(1001, 0, 2, 1, 1); |
| assertLine(1002, 0, 2, 0, 0); |
| assertLine(1003, 2, 0, 0, 0); |
| } |
| |
| @Test |
| public void testIfBranchCovered2() { |
| createIfBranch(); |
| probes[1] = true; |
| runMethodAnalzer(); |
| |
| assertLine(1001, 0, 2, 1, 1); |
| assertLine(1002, 2, 0, 0, 0); |
| assertLine(1003, 0, 2, 0, 0); |
| } |
| |
| @Test |
| public void testIfBranchCovered3() { |
| createIfBranch(); |
| probes[0] = true; |
| probes[1] = true; |
| runMethodAnalzer(); |
| |
| assertLine(1001, 0, 2, 0, 2); |
| assertLine(1002, 0, 2, 0, 0); |
| assertLine(1003, 0, 2, 0, 0); |
| } |
| |
| // === Scenario: branch before unconditional probe === |
| |
| /** |
| * Covers case of {@link MethodAnalyzer#visitProbe(int)} after |
| * {@link MethodAnalyzer#visitJumpInsnWithProbe(int, Label, int, org.jacoco.core.internal.flow.IFrame)}. |
| */ |
| private void createIfBranchBeforeProbe() { |
| final Label l0 = new Label(); |
| final Label l1 = new Label(); |
| final Label l2 = new Label(); |
| method.visitLabel(l0); |
| method.visitLineNumber(1001, l0); |
| method.visitVarInsn(Opcodes.ILOAD, 1); |
| method.visitJumpInsn(Opcodes.IFNE, l1); |
| method.visitLabel(l2); |
| method.visitLineNumber(1002, l2); |
| method.visitMethodInsn(Opcodes.INVOKESTATIC, "Foo", "foo", "()V", |
| false); |
| method.visitLabel(l1); |
| method.visitLineNumber(1003, l1); |
| method.visitInsn(Opcodes.RETURN); |
| } |
| |
| @Test |
| public void testIfBranchBeforeProbeNotCovered() { |
| createIfBranchBeforeProbe(); |
| runMethodAnalzer(); |
| assertEquals(4, nextProbeId); |
| |
| assertLine(1001, 2, 0, 2, 0); |
| } |
| |
| @Test |
| public void testIfBranchBeforeProbeCovered1() { |
| createIfBranchBeforeProbe(); |
| probes[0] = true; |
| runMethodAnalzer(); |
| |
| assertLine(1001, 0, 2, 1, 1); |
| } |
| |
| @Test |
| public void testIfBranchBeforeProbeCovered2() { |
| createIfBranchBeforeProbe(); |
| probes[1] = true; |
| runMethodAnalzer(); |
| |
| assertLine(1001, 0, 2, 1, 1); |
| } |
| |
| @Test |
| public void testIfBranchBeforeProbeCovered3() { |
| createIfBranchBeforeProbe(); |
| probes[0] = true; |
| probes[1] = true; |
| runMethodAnalzer(); |
| |
| assertLine(1001, 0, 2, 0, 2); |
| } |
| |
| // === Scenario: branch which merges back === |
| |
| private void createIfBranchMerge() { |
| final Label l0 = new Label(); |
| method.visitLabel(l0); |
| method.visitLineNumber(1001, l0); |
| method.visitVarInsn(Opcodes.ILOAD, 1); |
| Label l1 = new Label(); |
| method.visitJumpInsn(Opcodes.IFEQ, l1); |
| final Label l2 = new Label(); |
| method.visitLabel(l2); |
| method.visitLineNumber(1002, l2); |
| method.visitInsn(Opcodes.NOP); |
| method.visitLabel(l1); |
| method.visitLineNumber(1003, l1); |
| method.visitInsn(Opcodes.RETURN); |
| } |
| |
| @Test |
| public void testIfBranchMergeNotCovered() { |
| createIfBranchMerge(); |
| runMethodAnalzer(); |
| assertEquals(3, nextProbeId); |
| |
| assertLine(1001, 2, 0, 2, 0); |
| assertLine(1002, 1, 0, 0, 0); |
| assertLine(1003, 1, 0, 0, 0); |
| } |
| |
| @Test |
| public void testIfBranchMergeCovered1() { |
| createIfBranchMerge(); |
| probes[0] = true; |
| runMethodAnalzer(); |
| |
| assertLine(1001, 0, 2, 1, 1); |
| assertLine(1002, 1, 0, 0, 0); |
| assertLine(1003, 1, 0, 0, 0); |
| } |
| |
| @Test |
| public void testIfBranchMergeCovered2() { |
| createIfBranchMerge(); |
| probes[1] = true; |
| runMethodAnalzer(); |
| |
| assertLine(1001, 0, 2, 1, 1); |
| assertLine(1002, 0, 1, 0, 0); |
| assertLine(1003, 1, 0, 0, 0); |
| } |
| |
| @Test |
| public void testIfBranchMergeCovered3() { |
| createIfBranchMerge(); |
| probes[0] = true; |
| probes[1] = true; |
| probes[2] = true; |
| runMethodAnalzer(); |
| |
| assertLine(1001, 0, 2, 0, 2); |
| assertLine(1002, 0, 1, 0, 0); |
| assertLine(1003, 0, 1, 0, 0); |
| } |
| |
| // === Scenario: branch which jump backwards === |
| |
| private void createJumpBackwards() { |
| final Label l0 = new Label(); |
| method.visitLabel(l0); |
| method.visitLineNumber(1001, l0); |
| final Label l1 = new Label(); |
| method.visitJumpInsn(Opcodes.GOTO, l1); |
| final Label l2 = new Label(); |
| method.visitLabel(l2); |
| method.visitLineNumber(1002, l2); |
| method.visitInsn(Opcodes.RETURN); |
| method.visitLabel(l1); |
| method.visitLineNumber(1003, l1); |
| method.visitJumpInsn(Opcodes.GOTO, l2); |
| } |
| |
| @Test |
| public void testJumpBackwardsNotCovered() { |
| createJumpBackwards(); |
| runMethodAnalzer(); |
| assertEquals(1, nextProbeId); |
| |
| assertLine(1001, 1, 0, 0, 0); |
| assertLine(1002, 1, 0, 0, 0); |
| assertLine(1003, 1, 0, 0, 0); |
| } |
| |
| @Test |
| public void testJumpBackwardsCovered() { |
| createJumpBackwards(); |
| probes[0] = true; |
| runMethodAnalzer(); |
| |
| assertLine(1001, 0, 1, 0, 0); |
| assertLine(1002, 0, 1, 0, 0); |
| assertLine(1003, 0, 1, 0, 0); |
| } |
| |
| // === Scenario: jump to first instruction === |
| |
| private void createJumpToFirst() { |
| final Label l1 = new Label(); |
| method.visitLabel(l1); |
| method.visitLineNumber(1001, l1); |
| method.visitVarInsn(Opcodes.ALOAD, 0); |
| method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "Foo", "test", "()Z", |
| false); |
| method.visitJumpInsn(Opcodes.IFEQ, l1); |
| final Label l2 = new Label(); |
| method.visitLabel(l2); |
| method.visitLineNumber(1002, l2); |
| method.visitInsn(Opcodes.RETURN); |
| } |
| |
| @Test |
| public void testJumpToFirstNotCovered() { |
| createJumpToFirst(); |
| runMethodAnalzer(); |
| assertEquals(2, nextProbeId); |
| |
| assertLine(1001, 3, 0, 2, 0); |
| assertLine(1002, 1, 0, 0, 0); |
| } |
| |
| @Test |
| public void testJumpToFirstCovered1() { |
| createJumpToFirst(); |
| probes[0] = true; |
| runMethodAnalzer(); |
| assertEquals(2, nextProbeId); |
| |
| assertLine(1001, 0, 3, 1, 1); |
| assertLine(1002, 1, 0, 0, 0); |
| } |
| |
| @Test |
| public void testJumpToFirstCovered2() { |
| createJumpToFirst(); |
| probes[0] = true; |
| probes[1] = true; |
| runMethodAnalzer(); |
| assertEquals(2, nextProbeId); |
| |
| assertLine(1001, 0, 3, 0, 2); |
| assertLine(1002, 0, 1, 0, 0); |
| } |
| |
| // === Scenario: table switch === |
| |
| private void createTableSwitch() { |
| final Label l0 = new Label(); |
| method.visitLabel(l0); |
| method.visitLineNumber(1001, l0); |
| method.visitVarInsn(Opcodes.ILOAD, 1); |
| Label l1 = new Label(); |
| Label l2 = new Label(); |
| Label l3 = new Label(); |
| method.visitTableSwitchInsn(1, 3, l3, new Label[] { l1, l2, l1 }); |
| method.visitLabel(l1); |
| method.visitLineNumber(1002, l1); |
| method.visitIntInsn(Opcodes.BIPUSH, 11); |
| method.visitVarInsn(Opcodes.ISTORE, 2); |
| final Label l4 = new Label(); |
| method.visitLabel(l4); |
| method.visitLineNumber(1003, l4); |
| Label l5 = new Label(); |
| method.visitJumpInsn(Opcodes.GOTO, l5); |
| method.visitLabel(l2); |
| method.visitLineNumber(1004, l2); |
| method.visitIntInsn(Opcodes.BIPUSH, 22); |
| method.visitVarInsn(Opcodes.ISTORE, 2); |
| final Label l6 = new Label(); |
| method.visitLabel(l6); |
| method.visitLineNumber(1005, l6); |
| method.visitJumpInsn(Opcodes.GOTO, l5); |
| method.visitLabel(l3); |
| method.visitLineNumber(1006, l3); |
| method.visitInsn(Opcodes.ICONST_0); |
| method.visitVarInsn(Opcodes.ISTORE, 2); |
| method.visitLabel(l5); |
| method.visitLineNumber(1007, l5); |
| method.visitVarInsn(Opcodes.ILOAD, 2); |
| method.visitInsn(Opcodes.IRETURN); |
| } |
| |
| @Test |
| public void testTableSwitchNotCovered() { |
| createTableSwitch(); |
| runMethodAnalzer(); |
| assertEquals(4, nextProbeId); |
| |
| assertLine(1001, 2, 0, 3, 0); |
| assertLine(1002, 2, 0, 0, 0); |
| assertLine(1003, 1, 0, 0, 0); |
| assertLine(1004, 2, 0, 0, 0); |
| assertLine(1005, 1, 0, 0, 0); |
| assertLine(1006, 2, 0, 0, 0); |
| assertLine(1007, 2, 0, 0, 0); |
| } |
| |
| @Test |
| public void testTableSwitchCovered1() { |
| createTableSwitch(); |
| probes[0] = true; |
| probes[3] = true; |
| runMethodAnalzer(); |
| assertEquals(4, nextProbeId); |
| |
| assertLine(1001, 0, 2, 2, 1); |
| assertLine(1002, 0, 2, 0, 0); |
| assertLine(1003, 0, 1, 0, 0); |
| assertLine(1004, 2, 0, 0, 0); |
| assertLine(1005, 1, 0, 0, 0); |
| assertLine(1006, 2, 0, 0, 0); |
| assertLine(1007, 0, 2, 0, 0); |
| } |
| |
| @Test |
| public void testTableSwitchCovered2() { |
| createTableSwitch(); |
| probes[2] = true; |
| probes[3] = true; |
| runMethodAnalzer(); |
| assertEquals(4, nextProbeId); |
| |
| assertLine(1001, 0, 2, 2, 1); |
| assertLine(1002, 2, 0, 0, 0); |
| assertLine(1003, 1, 0, 0, 0); |
| assertLine(1004, 2, 0, 0, 0); |
| assertLine(1005, 1, 0, 0, 0); |
| assertLine(1006, 0, 2, 0, 0); |
| assertLine(1007, 0, 2, 0, 0); |
| } |
| |
| @Test |
| public void testTableSwitchCovered3() { |
| createTableSwitch(); |
| probes[0] = true; |
| probes[1] = true; |
| probes[2] = true; |
| probes[3] = true; |
| runMethodAnalzer(); |
| assertEquals(4, nextProbeId); |
| |
| assertLine(1001, 0, 2, 0, 3); |
| assertLine(1002, 0, 2, 0, 0); |
| assertLine(1003, 0, 1, 0, 0); |
| assertLine(1004, 0, 2, 0, 0); |
| assertLine(1005, 0, 1, 0, 0); |
| assertLine(1006, 0, 2, 0, 0); |
| assertLine(1007, 0, 2, 0, 0); |
| } |
| |
| // === Scenario: table switch with merge === |
| |
| private void createTableSwitchMerge() { |
| final Label l0 = new Label(); |
| method.visitLabel(l0); |
| method.visitLineNumber(1001, l0); |
| method.visitInsn(Opcodes.ICONST_0); |
| method.visitVarInsn(Opcodes.ISTORE, 2); |
| final Label l1 = new Label(); |
| method.visitLabel(l1); |
| method.visitLineNumber(1002, l1); |
| method.visitVarInsn(Opcodes.ILOAD, 1); |
| Label l2 = new Label(); |
| Label l3 = new Label(); |
| Label l4 = new Label(); |
| method.visitTableSwitchInsn(1, 3, l4, new Label[] { l2, l3, l2 }); |
| method.visitLabel(l2); |
| method.visitLineNumber(1003, l2); |
| method.visitIincInsn(2, 1); |
| method.visitLabel(l3); |
| method.visitLineNumber(1004, l3); |
| method.visitIincInsn(2, 1); |
| method.visitLabel(l4); |
| method.visitLineNumber(1005, l4); |
| method.visitVarInsn(Opcodes.ILOAD, 2); |
| method.visitInsn(Opcodes.IRETURN); |
| } |
| |
| @Test |
| public void testTableSwitchMergeNotCovered() { |
| createTableSwitchMerge(); |
| runMethodAnalzer(); |
| assertEquals(5, nextProbeId); |
| |
| assertLine(1001, 2, 0, 0, 0); |
| assertLine(1002, 2, 0, 3, 0); |
| assertLine(1003, 1, 0, 0, 0); |
| assertLine(1004, 1, 0, 0, 0); |
| assertLine(1005, 2, 0, 0, 0); |
| } |
| |
| @Test |
| public void testTableSwitchMergeNotCovered1() { |
| createTableSwitchMerge(); |
| probes[0] = true; |
| probes[4] = true; |
| runMethodAnalzer(); |
| assertEquals(5, nextProbeId); |
| |
| assertLine(1001, 0, 2, 0, 0); |
| assertLine(1002, 0, 2, 2, 1); |
| assertLine(1003, 1, 0, 0, 0); |
| assertLine(1004, 1, 0, 0, 0); |
| assertLine(1005, 0, 2, 0, 0); |
| } |
| |
| @Test |
| public void testTableSwitchMergeNotCovered2() { |
| createTableSwitchMerge(); |
| probes[1] = true; |
| probes[3] = true; |
| probes[4] = true; |
| runMethodAnalzer(); |
| assertEquals(5, nextProbeId); |
| |
| assertLine(1001, 0, 2, 0, 0); |
| assertLine(1002, 0, 2, 2, 1); |
| assertLine(1003, 1, 0, 0, 0); |
| assertLine(1004, 0, 1, 0, 0); |
| assertLine(1005, 0, 2, 0, 0); |
| } |
| |
| @Test |
| public void testTableSwitchMergeNotCovered3() { |
| createTableSwitchMerge(); |
| probes[2] = true; |
| probes[3] = true; |
| probes[4] = true; |
| runMethodAnalzer(); |
| assertEquals(5, nextProbeId); |
| |
| assertLine(1001, 0, 2, 0, 0); |
| assertLine(1002, 0, 2, 2, 1); |
| assertLine(1003, 0, 1, 0, 0); |
| assertLine(1004, 0, 1, 0, 0); |
| assertLine(1005, 0, 2, 0, 0); |
| } |
| |
| @Test |
| public void testTableSwitchMergeNotCovered4() { |
| createTableSwitchMerge(); |
| probes[0] = true; |
| probes[1] = true; |
| probes[2] = true; |
| probes[3] = true; |
| probes[4] = true; |
| runMethodAnalzer(); |
| assertEquals(5, nextProbeId); |
| |
| assertLine(1001, 0, 2, 0, 0); |
| assertLine(1002, 0, 2, 0, 3); |
| assertLine(1003, 0, 1, 0, 0); |
| assertLine(1004, 0, 1, 0, 0); |
| assertLine(1005, 0, 2, 0, 0); |
| } |
| |
| // === Scenario: try/catch block === |
| |
| private void createTryCatchBlock() { |
| Label l1 = new Label(); |
| Label l2 = new Label(); |
| Label l3 = new Label(); |
| Label l4 = new Label(); |
| method.visitTryCatchBlock(l1, l2, l3, "java/lang/Exception"); |
| method.visitLabel(l1); |
| method.visitLineNumber(1001, l1); |
| method.visitVarInsn(Opcodes.ALOAD, 0); |
| method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", |
| "printStackTrace", "()V", false); |
| method.visitLabel(l2); |
| method.visitJumpInsn(Opcodes.GOTO, l4); |
| method.visitLabel(l3); |
| method.visitLineNumber(1002, l3); |
| method.visitVarInsn(Opcodes.ASTORE, 1); |
| method.visitLabel(l4); |
| method.visitLineNumber(1004, l4); |
| method.visitInsn(Opcodes.RETURN); |
| } |
| |
| @Test |
| public void testTryCatchBlockNotCovered() { |
| createTryCatchBlock(); |
| runMethodAnalzer(); |
| assertEquals(3, nextProbeId); |
| assertEquals(CounterImpl.getInstance(5, 0), |
| result.getInstructionCounter()); |
| |
| assertLine(1001, 3, 0, 0, 0); |
| assertLine(1002, 1, 0, 0, 0); |
| assertLine(1004, 1, 0, 0, 0); |
| } |
| |
| @Test |
| public void testTryCatchBlockFullyCovered() { |
| createTryCatchBlock(); |
| probes[0] = true; |
| probes[1] = true; |
| probes[2] = true; |
| runMethodAnalzer(); |
| assertEquals(3, nextProbeId); |
| assertEquals(CounterImpl.getInstance(0, 5), |
| result.getInstructionCounter()); |
| |
| assertLine(1001, 0, 3, 0, 0); |
| assertLine(1002, 0, 1, 0, 0); |
| assertLine(1004, 0, 1, 0, 0); |
| } |
| |
| // === Scenario: try/finally === |
| |
| private void createTryFinally() { |
| final Label l0 = new Label(); |
| final Label l1 = new Label(); |
| final Label l2 = new Label(); |
| final Label l3 = new Label(); |
| |
| method.visitTryCatchBlock(l0, l2, l2, null); |
| |
| method.visitLabel(l0); |
| method.visitLineNumber(1001, l0); |
| |
| method.visitJumpInsn(Opcodes.IFEQ, l1); |
| // probe[0] |
| method.visitInsn(Opcodes.RETURN); |
| method.visitLabel(l1); |
| // probe[1] |
| method.visitInsn(Opcodes.RETURN); |
| |
| method.visitLabel(l2); |
| method.visitJumpInsn(Opcodes.IFEQ, l3); |
| // probe[2] |
| method.visitInsn(Opcodes.RETURN); |
| method.visitLabel(l3); |
| // probe[3] |
| method.visitInsn(Opcodes.RETURN); |
| } |
| |
| @Test |
| public void testTryFinallyWithoutFilter() { |
| createTryFinally(); |
| probes[0] = true; |
| probes[3] = true; |
| runMethodAnalzer(); |
| assertEquals(4, nextProbeId); |
| |
| assertLine(1001, 2, 4, 2, 2); |
| } |
| |
| private static final IFilter TRY_FINALLY_FILTER = new IFilter() { |
| public void filter(final String className, final String superClassName, |
| final MethodNode methodNode, final IFilterOutput output) { |
| final AbstractInsnNode i1 = methodNode.instructions.get(2); |
| final AbstractInsnNode i2 = methodNode.instructions.get(7); |
| assertEquals(Opcodes.IFEQ, i1.getOpcode()); |
| assertEquals(Opcodes.IFEQ, i2.getOpcode()); |
| output.merge(i1, i2); |
| // Merging of already merged instructions won't change result: |
| output.merge(i1, i2); |
| } |
| }; |
| |
| @Test |
| public void testTryFinallyMergeSameBranch() { |
| createTryFinally(); |
| probes[0] = true; |
| probes[2] = true; |
| runMethodAnalzer(TRY_FINALLY_FILTER); |
| assertLine(1001, 2, 3, 1, 1); |
| } |
| |
| @Test |
| public void testTryFinallyMergeDifferentBranches() { |
| createTryFinally(); |
| probes[0] = true; |
| probes[3] = true; |
| runMethodAnalzer(TRY_FINALLY_FILTER); |
| assertLine(1001, 2, 3, 0, 2); |
| } |
| |
| private void runMethodAnalzer() { |
| runMethodAnalzer(Filters.NONE); |
| } |
| |
| private void runMethodAnalzer(IFilter filter) { |
| LabelFlowAnalyzer.markLabels(method); |
| final MethodAnalyzer analyzer = new MethodAnalyzer("Foo", |
| "java/lang/Object", "doit", "()V", null, probes, filter); |
| final MethodProbesAdapter probesAdapter = new MethodProbesAdapter( |
| analyzer, this); |
| // note that CheckMethodAdapter verifies that this test does not violate |
| // contracts of ASM API |
| analyzer.accept(method, new CheckMethodAdapter(probesAdapter)); |
| result = analyzer.getCoverage(); |
| } |
| |
| private void assertLine(int nr, int insnMissed, int insnCovered, |
| int branchesMissed, int branchesCovered) { |
| final ILine line = result.getLine(nr); |
| assertEquals("Instructions in line " + nr, |
| CounterImpl.getInstance(insnMissed, insnCovered), |
| line.getInstructionCounter()); |
| assertEquals("Branches in line " + nr, |
| CounterImpl.getInstance(branchesMissed, branchesCovered), |
| line.getBranchCounter()); |
| } |
| |
| } |