package net.bytebuddy.implementation.bind.annotation; import net.bytebuddy.description.annotation.AnnotationList; import net.bytebuddy.description.method.ParameterList; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.bind.MethodDelegationBinder; import net.bytebuddy.implementation.bytecode.StackManipulation; import net.bytebuddy.implementation.bytecode.StackSize; import net.bytebuddy.implementation.bytecode.assign.Assigner; import net.bytebuddy.test.utility.ObjectPropertyAssertion; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.*; public class AllArgumentsBinderTest extends AbstractAnnotationBinderTest<AllArguments> { private static final String FOO = "foo"; @Mock private TypeDescription.Generic firstSourceType, secondSourceType, genericInstrumentedType; @Mock private TypeDescription rawTargetType, rawComponentType; @Mock private TypeDescription.Generic targetType, componentType; public AllArgumentsBinderTest() { super(AllArguments.class); } @Override @Before @SuppressWarnings("unchecked") public void setUp() throws Exception { super.setUp(); when(firstSourceType.getStackSize()).thenReturn(StackSize.SINGLE); when(secondSourceType.getStackSize()).thenReturn(StackSize.SINGLE); when(componentType.asErasure()).thenReturn(rawComponentType); when(targetType.getComponentType()).thenReturn(componentType); when(targetType.asErasure()).thenReturn(rawTargetType); when(firstSourceType.asGenericType()).thenReturn(firstSourceType); when(firstSourceType.accept(any(TypeDescription.Generic.Visitor.class))).thenReturn(firstSourceType); when(secondSourceType.asGenericType()).thenReturn(secondSourceType); when(secondSourceType.accept(any(TypeDescription.Generic.Visitor.class))).thenReturn(secondSourceType); } @Override protected TargetMethodAnnotationDrivenBinder.ParameterBinder<AllArguments> getSimpleBinder() { return AllArguments.Binder.INSTANCE; } @Test public void testLegalStrictBindingRuntimeType() throws Exception { when(target.getIndex()).thenReturn(1); testLegalStrictBinding(Assigner.Typing.STATIC); } @Test public void testLegalStrictBindingNoRuntimeType() throws Exception { when(target.getIndex()).thenReturn(1); RuntimeType runtimeType = mock(RuntimeType.class); doReturn(RuntimeType.class).when(runtimeType).annotationType(); when(target.getDeclaredAnnotations()).thenReturn(new AnnotationList.ForLoadedAnnotations(runtimeType)); testLegalStrictBinding(Assigner.Typing.DYNAMIC); } private void testLegalStrictBinding(Assigner.Typing typing) throws Exception { when(annotation.value()).thenReturn(AllArguments.Assignment.STRICT); when(stackManipulation.isValid()).thenReturn(true); when(source.getParameters()).thenReturn(new ParameterList.Explicit.ForTypes(source, firstSourceType, secondSourceType)); when(source.isStatic()).thenReturn(false); when(targetType.isArray()).thenReturn(true); when(targetType.getComponentType()).thenReturn(componentType); when(componentType.getStackSize()).thenReturn(StackSize.SINGLE); when(target.getType()).thenReturn(targetType); MethodDelegationBinder.ParameterBinding<?> parameterBinding = AllArguments.Binder.INSTANCE .bind(annotationDescription, source, target, implementationTarget, assigner, typing); assertThat(parameterBinding.isValid(), is(true)); verify(source, atLeast(1)).getParameters(); verify(source, atLeast(1)).isStatic(); verify(target, atLeast(1)).getType(); verify(target, never()).getDeclaredAnnotations(); verify(assigner).assign(firstSourceType, componentType, typing); verify(assigner).assign(secondSourceType, componentType, typing); verifyNoMoreInteractions(assigner); } @Test public void testIllegalBinding() throws Exception { when(target.getIndex()).thenReturn(1); when(annotation.value()).thenReturn(AllArguments.Assignment.STRICT); when(stackManipulation.isValid()).thenReturn(false); when(source.getParameters()).thenReturn(new ParameterList.Explicit.ForTypes(source, firstSourceType, secondSourceType)); when(source.isStatic()).thenReturn(false); when(targetType.isArray()).thenReturn(true); when(targetType.getComponentType()).thenReturn(componentType); when(componentType.getStackSize()).thenReturn(StackSize.SINGLE); when(target.getType()).thenReturn(targetType); when(target.getDeclaredAnnotations()).thenReturn(new AnnotationList.Empty()); MethodDelegationBinder.ParameterBinding<?> parameterBinding = AllArguments.Binder.INSTANCE .bind(annotationDescription, source, target, implementationTarget, assigner, Assigner.Typing.STATIC); assertThat(parameterBinding.isValid(), is(false)); verify(source, atLeast(1)).getParameters(); verify(source, atLeast(1)).isStatic(); verify(target, atLeast(1)).getType(); verify(target, never()).getDeclaredAnnotations(); verify(assigner).assign(firstSourceType, componentType, Assigner.Typing.STATIC); verifyNoMoreInteractions(assigner); } @Test public void testLegalSlackBinding() throws Exception { when(target.getIndex()).thenReturn(1); when(annotation.value()).thenReturn(AllArguments.Assignment.SLACK); when(stackManipulation.isValid()).thenReturn(false); when(source.getParameters()).thenReturn(new ParameterList.Explicit.ForTypes(source, firstSourceType, secondSourceType)); when(source.isStatic()).thenReturn(false); when(targetType.isArray()).thenReturn(true); when(targetType.getComponentType()).thenReturn(componentType); when(componentType.getStackSize()).thenReturn(StackSize.SINGLE); when(target.getType()).thenReturn(targetType); when(target.getDeclaredAnnotations()).thenReturn(new AnnotationList.Empty()); when(rawComponentType.getInternalName()).thenReturn(FOO); MethodDelegationBinder.ParameterBinding<?> parameterBinding = AllArguments.Binder.INSTANCE .bind(annotationDescription, source, target, implementationTarget, assigner, Assigner.Typing.STATIC); MethodVisitor methodVisitor = mock(MethodVisitor.class); Implementation.Context implementationContext = mock(Implementation.Context.class); StackManipulation.Size size = parameterBinding.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(1)); assertThat(size.getMaximalSize(), is(1)); verify(methodVisitor).visitInsn(Opcodes.ICONST_0); verify(methodVisitor).visitTypeInsn(Opcodes.ANEWARRAY, FOO); verifyNoMoreInteractions(methodVisitor); verifyZeroInteractions(implementationContext); assertThat(parameterBinding.isValid(), is(true)); verify(source, atLeast(1)).getParameters(); verify(source, atLeast(1)).isStatic(); verify(target, atLeast(1)).getType(); verify(target, never()).getDeclaredAnnotations(); verify(assigner).assign(firstSourceType, componentType, Assigner.Typing.STATIC); verify(assigner).assign(secondSourceType, componentType, Assigner.Typing.STATIC); verifyNoMoreInteractions(assigner); } @Test(expected = IllegalStateException.class) public void testNonArrayTypeBinding() throws Exception { when(target.getIndex()).thenReturn(0); TypeDescription.Generic targetType = mock(TypeDescription.Generic.class); TypeDescription rawTargetType = mock(TypeDescription.class); when(targetType.asErasure()).thenReturn(rawTargetType); when(targetType.isArray()).thenReturn(false); when(target.getType()).thenReturn(targetType); AllArguments.Binder.INSTANCE.bind(annotationDescription, source, target, implementationTarget, assigner, Assigner.Typing.STATIC); } @Test public void testObjectProperties() throws Exception { ObjectPropertyAssertion.of(AllArguments.Assignment.class).apply(); ObjectPropertyAssertion.of(AllArguments.Binder.class).apply(); } }