package net.bytebuddy.implementation;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.scaffold.MethodGraph;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.implementation.bytecode.StackSize;
import net.bytebuddy.test.utility.MockitoRule;
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 abstract class AbstractImplementationTargetTest {
protected static final String FOO = "foo", QUX = "qux", BAZ = "baz", QUXBAZ = "quxbaz", FOOBAZ = "foobaz", BAZBAR = "bazbar";
@Rule
public TestRule mockitoRule = new MockitoRule(this);
@Mock
protected MethodGraph.Linked methodGraph, superGraph, defaultGraph;
@Mock
protected TypeDescription instrumentedType, methodDeclaringType, returnType, defaultMethodDeclaringType;
@Mock
protected TypeDescription.Generic genericInstrumentedType, genericReturnType;
@Mock
protected MethodDescription.InDefinedShape invokableMethod, defaultMethod;
@Mock
protected MethodDescription.SignatureToken invokableToken, defaultToken;
protected Implementation.Target.AbstractBase.DefaultMethodInvocation defaultMethodInvocation;
@Before
@SuppressWarnings("unchecked")
public void setUp() throws Exception {
when(instrumentedType.asErasure()).thenReturn(instrumentedType);
when(instrumentedType.getInternalName()).thenReturn(BAZ);
when(methodGraph.getSuperClassGraph()).thenReturn(superGraph);
when(superGraph.locate(any(MethodDescription.SignatureToken.class))).thenReturn(MethodGraph.Node.Unresolved.INSTANCE);
when(superGraph.locate(invokableToken)).thenReturn(new MethodGraph.Node.Simple(invokableMethod));
when(methodGraph.getInterfaceGraph(defaultMethodDeclaringType)).thenReturn(defaultGraph);
when(defaultGraph.locate(any(MethodDescription.SignatureToken.class))).thenReturn(MethodGraph.Node.Unresolved.INSTANCE);
when(defaultGraph.locate(defaultToken)).thenReturn(new MethodGraph.Node.Simple(defaultMethod));
when(methodDeclaringType.asErasure()).thenReturn(methodDeclaringType);
when(invokableMethod.getDeclaringType()).thenReturn(methodDeclaringType);
when(invokableMethod.getReturnType()).thenReturn(genericReturnType);
when(returnType.getStackSize()).thenReturn(StackSize.ZERO);
when(genericReturnType.getStackSize()).thenReturn(StackSize.ZERO);
when(returnType.asErasure()).thenReturn(returnType);
when(invokableMethod.getInternalName()).thenReturn(FOO);
when(invokableMethod.getDescriptor()).thenReturn(QUX);
when(invokableMethod.asSignatureToken()).thenReturn(invokableToken);
when(invokableMethod.asDefined()).thenReturn(invokableMethod);
when(defaultMethod.getInternalName()).thenReturn(QUXBAZ);
when(defaultMethod.getDescriptor()).thenReturn(FOOBAZ);
when(defaultMethod.getDeclaringType()).thenReturn(defaultMethodDeclaringType);
when(defaultMethod.getReturnType()).thenReturn(genericReturnType);
when(defaultMethod.asSignatureToken()).thenReturn(defaultToken);
when(defaultMethod.asDefined()).thenReturn(defaultMethod);
when(defaultMethod.isSpecializableFor(defaultMethodDeclaringType)).thenReturn(true);
when(defaultMethodDeclaringType.isInterface()).thenReturn(true);
when(defaultMethodDeclaringType.asErasure()).thenReturn(defaultMethodDeclaringType);
when(defaultMethodDeclaringType.getInternalName()).thenReturn(BAZBAR);
when(genericReturnType.asErasure()).thenReturn(returnType);
when(genericReturnType.asGenericType()).thenReturn(genericReturnType);
when(returnType.asGenericType()).thenReturn(genericReturnType);
when(genericInstrumentedType.asErasure()).thenReturn(instrumentedType);
when(genericInstrumentedType.asGenericType()).thenReturn(genericInstrumentedType);
when(instrumentedType.asGenericType()).thenReturn(genericInstrumentedType);
defaultMethodInvocation = Implementation.Target.AbstractBase.DefaultMethodInvocation.ENABLED;
}
protected abstract Implementation.Target makeImplementationTarget();
@Test
public void testDefaultMethodInvocation() throws Exception {
Implementation.SpecialMethodInvocation specialMethodInvocation = makeImplementationTarget().invokeDefault(defaultToken, defaultMethodDeclaringType);
assertThat(specialMethodInvocation.isValid(), is(true));
assertThat(specialMethodInvocation.getMethodDescription(), is((MethodDescription) defaultMethod));
assertThat(specialMethodInvocation.getTypeDescription(), is(defaultMethodDeclaringType));
MethodVisitor methodVisitor = mock(MethodVisitor.class);
Implementation.Context implementationContext = mock(Implementation.Context.class);
StackManipulation.Size size = specialMethodInvocation.apply(methodVisitor, implementationContext);
assertThat(size.getSizeImpact(), is(0));
assertThat(size.getMaximalSize(), is(0));
verify(methodVisitor).visitMethodInsn(Opcodes.INVOKESPECIAL, BAZBAR, QUXBAZ, FOOBAZ, true);
verifyNoMoreInteractions(methodVisitor);
verifyZeroInteractions(implementationContext);
}
@Test
public void testDefaultMethodInvocationNotSupported() throws Exception {
defaultMethodInvocation = Implementation.Target.AbstractBase.DefaultMethodInvocation.DISABLED;
Implementation.SpecialMethodInvocation specialMethodInvocation = makeImplementationTarget().invokeDefault(defaultToken, defaultMethodDeclaringType);
assertThat(specialMethodInvocation.isValid(), is(false));
}
@Test
public void testIllegalDefaultMethod() throws Exception {
assertThat(makeImplementationTarget().invokeDefault(mock(MethodDescription.SignatureToken.class), defaultMethodDeclaringType).isValid(), is(false));
}
@Test
public void testIllegalSuperMethod() throws Exception {
MethodDescription.SignatureToken token = mock(MethodDescription.SignatureToken.class);
when(token.getName()).thenReturn(FOO);
assertThat(makeImplementationTarget().invokeSuper(token).isValid(), is(false));
}
@Test
public void testIllegalSuperConstructor() throws Exception {
MethodDescription.SignatureToken token = mock(MethodDescription.SignatureToken.class);
when(token.getName()).thenReturn(MethodDescription.CONSTRUCTOR_INTERNAL_NAME);
assertThat(makeImplementationTarget().invokeSuper(token).isValid(), is(false));
}
}