• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / jmockit1 / 496

15 Nov 2025 05:33PM UTC coverage: 72.192% (-0.008%) from 72.2%
496

push

github

web-flow
Merge pull request #412 from hazendaz/renovate/major-spring-core

Update spring core to v7 (major)

5677 of 8360 branches covered (67.91%)

Branch coverage included in aggregate %.

11922 of 16018 relevant lines covered (74.43%)

0.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.08
/main/src/main/java/mockit/internal/expectations/RecordAndReplayExecution.java
1
/*
2
 * MIT License
3
 * Copyright (c) 2006-2025 JMockit developers
4
 * See LICENSE file for full license text.
5
 */
6
package mockit.internal.expectations;
7

8
import static mockit.internal.util.Utilities.NO_ARGS;
9

10
import edu.umd.cs.findbugs.annotations.NonNull;
11
import edu.umd.cs.findbugs.annotations.Nullable;
12

13
import java.util.ArrayList;
14
import java.util.List;
15
import java.util.concurrent.locks.ReentrantLock;
16

17
import mockit.Expectations;
18
import mockit.internal.expectations.invocation.ExpectedInvocation;
19
import mockit.internal.expectations.mocking.CaptureOfNewInstances;
20
import mockit.internal.expectations.mocking.FieldTypeRedefinitions;
21
import mockit.internal.expectations.mocking.PartialMocking;
22
import mockit.internal.expectations.mocking.TypeRedefinitions;
23
import mockit.internal.expectations.state.ExecutingTest;
24
import mockit.internal.state.TestRun;
25
import mockit.internal.util.ClassNaming;
26
import mockit.internal.util.DefaultValues;
27
import mockit.internal.util.ObjectMethods;
28

