All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mockit.internal.expectations.BaseVerificationPhase Maven / Gradle / Ivy

/*
 * Copyright (c) 2006-2013 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 mockit.internal.*;
import mockit.internal.expectations.argumentMatching.*;
import mockit.internal.expectations.invocation.*;
import mockit.internal.util.*;

public abstract class BaseVerificationPhase extends TestOnlyPhase
{
   final List expectationsInReplayOrder;
   final List invocationArgumentsInReplayOrder;
   private boolean allMockedInvocationsDuringReplayMustBeVerified;
   private Object[] mockedTypesAndInstancesToFullyVerify;
   protected Expectation currentVerification;
   protected int replayIndex;
   protected Error pendingError;

   protected BaseVerificationPhase(
      RecordAndReplayExecution recordAndReplay,
      List expectationsInReplayOrder, List invocationArgumentsInReplayOrder)
   {
      super(recordAndReplay);
      this.expectationsInReplayOrder = expectationsInReplayOrder;
      this.invocationArgumentsInReplayOrder = invocationArgumentsInReplayOrder;
   }

   public final void setAllInvocationsMustBeVerified() { allMockedInvocationsDuringReplayMustBeVerified = true; }

   public final void setMockedTypesToFullyVerify(Object[] mockedTypesAndInstancesToFullyVerify)
   {
      this.mockedTypesAndInstancesToFullyVerify = mockedTypesAndInstancesToFullyVerify;
   }

   @Override
   final Object handleInvocation(
      Object mock, int access, String mockClassDesc, String mockNameAndDesc, String genericSignature,
      String exceptions, boolean withRealImpl, Object[] args)
   {
      if (pendingError != null) {
         recordAndReplay.setErrorThrown(pendingError);
         pendingError = null;
         return null;
      }

      matchInstance = nextInstanceToMatch != null && mock == nextInstanceToMatch;

      ExpectedInvocation currentInvocation =
         new ExpectedInvocation(mock, access, mockClassDesc, mockNameAndDesc, matchInstance, genericSignature, args);
      currentInvocation.arguments.setMatchers(argMatchers);
      currentVerification = new Expectation(null, currentInvocation, true);

      currentExpectation = null;
      findNonStrictExpectation(mock, mockClassDesc, mockNameAndDesc, args);
      argMatchers = null;

      if (matchInstance) {
         nextInstanceToMatch = null;
      }

      if (recordAndReplay.getErrorThrown() != null) {
         return null;
      }

      if (currentExpectation == null) {
         pendingError = currentVerification.invocation.errorForMissingInvocation();
         currentExpectation = currentVerification;
      }

      return currentExpectation.invocation.getDefaultValueForReturnType(this);
   }

   abstract void findNonStrictExpectation(Object mock, String mockClassDesc, String mockNameAndDesc, Object[] args);

   final boolean matches(
      Object mock, String mockClassDesc, String mockNameAndDesc, Object[] args,
      Expectation replayExpectation, Object[] replayArgs)
   {
      ExpectedInvocation invocation = replayExpectation.invocation;
      Map instanceMap = getInstanceMap();

      if (
         invocation.isMatch(mock, mockClassDesc, mockNameAndDesc, instanceMap) &&
         (!matchInstance || invocation.isEquivalentInstance(mock, instanceMap))
      ) {
         Object[] originalArgs = invocation.arguments.prepareForVerification(args, argMatchers);
         boolean argumentsMatch = invocation.arguments.isMatch(replayArgs, instanceMap);
         invocation.arguments.setValuesWithNoMatchers(originalArgs);

         if (argumentsMatch) {
            addVerifiedExpectation(replayExpectation, replayArgs, argMatchers);
            return true;
         }
      }

      return false;
   }

   private void addVerifiedExpectation(Expectation expectation, Object[] args, List matchers)
   {
      int i = expectationsInReplayOrder.indexOf(expectation);
      addVerifiedExpectation(new VerifiedExpectation(expectation, args, matchers, i));
   }

   void addVerifiedExpectation(VerifiedExpectation verifiedExpectation)
   {
      recordAndReplay.executionState.verifiedExpectations.add(verifiedExpectation);
   }

   @Override
   public final void setMaxInvocationCount(int maxInvocations)
   {
      if (maxInvocations == 0 || pendingError == null) {
         super.setMaxInvocationCount(maxInvocations);
      }
   }

   @Override
   public final void setCustomErrorMessage(CharSequence customMessage)
   {
      Expectation expectation = getCurrentExpectation();

      if (pendingError == null) {
         expectation.setCustomErrorMessage(customMessage);
      }
      else if (customMessage != null) {
         String finalMessage = customMessage + "\n" + pendingError.getMessage();
         StackTraceElement[] previousStackTrace = pendingError.getStackTrace();
         pendingError = pendingError instanceof MissingInvocation ?
            new MissingInvocation(finalMessage) : new UnexpectedInvocation(finalMessage);
         pendingError.setStackTrace(previousStackTrace);
      }
   }

   final boolean evaluateInvocationHandlerIfExpectationMatchesCurrent(
      Expectation replayExpectation, Object[] replayArgs, InvocationHandlerResult handler, int matchedInvocations)
   {
      if (matchesCurrentVerification(replayExpectation, replayArgs)) {
         InvocationConstraints constraints = currentVerification.constraints;
         int originalInvocationCount = constraints.invocationCount;

         try {
            constraints.invocationCount = matchedInvocations + 1;
            handler.produceResult(
               replayExpectation.invocation.instance, replayExpectation.invocation, constraints, replayArgs);
         }
         finally {
            constraints.invocationCount = originalInvocationCount;
         }

         return true;
      }

      return false;
   }

   private boolean matchesCurrentVerification(Expectation replayExpectation, Object[] replayArgs)
   {
      ExpectedInvocation replayInvocation = replayExpectation.invocation;
      ExpectedInvocation verifiedInvocation = currentVerification.invocation;
      Map instanceMap = getInstanceMap();

      if (
         replayInvocation.isMatch(
            verifiedInvocation.instance, verifiedInvocation.getClassDesc(),
            verifiedInvocation.getMethodNameAndDescription(), instanceMap) &&
         (!matchInstance || replayInvocation.isEquivalentInstance(verifiedInvocation.instance, instanceMap))
      ) {
         if (verifiedInvocation.arguments.isMatch(replayArgs, instanceMap)) {
            addVerifiedExpectation(replayExpectation, replayArgs, verifiedInvocation.arguments.getMatchers());
            return true;
         }
      }

      return false;
   }

   protected Error endVerification()
   {
      if (pendingError != null) {
         return pendingError;
      }

      if (allMockedInvocationsDuringReplayMustBeVerified) {
         return validateThatAllInvocationsWereVerified();
      }

      return null;
   }

   private Error validateThatAllInvocationsWereVerified()
   {
      List notVerified = new ArrayList();

      for (int i = 0; i < expectationsInReplayOrder.size(); i++) {
         Expectation replayExpectation = expectationsInReplayOrder.get(i);

         if (replayExpectation != null && isEligibleForFullVerification(replayExpectation)) {
            Object[] replayArgs = invocationArgumentsInReplayOrder.get(i);

            if (!wasVerified(replayExpectation, replayArgs)) {
               notVerified.add(replayExpectation);
            }
         }
      }

      if (!notVerified.isEmpty()) {
         if (mockedTypesAndInstancesToFullyVerify == null) {
            Expectation firstUnexpected = notVerified.get(0);
            return firstUnexpected.invocation.errorForUnexpectedInvocation();
         }

         return validateThatUnverifiedInvocationsAreAllowed(notVerified);
      }

      return null;
   }

   private boolean isEligibleForFullVerification(Expectation replayExpectation)
   {
      return !replayExpectation.executedRealImplementation && replayExpectation.constraints.minInvocations <= 0;
   }

   private boolean wasVerified(Expectation replayExpectation, Object[] replayArgs)
   {
      InvocationArguments invokedArgs = replayExpectation.invocation.arguments;
      List expectationsVerified = recordAndReplay.executionState.verifiedExpectations;

      for (int j = 0; j < expectationsVerified.size(); j++) {
         VerifiedExpectation verified = expectationsVerified.get(j);

         if (verified.expectation == replayExpectation) {
            Object[] storedArgs = invokedArgs.prepareForVerification(verified.arguments, verified.argMatchers);
            boolean argumentsMatch = invokedArgs.isMatch(replayArgs, getInstanceMap());
            invokedArgs.setValuesWithNoMatchers(storedArgs);

            if (argumentsMatch) {
               if (shouldDiscardInformationAboutVerifiedInvocationOnceUsed()) {
                  expectationsVerified.remove(j);
               }

               return true;
            }
         }
      }

      invokedArgs.setValuesWithNoMatchers(replayArgs);
      return false;
   }

   boolean shouldDiscardInformationAboutVerifiedInvocationOnceUsed() { return false; }

   private Error validateThatUnverifiedInvocationsAreAllowed(List unverified)
   {
      for (Expectation expectation : unverified) {
         ExpectedInvocation invocation = expectation.invocation;

         if (isInvocationToBeVerified(invocation)) {
            return invocation.errorForUnexpectedInvocation();
         }
      }

      return null;
   }

   private boolean isInvocationToBeVerified(ExpectedInvocation unverifiedInvocation)
   {
      String invokedClassName = unverifiedInvocation.getClassName();
      Object invokedInstance = unverifiedInvocation.instance;

      for (Object mockedTypeOrInstance : mockedTypesAndInstancesToFullyVerify) {
         if (mockedTypeOrInstance instanceof Class) {
            Class mockedType = (Class) mockedTypeOrInstance;

            if (invokedClassName.equals(mockedType.getName())) {
               return true;
            }
         }
         else if (invokedInstance == null) {
            Class invokedClass = ClassLoad.loadClass(invokedClassName);

            if (invokedClass.isInstance(mockedTypeOrInstance)) {
               return true;
            }
         }
         else if (unverifiedInvocation.matchInstance) {
            if (mockedTypeOrInstance == invokedInstance) {
               return true;
            }
         }
         else if (invokedInstance.getClass().isInstance(mockedTypeOrInstance)) {
            return true;
         }
      }

      return false;
   }

   public final Object getArgumentValueForCurrentVerification(int parameterIndex)
   {
      List verifiedExpectations = recordAndReplay.executionState.verifiedExpectations;

      if (verifiedExpectations.isEmpty()) {
         return currentVerification.invocation.getArgumentValues()[parameterIndex];
      }

      VerifiedExpectation lastMatched = verifiedExpectations.get(verifiedExpectations.size() - 1);
      return lastMatched.arguments[parameterIndex];
   }

   public final void discardReplayedInvocations()
   {
      if (mockedTypesAndInstancesToFullyVerify == null) {
         expectationsInReplayOrder.clear();
         invocationArgumentsInReplayOrder.clear();
      }
      else {
         for (int i = expectationsInReplayOrder.size() - 1; i >= 0; i--) {
            Expectation expectation = expectationsInReplayOrder.get(i);

            if (isInvocationToBeVerified(expectation.invocation)) {
               expectationsInReplayOrder.remove(i);
               invocationArgumentsInReplayOrder.remove(i);
            }
         }
      }
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy