All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mockit.internal.injection.TestedClassInstantiations Maven / Gradle / Ivy

/*
 * Copyright (c) 2006 JMockit developers
 * This file is subject to the terms of the MIT license (see LICENSE.txt).
 */
package mockit.internal.injection;

import static mockit.internal.injection.TestedObject.getTestedAnnotationIfPresent;

import edu.umd.cs.findbugs.annotations.NonNull;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import mockit.Injectable;
import mockit.Tested;
import mockit.asm.jvmConstants.Access;
import mockit.internal.expectations.mocking.MockedType;

public final class TestedClassInstantiations {
    private static final int FIELD_ACCESS_MASK = Access.SYNTHETIC + Access.STATIC;
    private static final int METHOD_ACCESS_MASK = Access.BRIDGE + Access.VARARGS + Access.NATIVE + Access.ABSTRACT
            + Access.SYNTHETIC;

    @NonNull
    private final List testedFields;
    @NonNull
    private final List injectableFields;
    @NonNull
    final InjectionState injectionState;

    public TestedClassInstantiations() {
        testedFields = new LinkedList<>();
        injectableFields = new ArrayList<>();
        injectionState = new InjectionState();
    }

    public boolean findTestedAndInjectableMembers(@NonNull Class testClass) {
        findAllTestedAndInjectableMembersInTestClassHierarchy(testClass);

        return injectionState.injectionProviders.setInjectables(injectableFields) || !testedFields.isEmpty()
                || injectionState.interfaceResolution.canResolveInterfaces();
    }

    private void findAllTestedAndInjectableMembersInTestClassHierarchy(@NonNull Class testClass) {
        Class superclass = testClass.getSuperclass();

        if (superclass.getClassLoader() != null) {
            findAllTestedAndInjectableMembersInTestClassHierarchy(superclass);
        }

        examineInstanceFields(testClass);
        examineMethods(testClass);
    }

    private void examineInstanceFields(@NonNull Class testClass) {
        for (Field candidateField : testClass.getDeclaredFields()) {
            if ((candidateField.getModifiers() & FIELD_ACCESS_MASK) == 0) {
                addAsTestedOrInjectableFieldIfApplicable(candidateField);
            }
        }
    }

    private void examineMethods(@NonNull Class testClass) {
        for (Method candidateMethod : testClass.getDeclaredMethods()) {
            if ((candidateMethod.getModifiers() & METHOD_ACCESS_MASK) == 0) {
                addAsTestedMethodIfApplicable(candidateMethod);
            }
        }
    }

    private void addAsTestedOrInjectableFieldIfApplicable(@NonNull Field fieldFromTestClass) {
        for (Annotation fieldAnnotation : fieldFromTestClass.getDeclaredAnnotations()) {
            if (fieldAnnotation instanceof Injectable) {
                InjectionProvider mockedType = new MockedType(fieldFromTestClass);
                injectableFields.add(mockedType);
                break;
            }

            Tested testedMetadata = getTestedAnnotationIfPresent(fieldAnnotation);

            if (testedMetadata != null) {
                TestedField testedField = new TestedField(injectionState, fieldFromTestClass, testedMetadata);
                testedFields.add(testedField);
                break;
            }
        }
    }

    private void addAsTestedMethodIfApplicable(@NonNull Method methodFromTestClass) {
        for (Annotation methodAnnotation : methodFromTestClass.getDeclaredAnnotations()) {
            Tested testedMetadata = getTestedAnnotationIfPresent(methodAnnotation);

            if (testedMetadata != null) {
                addTestedMethodIfApplicable(methodFromTestClass);
                break;
            }
        }
    }

    private void addTestedMethodIfApplicable(@NonNull Method methodFromTestClass) {
        Class returnType = methodFromTestClass.getReturnType();

        if (returnType == Class.class) {
            Type[] parameterTypes = methodFromTestClass.getGenericParameterTypes();

            if (parameterTypes.length == 1) {
                Type parameterType = parameterTypes[0];

                if (parameterType instanceof ParameterizedType) {
                    ParameterizedType interfaceType = (ParameterizedType) parameterType;

                    if (interfaceType.getRawType() == Class.class) {
                        injectionState.interfaceResolution.addInterfaceResolutionMethod(interfaceType,
                                methodFromTestClass);
                    }
                }
            }
        }
    }

    public void assignNewInstancesToTestedFieldsFromBaseClasses(@NonNull Object testClassInstance) {
        injectionState.setInjectables(testClassInstance, injectableFields);

        Class testClass = testClassInstance.getClass();

        for (TestedField testedField : testedFields) {
            if (testedField.isFromBaseClass(testClass)) {
                instantiateTestedObject(testClassInstance, testedField);
            }
        }
    }

    public void assignNewInstancesToTestedFields(@NonNull Object testClassInstance, boolean beforeSetup,
            @NonNull List injectableParameters) {
        List injectables = injectableFields;

        if (!injectableParameters.isEmpty()) {
            injectables = new ArrayList<>(injectables);
            injectables.addAll(injectableParameters);
        }

        injectionState.setInjectables(testClassInstance, injectables);

        for (TestedField testedField : testedFields) {
            if (!beforeSetup || testedField.isAvailableDuringSetup()) {
                instantiateTestedObject(testClassInstance, testedField);
            }
        }
    }

    private void instantiateTestedObject(@NonNull Object testClassInstance, @NonNull TestedObject testedObject) {
        try {
            testedObject.instantiateWithInjectableValues(testClassInstance);
        } finally {
            injectionState.injectionProviders.resetConsumedInjectionProviders();
        }
    }

    public void clearTestedObjects() {
        injectionState.lifecycleMethods.executeTerminationMethodsIfAny();
        injectionState.clearTestedObjectsAndInstantiatedDependencies();
        resetTestedFields(false);
    }

    private void resetTestedFields(boolean duringTearDown) {
        Object testClassInstance = injectionState.getCurrentTestClassInstance();

        if (testClassInstance != null) {
            for (TestedObject testedField : testedFields) {
                testedField.clearIfAutomaticCreation(testClassInstance, duringTearDown);
            }
        }
    }

    public void clearTestedObjectsCreatedDuringSetup() {
        resetTestedFields(true);
    }

    @NonNull
    public BeanExporter getBeanExporter() {
        return injectionState.getBeanExporter();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy