package net.bytebuddy.implementation.bytecode.assign.reference; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.bytecode.StackManipulation; import net.bytebuddy.implementation.bytecode.assign.Assigner; import net.bytebuddy.test.utility.MockitoRule; import net.bytebuddy.test.utility.ObjectPropertyAssertion; import org.junit.After; 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 static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.*; public class ReferenceTypeAwareAssignerTest { private static final String FOO = "foo"; @Rule public TestRule mockitoRule = new MockitoRule(this); @Mock private MethodVisitor methodVisitor; @Mock private TypeDescription.Generic source, target; @Mock private TypeDescription rawSource, rawTarget; @Mock private Implementation.Context implementationContext; @Before public void setUp() throws Exception { when(source.asErasure()).thenReturn(rawSource); when(target.asErasure()).thenReturn(rawTarget); } @After public void tearDown() throws Exception { verifyZeroInteractions(implementationContext); } @Test public void testMutualAssignable() throws Exception { defineAssignability(true, true); StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign(source, target, Assigner.Typing.STATIC); assertThat(stackManipulation.isValid(), is(true)); StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); verifyZeroInteractions(methodVisitor); } @Test public void testSourceToTargetAssignable() throws Exception { defineAssignability(true, false); StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign(source, target, Assigner.Typing.STATIC); assertThat(stackManipulation.isValid(), is(true)); StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); verifyZeroInteractions(methodVisitor); } @Test(expected = IllegalStateException.class) public void testTargetToSourceAssignable() throws Exception { defineAssignability(false, true); StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign(source, target, Assigner.Typing.STATIC); assertThat(stackManipulation.isValid(), is(false)); stackManipulation.apply(methodVisitor, implementationContext); } @Test public void testTargetToSourceAssignableRuntimeType() throws Exception { defineAssignability(false, false); when(rawTarget.getInternalName()).thenReturn(FOO); StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign(source, target, Assigner.Typing.DYNAMIC); assertThat(stackManipulation.isValid(), is(true)); StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); verify(methodVisitor).visitTypeInsn(Opcodes.CHECKCAST, FOO); verifyNoMoreInteractions(methodVisitor); } @Test public void testPrimitiveAssignabilityWhenEqual() throws Exception { TypeDescription.Generic primitiveType = new TypeDescription.Generic.OfNonGenericType.ForLoadedType(int.class); // Note: cannot mock equals StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign(primitiveType, primitiveType, Assigner.Typing.DYNAMIC); assertThat(stackManipulation.isValid(), is(true)); StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); verifyZeroInteractions(methodVisitor); } @Test(expected = IllegalStateException.class) public void testPrimitiveAssignabilityWhenNotEqual() throws Exception { TypeDescription.Generic primitiveType = new TypeDescription.Generic.OfNonGenericType.ForLoadedType(int.class); // Note: cannot mock equals TypeDescription.Generic otherPrimitiveType = new TypeDescription.Generic.OfNonGenericType.ForLoadedType(long.class); // Note: cannot mock equals StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign(primitiveType, otherPrimitiveType, Assigner.Typing.DYNAMIC); assertThat(stackManipulation.isValid(), is(false)); stackManipulation.apply(methodVisitor, implementationContext); } private void defineAssignability(boolean sourceToTarget, boolean targetToSource) { if (sourceToTarget) { when(rawSource.isAssignableTo(rawTarget)).thenReturn(true); when(rawTarget.isAssignableFrom(rawSource)).thenReturn(true); } if (targetToSource) { when(rawTarget.isAssignableTo(rawSource)).thenReturn(true); when(rawSource.isAssignableFrom(rawTarget)).thenReturn(true); } } @Test public void testObjectProperties() throws Exception { ObjectPropertyAssertion.of(ReferenceTypeAwareAssigner.class).apply(); } }