package net.bytebuddy.dynamic.scaffold.inline; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.method.ParameterDescription; import net.bytebuddy.description.method.ParameterList; import net.bytebuddy.description.type.TypeDefinition; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.scaffold.MethodGraph; import net.bytebuddy.implementation.AbstractImplementationTargetTest; import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.bytecode.StackManipulation; import net.bytebuddy.implementation.bytecode.constant.NullConstant; import net.bytebuddy.matcher.ElementMatchers; import net.bytebuddy.test.utility.ObjectPropertyAssertion; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import java.util.Collections; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.*; public class RebaseImplementationTargetTest extends AbstractImplementationTargetTest { private static final String BAR = "bar"; @Mock private MethodDescription.InDefinedShape rebasedMethod; @Mock private MethodDescription.Token rebasedToken; @Mock private MethodDescription.SignatureToken rebasedSignatureToken; @Mock private MethodRebaseResolver.Resolution resolution; @Mock private TypeDescription rawSuperClass; @Mock private TypeDescription.Generic superClass; @Override @Before public void setUp() throws Exception { when(methodGraph.locate(Mockito.any(MethodDescription.SignatureToken.class))).thenReturn(MethodGraph.Node.Unresolved.INSTANCE); when(instrumentedType.getSuperClass()).thenReturn(superClass); when(superClass.asErasure()).thenReturn(rawSuperClass); when(rawSuperClass.getInternalName()).thenReturn(BAR); when(rebasedMethod.getInternalName()).thenReturn(QUX); when(rebasedMethod.asToken(ElementMatchers.is(instrumentedType))).thenReturn(rebasedToken); when(rebasedMethod.getDescriptor()).thenReturn(FOO); when(rebasedMethod.asDefined()).thenReturn(rebasedMethod); when(rebasedMethod.getReturnType()).thenReturn(genericReturnType); when(rebasedMethod.getParameters()).thenReturn(new ParameterList.Empty<ParameterDescription.InDefinedShape>()); when(rebasedMethod.getDeclaringType()).thenReturn(instrumentedType); when(rebasedMethod.asSignatureToken()).thenReturn(rebasedSignatureToken); super.setUp(); } @Override protected Implementation.Target makeImplementationTarget() { return new RebaseImplementationTarget(instrumentedType, methodGraph, defaultMethodInvocation, Collections.singletonMap(rebasedSignatureToken, resolution)); } @Test public void testNonRebasedMethodIsInvokable() throws Exception { when(invokableMethod.getDeclaringType()).thenReturn(instrumentedType); when(invokableMethod.isSpecializableFor(instrumentedType)).thenReturn(true); when(resolution.isRebased()).thenReturn(false); when(resolution.getResolvedMethod()).thenReturn(invokableMethod); Implementation.SpecialMethodInvocation specialMethodInvocation = makeImplementationTarget().invokeSuper(rebasedSignatureToken); assertThat(specialMethodInvocation.isValid(), is(true)); assertThat(specialMethodInvocation.getMethodDescription(), is((MethodDescription) invokableMethod)); assertThat(specialMethodInvocation.getTypeDescription(), is(instrumentedType)); MethodVisitor methodVisitor = mock(MethodVisitor.class); Implementation.Context implementationContext = mock(Implementation.Context.class); StackManipulation.Size size = specialMethodInvocation.apply(methodVisitor, implementationContext); verify(methodVisitor).visitMethodInsn(Opcodes.INVOKESPECIAL, BAZ, FOO, QUX, false); verifyNoMoreInteractions(methodVisitor); verifyZeroInteractions(implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); } @Test public void testRebasedMethodIsInvokable() throws Exception { when(invokableMethod.getDeclaringType()).thenReturn(instrumentedType); when(resolution.isRebased()).thenReturn(true); when(resolution.getResolvedMethod()).thenReturn(rebasedMethod); when(resolution.getAdditionalArguments()).thenReturn(StackManipulation.Trivial.INSTANCE); when(rebasedMethod.isSpecializableFor(instrumentedType)).thenReturn(true); Implementation.SpecialMethodInvocation specialMethodInvocation = makeImplementationTarget().invokeSuper(rebasedSignatureToken); assertThat(specialMethodInvocation.isValid(), is(true)); assertThat(specialMethodInvocation.getMethodDescription(), is((MethodDescription) rebasedMethod)); assertThat(specialMethodInvocation.getTypeDescription(), is(instrumentedType)); MethodVisitor methodVisitor = mock(MethodVisitor.class); Implementation.Context implementationContext = mock(Implementation.Context.class); StackManipulation.Size size = specialMethodInvocation.apply(methodVisitor, implementationContext); verify(methodVisitor).visitMethodInsn(Opcodes.INVOKESPECIAL, BAZ, QUX, FOO, false); verifyNoMoreInteractions(methodVisitor); verifyZeroInteractions(implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); } @Test public void testRebasedConstructorIsInvokable() throws Exception { when(rebasedMethod.isConstructor()).thenReturn(true); when(invokableMethod.getDeclaringType()).thenReturn(instrumentedType); when(resolution.isRebased()).thenReturn(true); when(resolution.getResolvedMethod()).thenReturn(rebasedMethod); when(resolution.getAdditionalArguments()).thenReturn(NullConstant.INSTANCE); when(rebasedMethod.isSpecializableFor(instrumentedType)).thenReturn(true); Implementation.SpecialMethodInvocation specialMethodInvocation = makeImplementationTarget().invokeSuper(rebasedSignatureToken); assertThat(specialMethodInvocation.isValid(), is(true)); assertThat(specialMethodInvocation.getMethodDescription(), is((MethodDescription) rebasedMethod)); assertThat(specialMethodInvocation.getTypeDescription(), is(instrumentedType)); MethodVisitor methodVisitor = mock(MethodVisitor.class); Implementation.Context implementationContext = mock(Implementation.Context.class); StackManipulation.Size size = specialMethodInvocation.apply(methodVisitor, implementationContext); verify(methodVisitor).visitInsn(Opcodes.ACONST_NULL); verify(methodVisitor).visitMethodInsn(Opcodes.INVOKESPECIAL, BAZ, QUX, FOO, false); verifyNoMoreInteractions(methodVisitor); verifyZeroInteractions(implementationContext); assertThat(size.getSizeImpact(), is(1)); assertThat(size.getMaximalSize(), is(1)); } @Test public void testNonSpecializableRebaseMethodIsNotInvokable() throws Exception { when(invokableMethod.getDeclaringType()).thenReturn(instrumentedType); when(resolution.isRebased()).thenReturn(true); when(resolution.getResolvedMethod()).thenReturn(rebasedMethod); when(resolution.getAdditionalArguments()).thenReturn(StackManipulation.Trivial.INSTANCE); when(rebasedMethod.isSpecializableFor(instrumentedType)).thenReturn(false); Implementation.SpecialMethodInvocation specialMethodInvocation = makeImplementationTarget().invokeSuper(rebasedSignatureToken); assertThat(specialMethodInvocation.isValid(), is(false)); } @Test public void testSuperTypeMethodIsInvokable() throws Exception { when(invokableMethod.isSpecializableFor(rawSuperClass)).thenReturn(true); Implementation.SpecialMethodInvocation specialMethodInvocation = makeImplementationTarget().invokeSuper(invokableToken); assertThat(specialMethodInvocation.isValid(), is(true)); assertThat(specialMethodInvocation.getMethodDescription(), is((MethodDescription) invokableMethod)); assertThat(specialMethodInvocation.getTypeDescription(), is(rawSuperClass)); MethodVisitor methodVisitor = mock(MethodVisitor.class); Implementation.Context implementationContext = mock(Implementation.Context.class); StackManipulation.Size size = specialMethodInvocation.apply(methodVisitor, implementationContext); verify(methodVisitor).visitMethodInsn(Opcodes.INVOKESPECIAL, BAR, FOO, QUX, false); verifyNoMoreInteractions(methodVisitor); verifyZeroInteractions(implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); } @Test public void testNonSpecializableSuperClassMethodIsNotInvokable() throws Exception { when(invokableMethod.isSpecializableFor(rawSuperClass)).thenReturn(false); when(resolution.isRebased()).thenReturn(false); when(resolution.getResolvedMethod()).thenReturn(invokableMethod); Implementation.SpecialMethodInvocation specialMethodInvocation = makeImplementationTarget().invokeSuper(invokableToken); assertThat(specialMethodInvocation.isValid(), is(false)); } @Test public void testOriginType() throws Exception { assertThat(makeImplementationTarget().getOriginType(), is((TypeDefinition) instrumentedType)); } @Test @SuppressWarnings("unchecked") public void testObjectProperties() throws Exception { ObjectPropertyAssertion.of(RebaseImplementationTarget.class).apply(); } }