/*
* 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.util.*;
import java.util.Map.*;
import java.lang.reflect.*;
import mockit.internal.expectations.injection.*;
import mockit.internal.state.*;
import mockit.internal.util.*;
public final class SharedFieldTypeRedefinitions extends FieldTypeRedefinitions
{
private final Map<MockedType, InstanceFactory> mockInstanceFactories;
private final List<MockedType> finalMockFields;
private TestedClassInstantiations testedClassInstantiations;
public SharedFieldTypeRedefinitions(Object objectWithMockFields)
{
super(objectWithMockFields);
mockInstanceFactories = new HashMap<MockedType, InstanceFactory>();
finalMockFields = new ArrayList<MockedType>();
}
public void redefineTypesForTestClass()
{
Class<?> testClass = parentObject.getClass();
TestRun.enterNoMockingZone();
try {
testedClassInstantiations = new TestedClassInstantiations();
if (!testedClassInstantiations.findTestedAndInjectableFields(testClass)) {
testedClassInstantiations = null;
}
clearTargetClasses();
redefineFieldTypes(testClass, true);
}
finally {
TestRun.exitNoMockingZone();
}
}
@Override
protected void redefineTypeForMockField()
{
TypeRedefinition typeRedefinition = new TypeRedefinition(parentObject, typeMetadata);
if (finalField) {
typeRedefinition.redefineTypeForFinalField();
finalMockFields.add(typeMetadata);
}
else {
InstanceFactory factory = typeRedefinition.redefineType();
if (factory != null) {
mockInstanceFactories.put(typeMetadata, factory);
}
else {
finalMockFields.add(typeMetadata);
}
}
addTargetClass();
}
public void assignNewInstancesToMockFields(Object target)
{
TestRun.getExecutingTest().clearInjectableAndNonStrictMocks();
for (Entry<MockedType, InstanceFactory> metadataAndFactory : mockInstanceFactories.entrySet()) {
typeMetadata = metadataAndFactory.getKey();
InstanceFactory instanceFactory = metadataAndFactory.getValue();
Object mock = assignNewInstanceToMockField(target, instanceFactory);
registerMock(mock);
}
obtainAndRegisterInstancesOfFinalFields(target);
}
private void obtainAndRegisterInstancesOfFinalFields(Object target)
{
for (MockedType metadata : finalMockFields) {
Object mock = FieldReflection.getFieldValue(metadata.field, target);
typeMetadata = metadata;
if (mock == null) {
registerMockedClassIfNonStrict();
}
else {
registerMock(mock);
}
}
}
private Object assignNewInstanceToMockField(Object target, InstanceFactory instanceFactory)
{
Field mockField = typeMetadata.field;
Object mock = FieldReflection.getFieldValue(mockField, target);
if (mock == null) {
try {
mock = instanceFactory.create();
}
catch (NoClassDefFoundError e) {
StackTrace.filterStackTrace(e);
e.printStackTrace();
throw e;
}
catch (ExceptionInInitializerError e) {
StackTrace.filterStackTrace(e);
e.printStackTrace();
throw e;
}
FieldReflection.setFieldValue(mockField, target, mock);
if (typeMetadata.getMaxInstancesToCapture() > 0) {
getCaptureOfNewInstances().resetCaptureCount(mockField);
}
}
return mock;
}
@Override
public boolean captureNewInstanceForApplicableMockField(Object mock)
{
if (captureOfNewInstances == null) {
return false;
}
Object fieldOwner = TestRun.getCurrentTestInstance();
return getCaptureOfNewInstances().captureNewInstanceForApplicableMockField(fieldOwner, mock);
}
public TestedClassInstantiations getTestedClassInstantiations() { return testedClassInstantiations; }
@Override
public void cleanUp()
{
TestRun.getExecutingTest().clearCascadingTypes();
super.cleanUp();
}
}