aboutsummaryrefslogtreecommitdiffstats
path: root/org.jacoco.core.test/src/org/jacoco/core/internal/analysis
diff options
context:
space:
mode:
Diffstat (limited to 'org.jacoco.core.test/src/org/jacoco/core/internal/analysis')
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/BundleCoverageImplTest.java2
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassAnalyzerTest.java2
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java4
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/CounterImplTest.java2
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionTest.java173
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionsBuilderTest.java189
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/LineImplTest.java2
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java80
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageCalculatorTest.java239
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageImplTest.java2
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/PackageCoverageTest.java2
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/SourceFileCoverageImplTest.java2
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/SourceNodeImplTest.java2
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/StringPoolTest.java2
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java222
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java128
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java134
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java54
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java48
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java102
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java12
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilterTest.java86
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java376
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilterTest.java98
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilterTest.java100
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilterTest.java281
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java61
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilterTest.java59
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilterTest.java52
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilterTest.java123
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java108
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java86
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java29
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java158
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java64
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java43
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java74
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilterTest.java51
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11FilterTest.java138
-rw-r--r--org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilterTest.java77
40 files changed, 3019 insertions, 448 deletions
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/BundleCoverageImplTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/BundleCoverageImplTest.java
index 82ad63fa..71d8e150 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/BundleCoverageImplTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/BundleCoverageImplTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassAnalyzerTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassAnalyzerTest.java
index ec65035f..372c6023 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassAnalyzerTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassAnalyzerTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java
index b219a878..7a53abf8 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/ClassCoverageImplTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
@@ -93,7 +93,7 @@ public class ClassCoverageImplTest {
assertEquals(CounterImpl.COUNTER_0_0, node.getInstructionCounter());
assertEquals(CounterImpl.COUNTER_0_0, node.getBranchCounter());
assertEquals(CounterImpl.COUNTER_0_0, node.getMethodCounter());
- assertEquals(CounterImpl.COUNTER_1_0, node.getClassCounter());
+ assertEquals(CounterImpl.COUNTER_0_0, node.getClassCounter());
}
@Test
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/CounterImplTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/CounterImplTest.java
index 8e8f769e..9e55820f 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/CounterImplTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/CounterImplTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionTest.java
new file mode 100644
index 00000000..e7e167e2
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionTest.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * 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.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());
+ }
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionsBuilderTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionsBuilderTest.java
new file mode 100644
index 00000000..b938caa7
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/InstructionsBuilderTest.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * 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.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());
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/LineImplTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/LineImplTest.java
index ffc3bfc1..115c72e6 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/LineImplTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/LineImplTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java
index c312e60c..01b29db4 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodAnalyzerTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
@@ -14,11 +14,15 @@ package org.jacoco.core.internal.analysis;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
import org.jacoco.core.analysis.ILine;
import org.jacoco.core.analysis.IMethodCoverage;
+import org.jacoco.core.internal.analysis.filter.FilterContextMock;
import org.jacoco.core.internal.analysis.filter.Filters;
import org.jacoco.core.internal.analysis.filter.IFilter;
+import org.jacoco.core.internal.analysis.filter.IFilterContext;
import org.jacoco.core.internal.analysis.filter.IFilterOutput;
import org.jacoco.core.internal.flow.IProbeIdGenerator;
import org.jacoco.core.internal.flow.LabelFlowAnalyzer;
@@ -109,8 +113,8 @@ public class MethodAnalyzerTest implements IProbeIdGenerator {
/** Filters the NOP instructions as ignored */
private static final IFilter NOP_FILTER = new IFilter() {
- public void filter(final String className, final String superClassName,
- final MethodNode methodNode, final IFilterOutput output) {
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
final AbstractInsnNode i1 = methodNode.instructions.get(2);
final AbstractInsnNode i2 = methodNode.instructions.get(3);
assertEquals(Opcodes.NOP, i1.getOpcode());
@@ -125,6 +129,9 @@ public class MethodAnalyzerTest implements IProbeIdGenerator {
probes[0] = true;
runMethodAnalzer(NOP_FILTER);
+ assertEquals(1002, result.getFirstLine());
+ assertEquals(1002, result.getLastLine());
+
assertLine(1001, 0, 0, 0, 0);
assertLine(1002, 0, 1, 0, 0);
}
@@ -318,22 +325,24 @@ public class MethodAnalyzerTest implements IProbeIdGenerator {
public void if_branch_merge_should_show_partial_branch_coverage_when_probe_for_first_branch_is_executed() {
createIfBranchMerge();
probes[0] = true;
+ probes[2] = true;
runMethodAnalzer();
assertLine(1001, 0, 2, 1, 1);
assertLine(1002, 1, 0, 0, 0);
- assertLine(1003, 1, 0, 0, 0);
+ assertLine(1003, 0, 1, 0, 0);
}
@Test
public void if_branch_merge_should_show_partial_branch_coverage_when_probe_for_second_branch_is_executed() {
createIfBranchMerge();
probes[1] = true;
+ probes[2] = true;
runMethodAnalzer();
assertLine(1001, 0, 2, 1, 1);
assertLine(1002, 0, 1, 0, 0);
- assertLine(1003, 1, 0, 0, 0);
+ assertLine(1003, 0, 1, 0, 0);
}
@Test
@@ -447,7 +456,7 @@ public class MethodAnalyzerTest implements IProbeIdGenerator {
assertLine(1002, 0, 1, 0, 0);
}
- // === Scenario: table switch ===
+ // === Scenario: table switch with and without replace filtering ===
private void createTableSwitch() {
final Label l0 = new Label();
@@ -492,6 +501,41 @@ public class MethodAnalyzerTest implements IProbeIdGenerator {
assertEquals(4, nextProbeId);
}
+ private static final IFilter SWITCH_FILTER = new IFilter() {
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ final AbstractInsnNode i = methodNode.instructions.get(3);
+ assertEquals(Opcodes.TABLESWITCH, i.getOpcode());
+ final AbstractInsnNode t1 = methodNode.instructions.get(6);
+ assertEquals(Opcodes.BIPUSH, t1.getOpcode());
+ final AbstractInsnNode t2 = methodNode.instructions.get(13);
+ assertEquals(Opcodes.BIPUSH, t2.getOpcode());
+
+ final Set<AbstractInsnNode> newTargets = new HashSet<AbstractInsnNode>();
+ newTargets.add(t1);
+ newTargets.add(t2);
+ output.replaceBranches(i, newTargets);
+ }
+ };
+
+ @Test
+ public void table_switch_with_filter_should_show_2_branches_when_original_replaced() {
+ createTableSwitch();
+ runMethodAnalzer(SWITCH_FILTER);
+
+ assertLine(1001, 2, 0, 2, 0);
+ }
+
+ @Test
+ public void table_switch_with_filter_should_show_full_branch_coverage_when_new_targets_covered() {
+ createTableSwitch();
+ probes[0] = true;
+ probes[1] = true;
+ runMethodAnalzer(SWITCH_FILTER);
+
+ assertLine(1001, 0, 2, 0, 2);
+ }
+
@Test
public void table_switch_should_show_missed_when_no_probes_are_executed() {
createTableSwitch();
@@ -708,13 +752,12 @@ public class MethodAnalyzerTest implements IProbeIdGenerator {
public void try_catch_should_show_exception_handler_missed_when_probe_is_not_executed() {
createTryCatchBlock();
probes[0] = true;
- probes[1] = true;
- probes[0] = true;
+ probes[2] = true;
runMethodAnalzer();
assertLine(1001, 0, 3, 0, 0);
- assertLine(1002, 0, 1, 0, 0);
- assertLine(1003, 1, 0, 0, 0);
+ assertLine(1002, 1, 0, 0, 0);
+ assertLine(1003, 0, 1, 0, 0);
}
@Test
@@ -777,8 +820,8 @@ public class MethodAnalyzerTest implements IProbeIdGenerator {
}
private static final IFilter TRY_FINALLY_FILTER = new IFilter() {
- public void filter(final String className, final String superClassName,
- final MethodNode methodNode, final IFilterOutput output) {
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
final AbstractInsnNode i1 = methodNode.instructions.get(2);
final AbstractInsnNode i2 = methodNode.instructions.get(7);
assertEquals(Opcodes.IFEQ, i1.getOpcode());
@@ -845,14 +888,21 @@ public class MethodAnalyzerTest implements IProbeIdGenerator {
private void runMethodAnalzer(IFilter filter) {
LabelFlowAnalyzer.markLabels(method);
- final MethodAnalyzer analyzer = new MethodAnalyzer("Foo",
- "java/lang/Object", "doit", "()V", null, probes, filter);
+ InstructionsBuilder builder = new InstructionsBuilder(probes);
+ final MethodAnalyzer analyzer = new MethodAnalyzer(builder);
+
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();
+
+ MethodCoverageImpl mc = new MethodCoverageImpl("doit", "V()", null);
+ MethodCoverageCalculator mcc = new MethodCoverageCalculator(
+ builder.getInstructions());
+ filter.filter(method, new FilterContextMock(), mcc);
+ mcc.calculate(mc);
+ result = mc;
}
private void assertLine(int nr, int insnMissed, int insnCovered,
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageCalculatorTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageCalculatorTest.java
new file mode 100644
index 00000000..306bc792
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageCalculatorTest.java
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * 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.analysis;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.jacoco.core.analysis.ISourceFileCoverage;
+import org.junit.Before;
+import org.junit.Test;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.InsnNode;
+
+/**
+ * Unit tests for {@link MethodCoverageCalculator}.
+ */
+public class MethodCoverageCalculatorTest {
+
+ private Map<AbstractInsnNode, Instruction> instructions;
+
+ // The purpose of this list is to link instruction nodes
+ private InsnList list;
+
+ private MethodCoverageImpl coverage;
+
+ @Before
+ public void setup() {
+ instructions = new HashMap<AbstractInsnNode, Instruction>();
+ coverage = new MethodCoverageImpl("run", "()V", null);
+ list = new InsnList();
+ }
+
+ @Test
+ public void should_report_instructions() {
+ addInsn(1, true);
+ addInsn(2, true);
+ addInsn(2, false);
+ addInsn(3, false);
+
+ MethodCoverageCalculator c = new MethodCoverageCalculator(instructions);
+ c.calculate(coverage);
+
+ assertLine(1, 0, 1, 0, 0);
+ assertLine(2, 1, 1, 0, 0);
+ assertLine(3, 1, 0, 0, 0);
+ }
+
+ @Test
+ public void should_report_instructions_with_branches() {
+ addInsn(1, false, false);
+ addInsn(2, false, false, true);
+ addInsn(3, false, true, true);
+
+ MethodCoverageCalculator c = new MethodCoverageCalculator(instructions);
+ c.calculate(coverage);
+
+ assertLine(1, 1, 0, 2, 0);
+ assertLine(2, 0, 1, 2, 1);
+ assertLine(3, 0, 1, 1, 2);
+ }
+
+ @Test
+ public void should_ignore_single_instruction() {
+ addInsn(1, true);
+ InsnNode i1 = addInsn(1, false);
+ addInsn(2, true);
+
+ MethodCoverageCalculator c = new MethodCoverageCalculator(instructions);
+ c.ignore(i1, i1);
+ c.calculate(coverage);
+
+ assertLine(1, 0, 1, 0, 0); // only one instruction not filtered
+ assertLine(2, 0, 1, 0, 0);
+ }
+
+ @Test
+ public void should_ignore_instruction_range() {
+ addInsn(1, true);
+ InsnNode i1 = addInsn(2, false);
+ addInsn(2, false);
+ addInsn(2, false);
+ addInsn(2, false);
+ InsnNode i2 = addInsn(2, false);
+ addInsn(3, true);
+
+ MethodCoverageCalculator c = new MethodCoverageCalculator(instructions);
+ c.ignore(i1, i2);
+ c.calculate(coverage);
+
+ assertLine(1, 0, 1, 0, 0);
+ assertLine(2, 0, 0, 0, 0); // all instructions filtered in line 2
+ assertLine(3, 0, 1, 0, 0);
+ }
+
+ @Test
+ public void should_exclude_ignored_instructions_from_computation_of_first_and_last_lines() {
+ InsnNode i1 = addInsn(1, false);
+ addInsn(2, false);
+ InsnNode i3 = addInsn(3, false);
+
+ MethodCoverageCalculator c = new MethodCoverageCalculator(instructions);
+ c.ignore(i1, i1);
+ c.ignore(i3, i3);
+ c.calculate(coverage);
+
+ assertEquals(2, coverage.getFirstLine());
+ assertEquals(2, coverage.getLastLine());
+ }
+
+ @Test
+ public void should_merge_instructions() {
+ addInsn(1, true);
+ InsnNode i1 = addInsn(2, false, true);
+ InsnNode i2 = addInsn(2, true, false);
+ addInsn(3, true);
+
+ MethodCoverageCalculator c = new MethodCoverageCalculator(instructions);
+ c.merge(i1, i2);
+ c.calculate(coverage);
+
+ assertLine(1, 0, 1, 0, 0);
+ assertLine(2, 0, 1, 0, 2); // one fully covered instruction left
+ assertLine(3, 0, 1, 0, 0);
+ }
+
+ @Test
+ public void should_merge_multiple_instructions() {
+ InsnNode i1 = addInsn(1, true, false, false);
+ InsnNode i2 = addInsn(1, false, true, false);
+ InsnNode i3 = addInsn(1, false, false, true);
+
+ MethodCoverageCalculator c = new MethodCoverageCalculator(instructions);
+ c.merge(i1, i2);
+ c.merge(i2, i3);
+ c.calculate(coverage);
+
+ assertLine(1, 0, 1, 0, 3); // one fully covered instruction left
+ }
+
+ @Test
+ public void should_merge_instructions_redundant() {
+ addInsn(1, true);
+ InsnNode i1 = addInsn(2, false, true);
+ InsnNode i2 = addInsn(2, true, false);
+ addInsn(3, true);
+
+ MethodCoverageCalculator c = new MethodCoverageCalculator(instructions);
+ c.merge(i1, i2);
+ c.merge(i2, i1);
+ c.calculate(coverage);
+
+ assertLine(1, 0, 1, 0, 0);
+ assertLine(2, 0, 1, 0, 2); // one fully covered instruction left
+ assertLine(3, 0, 1, 0, 0);
+ }
+
+ @Test
+ public void should_replace_branches() {
+ InsnNode i1 = addInsn(1);
+ InsnNode i2 = addInsn(2, true);
+ InsnNode i3 = addInsn(2, true);
+ InsnNode i4 = addInsn(2, false);
+
+ MethodCoverageCalculator c = new MethodCoverageCalculator(instructions);
+ c.replaceBranches(i1,
+ new HashSet<AbstractInsnNode>(Arrays.asList(i2, i3, i4)));
+ c.calculate(coverage);
+
+ assertLine(1, 0, 1, 1, 2); // branches coverage status replaced
+ assertLine(2, 1, 2, 0, 0); // still in place
+ }
+
+ @Test
+ public void should_replace_branches_with_merged_instructions() {
+ InsnNode i1 = addInsn(1, false, false, false);
+ InsnNode i2 = addInsn(2, true);
+ InsnNode i3 = addInsn(2, false);
+ InsnNode i4 = addInsn(2, false);
+
+ MethodCoverageCalculator c = new MethodCoverageCalculator(instructions);
+ c.merge(i4, i3);
+ c.merge(i3, i2);
+ c.replaceBranches(i1,
+ new HashSet<AbstractInsnNode>(Arrays.asList(i2, i3, i4)));
+ c.calculate(coverage);
+
+ assertLine(1, 0, 1, 0, 3);
+ }
+
+ @Test
+ public void should_work_without_lines() {
+ addInsn(ISourceFileCoverage.UNKNOWN_LINE, false);
+ addInsn(ISourceFileCoverage.UNKNOWN_LINE, false);
+ addInsn(ISourceFileCoverage.UNKNOWN_LINE, true);
+
+ MethodCoverageCalculator c = new MethodCoverageCalculator(instructions);
+ c.calculate(coverage);
+
+ assertEquals(ISourceFileCoverage.UNKNOWN_LINE, coverage.getFirstLine());
+ assertEquals(ISourceFileCoverage.UNKNOWN_LINE, coverage.getLastLine());
+ assertEquals(CounterImpl.getInstance(2, 1),
+ coverage.getInstructionCounter());
+ }
+
+ private void assertLine(int idx, int mi, int ci, int mb, int cb) {
+ assertEquals("instructions", CounterImpl.getInstance(mi, ci),
+ coverage.getLine(idx).getInstructionCounter());
+ assertEquals("branches", CounterImpl.getInstance(mb, cb),
+ coverage.getLine(idx).getBranchCounter());
+ }
+
+ private InsnNode addInsn(int line, boolean... branches) {
+ Instruction i = new Instruction(line);
+ int idx = 0;
+ for (boolean covered : branches) {
+ i.addBranch(covered, idx++);
+ }
+ InsnNode node = new InsnNode(Opcodes.NOP);
+ list.add(node);
+ instructions.put(node, i);
+ return node;
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageImplTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageImplTest.java
index fd04f448..5a100b0e 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageImplTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/MethodCoverageImplTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/PackageCoverageTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/PackageCoverageTest.java
index 76cf684a..1d81a027 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/PackageCoverageTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/PackageCoverageTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/SourceFileCoverageImplTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/SourceFileCoverageImplTest.java
index 69183e85..ed83ebaf 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/SourceFileCoverageImplTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/SourceFileCoverageImplTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/SourceNodeImplTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/SourceNodeImplTest.java
index 7e9a4233..25010428 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/SourceNodeImplTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/SourceNodeImplTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/StringPoolTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/StringPoolTest.java
index 18ca05d1..eca2460c 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/StringPoolTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/StringPoolTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java
new file mode 100644
index 00000000..f659632d
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AbstractMatcherTest.java
@@ -0,0 +1,222 @@
+/*******************************************************************************
+ * 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:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+import org.junit.Test;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.VarInsnNode;
+
+/**
+ * Unit tests for {@link AbstractMatcher}.
+ */
+public class AbstractMatcherTest {
+
+ private final AbstractMatcher matcher = new AbstractMatcher() {
+ };
+
+ private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "method_name", "()V", null, null);
+
+ @Test
+ public void skipNonOpcodes() {
+ m.visitFrame(Opcodes.F_FULL, 0, null, 0, null);
+ final Label label = new Label();
+ m.visitLabel(label);
+ m.visitLineNumber(42, label);
+ m.visitInsn(Opcodes.NOP);
+
+ // should skip all non opcodes
+ matcher.cursor = m.instructions.getFirst();
+ matcher.skipNonOpcodes();
+ assertSame(m.instructions.getLast(), matcher.cursor);
+
+ // should not change cursor when it points on instruction with opcode
+ matcher.skipNonOpcodes();
+ assertSame(m.instructions.getLast(), matcher.cursor);
+
+ // should not do anything when cursor is null
+ matcher.cursor = null;
+ matcher.skipNonOpcodes();
+ }
+
+ @Test
+ public void nextIs() {
+ m.visitInsn(Opcodes.NOP);
+ m.visitInsn(Opcodes.NOP);
+
+ // should set cursor to null when opcode mismatch
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIs(Opcodes.ATHROW);
+ assertNull(matcher.cursor);
+
+ // should set cursor to next instruction when match
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIs(Opcodes.NOP);
+ assertSame(m.instructions.getLast(), matcher.cursor);
+
+ // should not do anything when cursor is null
+ matcher.cursor = null;
+ matcher.nextIs(Opcodes.NOP);
+ }
+
+ @Test
+ public void nextIsSwitch() {
+ // should set cursor to null when opcode mismatch
+ m.visitInsn(Opcodes.NOP);
+ m.visitInsn(Opcodes.NOP);
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIsSwitch();
+ assertNull(matcher.cursor);
+
+ // should set cursor to next instruction when match
+ m.instructions.clear();
+ m.visitInsn(Opcodes.NOP);
+ m.visitTableSwitchInsn(0, 0, new Label());
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIsSwitch();
+ assertSame(m.instructions.getLast(), matcher.cursor);
+
+ // should set cursor to next instruction when match
+ m.instructions.clear();
+ m.visitInsn(Opcodes.NOP);
+ m.visitLookupSwitchInsn(new Label(), null, new Label[0]);
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIsSwitch();
+ assertSame(m.instructions.getLast(), matcher.cursor);
+
+ // should not do anything when cursor is null
+ matcher.cursor = null;
+ matcher.nextIsSwitch();
+ }
+
+ @Test
+ public void nextIsVar() {
+ m.visitInsn(Opcodes.NOP);
+ m.visitVarInsn(Opcodes.ILOAD, 42);
+
+ // should set cursor to null when opcode mismatch
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIsVar(Opcodes.ALOAD, "name");
+ assertNull(matcher.cursor);
+
+ // should set cursor to next instruction when match
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIsVar(Opcodes.ILOAD, "name");
+ assertSame(m.instructions.getLast(), matcher.cursor);
+
+ // should set cursor to null when var mismatch
+ matcher.cursor = m.instructions.getFirst();
+ matcher.vars.put("name", new VarInsnNode(Opcodes.ILOAD, 13));
+ matcher.nextIsVar(Opcodes.ILOAD, "name");
+ assertNull(matcher.cursor);
+
+ // should set cursor to next instruction when match
+ matcher.cursor = m.instructions.getFirst();
+ matcher.vars.put("name", new VarInsnNode(Opcodes.ILOAD, 42));
+ matcher.nextIsVar(Opcodes.ILOAD, "name");
+ assertSame(m.instructions.getLast(), matcher.cursor);
+
+ // should not do anything when cursor is null
+ matcher.cursor = null;
+ matcher.nextIsVar(Opcodes.ILOAD, "name");
+ }
+
+ @Test
+ public void nextIsInvoke() {
+ m.visitInsn(Opcodes.NOP);
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "owner", "name", "()V", false);
+
+ // should set cursor to null when opcode mismatch
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIsInvoke(Opcodes.INVOKESTATIC, "owner", "name", "()V");
+ assertNull(matcher.cursor);
+
+ // should set cursor to null when owner mismatch
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIsInvoke(Opcodes.INVOKEVIRTUAL, "another_owner", "name",
+ "()V");
+ assertNull(matcher.cursor);
+
+ // should set cursor to null when name mismatch
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIsInvoke(Opcodes.INVOKEVIRTUAL, "owner", "another_name",
+ "()V");
+ assertNull(matcher.cursor);
+
+ // should set cursor to null when descriptor mismatch
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIsInvoke(Opcodes.INVOKEVIRTUAL, "owner", "name",
+ "(Lanother_descriptor;)V");
+ assertNull(matcher.cursor);
+
+ // should set cursor to next instruction when match
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIsInvoke(Opcodes.INVOKEVIRTUAL, "owner", "name", "()V");
+ assertSame(m.instructions.getLast(), matcher.cursor);
+
+ // should not do anything when cursor is null
+ matcher.cursor = null;
+ matcher.nextIsInvoke(Opcodes.INVOKEVIRTUAL, "owner", "name", "()V");
+ }
+
+ @Test
+ public void nextIsType() {
+ m.visitInsn(Opcodes.NOP);
+ m.visitTypeInsn(Opcodes.NEW, "descriptor");
+
+ // should set cursor to null when opcode mismatch
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIsType(Opcodes.CHECKCAST, "descriptor");
+ assertNull(matcher.cursor);
+
+ // should set cursor to null when descriptor mismatch
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIsType(Opcodes.NEW, "another_descriptor");
+ assertNull(matcher.cursor);
+
+ // should set cursor to next instruction when match
+ matcher.cursor = m.instructions.getFirst();
+ matcher.nextIsType(Opcodes.NEW, "descriptor");
+ assertSame(m.instructions.getLast(), matcher.cursor);
+
+ // should not do anything when cursor is null
+ matcher.cursor = null;
+ matcher.nextIsType(Opcodes.NEW, "descriptor");
+ }
+
+ @Test
+ public void firstIsALoad0() {
+ // should set cursor to null when opcode mismatch
+ m.visitInsn(Opcodes.NOP);
+ matcher.firstIsALoad0(m);
+ assertNull(matcher.cursor);
+
+ // should set cursor to null when var mismatch
+ m.instructions.clear();
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ matcher.firstIsALoad0(m);
+ assertNull(matcher.cursor);
+
+ // should set cursor to first instruction when match
+ m.instructions.clear();
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ matcher.firstIsALoad0(m);
+ assertSame(m.instructions.getLast(), matcher.cursor);
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java
new file mode 100644
index 00000000..b8a0331b
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilterTest.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * 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:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+import org.junit.Test;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Unit tests for {@link AnnotationGeneratedFilter}.
+ */
+public class AnnotationGeneratedFilterTest extends FilterTestBase {
+
+ private final IFilter filter = new AnnotationGeneratedFilter();
+
+ @Test
+ public void should_filter_methods_annotated_with_runtime_visible_org_groovy_transform_Generated() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "hashCode", "()I", null, null);
+ m.visitAnnotation("Lgroovy/transform/Generated;", true);
+
+ m.visitInsn(Opcodes.ICONST_0);
+ m.visitInsn(Opcodes.IRETURN);
+
+ filter.filter(m, context, output);
+
+ assertMethodIgnored(m);
+ }
+
+ @Test
+ public void should_filter_methods_annotated_with_runtime_invisible_lombok_Generated() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "hashCode", "()I", null, null);
+ m.visitAnnotation("Llombok/Generated;", false);
+
+ m.visitInsn(Opcodes.ICONST_0);
+ m.visitInsn(Opcodes.IRETURN);
+
+ filter.filter(m, context, output);
+
+ assertMethodIgnored(m);
+ }
+
+ @Test
+ public void should_filter_classes_annotated_with_runtime_visible_org_immutables_value_Generated() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "hashCode", "()I", null, null);
+
+ m.visitInsn(Opcodes.ICONST_0);
+ m.visitInsn(Opcodes.IRETURN);
+
+ context.classAnnotations.add("Lorg/immutables/value/Generated;");
+
+ filter.filter(m, context, output);
+
+ assertMethodIgnored(m);
+ }
+
+ @Test
+ public void should_filter_classes_annotated_with_runtime_visible_org_apache_avro_specific_AvroGenerated() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "readExternal", "()V", null, null);
+
+ m.visitInsn(Opcodes.NOP);
+
+ context.classAnnotations
+ .add("Lorg/apache/avro/specific/AvroGenerated;");
+
+ filter.filter(m, context, output);
+
+ assertMethodIgnored(m);
+ }
+
+ @Test
+ public void should_filter_when_annotation_is_inner() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "hashCode", "()I", null, null);
+
+ m.visitInsn(Opcodes.ICONST_0);
+ m.visitInsn(Opcodes.IRETURN);
+
+ context.classAnnotations.add("Lorg/example/Class$Generated;");
+
+ filter.filter(m, context, output);
+
+ assertMethodIgnored(m);
+ }
+
+ @Test
+ public void should_not_filter_when_no_annotations() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "hashCode", "()I", null, null);
+
+ m.visitInsn(Opcodes.ICONST_0);
+ m.visitInsn(Opcodes.IRETURN);
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+ @Test
+ public void should_not_filter_when_other_annotations() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "hashCode", "()I", null, null);
+ m.visitAnnotation("LOtherAnnotation;", true);
+
+ m.visitInsn(Opcodes.ICONST_0);
+ m.visitInsn(Opcodes.IRETURN);
+
+ context.classAnnotations.add("LOtherAnnotation;");
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java
new file mode 100644
index 00000000..32bc9df3
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilterTest.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * 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:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+import org.junit.Test;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Unit tests for {@link EnumEmptyConstructorFilter}.
+ */
+public class EnumEmptyConstructorFilterTest extends FilterTestBase {
+
+ private final EnumEmptyConstructorFilter filter = new EnumEmptyConstructorFilter();
+
+ @Test
+ public void should_filter() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION,
+ Opcodes.ACC_PRIVATE, "<init>", "(Ljava/lang/String;I)V", null,
+ null);
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitVarInsn(Opcodes.ILOAD, 2);
+ m.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Enum", "<init>",
+ "(Ljava/lang/String;I)V", false);
+ m.visitInsn(Opcodes.RETURN);
+ context.superClassName = "java/lang/Enum";
+
+ filter.filter(m, context, output);
+
+ assertIgnored(new Range(m.instructions.getFirst(), m.instructions.getLast()));
+ }
+
+ /**
+ * <code><pre>
+ * enum E {
+ * ;
+ * private E() {
+ * ...
+ * }
+ * }
+ * </pre></code>
+ */
+ @Test
+ public void should_not_filter_non_empty_constructor() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION,
+ Opcodes.ACC_PRIVATE, "<init>", "(Ljava/lang/String;I)V", null,
+ null);
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitVarInsn(Opcodes.ILOAD, 2);
+ m.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Enum", "<init>",
+ "(Ljava/lang/String;I)V", false);
+ m.visitInsn(Opcodes.NOP);
+ m.visitInsn(Opcodes.RETURN);
+ context.superClassName = "java/lang/Enum";
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+ /**
+ * <code><pre>
+ * enum E {
+ * ;
+ * private E(long p) {
+ * }
+ * }
+ * </pre></code>
+ */
+ @Test
+ public void should_not_filter_constructor_with_additional_parameters() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION,
+ Opcodes.ACC_PRIVATE, "<init>", "(Ljava/lang/String;IJ)V", null,
+ null);
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitVarInsn(Opcodes.ILOAD, 2);
+ m.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Enum", "<init>",
+ "(Ljava/lang/String;I)V", false);
+ m.visitInsn(Opcodes.RETURN);
+ context.superClassName = "java/lang/Enum";
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+ /**
+ * <code><pre>
+ * enum E {
+ * ;
+ * private void method(String p1, int p2) {
+ * }
+ * }
+ * </pre></code>
+ */
+ @Test
+ public void should_not_filter_non_constructor() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION,
+ Opcodes.ACC_PRIVATE, "method", "(Ljava/lang/String;I)V", null,
+ null);
+ m.visitInsn(Opcodes.NOP);
+ context.superClassName = "java/lang/Enum";
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+ @Test
+ public void should_not_filter_non_Enum() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION,
+ Opcodes.ACC_PRIVATE, "<init>", "(Ljava/lang/String;I)V", null,
+ null);
+ m.visitInsn(Opcodes.NOP);
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java
index 9d7fb2ca..23f69f4e 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/EnumFilterTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
@@ -11,33 +11,28 @@
*******************************************************************************/
package org.jacoco.core.internal.analysis.filter;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
import org.jacoco.core.internal.instr.InstrSupport;
import org.junit.Test;
import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodNode;
-public class EnumFilterTest implements IFilterOutput {
+/**
+ * Unit tests for {@link EnumFilter}.
+ */
+public class EnumFilterTest extends FilterTestBase {
private final EnumFilter filter = new EnumFilter();
- private AbstractInsnNode fromInclusive;
- private AbstractInsnNode toInclusive;
-
@Test
public void testValues() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"values", "()[LFoo;", null, null);
m.visitInsn(Opcodes.NOP);
+ context.superClassName = "java/lang/Enum";
- filter.filter("Foo", "java/lang/Enum", m, this);
+ filter.filter(m, context, output);
- assertEquals(m.instructions.getFirst(), fromInclusive);
- assertEquals(m.instructions.getLast(), toInclusive);
+ assertMethodIgnored(m);
}
@Test
@@ -46,10 +41,9 @@ public class EnumFilterTest implements IFilterOutput {
"values", "()V", null, null);
m.visitInsn(Opcodes.NOP);
- filter.filter("Foo", "java/lang/Enum", m, this);
+ filter.filter(m, context, output);
- assertNull(fromInclusive);
- assertNull(toInclusive);
+ assertIgnored();
}
@Test
@@ -57,11 +51,11 @@ public class EnumFilterTest implements IFilterOutput {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"valueOf", "(Ljava/lang/String;)LFoo;", null, null);
m.visitInsn(Opcodes.NOP);
+ context.superClassName = "java/lang/Enum";
- filter.filter("Foo", "java/lang/Enum", m, this);
+ filter.filter(m, context, output);
- assertEquals(m.instructions.getFirst(), fromInclusive);
- assertEquals(m.instructions.getLast(), toInclusive);
+ assertMethodIgnored(m);
}
@Test
@@ -69,11 +63,11 @@ public class EnumFilterTest implements IFilterOutput {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"valueOf", "()V", null, null);
m.visitInsn(Opcodes.NOP);
+ context.superClassName = "java/lang/Enum";
- filter.filter("Foo", "java/lang/Enum", m, this);
+ filter.filter(m, context, output);
- assertNull(fromInclusive);
- assertNull(toInclusive);
+ assertIgnored();
}
@Test
@@ -82,21 +76,9 @@ public class EnumFilterTest implements IFilterOutput {
"values", "()[LFoo;", null, null);
m.visitInsn(Opcodes.NOP);
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertNull(fromInclusive);
- assertNull(toInclusive);
- }
-
- public void ignore(final AbstractInsnNode fromInclusive,
- final AbstractInsnNode toInclusive) {
- assertNull(this.fromInclusive);
- this.fromInclusive = fromInclusive;
- this.toInclusive = toInclusive;
- }
+ filter.filter(m, context, output);
- public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) {
- fail();
+ assertIgnored();
}
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java
new file mode 100644
index 00000000..a6c881d3
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterContextMock.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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.analysis.filter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * {@link IFilterContext} mock for unit tests.
+ */
+public class FilterContextMock implements IFilterContext {
+
+ public String className = "Foo";
+ public String superClassName = "java/lang/Object";
+ public Set<String> classAnnotations = new HashSet<String>();
+ public String sourceFileName = "Foo.java";
+ public String sourceDebugExtension;
+
+ public String getClassName() {
+ return className;
+ }
+
+ public String getSuperClassName() {
+ return superClassName;
+ }
+
+ public Set<String> getClassAnnotations() {
+ return classAnnotations;
+ }
+
+ public String getSourceFileName() {
+ return sourceFileName;
+ }
+
+ public String getSourceDebugExtension() {
+ return sourceDebugExtension;
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java
new file mode 100644
index 00000000..2378bee3
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FilterTestBase.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * 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:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Base class for tests of {@link IFilter} implementations.
+ */
+public abstract class FilterTestBase {
+
+ protected final FilterContextMock context = new FilterContextMock();
+
+ private final List<Range> ignoredRanges = new ArrayList<Range>();
+
+ private final Map<AbstractInsnNode, Set<AbstractInsnNode>> replacedBranches = new HashMap<AbstractInsnNode, Set<AbstractInsnNode>>();
+
+ protected final IFilterOutput output = new IFilterOutput() {
+ public void ignore(final AbstractInsnNode fromInclusive,
+ final AbstractInsnNode toInclusive) {
+ final Range range = new Range();
+ range.fromInclusive = fromInclusive;
+ range.toInclusive = toInclusive;
+ ignoredRanges.add(range);
+ }
+
+ public void merge(final AbstractInsnNode i1,
+ final AbstractInsnNode i2) {
+ fail();
+ }
+
+ public void replaceBranches(final AbstractInsnNode source,
+ final Set<AbstractInsnNode> newTargets) {
+ replacedBranches.put(source, newTargets);
+ }
+ };
+
+ final void assertIgnored(Range... ranges) {
+ assertArrayEquals(ranges, ignoredRanges.toArray(new Range[0]));
+ }
+
+ final void assertMethodIgnored(final MethodNode m) {
+ assertIgnored(
+ new Range(m.instructions.getFirst(), m.instructions.getLast()));
+ }
+
+ final void assertNoReplacedBranches() {
+ assertTrue(replacedBranches.isEmpty());
+ }
+
+ final void assertReplacedBranches(final AbstractInsnNode source,
+ final Set<AbstractInsnNode> newTargets) {
+ assertEquals(Collections.singletonMap(source, newTargets),
+ replacedBranches);
+ }
+
+ static class Range {
+ AbstractInsnNode fromInclusive;
+ AbstractInsnNode toInclusive;
+
+ Range() {
+ }
+
+ Range(AbstractInsnNode fromInclusive, AbstractInsnNode toInclusive) {
+ this.fromInclusive = fromInclusive;
+ this.toInclusive = toInclusive;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj.getClass() == Range.class) {
+ final Range other = (Range) obj;
+ return this.fromInclusive.equals(other.fromInclusive)
+ && this.toInclusive.equals(other.toInclusive);
+ }
+ return false;
+ }
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java
index 5e0ed6c9..6a9cf67f 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/FinallyFilterTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
@@ -24,6 +24,9 @@ import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodNode;
+/**
+ * Unit tests for {@link FinallyFilter}.
+ */
public class FinallyFilterTest implements IFilterOutput {
private final IFilter filter = new FinallyFilter();
@@ -383,7 +386,7 @@ public class FinallyFilterTest implements IFilterOutput {
}
private void execute() {
- filter.filter("", "", m, this);
+ filter.filter(m, new FilterContextMock(), this);
assertEquals("ignored", toIndexes(expectedIgnored),
toIndexes(actualIgnored));
assertEquals("merged", toIndexes(expectedMerged),
@@ -418,4 +421,9 @@ public class FinallyFilterTest implements IFilterOutput {
}
}
+ public void replaceBranches(final AbstractInsnNode source,
+ final Set<AbstractInsnNode> newTargets) {
+ fail();
+ }
+
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilterTest.java
deleted file mode 100644
index 6cf0febe..00000000
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilterTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*******************************************************************************
- * 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.filter;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
-import org.jacoco.core.internal.instr.InstrSupport;
-import org.junit.Test;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-
-public class GroovyGeneratedFilterTest implements IFilterOutput {
-
- private final IFilter filter = new GroovyGeneratedFilter();
-
- private AbstractInsnNode fromInclusive;
- private AbstractInsnNode toInclusive;
-
- @Test
- public void testNoAnnotations() {
- final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
- "hashCode", "()I", null, null);
-
- m.visitInsn(Opcodes.ICONST_0);
- m.visitInsn(Opcodes.IRETURN);
-
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertNull(fromInclusive);
- assertNull(toInclusive);
- }
-
- @Test
- public void testOtherAnnotation() {
- final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
- "hashCode", "()I", null, null);
- m.visitAnnotation("Lother/Annotation;", true);
-
- m.visitInsn(Opcodes.ICONST_0);
- m.visitInsn(Opcodes.IRETURN);
-
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertNull(fromInclusive);
- assertNull(toInclusive);
- }
-
- @Test
- public void testGroovyGeneratedAnnotation() {
- final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
- "hashCode", "()I", null, null);
- m.visitAnnotation("Lgroovy/transform/Generated;", true);
-
- m.visitInsn(Opcodes.ICONST_0);
- m.visitInsn(Opcodes.IRETURN);
-
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertEquals(m.instructions.getFirst(), fromInclusive);
- assertEquals(m.instructions.getLast(), toInclusive);
- }
-
- public void ignore(final AbstractInsnNode fromInclusive,
- final AbstractInsnNode toInclusive) {
- assertNull(this.fromInclusive);
- this.fromInclusive = fromInclusive;
- this.toInclusive = toInclusive;
- }
-
- public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) {
- fail();
- }
-
-}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java
new file mode 100644
index 00000000..127ae309
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilterTest.java
@@ -0,0 +1,376 @@
+/*******************************************************************************
+ * 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:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+import org.junit.Test;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Unit test for {@link KotlinCoroutineFilter}.
+ */
+public class KotlinCoroutineFilterTest extends FilterTestBase {
+
+ private final IFilter filter = new KotlinCoroutineFilter();
+
+ @Test
+ public void should_filter_suspending_lambdas_generated_by_Kotlin_1_3_30() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "invokeSuspend", "(Ljava/lang/Object;)Ljava/lang/Object;", null,
+ null);
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ m.visitLabel(new Label());
+ final Range range1 = new Range();
+ range1.fromInclusive = m.instructions.getLast();
+ m.visitMethodInsn(Opcodes.INVOKESTATIC,
+ "kotlin/coroutines/intrinsics/IntrinsicsKt",
+ "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;", false);
+ m.visitVarInsn(Opcodes.ASTORE, 4);
+
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ // line of "runBlocking"
+ m.visitFieldInsn(Opcodes.GETFIELD, "Target", "label", "I");
+ final Label dflt = new Label();
+ final Label state0 = new Label();
+ final Label state1 = new Label();
+ m.visitTableSwitchInsn(0, 1, dflt, state0, state1);
+
+ m.visitLabel(state0);
+
+ {
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/ResultKt",
+ "throwOnFailure", "(Ljava/lang/Object;)V", false);
+ range1.toInclusive = m.instructions.getLast();
+ }
+
+ // line before "suspendingFunction"
+ m.visitInsn(Opcodes.NOP);
+
+ // line of "suspendingFunction"
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "", "suspendingFunction",
+ "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", false);
+
+ m.visitInsn(Opcodes.DUP);
+ final Range range2 = new Range();
+ range2.fromInclusive = m.instructions.getLast();
+ m.visitVarInsn(Opcodes.ALOAD, 4);
+ final Label continuationLabelAfterLoadedResult = new Label();
+ m.visitJumpInsn(Opcodes.IF_ACMPNE, continuationLabelAfterLoadedResult);
+ // line of "runBlocking"
+ m.visitVarInsn(Opcodes.ALOAD, 4);
+ m.visitInsn(Opcodes.ARETURN);
+
+ m.visitLabel(state1);
+
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ m.visitFieldInsn(Opcodes.GETFIELD, "Target", "I$0", "I");
+ m.visitVarInsn(Opcodes.ISTORE, 3);
+
+ {
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitMethodInsn(Opcodes.INVOKESTATIC, "kotlin/ResultKt",
+ "throwOnFailure", "(Ljava/lang/Object;)V", false);
+ }
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ range2.toInclusive = m.instructions.getLast();
+ m.visitLabel(continuationLabelAfterLoadedResult);
+
+ // line after "suspendingFunction"
+ m.visitInsn(Opcodes.NOP);
+ m.visitInsn(Opcodes.ARETURN);
+
+ m.visitLabel(dflt);
+ final Range range0 = new Range();
+ range0.fromInclusive = m.instructions.getLast();
+ m.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException");
+ m.visitInsn(Opcodes.DUP);
+ m.visitLdcInsn("call to 'resume' before 'invoke' with coroutine");
+ m.visitMethodInsn(Opcodes.INVOKESPECIAL,
+ "java/lang/IllegalStateException", "<init>",
+ "(Ljava/lang/String;)V", false);
+ m.visitInsn(Opcodes.ATHROW);
+ range0.toInclusive = m.instructions.getLast();
+
+ filter.filter(m, context, output);
+
+ assertIgnored(range0, range1, range2);
+ }
+
+ /**
+ * <pre>
+ * runBlocking {
+ * val x = 42
+ * nop(x)
+ * suspendingFunction()
+ * nop(x)
+ * }
+ * </pre>
+ */
+ @Test
+ public void should_filter_suspending_lambdas() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "invokeSuspend", "(Ljava/lang/Object;)Ljava/lang/Object;", null,
+ null);
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ m.visitLabel(new Label());
+ final Range range1 = new Range();
+ range1.fromInclusive = m.instructions.getLast();
+ m.visitMethodInsn(Opcodes.INVOKESTATIC,
+ "kotlin/coroutines/intrinsics/IntrinsicsKt",
+ "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;", false);
+ m.visitVarInsn(Opcodes.ASTORE, 4);
+
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ // line of "runBlocking"
+ m.visitFieldInsn(Opcodes.GETFIELD, "Target", "label", "I");
+ final Label dflt = new Label();
+ final Label state0 = new Label();
+ final Label state1 = new Label();
+ m.visitTableSwitchInsn(0, 1, dflt, state0, state1);
+
+ m.visitLabel(state0);
+
+ {
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitInsn(Opcodes.DUP);
+ m.visitTypeInsn(Opcodes.INSTANCEOF, "kotlin/Result$Failure");
+ Label label = new Label();
+ m.visitJumpInsn(Opcodes.IFEQ, label);
+ m.visitTypeInsn(Opcodes.CHECKCAST, "kotlin/Result$Failure");
+ m.visitFieldInsn(Opcodes.GETFIELD, "kotlin/Result$Failure",
+ "exception", "Ljava/lang/Throwable");
+ m.visitInsn(Opcodes.ATHROW);
+ m.visitInsn(Opcodes.POP);
+ range1.toInclusive = m.instructions.getLast();
+ m.visitLabel(label);
+ }
+
+ // line before "suspendingFunction"
+ m.visitInsn(Opcodes.NOP);
+
+ // line of "suspendingFunction"
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "", "suspendingFunction",
+ "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", false);
+
+ m.visitInsn(Opcodes.DUP);
+ final Range range2 = new Range();
+ range2.fromInclusive = m.instructions.getLast();
+ m.visitVarInsn(Opcodes.ALOAD, 4);
+ final Label continuationLabelAfterLoadedResult = new Label();
+ m.visitJumpInsn(Opcodes.IF_ACMPNE, continuationLabelAfterLoadedResult);
+ // line of "runBlocking"
+ m.visitVarInsn(Opcodes.ALOAD, 4);
+ m.visitInsn(Opcodes.ARETURN);
+
+ m.visitLabel(state1);
+
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ m.visitFieldInsn(Opcodes.GETFIELD, "Target", "I$0", "I");
+ m.visitVarInsn(Opcodes.ISTORE, 3);
+
+ {
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitInsn(Opcodes.DUP);
+ m.visitTypeInsn(Opcodes.INSTANCEOF, "kotlin/Result$Failure");
+ final Label label = new Label();
+ m.visitJumpInsn(Opcodes.IFEQ, label);
+ m.visitTypeInsn(Opcodes.CHECKCAST, "kotlin/Result$Failure");
+ m.visitFieldInsn(Opcodes.GETFIELD, "kotlin/Result$Failure",
+ "exception", "Ljava/lang/Throwable");
+ m.visitInsn(Opcodes.ATHROW);
+ m.visitInsn(Opcodes.POP);
+ m.visitLabel(label);
+ }
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ range2.toInclusive = m.instructions.getLast();
+ m.visitLabel(continuationLabelAfterLoadedResult);
+
+ // line after "suspendingFunction"
+ m.visitInsn(Opcodes.NOP);
+ m.visitInsn(Opcodes.ARETURN);
+
+ m.visitLabel(dflt);
+ final Range range0 = new Range();
+ range0.fromInclusive = m.instructions.getLast();
+ m.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException");
+ m.visitInsn(Opcodes.DUP);
+ m.visitLdcInsn("call to 'resume' before 'invoke' with coroutine");
+ m.visitMethodInsn(Opcodes.INVOKESPECIAL,
+ "java/lang/IllegalStateException", "<init>",
+ "(Ljava/lang/String;)V", false);
+ m.visitInsn(Opcodes.ATHROW);
+ range0.toInclusive = m.instructions.getLast();
+
+ filter.filter(m, context, output);
+
+ assertIgnored(range0, range1, range2);
+ }
+
+ /**
+ * <pre>
+ * suspend fun example() {
+ * suspendingFunction()
+ * nop()
+ * }
+ * </pre>
+ */
+ @Test
+ public void should_filter_suspending_functions() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION,
+ Opcodes.ACC_STATIC, "example",
+ "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", null,
+ null);
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ final int continuationArgumentIndex = 0;
+ final int continuationIndex = 2;
+
+ m.visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex);
+ final Range range1 = new Range();
+ range1.fromInclusive = m.instructions.getLast();
+ m.visitTypeInsn(Opcodes.INSTANCEOF, "ExampleKt$example$1");
+ final Label createStateInstance = new Label();
+ m.visitJumpInsn(Opcodes.IFEQ, createStateInstance);
+
+ m.visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex);
+ m.visitTypeInsn(Opcodes.CHECKCAST, "ExampleKt$example$1");
+ m.visitVarInsn(Opcodes.ASTORE, continuationIndex);
+
+ m.visitVarInsn(Opcodes.ALOAD, continuationIndex);
+ m.visitFieldInsn(Opcodes.GETFIELD, "ExampleKt$example$1", "label", "I");
+
+ m.visitLdcInsn(Integer.valueOf(Integer.MIN_VALUE));
+ m.visitInsn(Opcodes.IAND);
+ m.visitJumpInsn(Opcodes.IFEQ, createStateInstance);
+
+ m.visitVarInsn(Opcodes.ALOAD, continuationIndex);
+ m.visitInsn(Opcodes.DUP);
+ m.visitFieldInsn(Opcodes.GETFIELD, "ExampleKt$example$1", "label", "I");
+
+ m.visitLdcInsn(Integer.valueOf(Integer.MIN_VALUE));
+ m.visitInsn(Opcodes.ISUB);
+ m.visitFieldInsn(Opcodes.PUTFIELD, "ExampleKt$example$1", "label", "I");
+
+ final Label afterCoroutineStateCreated = new Label();
+ m.visitJumpInsn(Opcodes.GOTO, afterCoroutineStateCreated);
+
+ m.visitLabel(createStateInstance);
+
+ m.visitTypeInsn(Opcodes.NEW, "ExampleKt$example$1");
+ m.visitInsn(Opcodes.DUP);
+ m.visitVarInsn(Opcodes.ALOAD, continuationArgumentIndex);
+ m.visitMethodInsn(Opcodes.INVOKESPECIAL, "ExampleKt$example$1",
+ "<init>", "(Lkotlin/coroutines/Continuation;)V", false);
+
+ m.visitVarInsn(Opcodes.ASTORE, continuationIndex);
+
+ m.visitLabel(afterCoroutineStateCreated);
+
+ m.visitVarInsn(Opcodes.ALOAD, continuationIndex);
+ m.visitFieldInsn(Opcodes.GETFIELD, "ExampleKt$example$1", "result",
+ "Ljava/lang/Object;");
+ m.visitVarInsn(Opcodes.ASTORE, 1);
+
+ m.visitMethodInsn(Opcodes.INVOKESTATIC,
+ "kotlin/coroutines/intrinsics/IntrinsicsKt",
+ "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;", false);
+
+ // line of "fun"
+ m.visitVarInsn(Opcodes.ASTORE, 3);
+
+ m.visitVarInsn(Opcodes.ALOAD, continuationIndex);
+ m.visitFieldInsn(Opcodes.GETFIELD, "ExampleKt$example$1", "label", "I");
+ final Label dflt = new Label();
+ final Label state0 = new Label();
+ final Label state1 = new Label();
+ m.visitTableSwitchInsn(0, 1, dflt, state0, state1);
+
+ m.visitLabel(state0);
+
+ {
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitInsn(Opcodes.DUP);
+ m.visitTypeInsn(Opcodes.INSTANCEOF, "kotlin/Result$Failure");
+ Label label = new Label();
+ m.visitJumpInsn(Opcodes.IFEQ, label);
+ m.visitTypeInsn(Opcodes.CHECKCAST, "kotlin/Result$Failure");
+ m.visitFieldInsn(Opcodes.GETFIELD, "kotlin/Result$Failure",
+ "exception", "Ljava/lang/Throwable");
+ m.visitInsn(Opcodes.ATHROW);
+ m.visitInsn(Opcodes.POP);
+ range1.toInclusive = m.instructions.getLast();
+ m.visitLabel(label);
+ }
+
+ // line of "suspendingFunction"
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "", "suspendingFunction",
+ "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", false);
+
+ m.visitInsn(Opcodes.DUP);
+ final Range range2 = new Range();
+ range2.fromInclusive = m.instructions.getLast();
+ m.visitVarInsn(Opcodes.ALOAD, 3);
+ final Label continuationLabelAfterLoadedResult = new Label();
+ m.visitJumpInsn(Opcodes.IF_ACMPNE, continuationLabelAfterLoadedResult);
+ // line of "fun"
+ m.visitVarInsn(Opcodes.ALOAD, 3);
+ m.visitInsn(Opcodes.ARETURN);
+
+ m.visitLabel(state1);
+
+ {
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitInsn(Opcodes.DUP);
+ m.visitTypeInsn(Opcodes.INSTANCEOF, "kotlin/Result$Failure");
+ final Label label = new Label();
+ m.visitJumpInsn(Opcodes.IFEQ, label);
+ m.visitTypeInsn(Opcodes.CHECKCAST, "kotlin/Result$Failure");
+ m.visitFieldInsn(Opcodes.GETFIELD, "kotlin/Result$Failure",
+ "exception", "Ljava/lang/Throwable");
+ m.visitInsn(Opcodes.ATHROW);
+ m.visitInsn(Opcodes.POP);
+ m.visitLabel(label);
+ }
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ range2.toInclusive = m.instructions.getLast();
+ m.visitLabel(continuationLabelAfterLoadedResult);
+
+ // line after "suspendingFunction"
+ m.visitInsn(Opcodes.NOP);
+ m.visitInsn(Opcodes.ARETURN);
+
+ m.visitLabel(dflt);
+ final Range range0 = new Range();
+ range0.fromInclusive = m.instructions.getLast();
+ m.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException");
+ m.visitInsn(Opcodes.DUP);
+ m.visitLdcInsn("call to 'resume' before 'invoke' with coroutine");
+ m.visitMethodInsn(Opcodes.INVOKESPECIAL,
+ "java/lang/IllegalStateException", "<init>",
+ "(Ljava/lang/String;)V", false);
+ m.visitInsn(Opcodes.ATHROW);
+ range0.toInclusive = m.instructions.getLast();
+
+ filter.filter(m, context, output);
+
+ assertIgnored(range0, range1, range2);
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilterTest.java
new file mode 100644
index 00000000..8dfa765e
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilterTest.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * 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:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+import org.junit.Test;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Unit test for {@link KotlinDefaultArgumentsFilter}.
+ */
+public class KotlinDefaultArgumentsFilterTest extends FilterTestBase {
+
+ private final IFilter filter = new KotlinDefaultArgumentsFilter();
+
+ private static MethodNode createMethod(final int access, final String name,
+ final String descriptor) {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION,
+ access, name, descriptor, null, null);
+
+ m.visitVarInsn(Opcodes.ILOAD, 2);
+ m.visitInsn(Opcodes.ICONST_1);
+ m.visitInsn(Opcodes.IAND);
+ final Label label = new Label();
+ m.visitJumpInsn(Opcodes.IFEQ, label);
+ // default argument
+ m.visitLdcInsn(Integer.valueOf(42));
+ m.visitVarInsn(Opcodes.ISTORE, 1);
+ m.visitLabel(label);
+
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ m.visitVarInsn(Opcodes.ILOAD, 1);
+ m.visitMethodInsn(Opcodes.INVOKESPECIAL, "Target", "origin", "(I)V",
+ false);
+ m.visitInsn(Opcodes.RETURN);
+
+ return m;
+ }
+
+ @Test
+ public void should_filter() {
+ final MethodNode m = createMethod(Opcodes.ACC_SYNTHETIC,
+ "origin$default", "(LTarget;IILjava/lang/Object;)V");
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ filter.filter(m, context, output);
+
+ assertIgnored(new Range(m.instructions.get(3), m.instructions.get(3)));
+ }
+
+ @Test
+ public void should_not_filter_when_not_kotlin() {
+ final MethodNode m = createMethod(Opcodes.ACC_SYNTHETIC,
+ "not_kotlin_synthetic$default",
+ "(LTarget;IILjava/lang/Object;)V");
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+ @Test
+ public void should_not_filter_when_suffix_absent() {
+ final MethodNode m = createMethod(Opcodes.ACC_SYNTHETIC,
+ "synthetic_without_suffix", "(LTarget;IILjava/lang/Object;)V");
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+ @Test
+ public void should_not_filter_when_not_synthetic() {
+ final MethodNode m = createMethod(0, "not_synthetic$default",
+ "(LTarget;IILjava/lang/Object;)V");
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilterTest.java
new file mode 100644
index 00000000..8a6e8356
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilterTest.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * 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:
+ * Nikolay Krasko - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+import org.junit.Test;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Unit tests for {@link KotlinGeneratedFilter}.
+ */
+public class KotlinGeneratedFilterTest extends FilterTestBase {
+
+ private final IFilter filter = new KotlinGeneratedFilter();
+
+ @Test
+ public void testNoLinesForKotlinWithDebug() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "hashCode", "()I", null, null);
+ m.visitInsn(Opcodes.ICONST_0);
+ m.visitInsn(Opcodes.IRETURN);
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ filter.filter(m, context, output);
+
+ assertMethodIgnored(m);
+ }
+
+ @Test
+ public void testWithLinesForKotlinWithDebug() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "hashCode", "()I", null, null);
+ m.visitAnnotation("Lother/Annotation;", false);
+ m.visitLineNumber(12, new Label());
+ m.visitInsn(Opcodes.ICONST_0);
+ m.visitInsn(Opcodes.IRETURN);
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+ @Test
+ public void testNoLinesNonKotlinWithDebug() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "hashCode", "()I", null, null);
+ m.visitInsn(Opcodes.ICONST_0);
+ m.visitInsn(Opcodes.IRETURN);
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+ @Test
+ public void testNoLinesForKotlinNoDebug() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "hashCode", "()I", null, null);
+ m.visitInsn(Opcodes.ICONST_0);
+ m.visitInsn(Opcodes.IRETURN);
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+ context.sourceFileName = null;
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+ @Test
+ public void testWithLinesForKotlinNoDebug() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "hashCode", "()I", null, null);
+ m.visitInsn(Opcodes.ICONST_0);
+ m.visitInsn(Opcodes.IRETURN);
+ m.visitLineNumber(12, new Label());
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+ context.sourceFileName = null;
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilterTest.java
new file mode 100644
index 00000000..fe3b9553
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilterTest.java
@@ -0,0 +1,281 @@
+/*******************************************************************************
+ * 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:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+import org.junit.Test;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Unit tests for {@link KotlinInlineFilter}.
+ */
+public class KotlinInlineFilterTest extends FilterTestBase {
+
+ private final KotlinInlineFilter filter = new KotlinInlineFilter();
+
+ private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "callsite", "()V", null, null);
+
+ @Test
+ public void should_filter() {
+ context.sourceFileName = "callsite.kt";
+ context.sourceDebugExtension = "" //
+ + "SMAP\n" //
+ + "callsite.kt\n" // OutputFileName=callsite.kt
+ + "Kotlin\n" // DefaultStratumId=Kotlin
+ + "*S Kotlin\n" // StratumID=Kotlin
+ + "*F\n" // FileSection
+ + "+ 1 callsite.kt\n" // FileID=1,FileName=callsite.kt
+ + "CallsiteKt\n" //
+ + "+ 2 a.kt\n" // FileID=2,FileName=a.kt
+ + "AKt\n" //
+ + "+ 3 b.kt\n" // FileID=3,FileName=b.kt
+ + "BKt\n" //
+ + "*L\n" // LineSection
+ + "1#1,8:1\n" // InputStartLine=1,LineFileID=1,RepeatCount=8,OutputStartLine=1
+ + "2#2,2:9\n" // InputStartLine=2,LineFileID=2,RepeatCount=2,OutputStartLine=9
+ + "2#3,2:11\n" // InputStartLine=2,LineFileID=3,RepeatCount=2,OutputStartLine=11
+ + "*E\n"; // EndSection
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ m.visitLineNumber(2, new Label());
+ m.visitInsn(Opcodes.NOP);
+
+ m.visitLineNumber(9, new Label());
+ shouldIgnorePrevious(m);
+ m.visitMethodInsn(Opcodes.INVOKESTATIC, "Stubs", "nop", "()V", false);
+ shouldIgnorePrevious(m);
+ m.visitLineNumber(10, new Label());
+ shouldIgnorePrevious(m);
+ m.visitInsn(Opcodes.NOP);
+ shouldIgnorePrevious(m);
+
+ m.visitLineNumber(3, new Label());
+ m.visitInsn(Opcodes.NOP);
+
+ m.visitLineNumber(11, new Label());
+ shouldIgnorePrevious(m);
+ m.visitMethodInsn(Opcodes.INVOKESTATIC, "Stubs", "nop", "()V", false);
+ shouldIgnorePrevious(m);
+ m.visitLineNumber(12, new Label());
+ shouldIgnorePrevious(m);
+ m.visitInsn(Opcodes.NOP);
+ shouldIgnorePrevious(m);
+
+ m.visitLineNumber(4, new Label());
+ m.visitInsn(Opcodes.RETURN);
+
+ filter.filter(m, context, output);
+
+ assertIgnored(expectedRanges.toArray(new Range[0]));
+
+ // should not reparse:
+ context.sourceDebugExtension = "";
+ filter.filter(m, context, output);
+ }
+
+ /**
+ * <pre>
+ * inline fun inlined_top_level() {
+ * Stubs.nop()
+ * }
+ *
+ * class Callsite {
+ * fun inlined() {
+ * Stubs.nop()
+ * }
+ *
+ * fun callsite {
+ * inlined_top_level()
+ * inlined()
+ * }
+ * }
+ * </pre>
+ */
+ @Test
+ public void should_filter_when_in_same_file() {
+ context.sourceFileName = "example.kt";
+ context.sourceDebugExtension = "" //
+ + "SMAP\n" //
+ + "example.kt\n" // OutputFileName=example.kt
+ + "Kotlin\n" // DefaultStratumId=Kotlin
+ + "*S Kotlin\n" // StratumID=Kotlin
+ + "*F\n" // FileSection
+ + "+ 1 example.kt\n" // FileID=1,FileName=example.kt
+ + "Callsite\n" //
+ + "+ 2 example.kt\n" // FileID=2,FileName=example.kt
+ + "ExampleKt\n" //
+ + "*L\n" // LineSection
+ + "1#1,15:1\n" // InputStartLine=1,LineFileID=1,RepeatCount=10,OutputStartLine=1
+ + "7#1,2:18\n" // InputStartLine=7,LineFileID=1,RepeatCount=2,OutputStartLine=18
+ + "2#2,2:16\n" // InputStartLine=2,LineFileID=2,RepeatCount=2,OutputStartLine=16
+ + "*E\n"; // EndSection
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ m.visitLineNumber(11, new Label());
+ m.visitInsn(Opcodes.NOP);
+ m.visitLineNumber(16, new Label());
+ shouldIgnorePrevious(m);
+ m.visitMethodInsn(Opcodes.INVOKESTATIC, "Stubs", "nop", "()V", false);
+ shouldIgnorePrevious(m);
+ m.visitLineNumber(17, new Label());
+ shouldIgnorePrevious(m);
+ m.visitInsn(Opcodes.NOP);
+ shouldIgnorePrevious(m);
+
+ m.visitLineNumber(12, new Label());
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ m.visitVarInsn(Opcodes.ASTORE, 1);
+ m.visitLineNumber(18, new Label());
+ shouldIgnorePrevious(m);
+ m.visitMethodInsn(Opcodes.INVOKESTATIC, "Stubs", "nop", "()V", false);
+ shouldIgnorePrevious(m);
+ m.visitLineNumber(19, new Label());
+ shouldIgnorePrevious(m);
+ m.visitInsn(Opcodes.NOP);
+ shouldIgnorePrevious(m);
+
+ m.visitLineNumber(13, new Label());
+ m.visitInsn(Opcodes.RETURN);
+
+ filter.filter(m, context, output);
+
+ assertIgnored(expectedRanges.toArray(new Range[0]));
+ }
+
+ @Test
+ public void should_not_parse_SourceDebugExtension_attribute_when_no_kotlin_metadata_annotation() {
+ context.sourceDebugExtension = "SMAP";
+
+ m.visitLineNumber(1, new Label());
+ m.visitInsn(Opcodes.RETURN);
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+ @Test
+ public void should_not_filter_when_no_SourceDebugExtension_attribute() {
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ m.visitLineNumber(1, new Label());
+ m.visitInsn(Opcodes.RETURN);
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ }
+
+ @Test
+ public void should_throw_exception_when_SMAP_incomplete() {
+ context.sourceDebugExtension = "" //
+ + "SMAP\n";
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ try {
+ filter.filter(m, context, output);
+ fail("exception expected");
+ } catch (final IllegalStateException e) {
+ assertEquals("Unexpected SMAP line: null", e.getMessage());
+ }
+ }
+
+ @Test
+ public void should_throw_exception_when_unexpected_FileInfo() {
+ context.sourceFileName = "callsite.kt";
+ context.sourceDebugExtension = "" //
+ + "SMAP\n" //
+ + "callsite.kt\n" //
+ + "Kotlin\n" //
+ + "*S Kotlin\n" //
+ + "*F\n" //
+ + "xxx";
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ try {
+ filter.filter(m, context, output);
+ fail("exception expected");
+ } catch (final IllegalStateException e) {
+ assertEquals("Unexpected SMAP line: xxx", e.getMessage());
+ }
+ }
+
+ @Test
+ public void should_throw_exception_when_no_SourceFileId_for_SourceFile() {
+ context.sourceFileName = "example.kt";
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+ context.sourceDebugExtension = "" //
+ + "SMAP\n" //
+ + "example.kt\n" //
+ + "Kotlin\n" //
+ + "*S Kotlin\n" //
+ + "*F\n" //
+ + "+ 1 another.kt\n" //
+ + "AnotherKt\n" //
+ + "*L\n" //
+ + "*E\n";
+
+ try {
+ filter.filter(m, context, output);
+ fail("exception expected");
+ } catch (final IllegalStateException e) {
+ assertEquals("Unexpected SMAP FileSection", e.getMessage());
+ }
+ }
+
+ @Test
+ public void should_throw_exception_when_unexpected_LineInfo() {
+ context.sourceFileName = "callsite.kt";
+ context.sourceDebugExtension = "" //
+ + "SMAP\n" //
+ + "callsite.kt\n" //
+ + "Kotlin\n" //
+ + "*S Kotlin\n" //
+ + "*F\n" //
+ + "+ 1 callsite.kt\n" //
+ + "Callsite\n" //
+ + "*L\n" //
+ + "xxx";
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+
+ try {
+ filter.filter(m, context, output);
+ fail("exception expected");
+ } catch (final IllegalStateException e) {
+ assertEquals("Unexpected SMAP line: xxx", e.getMessage());
+ }
+ }
+
+ private final List<Range> expectedRanges = new ArrayList<Range>();
+
+ private void shouldIgnorePrevious(final MethodNode m) {
+ expectedRanges.add(
+ new Range(m.instructions.getLast(), m.instructions.getLast()));
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java
new file mode 100644
index 00000000..c9e34bab
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilterTest.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * 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:
+ * Fabian Mastenbroek - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+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;
+
+/**
+ * Unit tests for {@link KotlinLateinitFilter}.
+ */
+public class KotlinLateinitFilterTest extends FilterTestBase {
+
+ private final KotlinLateinitFilter filter = new KotlinLateinitFilter();
+
+ private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "name", "()V", null, null);
+
+ @Test
+ public void testLateinitBranchIsFiltered() {
+ final Label l1 = new Label();
+ final Label l2 = new Label();
+
+ m.visitLabel(l1);
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ m.visitFieldInsn(Opcodes.GETFIELD,
+ "com/better/alarm/background/VibrationService", "wakeLock",
+ "Landroid/os/PowerManager$WakeLock;");
+ m.visitInsn(Opcodes.DUP);
+ m.visitJumpInsn(Opcodes.IFNONNULL, l2);
+
+ final AbstractInsnNode expectedFrom = m.instructions.getLast();
+
+ m.visitLdcInsn("wakelock");
+ m.visitMethodInsn(Opcodes.INVOKESTATIC,
+ "kotlin/jvm/internal/Intrinsics",
+ "throwUninitializedPropertyAccessException",
+ "(Ljava/lang/String;)V", false);
+ final AbstractInsnNode expectedTo = m.instructions.getLast();
+ m.visitLabel(l2);
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+ "android/os/PowerManager$WakeLock", "acquire", "", false);
+
+ filter.filter(m, context, output);
+
+ assertIgnored(new Range(expectedFrom, expectedTo));
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilterTest.java
new file mode 100644
index 00000000..0d08ae3f
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilterTest.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * 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:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+import org.junit.Test;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Unit tests for {@link KotlinNotNullOperatorFilter}.
+ */
+public class KotlinNotNullOperatorFilterTest extends FilterTestBase {
+
+ private final KotlinNotNullOperatorFilter filter = new KotlinNotNullOperatorFilter();
+
+ private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "example", "()V", null, null);
+
+ /**
+ * <pre>
+ * return x!!.length
+ * </pre>
+ */
+ @Test
+ public void should_filter() {
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitInsn(Opcodes.DUP);
+
+ final Range range = new Range();
+ final Label label = new Label();
+ m.visitJumpInsn(Opcodes.IFNONNULL, label);
+ range.fromInclusive = m.instructions.getLast();
+ // no line number here and hence no probe
+ m.visitMethodInsn(Opcodes.INVOKESTATIC,
+ "kotlin/jvm/internal/Intrinsics", "throwNpe", "()V", false);
+ range.toInclusive = m.instructions.getLast();
+
+ m.visitLabel(label);
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "length",
+ "()I", false);
+ m.visitInsn(Opcodes.IRETURN);
+
+ filter.filter(m, context, output);
+
+ assertIgnored(range);
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilterTest.java
new file mode 100644
index 00000000..9fc3b3da
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilterTest.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * 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:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+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;
+
+/**
+ * Unit tests for {@link KotlinUnsafeCastOperatorFilter}.
+ */
+public class KotlinUnsafeCastOperatorFilterTest extends FilterTestBase {
+
+ private final KotlinUnsafeCastOperatorFilter filter = new KotlinUnsafeCastOperatorFilter();
+
+ private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "name", "()V", null, null);
+
+ @Test
+ public void should_filter() {
+ final Label label = new Label();
+
+ m.visitInsn(Opcodes.DUP);
+ m.visitJumpInsn(Opcodes.IFNONNULL, label);
+ final AbstractInsnNode expectedFrom = m.instructions.getLast();
+ m.visitTypeInsn(Opcodes.NEW, "kotlin/TypeCastException");
+ m.visitInsn(Opcodes.DUP);
+ m.visitLdcInsn("null cannot be cast to non-null type kotlin.String");
+ m.visitMethodInsn(Opcodes.INVOKESPECIAL, "kotlin/TypeCastException",
+ "<init>", "(Ljava/lang/String;)V", false);
+ m.visitInsn(Opcodes.ATHROW);
+ final AbstractInsnNode expectedTo = m.instructions.getLast();
+ m.visitLabel(label);
+
+ filter.filter(m, context, output);
+
+ assertIgnored(new Range(expectedFrom, expectedTo));
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilterTest.java
new file mode 100644
index 00000000..04d40a05
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilterTest.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * 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:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+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;
+
+/**
+ * Unit tests for {@link KotlinWhenFilter}.
+ */
+public class KotlinWhenFilterTest extends FilterTestBase {
+
+ private final KotlinWhenFilter filter = new KotlinWhenFilter();
+
+ private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "name", "()V", null, null);
+
+ @Test
+ public void should_filter_implicit_else() {
+ final Label label = new Label();
+
+ final Range range1 = new Range();
+
+ m.visitInsn(Opcodes.NOP);
+
+ m.visitJumpInsn(Opcodes.IFEQ, label);
+ range1.fromInclusive = m.instructions.getLast();
+ range1.toInclusive = m.instructions.getLast();
+
+ m.visitInsn(Opcodes.NOP);
+
+ final Range range2 = new Range();
+ m.visitLabel(label);
+ range2.fromInclusive = m.instructions.getLast();
+ m.visitTypeInsn(Opcodes.NEW, "kotlin/NoWhenBranchMatchedException");
+ m.visitInsn(Opcodes.DUP);
+ m.visitMethodInsn(Opcodes.INVOKESPECIAL,
+ "kotlin/NoWhenBranchMatchedException", "<init>", "()V", false);
+ m.visitInsn(Opcodes.ATHROW);
+ range2.toInclusive = m.instructions.getLast();
+
+ filter.filter(m, context, output);
+
+ assertIgnored(range1, range2);
+ assertNoReplacedBranches();
+ }
+
+ @Test
+ public void should_not_filter_explicit_else() {
+ final Label label = new Label();
+
+ m.visitInsn(Opcodes.NOP);
+
+ m.visitJumpInsn(Opcodes.IFEQ, label);
+
+ m.visitInsn(Opcodes.NOP);
+
+ m.visitLabel(label);
+ m.visitTypeInsn(Opcodes.NEW, "kotlin/NoWhenBranchMatchedException");
+ m.visitInsn(Opcodes.DUP);
+ m.visitMethodInsn(Opcodes.INVOKESPECIAL,
+ "kotlin/NoWhenBranchMatchedException", "<init>", "()V", false);
+ m.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Throwable");
+ m.visitInsn(Opcodes.ATHROW);
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
+ assertNoReplacedBranches();
+ }
+
+ @Test
+ public void should_filter_implicit_default() {
+ final Label case1 = new Label();
+ final Label caseDefault = new Label();
+ final Label after = new Label();
+
+ m.visitInsn(Opcodes.NOP);
+
+ m.visitTableSwitchInsn(0, 0, caseDefault, case1);
+ final AbstractInsnNode switchNode = m.instructions.getLast();
+ final Set<AbstractInsnNode> newTargets = new HashSet<AbstractInsnNode>();
+
+ m.visitLabel(case1);
+ m.visitInsn(Opcodes.ICONST_1);
+ newTargets.add(m.instructions.getLast());
+ m.visitJumpInsn(Opcodes.GOTO, after);
+
+ final Range range1 = new Range();
+ m.visitLabel(caseDefault);
+ range1.fromInclusive = m.instructions.getLast();
+ m.visitTypeInsn(Opcodes.NEW, "kotlin/NoWhenBranchMatchedException");
+ m.visitInsn(Opcodes.DUP);
+ m.visitMethodInsn(Opcodes.INVOKESPECIAL,
+ "kotlin/NoWhenBranchMatchedException", "<init>", "()V", false);
+ m.visitInsn(Opcodes.ATHROW);
+ range1.toInclusive = m.instructions.getLast();
+
+ m.visitLabel(after);
+
+ filter.filter(m, context, output);
+
+ assertIgnored(range1);
+ assertReplacedBranches(switchNode, newTargets);
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java
new file mode 100644
index 00000000..df42803d
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilterTest.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * 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:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+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;
+
+/**
+ * Unit tests for {@link KotlinWhenStringFilter}.
+ */
+public class KotlinWhenStringFilterTest extends FilterTestBase {
+
+ private final IFilter filter = new KotlinWhenStringFilter();
+
+ @Test
+ public void should_filter() {
+ final Set<AbstractInsnNode> expectedNewTargets = new HashSet<AbstractInsnNode>();
+
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "name", "()V", null, null);
+
+ final Label h1 = new Label();
+ final Label sameHash = new Label();
+ final Label h2 = new Label();
+ final Label case1 = new Label();
+ final Label case2 = new Label();
+ final Label case3 = new Label();
+ final Label defaultCase = new Label();
+
+ // filter should not remember this unrelated slot
+ m.visitLdcInsn("");
+ m.visitVarInsn(Opcodes.ASTORE, 1);
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+
+ // switch (...)
+ m.visitVarInsn(Opcodes.ASTORE, 2);
+ m.visitVarInsn(Opcodes.ALOAD, 2);
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode",
+ "()I", false);
+ m.visitTableSwitchInsn(97, 98, defaultCase, h1, h2);
+
+ // case "a"
+ m.visitLabel(h1);
+ final AbstractInsnNode expectedFromInclusive = m.instructions.getLast();
+
+ m.visitVarInsn(Opcodes.ALOAD, 2);
+ m.visitLdcInsn("a");
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals",
+ "(Ljava/lang/Object;)Z", false);
+ m.visitJumpInsn(Opcodes.IFEQ, sameHash);
+ m.visitJumpInsn(Opcodes.GOTO, case1);
+
+ // case "\u0000a"
+ m.visitLabel(sameHash);
+ m.visitVarInsn(Opcodes.ALOAD, 2);
+ m.visitLdcInsn("\u0000a");
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals",
+ "(Ljava/lang/Object;)Z", false);
+ m.visitJumpInsn(Opcodes.IFEQ, defaultCase);
+ m.visitJumpInsn(Opcodes.GOTO, case2);
+
+ // case "b"
+ m.visitLabel(h2);
+ m.visitVarInsn(Opcodes.ALOAD, 2);
+ m.visitLdcInsn("\u0000a");
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals",
+ "(Ljava/lang/Object;)Z", false);
+ m.visitJumpInsn(Opcodes.IFEQ, defaultCase);
+ m.visitJumpInsn(Opcodes.GOTO, case3);
+ final AbstractInsnNode expectedToInclusive = m.instructions.getLast();
+
+ m.visitLabel(case1);
+ m.visitInsn(Opcodes.RETURN);
+ expectedNewTargets.add(m.instructions.getLast());
+ m.visitLabel(case2);
+ m.visitInsn(Opcodes.RETURN);
+ expectedNewTargets.add(m.instructions.getLast());
+ m.visitLabel(case3);
+ m.visitInsn(Opcodes.RETURN);
+ expectedNewTargets.add(m.instructions.getLast());
+ m.visitLabel(defaultCase);
+ m.visitInsn(Opcodes.RETURN);
+ expectedNewTargets.add(m.instructions.getLast());
+
+ filter.filter(m, context, output);
+
+ assertReplacedBranches(expectedFromInclusive.getPrevious(),
+ expectedNewTargets);
+ assertIgnored(new Range(expectedFromInclusive, expectedToInclusive));
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java
deleted file mode 100644
index 3e2b497a..00000000
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilterTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*******************************************************************************
- * 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.filter;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
-import org.jacoco.core.internal.instr.InstrSupport;
-import org.junit.Test;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-
-public class LombokGeneratedFilterTest implements IFilterOutput {
-
- private final IFilter filter = new LombokGeneratedFilter();
-
- private AbstractInsnNode fromInclusive;
- private AbstractInsnNode toInclusive;
-
- @Test
- public void testNoAnnotations() {
- final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
- "hashCode", "()I", null, null);
-
- m.visitInsn(Opcodes.ICONST_0);
- m.visitInsn(Opcodes.IRETURN);
-
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertNull(fromInclusive);
- assertNull(toInclusive);
- }
-
- @Test
- public void testOtherAnnotation() {
- final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
- "hashCode", "()I", null, null);
- m.visitAnnotation("Lother/Annotation;", false);
-
- m.visitInsn(Opcodes.ICONST_0);
- m.visitInsn(Opcodes.IRETURN);
-
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertNull(fromInclusive);
- assertNull(toInclusive);
- }
-
- @Test
- public void testLombokGeneratedAnnotation() {
- final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
- "hashCode", "()I", null, null);
- m.visitAnnotation("Llombok/Generated;", false);
-
- m.visitInsn(Opcodes.ICONST_0);
- m.visitInsn(Opcodes.IRETURN);
-
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertEquals(m.instructions.getFirst(), fromInclusive);
- assertEquals(m.instructions.getLast(), toInclusive);
- }
-
- public void ignore(final AbstractInsnNode fromInclusive,
- final AbstractInsnNode toInclusive) {
- assertNull(this.fromInclusive);
- this.fromInclusive = fromInclusive;
- this.toInclusive = toInclusive;
- }
-
- public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) {
- fail();
- }
-
-}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java
index 24c67609..ac42e64e 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilterTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
@@ -11,22 +11,18 @@
*******************************************************************************/
package org.jacoco.core.internal.analysis.filter;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
import org.jacoco.core.internal.instr.InstrSupport;
import org.junit.Test;
import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodNode;
-public class PrivateEmptyNoArgConstructorFilterTest implements IFilterOutput {
+/**
+ * Unit tests for {@link PrivateEmptyNoArgConstructorFilter}.
+ */
+public class PrivateEmptyNoArgConstructorFilterTest extends FilterTestBase {
private final IFilter filter = new PrivateEmptyNoArgConstructorFilter();
- private AbstractInsnNode fromInclusive;
- private AbstractInsnNode toInclusive;
-
@Test
public void test() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION,
@@ -37,20 +33,9 @@ public class PrivateEmptyNoArgConstructorFilterTest implements IFilterOutput {
"()V", false);
m.visitInsn(Opcodes.RETURN);
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertEquals(m.instructions.getFirst(), fromInclusive);
- assertEquals(m.instructions.getLast(), toInclusive);
- }
-
- public void ignore(final AbstractInsnNode fromInclusive,
- final AbstractInsnNode toInclusive) {
- this.fromInclusive = fromInclusive;
- this.toInclusive = toInclusive;
- }
+ filter.filter(m, context, output);
- public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) {
- fail();
+ assertMethodIgnored(m);
}
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java
new file mode 100644
index 00000000..3f726185
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilterTest.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * 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:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+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;
+
+/**
+ * Unit tests for {@link StringSwitchEcjFilter}.
+ */
+public class StringSwitchEcjFilterTest extends FilterTestBase {
+
+ private final IFilter filter = new StringSwitchEcjFilter();
+
+ @Test
+ public void should_filter() {
+ final Set<AbstractInsnNode> expectedNewTargets = new HashSet<AbstractInsnNode>();
+
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "name", "()V", null, null);
+
+ final Label case1 = new Label();
+ final Label case2 = new Label();
+ final Label case3 = new Label();
+ final Label caseDefault = new Label();
+ final Label h1 = new Label();
+ final Label h2 = new Label();
+
+ // filter should not remember this unrelated slot
+ m.visitLdcInsn("");
+ m.visitVarInsn(Opcodes.ASTORE, 1);
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+
+ // switch (...)
+ m.visitInsn(Opcodes.DUP);
+ m.visitVarInsn(Opcodes.ASTORE, 2);
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode",
+ "()I", false);
+ m.visitTableSwitchInsn(97, 98, caseDefault, h1, h2);
+ final AbstractInsnNode switchNode = m.instructions.getLast();
+
+ m.visitLabel(h1);
+
+ m.visitVarInsn(Opcodes.ALOAD, 2);
+ m.visitLdcInsn("a");
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals",
+ "(Ljava/lang/Object;)Z", false);
+ // if equal "a", then goto its case
+ m.visitJumpInsn(Opcodes.IFNE, case1);
+
+ m.visitVarInsn(Opcodes.ALOAD, 2);
+ m.visitLdcInsn("\0a");
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals",
+ "(Ljava/lang/Object;)Z", false);
+ // if equal "\0a", then goto its case
+ m.visitJumpInsn(Opcodes.IFNE, case2);
+
+ // goto default case
+ m.visitJumpInsn(Opcodes.GOTO, caseDefault);
+
+ m.visitLabel(h2);
+
+ m.visitVarInsn(Opcodes.ALOAD, 2);
+ m.visitLdcInsn("b");
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals",
+ "(Ljava/lang/Object;)Z", false);
+ // if equal "b", then goto its case
+ m.visitJumpInsn(Opcodes.IFNE, case3);
+
+ // goto default case
+ m.visitJumpInsn(Opcodes.GOTO, caseDefault);
+ final AbstractInsnNode expectedToInclusive = m.instructions.getLast();
+
+ m.visitLabel(case1);
+ m.visitInsn(Opcodes.RETURN);
+ expectedNewTargets.add(m.instructions.getLast());
+ m.visitLabel(case2);
+ m.visitInsn(Opcodes.RETURN);
+ expectedNewTargets.add(m.instructions.getLast());
+ m.visitLabel(case3);
+ m.visitInsn(Opcodes.RETURN);
+ expectedNewTargets.add(m.instructions.getLast());
+ m.visitLabel(caseDefault);
+ m.visitInsn(Opcodes.RETURN);
+ expectedNewTargets.add(m.instructions.getLast());
+
+ filter.filter(m, context, output);
+
+ assertReplacedBranches(switchNode, expectedNewTargets);
+ assertIgnored(new Range(switchNode.getNext(), expectedToInclusive));
+ }
+
+ @Test
+ public void should_filter_when_default_is_first() {
+ final Set<AbstractInsnNode> expectedNewTargets = new HashSet<AbstractInsnNode>();
+
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "name", "()V", null, null);
+
+ final Label case1 = new Label();
+ final Label caseDefault = new Label();
+ final Label h1 = new Label();
+
+ // filter should not remember this unrelated slot
+ m.visitLdcInsn("");
+ m.visitVarInsn(Opcodes.ASTORE, 1);
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+
+ // switch (...)
+ m.visitInsn(Opcodes.DUP);
+ m.visitVarInsn(Opcodes.ASTORE, 2);
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode",
+ "()I", false);
+ m.visitLookupSwitchInsn(caseDefault, new int[] { 97 },
+ new Label[] { h1 });
+ final AbstractInsnNode switchNode = m.instructions.getLast();
+
+ m.visitLabel(h1);
+
+ m.visitVarInsn(Opcodes.ALOAD, 2);
+ m.visitLdcInsn("a");
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals",
+ "(Ljava/lang/Object;)Z", false);
+ // if equal "a", then goto its case
+ m.visitJumpInsn(Opcodes.IFNE, case1);
+
+ final AbstractInsnNode expectedToInclusive = m.instructions.getLast();
+
+ m.visitLabel(caseDefault);
+ m.visitInsn(Opcodes.RETURN);
+ expectedNewTargets.add(m.instructions.getLast());
+ m.visitLabel(case1);
+ m.visitInsn(Opcodes.RETURN);
+ expectedNewTargets.add(m.instructions.getLast());
+
+ filter.filter(m, context, output);
+
+ assertReplacedBranches(switchNode, expectedNewTargets);
+ assertIgnored(new Range(switchNode.getNext(), expectedToInclusive));
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java
index 2dd9359d..592c6998 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilterTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
@@ -11,10 +11,6 @@
*******************************************************************************/
package org.jacoco.core.internal.analysis.filter;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
import org.jacoco.core.internal.instr.InstrSupport;
import org.junit.Test;
import org.objectweb.asm.Label;
@@ -22,23 +18,24 @@ import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodNode;
-public class StringSwitchJavacFilterTest implements IFilterOutput {
+/**
+ * Unit tests for {@link StringSwitchJavacFilter}.
+ */
+public class StringSwitchJavacFilterTest extends FilterTestBase {
private final IFilter filter = new StringSwitchJavacFilter();
private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"name", "()V", null, null);
- private AbstractInsnNode fromInclusive;
- private AbstractInsnNode toInclusive;
+ private AbstractInsnNode expectedFromInclusive;
+ private AbstractInsnNode expectedToInclusive;
- @Test
- public void should_filter_code_generated_by_javac() {
+ private void createFirstSwitch() {
final Label h1 = new Label();
final Label h1_2 = new Label();
final Label h2 = new Label();
final Label secondSwitch = new Label();
- final Label cases = new Label();
m.visitInsn(Opcodes.ICONST_M1);
m.visitVarInsn(Opcodes.ISTORE, 2);
@@ -48,7 +45,7 @@ public class StringSwitchJavacFilterTest implements IFilterOutput {
"()I", false);
m.visitLookupSwitchInsn(secondSwitch, new int[] { 97, 98 },
new Label[] { h1, h2 });
- final AbstractInsnNode fromInclusive = m.instructions.getLast();
+ expectedFromInclusive = m.instructions.getLast();
m.visitLabel(h1);
m.visitVarInsn(Opcodes.ALOAD, 1);
@@ -87,15 +84,34 @@ public class StringSwitchJavacFilterTest implements IFilterOutput {
m.visitVarInsn(Opcodes.ISTORE, 2);
m.visitLabel(secondSwitch);
- final AbstractInsnNode toInclusive = m.instructions.getLast();
+ expectedToInclusive = m.instructions.getLast();
m.visitVarInsn(Opcodes.ILOAD, 2);
+ }
+
+ @Test
+ public void should_filter_code_generated_by_javac() {
+ createFirstSwitch();
+
+ final Label cases = new Label();
m.visitTableSwitchInsn(0, 2, cases);
m.visitLabel(cases);
- filter.filter("Foo", "java/lang/Object", m, this);
+ filter.filter(m, context, output);
+
+ assertIgnored(new Range(expectedFromInclusive, expectedToInclusive));
+ }
+
+ @Test
+ public void should_filter_when_javac_generates_lookupswitch() {
+ createFirstSwitch();
+
+ final Label cases = new Label();
+ m.visitLookupSwitchInsn(cases, null, new Label[] {});
+ m.visitLabel(cases);
+
+ filter.filter(m, context, output);
- assertEquals(fromInclusive, this.fromInclusive);
- assertEquals(toInclusive, this.toInclusive);
+ assertIgnored(new Range(expectedFromInclusive, expectedToInclusive));
}
@Test
@@ -140,21 +156,9 @@ public class StringSwitchJavacFilterTest implements IFilterOutput {
m.visitLabel(cases);
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertNull(this.fromInclusive);
- assertNull(this.toInclusive);
- }
-
- public void ignore(final AbstractInsnNode fromInclusive,
- final AbstractInsnNode toInclusive) {
- assertNull(this.fromInclusive);
- this.fromInclusive = fromInclusive;
- this.toInclusive = toInclusive;
- }
+ filter.filter(m, context, output);
- public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) {
- fail();
+ assertIgnored();
}
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java
index 5e2b4379..a40b2349 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilterTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
@@ -11,28 +11,23 @@
*******************************************************************************/
package org.jacoco.core.internal.analysis.filter;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
import org.jacoco.core.internal.instr.InstrSupport;
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.LabelNode;
import org.objectweb.asm.tree.MethodNode;
-public class SynchronizedFilterTest implements IFilterOutput {
+/**
+ * Unit tests for {@link SynchronizedFilter}.
+ */
+public class SynchronizedFilterTest extends FilterTestBase {
private final SynchronizedFilter filter = new SynchronizedFilter();
private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"name", "()V", null, null);
- private AbstractInsnNode fromInclusive;
- private AbstractInsnNode toInclusive;
-
@Test
public void javac() {
final Label start = new Label();
@@ -64,9 +59,10 @@ public class SynchronizedFilterTest implements IFilterOutput {
m.visitLabel(exit);
m.visitInsn(Opcodes.RETURN);
- filter.filter("Foo", "java/lang/Object", m, this);
- assertEquals(handler.info, fromInclusive);
- assertEquals(((LabelNode) exit.info).getPrevious(), toInclusive);
+ filter.filter(m, context, output);
+
+ assertIgnored(new Range((LabelNode) handler.info,
+ ((LabelNode) exit.info).getPrevious()));
}
/**
@@ -117,8 +113,9 @@ public class SynchronizedFilterTest implements IFilterOutput {
m.visitLabel(exit);
m.visitInsn(Opcodes.RETURN);
- filter.filter("Foo", "java/lang/Object", m, this);
- assertNull(fromInclusive);
+ filter.filter(m, context, output);
+
+ assertIgnored();
}
@Test
@@ -152,20 +149,10 @@ public class SynchronizedFilterTest implements IFilterOutput {
m.visitLabel(exit);
m.visitInsn(Opcodes.RETURN);
- filter.filter("Foo", "java/lang/Object", m, this);
- assertEquals(handler.info, fromInclusive);
- assertEquals(((LabelNode) exit.info).getPrevious(), toInclusive);
- }
-
- public void ignore(AbstractInsnNode fromInclusive,
- AbstractInsnNode toInclusive) {
- assertNull(this.fromInclusive);
- this.fromInclusive = fromInclusive;
- this.toInclusive = toInclusive;
- }
+ filter.filter(m, context, output);
- public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) {
- fail();
+ assertIgnored(new Range((LabelNode) handler.info,
+ ((LabelNode) exit.info).getPrevious()));
}
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java
index 06344d52..5bbae983 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/SyntheticFilterTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
@@ -11,33 +11,27 @@
*******************************************************************************/
package org.jacoco.core.internal.analysis.filter;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
import org.jacoco.core.internal.instr.InstrSupport;
import org.junit.Test;
import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodNode;
-public class SyntheticFilterTest implements IFilterOutput {
+/**
+ * Unit tests for {@link SyntheticFilter}.
+ */
+public class SyntheticFilterTest extends FilterTestBase {
private final SyntheticFilter filter = new SyntheticFilter();
- private AbstractInsnNode fromInclusive;
- private AbstractInsnNode toInclusive;
-
@Test
public void testNonSynthetic() {
final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
"name", "()V", null, null);
m.visitInsn(Opcodes.NOP);
- filter.filter("Foo", "java/lang/Object", m, this);
+ filter.filter(m, context, output);
- assertNull(fromInclusive);
- assertNull(toInclusive);
+ assertIgnored();
}
@Test
@@ -46,10 +40,9 @@ public class SyntheticFilterTest implements IFilterOutput {
Opcodes.ACC_SYNTHETIC, "name", "()V", null, null);
m.visitInsn(Opcodes.NOP);
- filter.filter("Foo", "java/lang/Object", m, this);
+ filter.filter(m, context, output);
- assertEquals(m.instructions.getFirst(), fromInclusive);
- assertEquals(m.instructions.getLast(), toInclusive);
+ assertMethodIgnored(m);
}
@Test
@@ -58,21 +51,50 @@ public class SyntheticFilterTest implements IFilterOutput {
Opcodes.ACC_SYNTHETIC, "lambda$1", "()V", null, null);
m.visitInsn(Opcodes.NOP);
- filter.filter("Foo", "java/lang/Object", m, this);
+ filter.filter(m, context, output);
- assertNull(fromInclusive);
- assertNull(toInclusive);
+ assertIgnored();
}
- public void ignore(final AbstractInsnNode fromInclusive,
- final AbstractInsnNode toInclusive) {
- assertNull(this.fromInclusive);
- this.fromInclusive = fromInclusive;
- this.toInclusive = toInclusive;
+ @Test
+ public void should_not_filter_method_with_suffix_default_in_kotlin_classes() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION,
+ Opcodes.ACC_SYNTHETIC | Opcodes.ACC_BRIDGE, "example$default",
+ "(LTarget;Ljava/lang/String;Ijava/lang/Object;)V", null, null);
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+ m.visitInsn(Opcodes.NOP);
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
}
- public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) {
- fail();
+ @Test
+ public void should_filter_synthetic_method_with_suffix_default_in_non_kotlin_classes() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION,
+ Opcodes.ACC_SYNTHETIC | Opcodes.ACC_BRIDGE, "example$default",
+ "(LTarget;Ljava/lang/String;Ijava/lang/Object;)V", null, null);
+ m.visitInsn(Opcodes.NOP);
+
+ filter.filter(m, context, output);
+
+ assertMethodIgnored(m);
+ }
+
+ @Test
+ public void should_not_filter_synthetic_methods_whose_last_argument_is_kotlin_coroutine_continuation() {
+ final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION,
+ Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC, "example",
+ "(Lkotlin/coroutines/Continuation;)Ljava/lang/Object;", null,
+ null);
+ context.classAnnotations
+ .add(KotlinGeneratedFilter.KOTLIN_METADATA_DESC);
+ m.visitInsn(Opcodes.NOP);
+
+ filter.filter(m, context, output);
+
+ assertIgnored();
}
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilterTest.java
index 248ca4e9..2a930d0d 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilterTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
@@ -11,20 +11,16 @@
*******************************************************************************/
package org.jacoco.core.internal.analysis.filter;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import java.util.ArrayList;
-import java.util.List;
-
import org.jacoco.core.internal.instr.InstrSupport;
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;
-public class TryWithResourcesEcjFilterTest implements IFilterOutput {
+/**
+ * Unit tests for {@link TryWithResourcesEcjFilter}.
+ */
+public class TryWithResourcesEcjFilterTest extends FilterTestBase {
private final TryWithResourcesEcjFilter filter = new TryWithResourcesEcjFilter();
@@ -310,15 +306,9 @@ public class TryWithResourcesEcjFilterTest implements IFilterOutput {
// additional handlers
m.visitInsn(Opcodes.NOP);
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertEquals(2, from.size());
-
- assertEquals(range0.fromInclusive, from.get(0));
- assertEquals(range0.toInclusive, to.get(0));
+ filter.filter(m, context, output);
- assertEquals(range1.fromInclusive, from.get(1));
- assertEquals(range1.toInclusive, to.get(1));
+ assertIgnored(range0, range1);
}
/**
@@ -598,32 +588,9 @@ public class TryWithResourcesEcjFilterTest implements IFilterOutput {
// additional handlers
m.visitInsn(Opcodes.NOP);
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertEquals(2, from.size());
-
- assertEquals(range0.fromInclusive, from.get(0));
- assertEquals(range0.toInclusive, to.get(0));
-
- assertEquals(range1.fromInclusive, from.get(1));
- assertEquals(range1.toInclusive, to.get(1));
- }
-
- static class Range {
- AbstractInsnNode fromInclusive;
- AbstractInsnNode toInclusive;
- }
-
- private final List<AbstractInsnNode> from = new ArrayList<AbstractInsnNode>();
- private final List<AbstractInsnNode> to = new ArrayList<AbstractInsnNode>();
-
- public void ignore(AbstractInsnNode from, AbstractInsnNode to) {
- this.from.add(from);
- this.to.add(to);
- }
+ filter.filter(m, context, output);
- public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) {
- fail();
+ assertIgnored(range0, range1);
}
}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11FilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11FilterTest.java
new file mode 100644
index 00000000..cab9ee1f
--- /dev/null
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11FilterTest.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * 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:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.jacoco.core.internal.instr.InstrSupport;
+import org.junit.Test;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Unit tests for {@link TryWithResourcesJavac11Filter}.
+ */
+public class TryWithResourcesJavac11FilterTest extends FilterTestBase {
+
+ private final TryWithResourcesJavac11Filter filter = new TryWithResourcesJavac11Filter();
+
+ private final MethodNode m = new MethodNode(InstrSupport.ASM_API_VERSION, 0,
+ "name", "()V", null, null);
+
+ /**
+ * <pre>
+ * try (r = new ...) {
+ * ...
+ * }
+ * </pre>
+ */
+ @Test
+ public void without_null_check() {
+ final Range range1 = new Range();
+ final Range range2 = new Range();
+
+ final Label e = new Label();
+ final Label t = new Label();
+
+ final Label handler = new Label();
+ m.visitTryCatchBlock(handler, handler, handler, "java/lang/Throwable");
+
+ m.visitInsn(Opcodes.NOP);
+
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ range1.fromInclusive = m.instructions.getLast();
+ m.visitMethodInsn(Opcodes.INVOKEINTERFACE, "Resource", "close",
+ "()V", false);
+ m.visitJumpInsn(Opcodes.GOTO, e);
+ range1.toInclusive = m.instructions.getLast();
+
+ m.visitLabel(handler);
+ range2.fromInclusive = m.instructions.getLast();
+ m.visitVarInsn(Opcodes.ASTORE, 1);
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ m.visitMethodInsn(Opcodes.INVOKEINTERFACE, "Resource", "close",
+ "()V", false);
+ m.visitJumpInsn(Opcodes.GOTO, t);
+
+ m.visitVarInsn(Opcodes.ASTORE, 2);
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitVarInsn(Opcodes.ALOAD, 2);
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable",
+ "addSuppressed", "(Ljava/lang/Throwable;)V", false);
+ m.visitLabel(t);
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitInsn(Opcodes.ATHROW);
+ range2.toInclusive = m.instructions.getLast();
+
+ m.visitLabel(e);
+
+ filter.filter(m, context, output);
+
+ assertIgnored(range1, range2);
+ }
+
+ /**
+ * <pre>
+ * try (r = open()) {
+ * ...
+ * }
+ * </pre>
+ */
+ @Test
+ public void with_null_check() {
+ final Range range1 = new Range();
+ final Range range2 = new Range();
+
+ final Label e = new Label();
+ final Label t = new Label();
+
+ final Label handler = new Label();
+ m.visitTryCatchBlock(handler, handler, handler, "java/lang/Throwable");
+
+ m.visitInsn(Opcodes.NOP);
+
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ range1.fromInclusive = m.instructions.getLast();
+ m.visitJumpInsn(Opcodes.IFNULL, e);
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ m.visitMethodInsn(Opcodes.INVOKEINTERFACE, "Resource", "close",
+ "()V", false);
+ m.visitJumpInsn(Opcodes.GOTO, e);
+ range1.toInclusive = m.instructions.getLast();
+
+ m.visitLabel(handler);
+ range2.fromInclusive = m.instructions.getLast();
+ m.visitVarInsn(Opcodes.ASTORE, 1);
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ m.visitJumpInsn(Opcodes.IFNULL, t);
+ m.visitVarInsn(Opcodes.ALOAD, 0);
+ m.visitMethodInsn(Opcodes.INVOKEINTERFACE, "Resource", "close",
+ "()V", false);
+ m.visitJumpInsn(Opcodes.GOTO, t);
+
+ m.visitVarInsn(Opcodes.ASTORE, 2);
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitVarInsn(Opcodes.ALOAD, 2);
+ m.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable",
+ "addSuppressed", "(Ljava/lang/Throwable;)V", false);
+ m.visitLabel(t);
+ m.visitVarInsn(Opcodes.ALOAD, 1);
+ m.visitInsn(Opcodes.ATHROW);
+ range2.toInclusive = m.instructions.getLast();
+
+ m.visitLabel(e);
+
+ filter.filter(m, context, output);
+
+ assertIgnored(range1, range2);
+ }
+
+}
diff --git a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilterTest.java b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilterTest.java
index 83109eae..002ad339 100644
--- a/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilterTest.java
+++ b/org.jacoco.core.test/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilterTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * 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
@@ -11,20 +11,16 @@
*******************************************************************************/
package org.jacoco.core.internal.analysis.filter;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import java.util.ArrayList;
-import java.util.List;
-
import org.jacoco.core.internal.instr.InstrSupport;
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;
-public class TryWithResourcesJavacFilterTest implements IFilterOutput {
+/**
+ * Unit tests for {@link TryWithResourcesJavacFilter}.
+ */
+public class TryWithResourcesJavacFilterTest extends FilterTestBase {
private final TryWithResourcesJavacFilter filter = new TryWithResourcesJavacFilter();
@@ -219,21 +215,9 @@ public class TryWithResourcesJavacFilterTest implements IFilterOutput {
m.visitVarInsn(Opcodes.ALOAD, 8);
m.visitInsn(Opcodes.ATHROW);
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertEquals(4, from.size());
-
- assertEquals(range0.fromInclusive, from.get(0));
- assertEquals(range0.toInclusive, to.get(0));
-
- assertEquals(range1.fromInclusive, from.get(1));
- assertEquals(range1.toInclusive, to.get(1));
+ filter.filter(m, context, output);
- assertEquals(range2.fromInclusive, from.get(2));
- assertEquals(range2.toInclusive, to.get(2));
-
- assertEquals(range3.fromInclusive, from.get(3));
- assertEquals(range3.toInclusive, to.get(3));
+ assertIgnored(range0, range1, range2, range3);
}
/**
@@ -548,21 +532,9 @@ public class TryWithResourcesJavacFilterTest implements IFilterOutput {
m.visitVarInsn(Opcodes.ALOAD, 11);
m.visitInsn(Opcodes.ATHROW);
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertEquals(4, from.size());
-
- assertEquals(range0.fromInclusive, from.get(0));
- assertEquals(range0.toInclusive, to.get(0));
-
- assertEquals(range1.fromInclusive, from.get(1));
- assertEquals(range1.toInclusive, to.get(1));
-
- assertEquals(range2.fromInclusive, from.get(2));
- assertEquals(range2.toInclusive, to.get(2));
+ filter.filter(m, context, output);
- assertEquals(range3.fromInclusive, from.get(3));
- assertEquals(range3.toInclusive, to.get(3));
+ assertIgnored(range0, range1, range2, range3);
}
/**
@@ -726,15 +698,9 @@ public class TryWithResourcesJavacFilterTest implements IFilterOutput {
m.visitLabel(end);
- filter.filter("Foo", "java/lang/Object", m, this);
+ filter.filter(m, context, output);
- assertEquals(2, from.size());
-
- assertEquals(range0.fromInclusive, from.get(0));
- assertEquals(range0.toInclusive, to.get(0));
-
- assertEquals(range1.fromInclusive, from.get(1));
- assertEquals(range1.toInclusive, to.get(1));
+ assertIgnored(range0, range1);
}
/**
@@ -794,26 +760,9 @@ public class TryWithResourcesJavacFilterTest implements IFilterOutput {
m.visitVarInsn(Opcodes.ALOAD, 4);
m.visitInsn(Opcodes.ATHROW);
- filter.filter("Foo", "java/lang/Object", m, this);
-
- assertEquals(0, from.size());
- }
-
- static class Range {
- AbstractInsnNode fromInclusive;
- AbstractInsnNode toInclusive;
- }
-
- private final List<AbstractInsnNode> from = new ArrayList<AbstractInsnNode>();
- private final List<AbstractInsnNode> to = new ArrayList<AbstractInsnNode>();
-
- public void ignore(AbstractInsnNode from, AbstractInsnNode to) {
- this.from.add(from);
- this.to.add(to);
- }
+ filter.filter(m, context, output);
- public void merge(final AbstractInsnNode i1, final AbstractInsnNode i2) {
- fail();
+ assertIgnored();
}
}