All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
mockit.internal.expectations.mocking.CaptureOfNewInstances Maven / Gradle / Ivy
/*
* Copyright (c) 2006 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 javax.annotation.*;
import mockit.external.asm.*;
import mockit.internal.*;
import mockit.internal.capturing.*;
import mockit.internal.startup.*;
import mockit.internal.state.*;
import mockit.internal.util.*;
import static mockit.external.asm.ClassReader.*;
import static mockit.internal.reflection.FieldReflection.*;
public class CaptureOfNewInstances extends CaptureOfImplementations
{
static final class Capture
{
@Nonnull final MockedType typeMetadata;
@Nullable private Object originalMockInstance;
@Nonnull private final List instancesCaptured;
private Capture(@Nonnull MockedType typeMetadata, @Nullable Object originalMockInstance)
{
this.typeMetadata = typeMetadata;
this.originalMockInstance = originalMockInstance;
instancesCaptured = new ArrayList(4);
}
private boolean isInstanceAlreadyCaptured(@Nonnull Object mock)
{
return Utilities.containsReference(instancesCaptured, mock);
}
private boolean captureInstance(@Nullable Object fieldOwner, @Nonnull Object instance)
{
if (instancesCaptured.size() < typeMetadata.getMaxInstancesToCapture()) {
if (fieldOwner != null && typeMetadata.field != null && originalMockInstance == null) {
originalMockInstance = getFieldValue(typeMetadata.field, fieldOwner);
}
instancesCaptured.add(instance);
return true;
}
return false;
}
void reset()
{
originalMockInstance = null;
instancesCaptured.clear();
}
}
@Nonnull private final Map, List> baseTypeToCaptures;
@Nonnull private final List> partiallyMockedBaseTypes;
CaptureOfNewInstances()
{
baseTypeToCaptures = new HashMap, List>();
partiallyMockedBaseTypes = new ArrayList>();
}
@Nonnull
protected final Collection> getCapturesForAllBaseTypes() { return baseTypeToCaptures.values(); }
void useDynamicMocking(@Nonnull Class baseType)
{
partiallyMockedBaseTypes.add(baseType);
List> mockedClasses = TestRun.mockFixture().getMockedClasses();
for (Class mockedClass : mockedClasses) {
if (baseType.isAssignableFrom(mockedClass)) {
if (mockedClass != baseType || !baseType.isInterface()) {
redefineClassForDynamicPartialMocking(baseType, mockedClass);
}
}
}
}
private static void redefineClassForDynamicPartialMocking(@Nonnull Class baseType, @Nonnull Class mockedClass)
{
ClassReader classReader = ClassFile.createReaderOrGetFromCache(mockedClass);
ExpectationsModifier modifier = newModifier(mockedClass.getClassLoader(), classReader, baseType, null);
modifier.useDynamicMocking(true);
classReader.accept(modifier, SKIP_FRAMES);
byte[] modifiedClassfile = modifier.toByteArray();
Startup.redefineMethods(mockedClass, modifiedClassfile);
}
@Nonnull
private static ExpectationsModifier newModifier(
@Nullable ClassLoader cl, @Nonnull ClassReader cr, @Nonnull Class baseType, @Nullable MockedType typeMetadata)
{
ExpectationsModifier modifier = new ExpectationsModifier(cl, cr, typeMetadata);
modifier.setClassNameForCapturedInstanceMethods(Type.getInternalName(baseType));
return modifier;
}
@Nonnull @Override
protected final BaseClassModifier createModifier(
@Nullable ClassLoader cl, @Nonnull ClassReader cr, @Nonnull Class baseType, @Nullable MockedType typeMetadata)
{
ExpectationsModifier modifier = newModifier(cl, cr, baseType, typeMetadata);
if (partiallyMockedBaseTypes.contains(baseType)) {
modifier.useDynamicMocking(true);
}
return modifier;
}
@Override
protected final void redefineClass(@Nonnull Class realClass, @Nonnull byte[] modifiedClass)
{
new RedefinitionEngine(realClass).redefineMethodsWhileRegisteringTheClass(modifiedClass);
}
final void registerCaptureOfNewInstances(@Nonnull MockedType typeMetadata, @Nullable Object mockInstance)
{
Class baseType = typeMetadata.getClassType();
if (!typeMetadata.isFinalFieldOrParameter()) {
makeSureAllSubtypesAreModified(typeMetadata);
}
List captures = baseTypeToCaptures.get(baseType);
if (captures == null) {
captures = new ArrayList();
baseTypeToCaptures.put(baseType, captures);
}
captures.add(new Capture(typeMetadata, mockInstance));
}
final void makeSureAllSubtypesAreModified(@Nonnull MockedType typeMetadata)
{
Class baseType = typeMetadata.getClassType();
makeSureAllSubtypesAreModified(baseType, typeMetadata.fieldFromTestClass, typeMetadata);
}
public final boolean captureNewInstance(@Nullable Object fieldOwner, @Nonnull Object mock)
{
Class mockedClass = mock.getClass();
List captures = baseTypeToCaptures.get(mockedClass);
boolean constructorModifiedForCaptureOnly = captures == null;
if (constructorModifiedForCaptureOnly) {
captures = findCaptures(mockedClass);
if (captures == null) {
return false;
}
}
Capture captureFound = findCapture(fieldOwner, mock, captures);
if (captureFound != null) {
if (captureFound.typeMetadata.injectable) {
TestRun.getExecutingTest().addCapturedInstanceForInjectableMock(captureFound.originalMockInstance, mock);
constructorModifiedForCaptureOnly = true;
}
else {
TestRun.getExecutingTest().addCapturedInstance(captureFound.originalMockInstance, mock);
}
}
return constructorModifiedForCaptureOnly;
}
@Nullable
private List findCaptures(@Nonnull Class mockedClass)
{
Class[] interfaces = mockedClass.getInterfaces();
for (Class anInterface : interfaces) {
List found = baseTypeToCaptures.get(anInterface);
if (found != null) {
return found;
}
}
Class superclass = mockedClass.getSuperclass();
if (superclass == Object.class) {
return null;
}
List found = baseTypeToCaptures.get(superclass);
return found != null ? found : findCaptures(superclass);
}
@Nullable
private static Capture findCapture(
@Nullable Object fieldOwner, @Nonnull Object mock, @Nonnull List captures)
{
for (Capture capture : captures) {
if (capture.isInstanceAlreadyCaptured(mock)) {
break;
}
else if (capture.captureInstance(fieldOwner, mock)) {
return capture;
}
}
return null;
}
public final void cleanUp()
{
baseTypeToCaptures.clear();
partiallyMockedBaseTypes.clear();
}
}