29
public final class RecordAndReplayExecution {
30
    public static final ReentrantLock RECORD_OR_REPLAY_LOCK = new ReentrantLock();
1✔
31
    public static final ReentrantLock TEST_ONLY_PHASE_LOCK = new ReentrantLock();
1✔
32

33
    @Nullable
34
    private final PartialMocking partialMocking;
35
    @NonNull
36
    private final PhasedExecutionState executionState;
37
    @NonNull
38
    private final FailureState failureState;
39
    @Nullable
40
    private RecordPhase recordPhase;
41
    @Nullable
42
    private ReplayPhase replayPhase;
43
    @Nullable
44
    private BaseVerificationPhase verificationPhase;
45

46
    public RecordAndReplayExecution() {
1✔
47
        executionState = new PhasedExecutionState();
1✔
48
        partialMocking = null;
1✔
49
        discoverMockedTypesAndInstancesForMatchingOnInstance();
1✔
50
        failureState = new FailureState();
1✔
51
        replayPhase = new ReplayPhase(executionState, failureState);
1✔
52
    }
1✔
53

54
    public RecordAndReplayExecution(@NonNull Expectations targetObject,
55
            @Nullable Object... instancesToBePartiallyMocked) {
1✔
56
        TestRun.enterNoMockingZone();
1✔
57
        ExecutingTest executingTest = TestRun.getExecutingTest();
1✔
58
        executingTest.setShouldIgnoreMockingCallbacks(true);
1✔
59

60
        try {
61
            RecordAndReplayExecution previous = executingTest.getPreviousRecordAndReplay();
1✔
62

63
            executionState = previous == null ? new PhasedExecutionState() : previous.executionState;
1✔
64
            failureState = new FailureState();
1✔
65
            recordPhase = new RecordPhase(executionState);
1✔
66

67
            executingTest.setRecordAndReplay(this);
1✔
68
            partialMocking = applyPartialMocking(instancesToBePartiallyMocked);
1✔
69
            discoverMockedTypesAndInstancesForMatchingOnInstance();
1✔
70

71
            // noinspection LockAcquiredButNotSafelyReleased
72
            TEST_ONLY_PHASE_LOCK.lock();
1✔
73
        } catch (RuntimeException e) {
1✔
74
            executingTest.setRecordAndReplay(null);
1✔
75
            throw e;
1✔
76
        } finally {
77
            executingTest.setShouldIgnoreMockingCallbacks(false);
1✔
78
            TestRun.exitNoMockingZone();
1✔
79
        }
80
    }
1✔
81

82
    private void discoverMockedTypesAndInstancesForMatchingOnInstance() {
83
        TypeRedefinitions fieldTypeRedefinitions = TestRun.getFieldTypeRedefinitions();
1✔
84

85
        if (fieldTypeRedefinitions != null) {
1✔
86
            List<Class<?>> fields = fieldTypeRedefinitions.getTargetClasses();
1✔
87
            List<Class<?>> targetClasses = new ArrayList<>(fields);
1✔
88

89
            TypeRedefinitions paramTypeRedefinitions = TestRun.getExecutingTest().getParameterRedefinitions();
1✔
90

91
            if (paramTypeRedefinitions != null) {
1✔
92
                targetClasses.addAll(paramTypeRedefinitions.getTargetClasses());
1✔
93
            }
94

95
            executionState.instanceBasedMatching.discoverMockedTypesToMatchOnInstances(targetClasses);
1✔
96

97
            if (partialMocking != null && !partialMocking.targetInstances.isEmpty()) {
1!
98
                executionState.partiallyMockedInstances = new PartiallyMockedInstances(partialMocking.targetInstances);
1✔
99
            }
100
        }
101
    }
1✔
102

103
    @Nullable
104
    private static PartialMocking applyPartialMocking(@Nullable Object... instances) {
105
        if (instances == null || instances.length == 0) {
1!
106
            return null;
1✔
107
        }
108

109
        PartialMocking mocking = new PartialMocking();
1✔
110
        mocking.redefineTypes(instances);
1✔
111
        return mocking;
1✔
112
    }
113

114
    @Nullable
115
    public RecordPhase getRecordPhase() {
116
        return recordPhase;
1✔
117
    }
118

119
    /**
120
     * Only to be called from generated bytecode or from the Mocking Bridge.
121
     */
122
    @Nullable
123
    public static Object recordOrReplay(@Nullable Object mock, int mockAccess, @NonNull String classDesc,
124
            @NonNull String mockDesc, @Nullable String genericSignature, int executionModeOrdinal,
125
            @Nullable Object[] args) throws Throwable {
126
        @NonNull
127
        Object[] mockArgs = args == null ? NO_ARGS : args;
1✔
128
        ExecutionMode executionMode = ExecutionMode.values()[executionModeOrdinal];
1✔
129

130
        if (notToBeMocked(mock, classDesc)) {
1✔
131
            // This occurs if called from a custom argument matching method, in a call to an overridden Object method
132
            // (equals, hashCode,
133
            // toString), from a different thread during recording/verification, or during replay but between tests.
134
            return defaultReturnValue(mock, classDesc, mockDesc, genericSignature, executionMode, mockArgs);
1✔
135
        }
136

137
        ExecutingTest executingTest = TestRun.getExecutingTest();
1✔
138

139
        if (executingTest.isShouldIgnoreMockingCallbacks()) {
1✔
140
            // This occurs when called from a reentrant delegate method, or during static initialization of a mocked
141
            // class.
142
            return defaultReturnValue(executingTest, mock, classDesc, mockDesc, genericSignature, executionMode,
1✔
143
                    mockArgs);
144
        }
145

146
        if (executingTest.shouldProceedIntoRealImplementation(mock, classDesc)
1✔
147
                || executionMode.isToExecuteRealImplementation(mock)) {
1✔
148
            return Void.class;
1✔
149
        }
150

151
        boolean isConstructor = mock != null && mockDesc.startsWith("<init>");
1✔
152
        RECORD_OR_REPLAY_LOCK.lock();
1✔
153

154
        try {
155
            RecordAndReplayExecution instance = executingTest.getOrCreateRecordAndReplay();
1✔
156

157
            if (isConstructor && instance.handleCallToConstructor(mock, classDesc)) {
1✔
158
                return instance.getResultForConstructor(mock, executionMode);
1✔
159
            }
160

161
            return instance.getResult(mock, mockAccess, classDesc, mockDesc, genericSignature, executionMode, mockArgs);
1✔
162
        } finally {
163
            RECORD_OR_REPLAY_LOCK.unlock();
1✔
164
        }
165
    }
166

167
    private static boolean notToBeMocked(@Nullable Object mock, @NonNull String classDesc) {
168
        return RECORD_OR_REPLAY_LOCK.isHeldByCurrentThread()
1✔
169
                || TEST_ONLY_PHASE_LOCK.isLocked() && !TEST_ONLY_PHASE_LOCK.isHeldByCurrentThread()
1✔
170
                || !TestRun.mockFixture().isStillMocked(mock, classDesc);
1✔
171
    }
172

173
    @NonNull
174
    private static Object defaultReturnValue(@Nullable Object mock, @NonNull String classDesc,
175
            @NonNull String nameAndDesc, @Nullable String genericSignature, @NonNull ExecutionMode executionMode,
176
            @NonNull Object[] args) {
177
        if (executionMode.isToExecuteRealImplementation(mock)) {
1✔
178
            return Void.class;
1✔
179
        }
180

181
        if (mock != null) {
1✔
182
            Object rv = ObjectMethods.evaluateOverride(mock, nameAndDesc, args);
1✔
183

184
            if (rv != null) {
1✔
185
                return executionMode.isToExecuteRealObjectOverride(mock) ? Void.class : rv;
1!
186
            }
187
        }
188

189
        String returnTypeDesc = DefaultValues.getReturnTypeDesc(nameAndDesc);
1✔
190

191
        if (returnTypeDesc.charAt(0) == 'L') {
1✔
192
            ExpectedInvocation invocation = new ExpectedInvocation(mock, classDesc, nameAndDesc, genericSignature,
1✔
193
                    args);
194
            Object cascadedInstance = invocation.getDefaultValueForReturnType();
1✔
195

196
            if (cascadedInstance != null) {
1!
197
                return cascadedInstance;
1✔
198
            }
199
        }
200

201
        return Void.class;
1✔
202
    }
203

204
    @Nullable
205
    private static Object defaultReturnValue(@NonNull ExecutingTest executingTest, @Nullable Object mock,
206
            @NonNull String classDesc, @NonNull String nameAndDesc, @Nullable String genericSignature,
207
            @NonNull ExecutionMode executionMode, @NonNull Object[] args) throws Throwable {
208
        RecordAndReplayExecution execution = executingTest.getCurrentRecordAndReplay();
1✔
209

210
        if (execution != null) {
1!
211
            Expectation recordedExpectation = execution.executionState.findExpectation(mock, classDesc, nameAndDesc,
×
212
                    args);
213

214
            if (recordedExpectation != null) {
×
215
                return recordedExpectation.produceResult(mock, args);
×
216
            }
217
        }
218

219
        return defaultReturnValue(mock, classDesc, nameAndDesc, genericSignature, executionMode, args);
1✔
220
    }
221

222
    private boolean handleCallToConstructor(@NonNull Object mock, @NonNull String classDesc) {
223
        if (replayPhase != null) {
1✔
224
            TypeRedefinitions paramTypeRedefinitions = TestRun.getExecutingTest().getParameterRedefinitions();
1✔
225

226
            if (paramTypeRedefinitions != null) {
1✔
227
                CaptureOfNewInstances paramTypeCaptures = paramTypeRedefinitions.getCaptureOfNewInstances();
1✔
228

229
                if (paramTypeCaptures != null && paramTypeCaptures.captureNewInstance(null, mock)) {
1✔
230
                    return true;
1✔
231
                }
232
            }
233

234
            FieldTypeRedefinitions fieldTypeRedefinitions = TestRun.getFieldTypeRedefinitions();
1✔
235

236
            if (fieldTypeRedefinitions != null
1!
237
                    && fieldTypeRedefinitions.captureNewInstanceForApplicableMockField(mock)) {
1✔
238
                return true;
1✔
239
            }
240
        }
241

242
        return isCallToSuperClassConstructor(mock, classDesc);
1✔
243
    }
244

245
    private static boolean isCallToSuperClassConstructor(@NonNull Object mock, @NonNull String calledClassDesc) {
246
        Class<?> mockedClass = mock.getClass();
1✔
247

248
        if (ClassNaming.isAnonymousClass(mockedClass)) {
1!
249
            // An anonymous class instantiation always invokes the constructor on the super-class,
250
            // so that is the class we need to consider, not the anonymous one.
251
            mockedClass = mockedClass.getSuperclass();
×
252

253
            if (mockedClass == Object.class) {
×
254
                return false;
×
255
            }
256
        }
257

258
        String calledClassName = calledClassDesc.replace('/', '.');
1✔
259

260
        return !calledClassName.equals(mockedClass.getName());
1✔
261
    }
262

263
    @Nullable
264
    private Object getResultForConstructor(@NonNull Object mock, @NonNull ExecutionMode executionMode) {
265
        return executionMode == ExecutionMode.Regular || executionMode == ExecutionMode.Partial && replayPhase == null
1✔
266
                || TestRun.getExecutingTest().isInjectableMock(mock) ? null : Void.class;
1!
267
    }
268

269
    @Nullable
270
    private Object getResult(@Nullable Object mock, int mockAccess, @NonNull String classDesc, @NonNull String mockDesc,
271
            @Nullable String genericSignature, @NonNull ExecutionMode executionMode, @NonNull Object[] args)
272
            throws Throwable {
273
        Phase currentPhase = getCurrentPhase();
1✔
274
        failureState.clearErrorThrown();
1✔
275

276
        boolean withRealImpl = executionMode.isWithRealImplementation(mock);
1✔
277
        Object result = currentPhase.handleInvocation(mock, mockAccess, classDesc, mockDesc, genericSignature,
1✔
278
                withRealImpl, args);
279

280
        failureState.reportErrorThrownIfAny();
1✔
281
        return result;
1✔
282
    }
283

284
    @NonNull
285
    private Phase getCurrentPhase() {
286
        ReplayPhase replay = replayPhase;
1✔
287

288
        if (replay == null) {
1✔
289
            RecordPhase recordPhaseLocal = recordPhase;
1✔
290
            assert recordPhaseLocal != null;
1!
291
            return recordPhaseLocal;
1✔
292
        }
293

294
        BaseVerificationPhase verification = verificationPhase;
1✔
295

296
        if (verification != null) {
1✔
297
            return verification;
1✔
298
        }
299

300
        return replay;
1✔
301
    }
302

303
    @NonNull
304
    public BaseVerificationPhase startVerifications(boolean inOrder,
305
            @Nullable Object[] mockedTypesAndInstancesToVerify) {
306
        assert replayPhase != null;
1!
307

308
        if (inOrder) {
1✔
309
            verificationPhase = new OrderedVerificationPhase(replayPhase);
1✔
310
        } else if (mockedTypesAndInstancesToVerify == null) {
1✔
311
            verificationPhase = new UnorderedVerificationPhase(replayPhase);
1✔
312
        } else {
313
            verificationPhase = new FullVerificationPhase(replayPhase, mockedTypesAndInstancesToVerify);
1✔
314
        }
315

316
        return verificationPhase;
1✔
317
    }
318

319
    @Nullable
320
    public static Error endCurrentReplayIfAny() {
321
        RecordAndReplayExecution instance = TestRun.getRecordAndReplayForRunningTest();
1✔
322
        return instance == null ? null : instance.endExecution();
1✔
323
    }
324

325
    @Nullable
326
    private Error endExecution() {
327
        if (TEST_ONLY_PHASE_LOCK.isLocked()) {
1✔
328
            TEST_ONLY_PHASE_LOCK.unlock();
1✔
329
        }
330

331
        ReplayPhase replay = switchFromRecordToReplayIfNotYet();
1✔
332
        Error error = replay.endExecution();
1✔
333

334
        if (error == null) {
1✔
335
            error = failureState.getErrorThrownInAnotherThreadIfAny();
1✔
336
        }
337

338
        if (error == null && verificationPhase != null) {
1✔
339
            error = verificationPhase.endVerification();
1✔
340
            verificationPhase = null;
1✔
341
        }
342

343
        return error;
1✔
344
    }
345

346
    @NonNull
347
    private ReplayPhase switchFromRecordToReplayIfNotYet() {
348
        if (replayPhase == null) {
1✔
349
            recordPhase = null;
1✔
350
            replayPhase = new ReplayPhase(executionState, failureState);
1✔
351
        }
352

353
        return replayPhase;
1✔
354
    }
355

356
    @Nullable
357
    TestOnlyPhase getCurrentTestOnlyPhase() {
358
        return recordPhase != null ? recordPhase : verificationPhase;
1✔
359
    }
360

361
    void endInvocations() {
362
        TEST_ONLY_PHASE_LOCK.unlock();
1✔
363

364
        if (verificationPhase == null) {
1✔
365
            switchFromRecordToReplayIfNotYet();
1✔
366
        } else {
367
            Error error = verificationPhase.endVerification();
1✔
368
            verificationPhase = null;
1✔
369

370
            if (error != null) {
1✔
371
                throw error;
1✔
372
            }
373
        }
374
    }
1✔
375
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc