package net.bytebuddy.implementation.bytecode.constant; import net.bytebuddy.ClassFileVersion; import net.bytebuddy.description.field.FieldDescription; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.method.ParameterList; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeList; import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.bytecode.StackManipulation; import net.bytebuddy.implementation.bytecode.StackSize; import net.bytebuddy.test.utility.MockitoRule; import net.bytebuddy.test.utility.ObjectPropertyAssertion; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; import org.mockito.Mock; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Collections; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.*; public class MethodConstantTest { private static final String FOO = "foo", BAR = "bar", QUX = "qux", BAZ = "baz"; @Rule public TestRule mockitoRule = new MockitoRule(this); @Mock private MethodDescription.InDefinedShape methodDescription; @Mock private TypeDescription declaringType, parameterType, fieldType, instrumentedType; @Mock private ClassFileVersion classFileVersion; @Mock private TypeDescription.Generic genericFieldType; @Mock private ParameterList<?> parameterList; @Mock private TypeList.Generic typeList; @Mock private TypeList rawTypeList; @Mock private MethodVisitor methodVisitor; @Mock private Implementation.Context implementationContext; @Mock private FieldDescription.InDefinedShape fieldDescription; @Before @SuppressWarnings("unchecked") public void setUp() throws Exception { when(declaringType.asErasure()).thenReturn(declaringType); when(methodDescription.getDeclaringType()).thenReturn(declaringType); when(methodDescription.getInternalName()).thenReturn(FOO); when(methodDescription.getParameters()).thenReturn((ParameterList) parameterList); when(parameterList.asTypeList()).thenReturn(typeList); when(declaringType.getDescriptor()).thenReturn(BAR); when(typeList.asErasures()).thenReturn(rawTypeList); when(rawTypeList.iterator()).thenReturn(Collections.singletonList(parameterType).iterator()); when(parameterType.getDescriptor()).thenReturn(QUX); when(fieldDescription.getType()).thenReturn(genericFieldType); when(fieldDescription.isStatic()).thenReturn(true); when(genericFieldType.asErasure()).thenReturn(fieldType); when(genericFieldType.getStackSize()).thenReturn(StackSize.SINGLE); when(fieldDescription.getDeclaringType()).thenReturn(declaringType); when(declaringType.getInternalName()).thenReturn(BAZ); when(fieldDescription.getInternalName()).thenReturn(FOO); when(fieldDescription.getDescriptor()).thenReturn(QUX); when(fieldDescription.asDefined()).thenReturn(fieldDescription); when(implementationContext.getClassFileVersion()).thenReturn(classFileVersion); when(implementationContext.getInstrumentedType()).thenReturn(instrumentedType); } @Test public void testMethod() throws Exception { StackManipulation.Size size = MethodConstant.forMethod(methodDescription).apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(1)); assertThat(size.getMaximalSize(), is(6)); verify(methodVisitor).visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Class.class), "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false); } @Test public void testMethodCached() throws Exception { when(implementationContext.cache(any(StackManipulation.class), any(TypeDescription.class))).thenReturn(fieldDescription); StackManipulation.Size size = MethodConstant.forMethod(methodDescription).cached().apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(1)); assertThat(size.getMaximalSize(), is(1)); verify(methodVisitor).visitFieldInsn(Opcodes.GETSTATIC, BAZ, FOO, QUX); verifyNoMoreInteractions(methodVisitor); verify(implementationContext).cache(MethodConstant.forMethod(methodDescription), new TypeDescription.ForLoadedType(Method.class)); verifyNoMoreInteractions(implementationContext); } @Test public void testConstructor() throws Exception { when(methodDescription.isConstructor()).thenReturn(true); StackManipulation.Size size = MethodConstant.forMethod(methodDescription).apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(1)); assertThat(size.getMaximalSize(), is(5)); verify(methodVisitor).visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Class.class), "getDeclaredConstructor", "([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;", false); } @Test public void testConstructorCached() throws Exception { when(methodDescription.isConstructor()).thenReturn(true); when(implementationContext.cache(any(StackManipulation.class), any(TypeDescription.class))).thenReturn(fieldDescription); StackManipulation.Size size = MethodConstant.forMethod(methodDescription).cached().apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(1)); assertThat(size.getMaximalSize(), is(1)); verify(methodVisitor).visitFieldInsn(Opcodes.GETSTATIC, BAZ, FOO, QUX); verifyNoMoreInteractions(methodVisitor); verify(implementationContext).cache(MethodConstant.forMethod(methodDescription), new TypeDescription.ForLoadedType(Constructor.class)); verifyNoMoreInteractions(implementationContext); } @Test(expected = IllegalStateException.class) public void testTypeInitializer() throws Exception { when(methodDescription.isTypeInitializer()).thenReturn(true); MethodConstant.CanCache methodConstant = MethodConstant.forMethod(methodDescription); assertThat(methodConstant.isValid(), is(false)); assertThat(methodConstant.cached().isValid(), is(false)); methodConstant.apply(methodVisitor, implementationContext); } @Test public void testObjectProperties() throws Exception { ObjectPropertyAssertion.of(MethodConstant.ForMethod.class).apply(); ObjectPropertyAssertion.of(MethodConstant.ForConstructor.class).apply(); ObjectPropertyAssertion.of(MethodConstant.CachedMethod.class).apply(); ObjectPropertyAssertion.of(MethodConstant.CachedConstructor.class).apply(); ObjectPropertyAssertion.of(MethodConstant.CanCacheIllegal.class).apply(); } }