/*
* Copyright (c) 2006 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal.mockups;
import java.lang.reflect.*;
import javax.annotation.*;
import mockit.*;
import mockit.internal.*;
import mockit.internal.reflection.*;
import mockit.internal.state.*;
import mockit.internal.util.*;
public final class MockMethodBridge extends MockingBridge
{
@Nonnull public static final MockingBridge MB = new MockMethodBridge();
private MockMethodBridge() { super("$MMB"); }
@Nullable @Override
public Object invoke(@Nullable Object mockedInstance, Method method, @Nonnull Object[] args) throws Throwable
{
String mockClassDesc = (String) args[0];
String mockedClassDesc = (String) args[1];
String mockDesc = (String) args[4];
Object mockUp = TestRun.getMock(mockClassDesc, mockedInstance);
if (mockUp == null || notToBeMocked(mockedInstance, mockedClassDesc)) {
return DefaultValues.computeForReturnType(mockDesc);
}
String mockName = (String) args[3];
int mockStateIndex = (Integer) args[5];
Object[] mockArgs = extractMockArguments(6, args);
return callMock(mockedInstance, mockUp, mockedClassDesc, mockName, mockDesc, mockStateIndex, mockArgs);
}
@Nullable
private static Object callMock(
@Nullable Object mockedInstance, @Nonnull Object mockUp, @Nonnull String mockedClassDesc,
@Nonnull String mockOrMockedName, @Nonnull String mockOrMockedDesc, int mockStateIndex,
@Nonnull Object[] mockArgs)
throws Throwable
{
Class<?> mockUpClass = mockUp.getClass();
if (mockStateIndex < 0) {
return executeSimpleMockMethod(mockUpClass, mockUp, mockOrMockedName, mockOrMockedDesc, mockArgs);
}
MockState mockState = TestRun.getMockStates().getMockState(mockUp, mockStateIndex);
if (!mockState.mockMethod.hasInvocationParameter) {
return executeMockMethodWithoutInvocationArgument(mockState, mockUpClass, mockUp, mockOrMockedDesc, mockArgs);
}
if (mockState.shouldProceedIntoRealImplementation(mockedInstance, mockedClassDesc)) {
return Void.class;
}
return executeMockMethodWithInvocationArgument(
mockState, mockUpClass, mockUp, mockedInstance, mockedClassDesc, mockOrMockedName, mockOrMockedDesc, mockArgs);
}
@Nullable
private static Object executeSimpleMockMethod(
@Nonnull Class<?> mockUpClass, @Nullable Object mockUp,
@Nonnull String mockOrMockedName, @Nonnull String mockOrMockedDesc, @Nonnull Object[] mockArgs)
throws Throwable
{
Class<?>[] paramClasses = TypeDescriptor.getParameterTypes(mockOrMockedDesc);
Object result =
MethodReflection.invokeWithCheckedThrows(mockUpClass, mockUp, mockOrMockedName, paramClasses, mockArgs);
return result;
}
@Nullable
private static Object executeMockMethodWithoutInvocationArgument(
@Nonnull MockState mockState, @Nonnull Class<?> mockUpClass, @Nullable Object mockUp,
@Nonnull String mockOrMockedDesc, @Nonnull Object[] mockArgs)
throws Throwable
{
Class<?>[] paramClasses = TypeDescriptor.getParameterTypes(mockOrMockedDesc);
Method mockMethod = mockState.getMockMethod(mockUpClass, paramClasses);
Object result = MethodReflection.invokeWithCheckedThrows(mockUp, mockMethod, mockArgs);
return result;
}
@Nullable
private static Object executeMockMethodWithInvocationArgument(
@Nonnull MockState mockState, @Nonnull Class<?> mockUpClass, @Nullable Object mockUp,
@Nullable Object mockedInstance, @Nonnull String mockedClassDesc, @Nonnull String mockedName,
@Nonnull String mockedDesc, @Nonnull Object[] mockArgs)
throws Throwable
{
Class<?>[] paramClasses;
Method mockMethod;
MockInvocation invocation;
Object[] executionArgs;
if (mockState.mockMethod.isAdvice) {
paramClasses = new Class[] {Invocation.class};
mockMethod = mockState.getMockMethod(mockUpClass, paramClasses);
invocation = new MockInvocation(mockedInstance, mockArgs, mockState, mockedClassDesc, mockedName, mockedDesc);
executionArgs = new Object[] {invocation};
}
else {
paramClasses = TypeDescriptor.getParameterTypes(mockedDesc);
mockMethod = mockState.getMockMethod(mockUpClass, paramClasses);
//noinspection AssignmentToMethodParameter
mockedDesc = mockState.mockMethod.mockDescWithoutInvocationParameter;
invocation = new MockInvocation(mockedInstance, mockArgs, mockState, mockedClassDesc, mockedName, mockedDesc);
executionArgs = ParameterReflection.argumentsWithExtraFirstValue(mockArgs, invocation);
}
Object result = MethodReflection.invokeWithCheckedThrows(mockUp, mockMethod, executionArgs);
return invocation.shouldProceedIntoConstructor() ? Void.class : result;
}
}