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