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

mockit.internal.faking.FakeMethodBridge 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.faking;

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

import java.lang.reflect.Method;

import mockit.Invocation;
import mockit.internal.ClassLoadingBridge;
import mockit.internal.reflection.MethodReflection;
import mockit.internal.reflection.ParameterReflection;
import mockit.internal.state.TestRun;
import mockit.internal.util.DefaultValues;
import mockit.internal.util.TypeDescriptor;

public final class FakeMethodBridge extends ClassLoadingBridge {
    @NonNull
    public static final ClassLoadingBridge MB = new FakeMethodBridge();

    private FakeMethodBridge() {
        super("$FMB");
    }

    @Nullable
    @Override
    public Object invoke(@Nullable Object fakedInstance, Method method, @NonNull Object[] args) throws Throwable {
        String fakeClassDesc = (String) args[0];
        String fakedClassDesc = (String) args[1];
        String fakeDesc = (String) args[4];

        Object fake = TestRun.getFake(fakeClassDesc, fakedInstance);

        if (fake == null || notToBeMocked(fakedInstance, fakedClassDesc)) {
            return DefaultValues.computeForReturnType(fakedClassDesc);
        }

        String fakeName = (String) args[3];
        int fakeStateIndex = (Integer) args[5];
        Object[] fakeArgs = extractArguments(6, args);

        return callFake(fakedInstance, fake, fakedClassDesc, fakeName, fakeDesc, fakeStateIndex, fakeArgs);
    }

    @Nullable
    private static Object callFake(@Nullable Object fakedInstance, @NonNull Object fake, @NonNull String fakedClassDesc,
            @NonNull String fakeOrFakedName, @NonNull String fakeOrFakedDesc, int fakeStateIndex,
            @NonNull Object[] fakeArgs) throws Throwable {
        Class fakeClass = fake.getClass();

        if (fakeStateIndex < 0) {
            return executeSimpleFakeMethod(fakeClass, fake, fakeOrFakedName, fakeOrFakedDesc, fakeArgs);
        }

        FakeState fakeState = TestRun.getFakeStates().getFakeState(fake, fakeStateIndex);

        if (!fakeState.fakeMethod.hasInvocationParameter()) {
            return executeFakeMethodWithoutInvocationArgument(fakeState, fakeClass, fake, fakeOrFakedDesc, fakeArgs);
        }

        if (fakeState.shouldProceedIntoRealImplementation(fakedInstance, fakedClassDesc)) {
            return Void.class;
        }

        return executeFakeMethodWithInvocationArgument(fakeState, fakeClass, fake, fakedInstance, fakedClassDesc,
                fakeOrFakedName, fakeOrFakedDesc, fakeArgs);
    }

    @Nullable
    private static Object executeSimpleFakeMethod(@NonNull Class fakeClass, @Nullable Object fake,
            @NonNull String fakeOrFakedName, @NonNull String fakeOrFakedDesc, @NonNull Object[] fakeArgs)
            throws Throwable {
        Class[] paramClasses = TypeDescriptor.getParameterTypes(fakeOrFakedDesc);
        return MethodReflection.invokeWithCheckedThrows(fakeClass, fake, fakeOrFakedName, paramClasses, fakeArgs);
    }

    @Nullable
    private static Object executeFakeMethodWithoutInvocationArgument(@NonNull FakeState fakeState,
            @NonNull Class fakeClass, @Nullable Object fake, @NonNull String fakeOrFakedDesc,
            @NonNull Object[] fakeArgs) throws Throwable {
        Class[] paramClasses = TypeDescriptor.getParameterTypes(fakeOrFakedDesc);
        Method fakeMethod = fakeState.getFakeMethod(fakeClass, paramClasses);
        return MethodReflection.invokeWithCheckedThrows(fake, fakeMethod, fakeArgs);
    }

    @Nullable
    private static Object executeFakeMethodWithInvocationArgument(@NonNull FakeState fakeState,
            @NonNull Class fakeClass, @Nullable Object fake, @Nullable Object fakedInstance,
            @NonNull String fakedClassDesc, @NonNull String fakedName, @NonNull String fakedDesc,
            @NonNull Object[] fakeArgs) throws Throwable {
        Class[] paramClasses;
        Method fakeMethod;
        FakeInvocation invocation;
        Object[] executionArgs;

        if (fakeState.fakeMethod.hasInvocationParameterOnly()) {
            paramClasses = new Class[] { Invocation.class };
            fakeMethod = fakeState.getFakeMethod(fakeClass, paramClasses);
            invocation = new FakeInvocation(fakedInstance, fakeArgs, fakeState, fakedClassDesc, fakedName, fakedDesc);
            executionArgs = new Object[] { invocation };
        } else {
            paramClasses = TypeDescriptor.getParameterTypes(fakedDesc);
            fakeMethod = fakeState.getFakeMethod(fakeClass, paramClasses);

            // noinspection AssignmentToMethodParameter
            fakedDesc = fakeState.fakeMethod.fakeDescWithoutInvocationParameter;
            invocation = new FakeInvocation(fakedInstance, fakeArgs, fakeState, fakedClassDesc, fakedName, fakedDesc);
            executionArgs = ParameterReflection.argumentsWithExtraFirstValue(fakeArgs, invocation);
        }

        Object result = MethodReflection.invokeWithCheckedThrows(fake, fakeMethod, executionArgs);
        return invocation.shouldProceedIntoConstructor() ? Void.class : result;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy