package org.pitest.mutationtest.engine.gregor.analysis;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import org.pitest.classinfo.ClassByteArraySource;
import org.pitest.classinfo.ClassName;
import org.pitest.classpath.ClassloaderByteArraySource;
import org.pitest.util.IsolationUtils;
public class InstructionTrackingMethodVisitorTest {
private final ClassByteArraySource byteSource = new ClassloaderByteArraySource(
IsolationUtils
.getContextClassLoader());
private final InstructionCounter counter = new DefaultInstructionCounter();
@Test
public void shouldGiveIndexConsistentWithTreeApiForStringEquals() {
analyse(String.class, "equals");
final MethodNode tree = makeTree(String.class, "equals");
assertEquals(tree.instructions.size(),
this.counter.currentInstructionCount());
}
class HasMethodCallsAndBranches {
public int foo(final long j) {
if (j > 64000) {
bar();
}
return 32;
}
private void bar() {
}
}
@Test
public void shouldGiveIndexConsistentWithTreeApiWhenMethodCallsPresent() {
analyse(HasMethodCallsAndBranches.class, "foo");
final MethodNode tree = makeTree(HasMethodCallsAndBranches.class, "foo");
assertEquals(tree.instructions.size(),
this.counter.currentInstructionCount());
}
class HasSwitchStatements {
public int foo(final int j) {
switch (j) {
case 1:
return 3;
case 2:
return 4;
}
switch (j) {
case 34:
return 1;
case 9:
return 2;
default:
return 6;
}
}
}
@Test
public void shouldGiveIndexConsistentWithTreeApiWhenSwitchStatementsPresent() {
analyse(HasSwitchStatements.class, "foo");
final MethodNode tree = makeTree(HasSwitchStatements.class, "foo");
assertEquals(tree.instructions.size(),
this.counter.currentInstructionCount());
}
private InstructionTrackingMethodVisitor analyse(final Class<?> clazz,
final String targetMethod) {
final ClassReader reader = new ClassReader(this.byteSource.getBytes(
clazz.getName()).value());
final Analyser cv = new Analyser(targetMethod);
reader.accept(cv, 0);
return cv.testee;
}
private MethodNode makeTree(final Class<?> clazz, final String name) {
final ClassReader reader = new ClassReader(this.byteSource.getBytes(
ClassName.fromClass(clazz).asJavaName()).value());
final ClassNode tree = new ClassNode();
reader.accept(tree, 0);
for (Object m : tree.methods) {
MethodNode mn = (MethodNode) m;
if (mn.name.equals(name)) {
return mn;
}
}
throw new RuntimeException("Method " + name + " not found in " + clazz);
}
private class Analyser extends ClassVisitor {
private final String targetMethod;
InstructionTrackingMethodVisitor testee;
public Analyser(final String targetMethod) {
super(Opcodes.ASM4);
this.targetMethod = targetMethod;
}
@Override
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
if (name.equals(this.targetMethod)) {
this.testee = new InstructionTrackingMethodVisitor(super.visitMethod(
access, name, desc, signature, exceptions),
InstructionTrackingMethodVisitorTest.this.counter);
return this.testee;
} else {
return null;
}
}
}
}