| /******************************************************************************* |
| * Copyright (c) 2009, 2017 Mountainminds GmbH & Co. KG and Contributors |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Marc R. Hoffmann - initial API and implementation |
| * |
| *******************************************************************************/ |
| package org.jacoco.core.internal.flow; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| |
| import org.junit.Test; |
| import org.objectweb.asm.ClassVisitor; |
| import org.objectweb.asm.Label; |
| import org.objectweb.asm.MethodVisitor; |
| import org.objectweb.asm.Opcodes; |
| |
| /** |
| * Unit tests for {@link ClassProbesAdapter}. |
| */ |
| public class ClassProbesAdapterTest { |
| |
| private static class MockMethodVisitor extends MethodProbesVisitor { |
| |
| boolean frame = false; |
| |
| @Override |
| public void visitJumpInsnWithProbe(int opcode, Label label, |
| int probeId, IFrame frame) { |
| frame.accept(this); |
| } |
| |
| @Override |
| public void visitTableSwitchInsnWithProbes(int min, int max, |
| Label dflt, Label[] labels, IFrame frame) { |
| frame.accept(this); |
| } |
| |
| @Override |
| public void visitLookupSwitchInsnWithProbes(Label dflt, int[] keys, |
| Label[] labels, IFrame frame) { |
| frame.accept(this); |
| } |
| |
| @Override |
| public void visitFrame(int type, int nLocal, Object[] local, |
| int nStack, Object[] stack) { |
| frame = true; |
| } |
| } |
| |
| private static class MockClassVisitor extends ClassProbesVisitor { |
| |
| int count; |
| |
| @Override |
| public MethodProbesVisitor visitMethod(int access, String name, |
| String desc, String signature, String[] exceptions) { |
| return null; |
| } |
| |
| @Override |
| public void visitTotalProbeCount(int count) { |
| this.count = count; |
| } |
| } |
| |
| @Test |
| public void testProbeCounter() { |
| final MockClassVisitor cv = new MockClassVisitor(); |
| final ClassProbesAdapter adapter = new ClassProbesAdapter(cv, false); |
| assertEquals(0, adapter.nextId()); |
| assertEquals(1, adapter.nextId()); |
| assertEquals(2, adapter.nextId()); |
| adapter.visitEnd(); |
| assertEquals(3, cv.count); |
| } |
| |
| @Test |
| public void testVisitClassMethods() { |
| final MockClassVisitor cv = new MockClassVisitor() { |
| @Override |
| public MethodProbesVisitor visitMethod(int access, String name, |
| String desc, String signature, String[] exceptions) { |
| return new MockMethodVisitor(); |
| } |
| }; |
| final ClassProbesAdapter adapter = new ClassProbesAdapter(cv, false); |
| adapter.visit(Opcodes.V1_5, 0, "Foo", null, "java/lang/Object", null); |
| writeMethod(adapter); |
| writeMethod(adapter); |
| writeMethod(adapter); |
| |
| assertEquals(0, cv.count); |
| adapter.visitEnd(); |
| assertEquals(3, cv.count); |
| } |
| |
| @Test |
| public void testVisitMethodNullMethodVisitor() { |
| final MockClassVisitor cv = new MockClassVisitor(); |
| final ClassProbesAdapter adapter = new ClassProbesAdapter(cv, false); |
| writeMethod(adapter); // 1 probe |
| writeMethodWithBranch(adapter); // 3 probes |
| writeMethodWithTableSwitch(adapter); // 3 probes |
| writeMethodWithLookupSwitch(adapter); // 3 probes |
| adapter.visitEnd(); |
| assertEquals(10, cv.count); |
| } |
| |
| @Test |
| public void testVisitWithFrames() { |
| final MockMethodVisitor mv = new MockMethodVisitor(); |
| final MockClassVisitor cv = new MockClassVisitor() { |
| @Override |
| public MethodProbesVisitor visitMethod(int access, String name, |
| String desc, String signature, String[] exceptions) { |
| return mv; |
| } |
| }; |
| final ClassProbesAdapter adapter = new ClassProbesAdapter(cv, true); |
| writeMethodWithBranch(adapter); |
| adapter.visitEnd(); |
| assertTrue(mv.frame); |
| } |
| |
| @Test |
| public void testVisitWithoutFrames() { |
| final MockMethodVisitor mv = new MockMethodVisitor(); |
| final MockClassVisitor cv = new MockClassVisitor() { |
| @Override |
| public MethodProbesVisitor visitMethod(int access, String name, |
| String desc, String signature, String[] exceptions) { |
| return mv; |
| } |
| }; |
| final ClassProbesAdapter adapter = new ClassProbesAdapter(cv, false); |
| writeMethodWithBranch(adapter); |
| adapter.visitEnd(); |
| assertFalse(mv.frame); |
| } |
| |
| private void writeMethod(final ClassVisitor cv) { |
| MethodVisitor mv = cv.visitMethod(0, "foo", "()V", null, null); |
| mv.visitCode(); |
| mv.visitInsn(Opcodes.RETURN); |
| mv.visitMaxs(0, 1); |
| mv.visitEnd(); |
| } |
| |
| private void writeMethodWithBranch(final ClassVisitor cv) { |
| MethodVisitor mv = cv.visitMethod(0, "foo", "()V", null, null); |
| mv.visitCode(); |
| mv.visitInsn(Opcodes.ICONST_0); |
| Label l = new Label(); |
| mv.visitJumpInsn(Opcodes.IFEQ, l); |
| mv.visitInsn(Opcodes.NOP); |
| mv.visitLabel(l); |
| mv.visitInsn(Opcodes.RETURN); |
| mv.visitMaxs(1, 1); |
| mv.visitEnd(); |
| } |
| |
| private void writeMethodWithTableSwitch(final ClassVisitor cv) { |
| MethodVisitor mv = cv.visitMethod(0, "foo", "()V", null, null); |
| mv.visitCode(); |
| mv.visitInsn(Opcodes.ICONST_0); |
| Label l1 = new Label(); |
| Label l2 = new Label(); |
| mv.visitTableSwitchInsn(0, 0, l1, new Label[] { l2 }); |
| mv.visitLabel(l1); |
| mv.visitInsn(Opcodes.NOP); |
| mv.visitLabel(l2); |
| mv.visitInsn(Opcodes.RETURN); |
| mv.visitMaxs(1, 1); |
| mv.visitEnd(); |
| } |
| |
| private void writeMethodWithLookupSwitch(final ClassVisitor cv) { |
| MethodVisitor mv = cv.visitMethod(0, "foo", "()V", null, null); |
| mv.visitCode(); |
| mv.visitInsn(Opcodes.ICONST_0); |
| Label l1 = new Label(); |
| Label l2 = new Label(); |
| mv.visitLookupSwitchInsn(l1, new int[] { 0 }, new Label[] { l2 }); |
| mv.visitLabel(l1); |
| mv.visitInsn(Opcodes.NOP); |
| mv.visitLabel(l2); |
| mv.visitInsn(Opcodes.RETURN); |
| mv.visitMaxs(1, 1); |
| mv.visitEnd(); |
| } |
| |
| } |