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 mocking/faking APIs and a code coverage tool, supporting both JUnit and TestNG. The mocking APIs allow all kinds of Java code, without testability restrictions, to be tested in isolation from selected dependencies.

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

import javax.annotation.*;

import mockit.asm.methods.*;
import mockit.asm.types.*;
import static mockit.asm.jvmConstants.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;");

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

         mw.visitVarInsn(opcode, varIndex);
      }
   }

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

      if (typeToCapture.charAt(0) == '[') {
         return ArrayType.create(typeToCapture);
      }

      return ObjectType.create(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) {
      JavaType parameterType = invocationBlockModifier.argumentMatching.getParameterType(parameterIndex);

      if (parameterType instanceof ReferenceType) {
         String parameterTypeDesc = ((ReferenceType) parameterType).getInternalName();
         return typeDesc.equals(parameterTypeDesc);
      }

      return isPrimitiveWrapper(typeDesc);
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy