1
2
3
4
5
6 package mockit.internal.expectations.state;
7
8 import static mockit.internal.util.Utilities.containsReference;
9
10 import edu.umd.cs.findbugs.annotations.NonNull;
11 import edu.umd.cs.findbugs.annotations.Nullable;
12
13 import java.lang.reflect.Type;
14 import java.util.ArrayList;
15 import java.util.IdentityHashMap;
16 import java.util.List;
17 import java.util.Map;
18
19 import mockit.internal.BaseInvocation;
20 import mockit.internal.expectations.RecordAndReplayExecution;
21 import mockit.internal.expectations.mocking.MockedType;
22 import mockit.internal.expectations.mocking.ParameterTypeRedefinitions;
23
24 public final class ExecutingTest {
25 @Nullable
26 private RecordAndReplayExecution currentRecordAndReplay;
27 @Nullable
28 private RecordAndReplayExecution recordAndReplayForLastTestMethod;
29
30 @NonNull
31 private final ThreadLocal<Boolean> shouldIgnoreMockingCallbacks;
32 @NonNull
33 private final ThreadLocal<BaseInvocation> proceedingInvocation;
34 private boolean proceeding;
35
36 @Nullable
37 private ParameterTypeRedefinitions parameterTypeRedefinitions;
38
39 @NonNull
40 private final List<Object> regularMocks;
41 @NonNull
42 private final List<Object> injectableMocks;
43 @NonNull
44 private final Map<Object, Object> originalToCapturedInstance;
45 @NonNull
46 private final CascadingTypes cascadingTypes;
47
48 public ExecutingTest() {
49 shouldIgnoreMockingCallbacks = ThreadLocal.withInitial(() -> false);
50 proceedingInvocation = new ThreadLocal<>();
51 regularMocks = new ArrayList<>();
52 injectableMocks = new ArrayList<>();
53 originalToCapturedInstance = new IdentityHashMap<>(4);
54 cascadingTypes = new CascadingTypes();
55 }
56
57 @NonNull
58 public RecordAndReplayExecution getOrCreateRecordAndReplay() {
59 if (currentRecordAndReplay == null) {
60 setRecordAndReplay(new RecordAndReplayExecution());
61 }
62
63 return currentRecordAndReplay;
64 }
65
66 @Nullable
67 public RecordAndReplayExecution getPreviousRecordAndReplay() {
68 RecordAndReplayExecution previous = currentRecordAndReplay;
69 currentRecordAndReplay = null;
70 return previous;
71 }
72
73 public void setRecordAndReplay(@Nullable RecordAndReplayExecution newRecordAndReplay) {
74 recordAndReplayForLastTestMethod = null;
75 currentRecordAndReplay = newRecordAndReplay;
76 }
77
78 @Nullable
79 public RecordAndReplayExecution getCurrentRecordAndReplay() {
80 return currentRecordAndReplay;
81 }
82
83 public boolean isShouldIgnoreMockingCallbacks() {
84 return shouldIgnoreMockingCallbacks.get();
85 }
86
87 public boolean setShouldIgnoreMockingCallbacks(boolean flag) {
88 boolean previousFlag = shouldIgnoreMockingCallbacks.get();
89 shouldIgnoreMockingCallbacks.set(flag);
90 return previousFlag;
91 }
92
93 public boolean isProceedingIntoRealImplementation() {
94 boolean result = proceeding;
95 proceeding = false;
96 return result;
97 }
98
99 public void markAsProceedingIntoRealImplementation() {
100 proceeding = true;
101 }
102
103 public void markAsProceedingIntoRealImplementation(@NonNull BaseInvocation invocation) {
104 BaseInvocation previousInvocation = proceedingInvocation.get();
105
106 if (previousInvocation != null) {
107 invocation.setPrevious(previousInvocation);
108 }
109
110 proceedingInvocation.set(invocation);
111 proceeding = true;
112 }
113
114 public boolean shouldProceedIntoRealImplementation(@Nullable Object mock, @NonNull String classDesc) {
115 BaseInvocation pendingInvocation = proceedingInvocation.get();
116
117
118 if (pendingInvocation != null && pendingInvocation.isMethodInSuperclass(mock, classDesc)) {
119 return true;
120 }
121
122 return isProceedingIntoRealImplementation();
123 }
124
125 public void clearProceedingState() {
126 BaseInvocation pendingInvocation = proceedingInvocation.get();
127 BaseInvocation previousInvocation = pendingInvocation.getPrevious();
128 proceedingInvocation.set(previousInvocation);
129 }
130
131 @NonNull
132 public RecordAndReplayExecution getRecordAndReplayForVerifications() {
133 if (currentRecordAndReplay == null) {
134 if (recordAndReplayForLastTestMethod != null) {
135 currentRecordAndReplay = recordAndReplayForLastTestMethod;
136 } else {
137
138
139
140 currentRecordAndReplay = new RecordAndReplayExecution();
141 }
142 }
143
144
145 RecordAndReplayExecution.TEST_ONLY_PHASE_LOCK.lock();
146
147 return currentRecordAndReplay;
148 }
149
150 @Nullable
151 public ParameterTypeRedefinitions getParameterRedefinitions() {
152 return parameterTypeRedefinitions;
153 }
154
155 public void setParameterRedefinitions(@NonNull ParameterTypeRedefinitions redefinitions) {
156 parameterTypeRedefinitions = redefinitions;
157 }
158
159 public void clearRegularAndInjectableMocks() {
160 regularMocks.clear();
161 injectableMocks.clear();
162 }
163
164 void addInjectableMock(@NonNull Object mock) {
165 if (!isInjectableMock(mock)) {
166 injectableMocks.add(mock);
167 }
168 }
169
170 public boolean isInjectableMock(@NonNull Object instance) {
171 return containsReference(injectableMocks, instance);
172 }
173
174 public boolean isUnmockedInstance(@NonNull Object instance) {
175 return !containsReference(regularMocks, instance) && !isInjectableMock(instance);
176 }
177
178 public static boolean isInstanceMethodWithStandardBehavior(@Nullable Object mock, @NonNull String nameAndDesc) {
179 return mock != null && nameAndDesc.charAt(0) != '<'
180 && ("equals(Ljava/lang/Object;)Z hashCode()I toString()Ljava/lang/String;".contains(nameAndDesc)
181 || mock instanceof Comparable<?> && nameAndDesc.startsWith("compareTo(L")
182 && nameAndDesc.endsWith(";)I"));
183 }
184
185 public void registerMock(@NonNull MockedType mockedType, @NonNull Object mock) {
186 if (mockedType.injectable) {
187 addInjectableMock(mock);
188 } else if (!containsReference(regularMocks, mock)) {
189 regularMocks.add(mock);
190 }
191
192 Type declaredType = mockedType.getDeclaredType();
193 cascadingTypes.addInstance(declaredType, mock);
194 }
195
196 @NonNull
197 public CascadingTypes getCascadingTypes() {
198 return cascadingTypes;
199 }
200
201 public void finishExecution() {
202 recordAndReplayForLastTestMethod = currentRecordAndReplay;
203 currentRecordAndReplay = null;
204
205 if (parameterTypeRedefinitions != null) {
206 parameterTypeRedefinitions.cleanUp();
207 parameterTypeRedefinitions = null;
208 }
209
210 cascadingTypes.clearNonSharedCascadingTypes();
211 }
212
213 public void addCapturedInstanceForInjectableMock(@Nullable Object originalInstance,
214 @NonNull Object capturedInstance) {
215 injectableMocks.add(capturedInstance);
216 addCapturedInstance(originalInstance, capturedInstance);
217 }
218
219 public void addCapturedInstance(@Nullable Object originalInstance, @NonNull Object capturedInstance) {
220 originalToCapturedInstance.put(capturedInstance, originalInstance);
221 }
222 }