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

mockit.internal.expectations.transformation.Capture 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.*;
import static mockit.internal.util.TypeConversion.*;

final class Capture
{
   @Nonnull private final InvocationBlockModifier invocationBlockModifier;
   @Nonnull private final MethodWriter mw;
   @Nonnegative private final int opcode;
   @Nonnegative private final int varIndex;
   @Nullable private String typeToCapture;
   @Nonnegative private int parameterIndex;
   @Nonnegative private boolean parameterIndexFixed;

   Capture(
      @Nonnull InvocationBlockModifier invocationBlockModifier, @Nonnegative int opcode, @Nonnegative int varIndex,
      @Nullable String typeToCapture, @Nonnegative int parameterIndex)
   {
      this.invocationBlockModifier = invocationBlockModifier;
      mw = invocationBlockModifier.getMethodWriter();
      this.opcode = opcode;
      this.varIndex = varIndex;
      this.typeToCapture = typeToCapture;
      this.parameterIndex = parameterIndex;
   }

   Capture(
      @Nonnull InvocationBlockModifier invocationBlockModifier, @Nonnegative int varIndex,
      @Nonnegative int parameterIndex)
   {
      this.invocationBlockModifier = invocationBlockModifier;
      mw = invocationBlockModifier.getMethodWriter();
      opcode = ALOAD;
      this.varIndex = varIndex;
      this.parameterIndex = parameterIndex;
   }

   /**
    * Generates bytecode that will be responsible for performing the following steps:
    * 1. Get the argument value (an Object) for the last matched invocation.
    * 2. Cast to a reference type or unbox to a primitive type, as needed.
    * 3. Store the converted value in its local variable.
    */
   void generateCodeToStoreCapturedValue()
   {
      if (opcode != ALOAD) {
         mw.visitIntInsn(SIPUSH, parameterIndex);

         if (typeToCapture == null) {
            mw.visitInsn(ACONST_NULL);
         }
         else {
            mw.visitLdcInsn(typeToCapture);
         }

         invocationBlockModifier.generateCallToActiveInvocationsMethod(
            "matchedArgument", "(ILjava/lang/String;)Ljava/lang/Object;");

         Type argType = getArgumentType();
         generateCastOrUnboxing(mw, argType, opcode);

         mw.visitVarInsn(opcode, varIndex);
      }
   }

   @Nonnull
   private Type getArgumentType()
   {
      if (typeToCapture == null) {
         return invocationBlockModifier.argumentMatching.getParameterType(parameterIndex);
      }

      if (typeToCapture.charAt(0) == '[') {
         return Type.getType(typeToCapture);
      }

      return Type.getType('L' + typeToCapture + ';');
   }

   boolean fixParameterIndex(@Nonnegative int originalIndex, @Nonnegative int newIndex)
   {
      if (!parameterIndexFixed && parameterIndex == originalIndex) {
         parameterIndex = newIndex;
         parameterIndexFixed = true;
         return true;
      }

      return false;
   }

   void generateCallToSetArgumentTypeIfNeeded()
   {
      if (opcode == ALOAD) {
         mw.visitIntInsn(SIPUSH, parameterIndex);
         mw.visitLdcInsn(varIndex);
         invocationBlockModifier.generateCallToActiveInvocationsMethod("setExpectedArgumentType", "(II)V");
      }
      else if (typeToCapture != null && !isTypeToCaptureSameAsParameterType(typeToCapture)) {
         mw.visitIntInsn(SIPUSH, parameterIndex);
         mw.visitLdcInsn(typeToCapture);
         invocationBlockModifier.generateCallToActiveInvocationsMethod(
            "setExpectedArgumentType", "(ILjava/lang/String;)V");
      }
   }

   private boolean isTypeToCaptureSameAsParameterType(@Nonnull String typeDesc)
   {
      Type parameterType = invocationBlockModifier.argumentMatching.getParameterType(parameterIndex);
      int sort = parameterType.getSort();

      if (sort == Type.Sort.OBJECT || sort == Type.Sort.ARRAY) {
         return typeDesc.equals(parameterType.getInternalName());
      }

      return isPrimitiveWrapper(typeDesc);
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy