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

mockit.internal.expectations.transformation.ArgumentMatching Maven / Gradle / Ivy

Go to download

JMockit is a Java toolkit for automated developer testing. It contains APIs for the creation of the objects to be tested, for mocking dependencies, and for faking external APIs; JUnit (4 & 5) and TestNG test runners are supported. It also contains an advanced code coverage tool.

There is a newer version: 1.49
Show newest version
/*
 * Copyright (c) 2006 Rogério Liesenfeld
 * This file is subject to the terms of the MIT license (see LICENSE.txt).
 */
package mockit.internal.expectations.transformation;

import javax.annotation.*;

import mockit.external.asm.*;
import static mockit.external.asm.Opcodes.*;

final class ArgumentMatching
{
   private static final Type[] NO_PARAMETERS = new Type[0];
   private static final String ANY_FIELDS =
      "any anyString anyInt anyBoolean anyLong anyDouble anyFloat anyChar anyShort anyByte";
   private static final String WITH_METHODS =
      "withArgThat(Lorg/hamcrest/Matcher;)Ljava/lang/Object; " +
      "with(Lmockit/Delegate;)Ljava/lang/Object; " +
      "withAny(Ljava/lang/Object;)Ljava/lang/Object; " +
      "withCapture()Ljava/lang/Object; withCapture(Ljava/util/List;)Ljava/lang/Object; " +
      "withCapture(Ljava/lang/Object;)Ljava/util/List; " +
      "withEqual(Ljava/lang/Object;)Ljava/lang/Object; withEqual(DD)D withEqual(FD)F " +
      "withInstanceLike(Ljava/lang/Object;)Ljava/lang/Object; " +
      "withInstanceOf(Ljava/lang/Class;)Ljava/lang/Object; " +
      "withNotEqual(Ljava/lang/Object;)Ljava/lang/Object; " +
      "withNull()Ljava/lang/Object; withNotNull()Ljava/lang/Object; " +
      "withSameInstance(Ljava/lang/Object;)Ljava/lang/Object; " +
      "withSubstring(Ljava/lang/CharSequence;)Ljava/lang/CharSequence; " +
      "withPrefix(Ljava/lang/CharSequence;)Ljava/lang/CharSequence; " +
      "withSuffix(Ljava/lang/CharSequence;)Ljava/lang/CharSequence; " +
      "withMatch(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;";

   @Nonnull private final InvocationBlockModifier modifier;

   // Helper fields that allow argument matchers to be moved to the correct positions of their corresponding parameters:
   @Nonnull private final int[] matcherStacks;
   @Nonnegative private int matcherCount;
   @Nonnull private Type[] parameterTypes;

   static boolean isAnyField(@Nonnull String name)
   {
      return name.startsWith("any") && ANY_FIELDS.contains(name);
   }

   static boolean isCallToArgumentMatcher(@Nonnull String name, @Nonnull String desc)
   {
      return name.startsWith("with") && WITH_METHODS.contains(name + desc);
   }

   ArgumentMatching(@Nonnull InvocationBlockModifier modifier)
   {
      this.modifier = modifier;
      matcherStacks = new int[40];
      parameterTypes = NO_PARAMETERS;
   }

   void addMatcher(@Nonnegative int stackSize) { matcherStacks[matcherCount++] = stackSize; }

   @Nonnegative int getMatcherCount() { return matcherCount; }
   @Nonnull Type getParameterType(@Nonnegative int parameterIndex) { return parameterTypes[parameterIndex]; }

   void generateCodeToAddArgumentMatcherForAnyField(
      @Nonnull String fieldOwner, @Nonnull String name, @Nonnull String desc)
   {
      MethodWriter mw = modifier.getMethodWriter();
      mw.visitFieldInsn(GETFIELD, fieldOwner, name, desc);
      modifier.generateCallToActiveInvocationsMethod(name);
   }

   boolean handleInvocationParameters(@Nonnegative int stackSize, @Nonnull String desc)
   {
      parameterTypes = Type.getArgumentTypes(desc);
      int stackAfter = stackSize - getSumOfParameterSizes();
      boolean mockedInvocationUsingTheMatchers = stackAfter < matcherStacks[0];

      if (mockedInvocationUsingTheMatchers) {
         generateCallsToMoveArgMatchers(stackAfter);
         modifier.argumentCapturing.generateCallsToSetArgumentTypesToCaptureIfAny();
         matcherCount = 0;
      }

      return mockedInvocationUsingTheMatchers;
   }

   @Nonnegative
   private int getSumOfParameterSizes()
   {
      @Nonnegative int sum = 0;

      for (Type argType : parameterTypes) {
         sum += argType.getSize();
      }

      return sum;
   }

   private void generateCallsToMoveArgMatchers(@Nonnegative int initialStack)
   {
      @Nonnegative int stack = initialStack;
      @Nonnegative int nextMatcher = 0;
      @Nonnegative int matcherStack = matcherStacks[0];

      for (int i = 0; i < parameterTypes.length && nextMatcher < matcherCount; i++) {
         stack += parameterTypes[i].getSize();

         if (stack == matcherStack || stack == matcherStack + 1) {
            if (nextMatcher < i) {
               generateCallToMoveArgMatcher(nextMatcher, i);
               modifier.argumentCapturing.updateCaptureIfAny(nextMatcher, i);
            }

            matcherStack = matcherStacks[++nextMatcher];
         }
      }
   }

   private void generateCallToMoveArgMatcher(@Nonnegative int originalMatcherIndex, @Nonnegative int toIndex)
   {
      MethodWriter mw = modifier.getMethodWriter();
      mw.visitIntInsn(SIPUSH, originalMatcherIndex);
      mw.visitIntInsn(SIPUSH, toIndex);
      modifier.generateCallToActiveInvocationsMethod("moveArgMatcher", "(II)V");
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy