
mockit.internal.mockups.MockMethodCollector Maven / Gradle / Ivy
/*
* Copyright (c) 2006-2013 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal.mockups;
import java.lang.reflect.*;
import static mockit.external.asm4.Opcodes.*;
import mockit.*;
import mockit.external.asm4.*;
import mockit.internal.*;
import mockit.internal.state.*;
import mockit.internal.util.*;
/**
* Responsible for collecting the signatures of all methods defined in a given mock class which are explicitly annotated
* as {@link mockit.Mock mocks}.
*/
final class MockMethodCollector extends ClassVisitor
{
private static final int INVALID_METHOD_ACCESSES = ACC_BRIDGE + ACC_SYNTHETIC + ACC_ABSTRACT + ACC_NATIVE;
private final MockMethods mockMethods;
private boolean collectingFromSuperClass;
private String enclosingClassDescriptor;
MockMethodCollector(MockMethods mockMethods) { this.mockMethods = mockMethods; }
void collectMockMethods(Class> mockClass)
{
ClassLoad.registerLoadedClass(mockClass);
Class> classToCollectMocksFrom = mockClass;
do {
ClassReader mcReader = ClassFile.createClassFileReader(classToCollectMocksFrom);
mcReader.accept(this, ClassReader.SKIP_FRAMES);
classToCollectMocksFrom = classToCollectMocksFrom.getSuperclass();
collectingFromSuperClass = true;
}
while (classToCollectMocksFrom != Object.class && classToCollectMocksFrom != MockUp.class);
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces)
{
if (!collectingFromSuperClass) {
mockMethods.setMockClassInternalName(name);
int p = name.lastIndexOf('$');
if (p > 0) {
enclosingClassDescriptor = "(L" + name.substring(0, p) + ";)V";
}
}
}
/**
* Adds the method specified to the set of mock methods, as long as it's annotated with {@code @Mock}.
*
* @param signature generic signature for a Java 5 generic method, ignored since redefinition only needs to consider
* the "erased" signature
* @param exceptions zero or more thrown exceptions in the method "throws" clause, also ignored
*/
@Override
public MethodVisitor visitMethod(
final int access, final String methodName, final String methodDesc, String signature, String[] exceptions)
{
if ((access & INVALID_METHOD_ACCESSES) != 0) {
return null;
}
if ("".equals(methodName)) {
if (!collectingFromSuperClass && methodDesc.equals(enclosingClassDescriptor)) {
enclosingClassDescriptor = null;
}
return null;
}
return new MethodVisitor()
{
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible)
{
if ("Lmockit/Mock;".equals(desc)) {
MockMethods.MockMethod mockMethod =
mockMethods.addMethod(collectingFromSuperClass, methodName, methodDesc, Modifier.isStatic(access));
if (mockMethod != null) {
return new MockAnnotationVisitor(mockMethod);
}
}
return null;
}
@Override
public void visitLocalVariable(
String paramName, String paramDesc, String paramSignature, Label start, Label end, int index)
{
String classDesc = mockMethods.getMockClassInternalName();
ParameterNames.registerName(classDesc, access, methodName, methodDesc, paramName, index);
}
};
}
private final class MockAnnotationVisitor extends AnnotationVisitor
{
private final MockMethods.MockMethod mockMethod;
private MockState mockState;
private MockAnnotationVisitor(MockMethods.MockMethod mockMethod)
{
this.mockMethod = mockMethod;
if (mockMethod.hasInvocationParameter) {
getMockState();
}
}
@Override
public void visit(String name, Object value)
{
Integer numInvocations = (Integer) value;
if ("invocations".equals(name)) {
getMockState().expectedInvocations = numInvocations;
}
else if ("minInvocations".equals(name)) {
getMockState().minExpectedInvocations = numInvocations;
}
else { // "maxInvocations"
getMockState().maxExpectedInvocations = numInvocations;
}
}
private MockState getMockState()
{
if (mockState == null) {
mockState = new MockState(mockMethod);
}
return mockState;
}
@Override
public void visitEnd()
{
if (mockState != null) {
if (mockMethod.canBeReentered()) {
mockState.makeReentrant();
}
mockMethods.addMockState(mockState);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy