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