1
2
3
4
5 package mockit.internal.faking;
6
7 import edu.umd.cs.findbugs.annotations.NonNull;
8 import edu.umd.cs.findbugs.annotations.Nullable;
9
10 import java.lang.reflect.Method;
11
12 import mockit.Invocation;
13 import mockit.internal.ClassLoadingBridge;
14 import mockit.internal.reflection.MethodReflection;
15 import mockit.internal.reflection.ParameterReflection;
16 import mockit.internal.state.TestRun;
17 import mockit.internal.util.DefaultValues;
18 import mockit.internal.util.TypeDescriptor;
19
20 public final class FakeMethodBridge extends ClassLoadingBridge {
21 @NonNull
22 public static final ClassLoadingBridge MB = new FakeMethodBridge();
23
24 private FakeMethodBridge() {
25 super("$FMB");
26 }
27
28 @Nullable
29 @Override
30 public Object invoke(@Nullable Object fakedInstance, Method method, @NonNull Object[] args) throws Throwable {
31 String fakeClassDesc = (String) args[0];
32 String fakedClassDesc = (String) args[1];
33 String fakeDesc = (String) args[4];
34
35 Object fake = TestRun.getFake(fakeClassDesc, fakedInstance);
36
37 if (fake == null || notToBeMocked(fakedInstance, fakedClassDesc)) {
38 return DefaultValues.computeForReturnType(fakedClassDesc);
39 }
40
41 String fakeName = (String) args[3];
42 int fakeStateIndex = (Integer) args[5];
43 Object[] fakeArgs = extractArguments(6, args);
44
45 return callFake(fakedInstance, fake, fakedClassDesc, fakeName, fakeDesc, fakeStateIndex, fakeArgs);
46 }
47
48 @Nullable
49 private static Object callFake(@Nullable Object fakedInstance, @NonNull Object fake, @NonNull String fakedClassDesc,
50 @NonNull String fakeOrFakedName, @NonNull String fakeOrFakedDesc, int fakeStateIndex,
51 @NonNull Object[] fakeArgs) throws Throwable {
52 Class<?> fakeClass = fake.getClass();
53
54 if (fakeStateIndex < 0) {
55 return executeSimpleFakeMethod(fakeClass, fake, fakeOrFakedName, fakeOrFakedDesc, fakeArgs);
56 }
57
58 FakeState fakeState = TestRun.getFakeStates().getFakeState(fake, fakeStateIndex);
59
60 if (!fakeState.fakeMethod.hasInvocationParameter()) {
61 return executeFakeMethodWithoutInvocationArgument(fakeState, fakeClass, fake, fakeOrFakedDesc, fakeArgs);
62 }
63
64 if (fakeState.shouldProceedIntoRealImplementation(fakedInstance, fakedClassDesc)) {
65 return Void.class;
66 }
67
68 return executeFakeMethodWithInvocationArgument(fakeState, fakeClass, fake, fakedInstance, fakedClassDesc,
69 fakeOrFakedName, fakeOrFakedDesc, fakeArgs);
70 }
71
72 @Nullable
73 private static Object executeSimpleFakeMethod(@NonNull Class<?> fakeClass, @Nullable Object fake,
74 @NonNull String fakeOrFakedName, @NonNull String fakeOrFakedDesc, @NonNull Object[] fakeArgs)
75 throws Throwable {
76 Class<?>[] paramClasses = TypeDescriptor.getParameterTypes(fakeOrFakedDesc);
77 return MethodReflection.invokeWithCheckedThrows(fakeClass, fake, fakeOrFakedName, paramClasses, fakeArgs);
78 }
79
80 @Nullable
81 private static Object executeFakeMethodWithoutInvocationArgument(@NonNull FakeState fakeState,
82 @NonNull Class<?> fakeClass, @Nullable Object fake, @NonNull String fakeOrFakedDesc,
83 @NonNull Object[] fakeArgs) throws Throwable {
84 Class<?>[] paramClasses = TypeDescriptor.getParameterTypes(fakeOrFakedDesc);
85 Method fakeMethod = fakeState.getFakeMethod(fakeClass, paramClasses);
86 return MethodReflection.invokeWithCheckedThrows(fake, fakeMethod, fakeArgs);
87 }
88
89 @Nullable
90 private static Object executeFakeMethodWithInvocationArgument(@NonNull FakeState fakeState,
91 @NonNull Class<?> fakeClass, @Nullable Object fake, @Nullable Object fakedInstance,
92 @NonNull String fakedClassDesc, @NonNull String fakedName, @NonNull String fakedDesc,
93 @NonNull Object[] fakeArgs) throws Throwable {
94 Class<?>[] paramClasses;
95 Method fakeMethod;
96 FakeInvocation invocation;
97 Object[] executionArgs;
98
99 if (fakeState.fakeMethod.hasInvocationParameterOnly()) {
100 paramClasses = new Class[] { Invocation.class };
101 fakeMethod = fakeState.getFakeMethod(fakeClass, paramClasses);
102 invocation = new FakeInvocation(fakedInstance, fakeArgs, fakeState, fakedClassDesc, fakedName, fakedDesc);
103 executionArgs = new Object[] { invocation };
104 } else {
105 paramClasses = TypeDescriptor.getParameterTypes(fakedDesc);
106 fakeMethod = fakeState.getFakeMethod(fakeClass, paramClasses);
107
108
109 fakedDesc = fakeState.fakeMethod.fakeDescWithoutInvocationParameter;
110 invocation = new FakeInvocation(fakedInstance, fakeArgs, fakeState, fakedClassDesc, fakedName, fakedDesc);
111 executionArgs = ParameterReflection.argumentsWithExtraFirstValue(fakeArgs, invocation);
112 }
113
114 Object result = MethodReflection.invokeWithCheckedThrows(fake, fakeMethod, executionArgs);
115 return invocation.shouldProceedIntoConstructor() ? Void.class : result;
116 }
117 }