Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
mockit.internal.expectations.ReplayPhase Maven / Gradle / Ivy
/*
* Copyright (c) 2006 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal.expectations;
import java.util.*;
import javax.annotation.*;
import mockit.internal.expectations.invocation.*;
import mockit.internal.state.*;
final class ReplayPhase extends Phase
{
// Fields for the handling of strict invocations:
private int initialStrictExpectationIndexForCurrentBlock;
int currentStrictExpectationIndex;
@Nullable private Expectation strictExpectation;
// Fields for the handling of invocations that are not strict:
@Nonnull final List invocations;
@Nonnull final List invocationInstances;
@Nonnull final List invocationArguments;
ReplayPhase(@Nonnull RecordAndReplayExecution recordAndReplay)
{
super(recordAndReplay);
invocations = new ArrayList();
invocationInstances = new ArrayList();
invocationArguments = new ArrayList();
initialStrictExpectationIndexForCurrentBlock =
Math.max(recordAndReplay.lastExpectationIndexInPreviousReplayPhase, 0);
positionOnFirstStrictExpectation();
}
private void positionOnFirstStrictExpectation()
{
List strictExpectations = getStrictExpectations();
if (strictExpectations.isEmpty()) {
currentStrictExpectationIndex = -1;
strictExpectation = null ;
}
else {
currentStrictExpectationIndex = initialStrictExpectationIndexForCurrentBlock;
strictExpectation =
currentStrictExpectationIndex < strictExpectations.size() ?
strictExpectations.get(currentStrictExpectationIndex) : null;
}
}
@Nonnull
private List getStrictExpectations() { return recordAndReplay.executionState.strictExpectations; }
@Override
@Nullable
Object handleInvocation(
@Nullable Object mock, int mockAccess, @Nonnull String mockClassDesc, @Nonnull String mockNameAndDesc,
@Nullable String genericSignature, boolean withRealImpl, @Nonnull Object[] args)
throws Throwable
{
Expectation notStrictExpectation =
recordAndReplay.executionState.findNotStrictExpectation(mock, mockClassDesc, mockNameAndDesc, args);
Object replacementInstance = mock == null ?
null : recordAndReplay.executionState.getReplacementInstanceForMethodInvocation(mock, mockNameAndDesc);
if (notStrictExpectation == null) {
notStrictExpectation = createExpectationIfNotStrictInvocation(
replacementInstance == null ? mock : replacementInstance,
mockAccess, mockClassDesc, mockNameAndDesc, genericSignature, args);
}
else if (notStrictExpectation.recordPhase != null) {
registerNewInstanceAsEquivalentToOneFromRecordedConstructorInvocation(mock, notStrictExpectation.invocation);
}
if (notStrictExpectation != null) {
invocations.add(notStrictExpectation);
invocationInstances.add(mock);
invocationArguments.add(args);
notStrictExpectation.constraints.incrementInvocationCount();
if (withRealImpl && replacementInstance != null) {
return produceResult(notStrictExpectation, replacementInstance, args);
}
return produceResult(notStrictExpectation, mock, withRealImpl, args);
}
return handleStrictInvocation(mock, mockClassDesc, mockNameAndDesc, withRealImpl, args);
}
@Nullable
private Expectation createExpectationIfNotStrictInvocation(
@Nullable Object mock, int mockAccess, @Nonnull String mockClassDesc, @Nonnull String mockNameAndDesc,
@Nullable String genericSignature, @Nonnull Object[] args)
{
Expectation expectation = null;
if (!TestRun.getExecutingTest().isStrictInvocation(mock, mockClassDesc, mockNameAndDesc)) {
ExpectedInvocation invocation =
new ExpectedInvocation(mock, mockAccess, mockClassDesc, mockNameAndDesc, false, genericSignature, args);
expectation = new Expectation(invocation);
recordAndReplay.executionState.addExpectation(expectation, false);
}
return expectation;
}
private void registerNewInstanceAsEquivalentToOneFromRecordedConstructorInvocation(
@Nullable Object mock, @Nonnull ExpectedInvocation invocation)
{
if (mock != null && invocation.isConstructor()) {
Map instanceMap = getInstanceMap();
Object recordedInstance = invocation.getRecordedInstance();
instanceMap.put(mock, recordedInstance);
}
}
@Nullable
private Object produceResult(
@Nonnull Expectation expectation, @Nonnull Object replacementInstance, @Nonnull Object[] args)
throws Throwable
{
if (expectation.recordPhase == null) {
expectation.executedRealImplementation = true;
}
else if (expectation.constraints.isInvocationCountMoreThanMaximumExpected()) {
recordAndReplay.setErrorThrown(expectation.invocation.errorForUnexpectedInvocation(args));
return null;
}
return expectation.executeRealImplementation(replacementInstance, args);
}
@Nullable
private Object produceResult(
@Nonnull Expectation expectation, @Nullable Object mock, boolean withRealImpl, @Nonnull Object[] args)
throws Throwable
{
boolean executeRealImpl = withRealImpl && expectation.recordPhase == null;
if (executeRealImpl) {
expectation.executedRealImplementation = true;
return Void.class;
}
if (expectation.constraints.isInvocationCountMoreThanMaximumExpected()) {
recordAndReplay.setErrorThrown(expectation.invocation.errorForUnexpectedInvocation(args));
return null;
}
return expectation.produceResult(mock, args);
}
@Nullable @SuppressWarnings({"OverlyComplexMethod", "OverlyLongMethod"})
private Object handleStrictInvocation(
@Nullable Object mock, @Nonnull String mockClassDesc, @Nonnull String mockNameAndDesc, boolean withRealImpl,
@Nonnull Object[] replayArgs)
throws Throwable
{
Map instanceMap = getInstanceMap();
while (true) {
Expectation expectation = strictExpectation;
if (expectation == null) {
return handleUnexpectedInvocation(mock, mockClassDesc, mockNameAndDesc, withRealImpl, replayArgs);
}
ExpectedInvocation invocation = expectation.invocation;
InvocationConstraints constraints = expectation.constraints;
if (invocation.isMatch(mock, mockClassDesc, mockNameAndDesc, null)) {
registerNewInstanceAsEquivalentToOneFromRecordedConstructorInvocation(mock, invocation);
Error error = invocation.assertThatArgumentsMatch(replayArgs, instanceMap);
if (error != null) {
if (constraints.isInvocationCountInExpectedRange()) {
moveToNextExpectation();
continue;
}
if (withRealImpl) {
return Void.class;
}
recordAndReplay.setErrorThrown(error);
return null;
}
constraints.incrementInvocationCount();
if (constraints.isInvocationCountAtMaximumAllowed()) {
moveToNextExpectation();
}
else if (constraints.isInvocationCountMoreThanMaximumExpected()) {
recordAndReplay.setErrorThrown(invocation.errorForUnexpectedInvocation(replayArgs));
return null;
}
return expectation.produceResult(mock, replayArgs);
}
else if (constraints.isInvocationCountInExpectedRange()) {
moveToNextExpectation();
}
else if (withRealImpl) {
return Void.class;
}
else {
recordAndReplay.setErrorThrown(
invocation.errorForUnexpectedInvocation(mock, mockClassDesc, mockNameAndDesc, replayArgs));
return null;
}
}
}
@Nullable
private Object handleUnexpectedInvocation(
@Nullable Object mock, @Nonnull String mockClassDesc, @Nonnull String mockNameAndDesc, boolean withRealImpl,
@Nonnull Object[] replayArgs)
{
if (withRealImpl) {
return Void.class;
}
recordAndReplay.setErrorThrown(
new ExpectedInvocation(mock, mockClassDesc, mockNameAndDesc, replayArgs).errorForUnexpectedInvocation());
return null;
}
private void moveToNextExpectation()
{
List strictExpectations = getStrictExpectations();
assert strictExpectation != null;
RecordPhase expectationBlock = strictExpectation.recordPhase;
assert expectationBlock != null;
currentStrictExpectationIndex++;
boolean hasNextExpectation = currentStrictExpectationIndex < strictExpectations.size();
strictExpectation = hasNextExpectation ? strictExpectations.get(currentStrictExpectationIndex) : null;
if (strictExpectation != null && strictExpectation.recordPhase != expectationBlock) {
initialStrictExpectationIndexForCurrentBlock = currentStrictExpectationIndex;
}
}
@Nullable
Error endExecution()
{
Expectation strict = strictExpectation;
strictExpectation = null;
Error missingInvocation = getErrorIfStrictExpectationIsMissing(strict);
if (missingInvocation == null) {
missingInvocation = getErrorForFirstNotStrictExpectationThatIsMissing();
if (missingInvocation == null) {
missingInvocation = getErrorIfNextStrictExpectationIsMissing();
}
}
return missingInvocation;
}
@Nullable
private Error getErrorIfStrictExpectationIsMissing(@Nullable Expectation strict)
{
if (strict != null && strict.constraints.isInvocationCountLessThanMinimumExpected()) {
return strict.invocation.errorForMissingInvocation(Collections.emptyList());
}
return null;
}
@Nullable
private Error getErrorForFirstNotStrictExpectationThatIsMissing()
{
List notStrictExpectations = recordAndReplay.executionState.notStrictExpectations;
// New expectations might get added to the list, so a regular loop would cause a CME.
for (int i = 0, n = notStrictExpectations.size(); i < n; i++) {
Expectation notStrict = notStrictExpectations.get(i);
InvocationConstraints constraints = notStrict.constraints;
if (constraints.isInvocationCountLessThanMinimumExpected()) {
List nonMatchingInvocations = getNonMatchingInvocations(notStrict);
return constraints.errorForMissingExpectations(notStrict.invocation, nonMatchingInvocations);
}
}
return null;
}
@Nonnull
private List getNonMatchingInvocations(@Nonnull Expectation unsatisfiedExpectation)
{
ExpectedInvocation unsatisfiedInvocation = unsatisfiedExpectation.invocation;
List nonMatchingInvocations = new ArrayList();
for (Expectation replayedExpectation : invocations) {
ExpectedInvocation replayedInvocation = replayedExpectation.invocation;
if (replayedExpectation != unsatisfiedExpectation && replayedInvocation.isMatch(unsatisfiedInvocation)) {
nonMatchingInvocations.add(replayedInvocation);
}
}
return nonMatchingInvocations;
}
@Nullable
private Error getErrorIfNextStrictExpectationIsMissing()
{
int nextStrictExpectationIndex = currentStrictExpectationIndex + 1;
List strictExpectations = getStrictExpectations();
if (nextStrictExpectationIndex < strictExpectations.size()) {
Expectation nextStrictExpectation = strictExpectations.get(nextStrictExpectationIndex);
if (nextStrictExpectation.constraints.isInvocationCountLessThanMinimumExpected()) {
return
nextStrictExpectation.invocation.errorForMissingInvocation(Collections.emptyList());
}
}
return null;
}
}