Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor coverage analysis package (#744)
* Encapsulate insn/branch status tracking in Instruction * Move Instruction to the analysis package * Encapsulate Instruction building in new class InstructionsBuilder * Separate coverage calculation from filtering
- Loading branch information
Showing
13 changed files
with
1,237 additions
and
574 deletions.
There are no files selected for viewing
173 changes: 173 additions & 0 deletions
173
org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2009, 2018 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.Arrays; | ||
|
||
import org.junit.Before; | ||
import org.junit.Test; | ||
|
||
/** | ||
* Unit tests for {@link Instruction}. | ||
*/ | ||
public class InstructionTest { | ||
|
||
private Instruction instruction; | ||
|
||
@Before | ||
public void setup() { | ||
instruction = new Instruction(123); | ||
} | ||
|
||
@Test | ||
public void getLine_should_return_line_number() { | ||
assertEquals(123, instruction.getLine()); | ||
} | ||
|
||
@Test | ||
public void new_instance_should_have_no_coverage_and_no_branches() { | ||
assertEquals(CounterImpl.COUNTER_1_0, | ||
instruction.getInstructionCounter()); | ||
assertEquals(CounterImpl.COUNTER_0_0, instruction.getBranchCounter()); | ||
} | ||
|
||
@Test | ||
public void addBranchWithInstruction_should_not_increment_branches_when_only_one_branch_is_added() { | ||
instruction.addBranch(new Instruction(122), 0); | ||
|
||
assertEquals(CounterImpl.COUNTER_0_0, instruction.getBranchCounter()); | ||
} | ||
|
||
@Test | ||
public void addBranchWithInstruction_should_increment_branches_when_two_branches_are_added() { | ||
instruction.addBranch(new Instruction(122), 0); | ||
instruction.addBranch(new Instruction(123), 1); | ||
|
||
assertEquals(CounterImpl.getInstance(2, 0), | ||
instruction.getBranchCounter()); | ||
} | ||
|
||
@Test | ||
public void addBranchWithInstruction_should_propagate_existing_coverage_status() { | ||
final Instruction target = new Instruction(122); | ||
target.addBranch(true, 0); | ||
|
||
instruction.addBranch(target, 0); | ||
|
||
assertEquals(CounterImpl.COUNTER_0_1, | ||
instruction.getInstructionCounter()); | ||
} | ||
|
||
@Test | ||
public void addBranchWithProbe_should_increment_branches_when_covered() { | ||
instruction.addBranch(true, 0); | ||
instruction.addBranch(true, 1); | ||
|
||
assertEquals(CounterImpl.getInstance(0, 1), | ||
instruction.getInstructionCounter()); | ||
assertEquals(CounterImpl.getInstance(0, 2), | ||
instruction.getBranchCounter()); | ||
} | ||
|
||
@Test | ||
public void addBranchWithProbe_should_increment_branches_when_not_covered() { | ||
instruction.addBranch(false, 0); | ||
instruction.addBranch(false, 1); | ||
|
||
assertEquals(CounterImpl.getInstance(1, 0), | ||
instruction.getInstructionCounter()); | ||
assertEquals(CounterImpl.getInstance(2, 0), | ||
instruction.getBranchCounter()); | ||
} | ||
|
||
@Test | ||
public void addBranchWithProbe_should_increment_branches_when_partly_covered() { | ||
instruction.addBranch(false, 0); | ||
instruction.addBranch(true, 1); | ||
|
||
assertEquals(CounterImpl.getInstance(0, 1), | ||
instruction.getInstructionCounter()); | ||
assertEquals(CounterImpl.getInstance(1, 1), | ||
instruction.getBranchCounter()); | ||
} | ||
|
||
@Test | ||
public void addBranchWithProbe_should_propagate_coverage_status_to_existing_predecessors() { | ||
final Instruction i1 = new Instruction(124); | ||
final Instruction i2 = new Instruction(125); | ||
instruction.addBranch(i1, 3); | ||
i1.addBranch(i2, 5); | ||
|
||
i2.addBranch(true, 8); | ||
|
||
assertEquals(CounterImpl.COUNTER_0_1, | ||
instruction.getInstructionCounter()); | ||
} | ||
|
||
@Test | ||
public void addBranch_should_count_large_number_of_branches() { | ||
for (int branch = 0; branch < 0x1000; branch++) { | ||
instruction.addBranch(true, branch); | ||
} | ||
|
||
assertEquals(CounterImpl.getInstance(0, 0x1000), | ||
instruction.getBranchCounter()); | ||
} | ||
|
||
@Test | ||
public void addBranch_should_propagate_coverage_status_over_very_long_sequence() { | ||
Instruction next = instruction; | ||
for (int i = 0; i < 0x10000; i++) { | ||
final Instruction insn = new Instruction(i); | ||
next.addBranch(insn, 0); | ||
next = insn; | ||
} | ||
next.addBranch(true, 0); | ||
|
||
assertEquals(CounterImpl.COUNTER_0_1, | ||
instruction.getInstructionCounter()); | ||
} | ||
|
||
@Test | ||
public void merge_should_calculate_superset_of_covered_branches() { | ||
final Instruction i1 = new Instruction(124); | ||
i1.addBranch(false, 1); | ||
i1.addBranch(false, 2); | ||
i1.addBranch(true, 3); | ||
i1.addBranch(true, 4); | ||
final Instruction i2 = new Instruction(124); | ||
i2.addBranch(false, 1); | ||
i2.addBranch(true, 2); | ||
i2.addBranch(false, 3); | ||
i2.addBranch(true, 4); | ||
|
||
instruction = i1.merge(i2); | ||
|
||
assertEquals(CounterImpl.getInstance(1, 3), | ||
instruction.getBranchCounter()); | ||
} | ||
|
||
@Test | ||
public void replaceBranches_should_calculate_coverage_on_new_branches() { | ||
Instruction i1 = new Instruction(1); | ||
Instruction i2 = new Instruction(2); | ||
Instruction i3 = new Instruction(3); | ||
i3.addBranch(true, 0); | ||
|
||
instruction = instruction.replaceBranches(Arrays.asList(i1, i2, i3)); | ||
|
||
assertEquals(CounterImpl.getInstance(2, 1), | ||
instruction.getBranchCounter()); | ||
} | ||
} |
189 changes: 189 additions & 0 deletions
189
org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionsBuilderTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2009, 2018 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.Map; | ||
|
||
import org.jacoco.core.analysis.ISourceFileCoverage; | ||
import org.jacoco.core.internal.flow.LabelInfo; | ||
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.InsnNode; | ||
|
||
/** | ||
* Unit tests for {@link InstructionsBuilder}. | ||
*/ | ||
public class InstructionsBuilderTest { | ||
|
||
private InstructionsBuilder builder; | ||
|
||
@Before | ||
public void setup() { | ||
builder = new InstructionsBuilder(new boolean[] { false, true }); | ||
} | ||
|
||
@Test | ||
public void current_line_number_should_be_applied_to_instructions() { | ||
InsnNode i1 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i1); | ||
|
||
builder.setCurrentLine(10); | ||
InsnNode i2 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i2); | ||
InsnNode i3 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i3); | ||
|
||
builder.setCurrentLine(20); | ||
InsnNode i4 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i4); | ||
|
||
Map<AbstractInsnNode, Instruction> map = builder.getInstructions(); | ||
assertEquals(ISourceFileCoverage.UNKNOWN_LINE, map.get(i1).getLine()); | ||
assertEquals(10, map.get(i2).getLine()); | ||
assertEquals(10, map.get(i3).getLine()); | ||
assertEquals(20, map.get(i4).getLine()); | ||
} | ||
|
||
@Test | ||
public void null_probearray_should_not_mark_instruction_as_covered() { | ||
builder = new InstructionsBuilder(null); | ||
|
||
InsnNode i1 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i1); | ||
builder.addProbe(5, 0); | ||
|
||
Map<AbstractInsnNode, Instruction> map = builder.getInstructions(); | ||
assertEquals(CounterImpl.COUNTER_1_0, | ||
map.get(i1).getInstructionCounter()); | ||
} | ||
|
||
@Test | ||
public void unexecuted_probe_should_not_mark_instruction_as_covered() { | ||
InsnNode i1 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i1); | ||
builder.addProbe(0, 0); | ||
|
||
Map<AbstractInsnNode, Instruction> map = builder.getInstructions(); | ||
assertEquals(CounterImpl.COUNTER_1_0, | ||
map.get(i1).getInstructionCounter()); | ||
} | ||
|
||
@Test | ||
public void executed_probe_should_mark_instruction_as_covered() { | ||
InsnNode i1 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i1); | ||
builder.addProbe(1, 0); | ||
|
||
Map<AbstractInsnNode, Instruction> map = builder.getInstructions(); | ||
assertEquals(CounterImpl.COUNTER_0_1, | ||
map.get(i1).getInstructionCounter()); | ||
} | ||
|
||
@Test | ||
public void subsequent_instructions_should_be_linked_by_default() { | ||
InsnNode i1 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i1); | ||
|
||
InsnNode i2 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i2); | ||
|
||
// mark i2 as covered | ||
builder.addProbe(1, 0); | ||
|
||
// coverage should be propagated to i1 | ||
Map<AbstractInsnNode, Instruction> map = builder.getInstructions(); | ||
assertEquals(CounterImpl.COUNTER_0_1, | ||
map.get(i1).getInstructionCounter()); | ||
} | ||
|
||
@Test | ||
public void subsequent_instructions_should_not_be_linked_when_noSuccessor_was_called() { | ||
InsnNode i1 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i1); | ||
builder.noSuccessor(); | ||
|
||
InsnNode i2 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i2); | ||
|
||
// mark i2 as covered | ||
builder.addProbe(1, 0); | ||
|
||
// coverage should not be propagated to i1 | ||
Map<AbstractInsnNode, Instruction> map = builder.getInstructions(); | ||
assertEquals(CounterImpl.COUNTER_1_0, | ||
map.get(i1).getInstructionCounter()); | ||
} | ||
|
||
@Test | ||
public void subsequent_instructions_should_be_linked_after_label_marked_as_successor() { | ||
InsnNode i1 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i1); | ||
|
||
Label l = new Label(); | ||
LabelInfo.setSuccessor(l); | ||
builder.addLabel(l); | ||
InsnNode i2 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i2); | ||
|
||
// mark i2 as covered | ||
builder.addProbe(1, 0); | ||
|
||
// coverage should be propagated to i1 | ||
Map<AbstractInsnNode, Instruction> map = builder.getInstructions(); | ||
assertEquals(CounterImpl.COUNTER_0_1, | ||
map.get(i1).getInstructionCounter()); | ||
} | ||
|
||
@Test | ||
public void subsequent_instructions_should_not_be_linked_after_label_not_marked_as_successor() { | ||
InsnNode i1 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i1); | ||
|
||
builder.addLabel(new Label()); | ||
InsnNode i2 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i2); | ||
|
||
// mark i2 as covered | ||
builder.addProbe(1, 0); | ||
|
||
// coverage should not be propagated to i1 | ||
Map<AbstractInsnNode, Instruction> map = builder.getInstructions(); | ||
assertEquals(CounterImpl.COUNTER_1_0, | ||
map.get(i1).getInstructionCounter()); | ||
} | ||
|
||
@Test | ||
public void jumps_should_propagate_coverage_status() { | ||
InsnNode i1 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i1); | ||
Label l2 = new Label(); | ||
builder.addJump(l2, 0); | ||
|
||
builder.addLabel(l2); | ||
InsnNode i2 = new InsnNode(Opcodes.NOP); | ||
builder.addInstruction(i2); | ||
|
||
// mark i2 as covered | ||
builder.addProbe(1, 0); | ||
|
||
// coverage should be propagated to i1 | ||
Map<AbstractInsnNode, Instruction> map = builder.getInstructions(); | ||
assertEquals(CounterImpl.COUNTER_0_1, | ||
map.get(i1).getInstructionCounter()); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.