package com.ikokoon.serenity.instrumentation.coverage; import org.apache.log4j.Logger; import org.objectweb.asm.Label; import org.objectweb.asm.MethodAdapter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import com.ikokoon.serenity.Collector; import com.ikokoon.toolkit.Toolkit; /** * This class actually enhances the lines to call the collector class which gathers the data on the lines that are executed during the unit tests. * * @author Michael Couck * @since 12.07.09 * @version 01.00 */ public class CoverageMethodAdapter extends MethodAdapter { /** The logger for the class. */ private Logger logger = Logger.getLogger(CoverageMethodAdapter.class); /** The type of parameters that the {@link Collector} takes in the coverage collection method. */ protected Type stringType = Type.getType(String.class); /** The type parameter for the line number in the {@link Collector} collect coverage method. */ protected Type intType = Type.getType(int.class); /** The array of type parameters for the {@link Collector} for the coverage method. */ protected Type[] types = new Type[] { stringType, stringType, stringType, intType }; /** The name of the class ({@link Collector}) that will be the collector for the method adapter. */ protected String collectorClassName = Type.getInternalName(Collector.class); /** The coverage method that is called on the {@link Collector} by the added instructions. */ protected String collectorMethodName = "collectCoverage"; /** The byte code signature of the coverage method in the {@link Collector}. */ protected String collectorMethodDescription = Type.getMethodDescriptor(Type.VOID_TYPE, types); /** The name of the class that this method adapter is enhancing the methods for. */ private String className; /** The name of the method that is being enhanced. */ private String methodName; /** The description of the method being enhanced. */ private String methodDescription; /** * The constructor initialises a {@link CoverageMethodAdapter} that takes all the interesting items for the method that is to be enhanced * including the parent method visitor. * * @param methodVisitor * the method visitor of the parent * @param className * the name of the class the method belongs to * @param methodName * the name of the method * @param methodDescription * the description of the method */ public CoverageMethodAdapter(MethodVisitor methodVisitor, Integer access, String className, String methodName, String methodDescription) { super(methodVisitor); this.className = Toolkit.slashToDot(className); this.methodName = methodName; this.methodDescription = methodDescription; logger.debug("Class name : " + className + ", name : " + methodName + ", desc : " + methodDescription); } /** * This is the method that actually adds the instructions to the enhanced class. It adds an instruction to call a collector class which then * collects the data about each line being called. This method puts five strings onto the stack. These are then popped by the call to the * collector class and passed as parameters to the collector method. */ public void visitLineNumber(int lineNumber, Label label) { logger.debug("visitLineNumber : " + lineNumber + ", " + label + ", " + label.getOffset() + ", " + className + ", " + methodName); this.mv.visitLdcInsn(className); this.mv.visitLdcInsn(methodName); this.mv.visitLdcInsn(methodDescription); this.mv.visitLdcInsn(lineNumber); this.mv.visitMethodInsn(Opcodes.INVOKESTATIC, collectorClassName, collectorMethodName, collectorMethodDescription); this.mv.visitLineNumber(lineNumber, label); } }