/*
* Copyright (c) 2006-2013 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal.expectations.mocking;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
import mockit.internal.state.*;
public final class ParameterTypeRedefinitions extends TypeRedefinitions
{
private final Type[] paramTypes;
private final Annotation[][] paramAnnotations;
private final Object[] paramValues;
private final MockedType[] mockParameters;
private final List<MockedType> injectableParameters;
public ParameterTypeRedefinitions(Object owner, Method testMethod, Object[] parameterValues)
{
super(owner);
TestRun.enterNoMockingZone();
try {
paramTypes = testMethod.getGenericParameterTypes();
paramAnnotations = testMethod.getParameterAnnotations();
int n = paramTypes.length;
paramValues = parameterValues == null || parameterValues.length != n ? new Object[n] : parameterValues;
mockParameters = new MockedType[n];
injectableParameters = new ArrayList<MockedType>(n);
String testClassDesc = mockit.external.asm4.Type.getInternalName(testMethod.getDeclaringClass());
String testMethodDesc = testMethod.getName() + mockit.external.asm4.Type.getMethodDescriptor(testMethod);
for (int i = 0; i < n; i++) {
getMockedTypeFromMockParameterDeclaration(testClassDesc, testMethodDesc, i);
}
redefineAndInstantiateMockedTypes();
}
finally {
TestRun.exitNoMockingZone();
}
}
private void getMockedTypeFromMockParameterDeclaration(String testClassDesc, String testMethodDesc, int paramIndex)
{
Type paramType = paramTypes[paramIndex];
Annotation[] annotationsOnParameter = paramAnnotations[paramIndex];
typeMetadata = new MockedType(testClassDesc, testMethodDesc, paramIndex, paramType, annotationsOnParameter);
mockParameters[paramIndex] = typeMetadata;
if (typeMetadata.injectable) {
injectableParameters.add(typeMetadata);
paramValues[paramIndex] = typeMetadata.providedValue;
}
}
private void redefineAndInstantiateMockedTypes()
{
for (int i = 0; i < mockParameters.length; i++) {
typeMetadata = mockParameters[i];
if (typeMetadata.isMockableType()) {
Object mockedInstance = redefineAndInstantiateMockedType();
paramValues[i] = mockedInstance;
typeMetadata.providedValue = mockedInstance;
}
}
}
private Object redefineAndInstantiateMockedType()
{
TypeRedefinition typeRedefinition = new TypeRedefinition(parentObject, typeMetadata);
Object mock = typeRedefinition.redefineType().create();
registerMock(mock);
if (typeMetadata.withInstancesToCapture()) {
registerCaptureOfNewInstances(mock);
}
addTargetClass();
typesRedefined++;
return mock;
}
private void registerCaptureOfNewInstances(Object originalInstance)
{
CaptureOfNewInstancesForParameters capture = getCaptureOfNewInstances();
if (capture == null) {
capture = new CaptureOfNewInstancesForParameters();
captureOfNewInstances = capture;
}
capture.registerCaptureOfNewInstances(typeMetadata, originalInstance);
capture.makeSureAllSubtypesAreModified(typeMetadata.getClassType());
}
@Override
public CaptureOfNewInstancesForParameters getCaptureOfNewInstances()
{
return (CaptureOfNewInstancesForParameters) captureOfNewInstances;
}
public List<MockedType> getInjectableParameters() { return injectableParameters; }
public Object[] getParameterValues() { return paramValues; }
}