
mockit.internal.mockups.MockMethods 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 java.util.*;
import mockit.internal.state.*;
import mockit.internal.util.*;
import mockit.internal.util.GenericTypeReflection.*;
/**
* A container for the mock methods "collected" from a mock class, separated in two sets: one with all the mock methods,
* and another with just the subset of static methods.
*/
final class MockMethods
{
final Class> realClass;
private final List methods;
private final GenericTypeReflection typeParametersToTypeArguments;
private String mockClassInternalName;
private List mockStates;
final class MockMethod
{
final String name;
final String desc;
final boolean isStatic;
final boolean hasInvocationParameter;
String mockedMethodDesc;
private final String mockDescWithoutInvocationParameter;
private GenericSignature mockSignature;
private int indexForMockState;
private boolean nativeRealMethod;
private MockMethod(String nameAndDesc, boolean isStatic)
{
int p = nameAndDesc.indexOf('(');
name = nameAndDesc.substring(0, p);
desc = nameAndDesc.substring(p);
this.isStatic = isStatic;
hasInvocationParameter = desc.startsWith("(Lmockit/Invocation;");
mockDescWithoutInvocationParameter = hasInvocationParameter ? '(' + desc.substring(20) : desc;
indexForMockState = -1;
}
boolean isMatch(String name, String desc, String signature)
{
if (this.name.equals(name)) {
if (hasMatchingParameters(desc, signature)) {
mockedMethodDesc = desc;
return true;
}
}
return false;
}
private boolean hasMatchingParameters(String desc, String signature)
{
boolean sameParametersIgnoringGenerics = mockDescWithoutInvocationParameter.equals(desc);
if (sameParametersIgnoringGenerics || signature == null) {
return sameParametersIgnoringGenerics;
}
if (mockSignature == null) {
mockSignature = typeParametersToTypeArguments.parseSignature(mockDescWithoutInvocationParameter);
}
return mockSignature.satisfiesGenericSignature(signature);
}
Class> getRealClass() { return realClass; }
String getMockNameAndDesc() { return name + desc; }
int getIndexForMockState() { return indexForMockState; }
boolean isForGenericMethod() { return mockSignature != null; }
boolean isForConstructor() { return "$init".equals(name); }
boolean isForNativeMethod() { return nativeRealMethod; }
void markAsNativeRealMethod() { nativeRealMethod = true; }
boolean canBeReentered()
{
return hasInvocationParameter && !nativeRealMethod && !isForConstructor();
}
boolean isReentrant() { return indexForMockState >= 0 && mockStates.get(indexForMockState).isReentrant(); }
boolean isDynamic() { return isReentrant() || hasInvocationParameter && isForConstructor(); }
boolean hasMatchingRealMethod() { return mockedMethodDesc != null; }
String errorMessage(String quantifier, int numExpectedInvocations, int timesInvoked)
{
String nameAndDesc = getMockNameAndDesc();
return
"Expected " + quantifier + ' ' + numExpectedInvocations + " invocation(s) of " +
new MethodFormatter(mockClassInternalName, nameAndDesc) + ", but was invoked " + timesInvoked + " time(s)";
}
@Override
public boolean equals(Object obj)
{
MockMethod other = (MockMethod) obj;
return realClass == other.getRealClass() && name.equals(other.name) && desc.equals(other.desc);
}
@Override
public int hashCode()
{
return 31 * (31 * realClass.hashCode() + name.hashCode()) + desc.hashCode();
}
}
MockMethods(Class> realClass, ParameterizedType mockedType)
{
this.realClass = realClass;
methods = new ArrayList();
typeParametersToTypeArguments = new GenericTypeReflection(realClass, mockedType);
}
MockMethod addMethod(boolean fromSuperClass, String name, String desc, boolean isStatic)
{
if (fromSuperClass && isMethodAlreadyAdded(name, desc)) {
return null;
}
String nameAndDesc = name + desc;
MockMethod mockMethod = new MockMethod(nameAndDesc, isStatic);
methods.add(mockMethod);
return mockMethod;
}
private boolean isMethodAlreadyAdded(String name, String desc)
{
int p = desc.lastIndexOf(')');
String params = desc.substring(0, p + 1);
for (MockMethod mockMethod : methods) {
if (mockMethod.name.equals(name) && mockMethod.desc.startsWith(params)) {
return true;
}
}
return false;
}
void addMockState(MockState mockState)
{
if (mockStates == null) {
mockStates = new ArrayList(4);
}
mockState.mockMethod.indexForMockState = mockStates.size();
mockStates.add(mockState);
}
/**
* Verifies if a mock method with the same signature of a given real method was previously collected from the mock
* class.
* This operation can be performed only once for any given mock method in this container, so that after the last real
* method is processed there should be no mock methods left unused in the container.
*/
MockMethod containsMethod(String name, String desc, String signature)
{
for (MockMethod mockMethod : methods) {
if (mockMethod.isMatch(name, desc, signature)) {
return mockMethod;
}
}
return null;
}
String getMockClassInternalName() { return mockClassInternalName; }
void setMockClassInternalName(String mockClassInternalName) { this.mockClassInternalName = mockClassInternalName; }
boolean hasUnusedMocks()
{
for (MockMethod method : methods) {
if (!method.hasMatchingRealMethod()) {
return true;
}
}
return false;
}
List getUnusedMockSignatures()
{
List signatures = new ArrayList(methods.size());
for (MockMethod mockMethod : methods) {
if (!"$clinit()V".equals(mockMethod.getMockNameAndDesc()) && !mockMethod.hasMatchingRealMethod()) {
signatures.add(mockMethod.getMockNameAndDesc());
}
}
return signatures;
}
void registerMockStates(boolean forStartupMock)
{
if (mockStates != null) {
MockStates mockStates = TestRun.getMockClasses().getMockStates();
if (!forStartupMock) {
mockStates.addMockStates(this.mockStates);
}
mockStates.addMockClassAndItsStates(mockClassInternalName, this.mockStates);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy