package net.bytebuddy.dynamic.scaffold.subclass;
import net.bytebuddy.description.ByteCodeElement;
import net.bytebuddy.description.annotation.AnnotationDescription;
import net.bytebuddy.description.annotation.AnnotationList;
import net.bytebuddy.description.annotation.AnnotationValue;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.method.MethodList;
import net.bytebuddy.description.method.ParameterDescription;
import net.bytebuddy.description.method.ParameterList;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.description.type.TypeList;
import net.bytebuddy.description.type.TypeVariableToken;
import net.bytebuddy.dynamic.Transformer;
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
import net.bytebuddy.dynamic.scaffold.MethodRegistry;
import net.bytebuddy.implementation.attribute.MethodAttributeAppender;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.matcher.LatentMatcher;
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.Opcodes;
import java.util.Collections;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.*;
public class ConstructorStrategyDefaultTest {
private static final String FOO = "foo";
private static final int MODIFIERS = 42;
@Rule
public TestRule mockitoRule = new MockitoRule(this);
@Mock
private MethodRegistry methodRegistry;
@Mock
private InstrumentedType instrumentedType;
@Mock
private TypeDescription.Generic superClass, typeDescription;
@Mock
private MethodDescription.InGenericShape methodDescription;
@Mock
private MethodDescription.Token token;
@Mock
private AnnotationValue<?, ?> defaultValue;
private MethodDescription.Token stripped;
@Before
@SuppressWarnings("unchecked")
public void setUp() throws Exception {
when(methodRegistry.append(any(LatentMatcher.class),
any(MethodRegistry.Handler.class),
any(MethodAttributeAppender.Factory.class),
any(Transformer.class))).thenReturn(methodRegistry);
when(instrumentedType.getSuperClass()).thenReturn(superClass);
when(superClass.getDeclaredMethods()).thenReturn(new MethodList.Explicit<MethodDescription.InGenericShape>(methodDescription));
when(methodDescription.isConstructor()).thenReturn(true);
when(methodDescription.isVisibleTo(instrumentedType)).thenReturn(true);
when(methodDescription.asToken(ElementMatchers.is(instrumentedType))).thenReturn(token);
when(token.getName()).thenReturn(FOO);
when(token.getModifiers()).thenReturn(MODIFIERS);
when(token.getTypeVariableTokens()).thenReturn(new ByteCodeElement.Token.TokenList<TypeVariableToken>());
when(token.getReturnType()).thenReturn(typeDescription);
when(token.getParameterTokens()).thenReturn(new ByteCodeElement.Token.TokenList<ParameterDescription.Token>());
when(token.getExceptionTypes()).thenReturn(new TypeList.Generic.Empty());
when(token.getAnnotations()).thenReturn(new AnnotationList.Empty());
when(token.getDefaultValue()).thenReturn((AnnotationValue) defaultValue);
when(token.getReceiverType()).thenReturn(typeDescription);
stripped = new MethodDescription.Token(FOO,
MODIFIERS,
Collections.<TypeVariableToken>emptyList(),
typeDescription,
Collections.<ParameterDescription.Token>emptyList(),
Collections.<TypeDescription.Generic>emptyList(),
Collections.<AnnotationDescription>emptyList(),
defaultValue,
TypeDescription.Generic.UNDEFINED);
}
@Test
public void testNoConstructorsStrategy() throws Exception {
assertThat(ConstructorStrategy.Default.NO_CONSTRUCTORS.extractConstructors(instrumentedType).size(), is(0));
assertThat(ConstructorStrategy.Default.NO_CONSTRUCTORS.inject(methodRegistry), is(methodRegistry));
verifyZeroInteractions(methodRegistry);
verifyZeroInteractions(instrumentedType);
}
@Test
public void testNoConstructorsStrategyWithAttributeAppender() throws Exception {
MethodAttributeAppender.Factory methodAttributeAppenderFactory = mock(MethodAttributeAppender.Factory.class);
ConstructorStrategy constructorStrategy = ConstructorStrategy.Default.NO_CONSTRUCTORS.with(methodAttributeAppenderFactory);
assertThat(constructorStrategy.extractConstructors(instrumentedType).size(), is(0));
assertThat(constructorStrategy.inject(methodRegistry), is(methodRegistry));
verifyZeroInteractions(methodRegistry);
verifyZeroInteractions(instrumentedType);
}
@Test
public void testNoConstructorsStrategyWithInheritedAnnotations() throws Exception {
ConstructorStrategy constructorStrategy = ConstructorStrategy.Default.NO_CONSTRUCTORS.withInheritedAnnotations();
assertThat(constructorStrategy.extractConstructors(instrumentedType).size(), is(0));
assertThat(constructorStrategy.inject(methodRegistry), is(methodRegistry));
verifyZeroInteractions(methodRegistry);
verifyZeroInteractions(instrumentedType);
}
@Test
@SuppressWarnings("unchecked")
public void testImitateSuperClassStrategy() throws Exception {
assertThat(ConstructorStrategy.Default.IMITATE_SUPER_CLASS.extractConstructors(instrumentedType), is(Collections.singletonList(stripped)));
assertThat(ConstructorStrategy.Default.IMITATE_SUPER_CLASS.inject(methodRegistry), is(methodRegistry));
verify(methodRegistry).append(any(LatentMatcher.class),
any(MethodRegistry.Handler.class),
eq(MethodAttributeAppender.NoOp.INSTANCE),
eq(Transformer.NoOp.<MethodDescription>make()));
verifyNoMoreInteractions(methodRegistry);
verify(instrumentedType, atLeastOnce()).getSuperClass();
verifyNoMoreInteractions(instrumentedType);
}
@Test
@SuppressWarnings("unchecked")
public void testImitateSuperClassStrategyWithAttributeAppender() throws Exception {
when(methodDescription.getModifiers()).thenReturn(Opcodes.ACC_PUBLIC);
MethodAttributeAppender.Factory methodAttributeAppenderFactory = mock(MethodAttributeAppender.Factory.class);
ConstructorStrategy constructorStrategy = ConstructorStrategy.Default.IMITATE_SUPER_CLASS.with(methodAttributeAppenderFactory);
assertThat(constructorStrategy.extractConstructors(instrumentedType), is(Collections.singletonList(stripped)));
assertThat(constructorStrategy.inject(methodRegistry), is(methodRegistry));
verify(methodRegistry).append(any(LatentMatcher.class),
any(MethodRegistry.Handler.class),
eq(methodAttributeAppenderFactory),
eq(Transformer.NoOp.<MethodDescription>make()));
verifyNoMoreInteractions(methodRegistry);
verify(instrumentedType, atLeastOnce()).getSuperClass();
verifyNoMoreInteractions(instrumentedType);
}
@Test
@SuppressWarnings("unchecked")
public void testImitateSuperClassStrategyWithInheritedAnnotations() throws Exception {
when(methodDescription.getModifiers()).thenReturn(Opcodes.ACC_PUBLIC);
ConstructorStrategy constructorStrategy = ConstructorStrategy.Default.IMITATE_SUPER_CLASS.withInheritedAnnotations();
assertThat(constructorStrategy.extractConstructors(instrumentedType), is(Collections.singletonList(stripped)));
assertThat(constructorStrategy.inject(methodRegistry), is(methodRegistry));
verify(methodRegistry).append(any(LatentMatcher.class),
any(MethodRegistry.Handler.class),
eq(MethodAttributeAppender.ForInstrumentedMethod.EXCLUDING_RECEIVER),
eq(Transformer.NoOp.<MethodDescription>make()));
verifyNoMoreInteractions(methodRegistry);
verify(instrumentedType, atLeastOnce()).getSuperClass();
verifyNoMoreInteractions(instrumentedType);
}
@Test
@SuppressWarnings("unchecked")
public void testImitateSuperClassPublicStrategy() throws Exception {
when(methodDescription.getModifiers()).thenReturn(Opcodes.ACC_PUBLIC);
assertThat(ConstructorStrategy.Default.IMITATE_SUPER_CLASS_PUBLIC.extractConstructors(instrumentedType), is(Collections.singletonList(stripped)));
assertThat(ConstructorStrategy.Default.IMITATE_SUPER_CLASS_PUBLIC.inject(methodRegistry), is(methodRegistry));
verify(methodRegistry).append(any(LatentMatcher.class),
any(MethodRegistry.Handler.class),
eq(MethodAttributeAppender.NoOp.INSTANCE),
eq(Transformer.NoOp.<MethodDescription>make()));
verifyNoMoreInteractions(methodRegistry);
verify(instrumentedType, atLeastOnce()).getSuperClass();
verifyNoMoreInteractions(instrumentedType);
}
@Test
@SuppressWarnings("unchecked")
public void testImitateSuperClassPublicStrategyWithAttributeAppender() throws Exception {
when(methodDescription.getModifiers()).thenReturn(Opcodes.ACC_PUBLIC);
MethodAttributeAppender.Factory methodAttributeAppenderFactory = mock(MethodAttributeAppender.Factory.class);
ConstructorStrategy constructorStrategy = ConstructorStrategy.Default.IMITATE_SUPER_CLASS_PUBLIC.with(methodAttributeAppenderFactory);
assertThat(constructorStrategy.extractConstructors(instrumentedType), is(Collections.singletonList(stripped)));
assertThat(constructorStrategy.inject(methodRegistry), is(methodRegistry));
verify(methodRegistry).append(any(LatentMatcher.class),
any(MethodRegistry.Handler.class),
eq(methodAttributeAppenderFactory),
eq(Transformer.NoOp.<MethodDescription>make()));
verifyNoMoreInteractions(methodRegistry);
verify(instrumentedType, atLeastOnce()).getSuperClass();
verifyNoMoreInteractions(instrumentedType);
}
@Test
@SuppressWarnings("unchecked")
public void testImitateSuperClassPublicStrategyWithInheritedAnnotations() throws Exception {
when(methodDescription.getModifiers()).thenReturn(Opcodes.ACC_PUBLIC);
ConstructorStrategy constructorStrategy = ConstructorStrategy.Default.IMITATE_SUPER_CLASS_PUBLIC.withInheritedAnnotations();
assertThat(constructorStrategy.extractConstructors(instrumentedType), is(Collections.singletonList(stripped)));
assertThat(constructorStrategy.inject(methodRegistry), is(methodRegistry));
verify(methodRegistry).append(any(LatentMatcher.class),
any(MethodRegistry.Handler.class),
eq(MethodAttributeAppender.ForInstrumentedMethod.EXCLUDING_RECEIVER),
eq(Transformer.NoOp.<MethodDescription>make()));
verifyNoMoreInteractions(methodRegistry);
verify(instrumentedType, atLeastOnce()).getSuperClass();
verifyNoMoreInteractions(instrumentedType);
}
@Test
public void testImitateSuperClassPublicStrategyDoesNotSeeNonPublic() throws Exception {
when(methodDescription.getModifiers()).thenReturn(0);
assertThat(ConstructorStrategy.Default.IMITATE_SUPER_CLASS_PUBLIC.extractConstructors(instrumentedType).size(), is(0));
}
@Test
@SuppressWarnings("unchecked")
public void testDefaultConstructorStrategy() throws Exception {
when(methodDescription.getParameters()).thenReturn(new ParameterList.Empty<ParameterDescription.InGenericShape>());
assertThat(ConstructorStrategy.Default.DEFAULT_CONSTRUCTOR.extractConstructors(instrumentedType),
is(Collections.singletonList(new MethodDescription.Token(Opcodes.ACC_PUBLIC))));
assertThat(ConstructorStrategy.Default.DEFAULT_CONSTRUCTOR.inject(methodRegistry), is(methodRegistry));
verify(methodRegistry).append(any(LatentMatcher.class),
any(MethodRegistry.Handler.class),
eq(MethodAttributeAppender.NoOp.INSTANCE),
eq(Transformer.NoOp.<MethodDescription>make()));
verifyNoMoreInteractions(methodRegistry);
verify(instrumentedType).getSuperClass();
verifyNoMoreInteractions(instrumentedType);
}
@Test
@SuppressWarnings("unchecked")
public void testDefaultConstructorStrategyWithAttributeAppender() throws Exception {
when(methodDescription.getParameters()).thenReturn(new ParameterList.Empty<ParameterDescription.InGenericShape>());
MethodAttributeAppender.Factory methodAttributeAppenderFactory = mock(MethodAttributeAppender.Factory.class);
ConstructorStrategy constructorStrategy = ConstructorStrategy.Default.DEFAULT_CONSTRUCTOR.with(methodAttributeAppenderFactory);
assertThat(constructorStrategy.extractConstructors(instrumentedType),
is(Collections.singletonList(new MethodDescription.Token(Opcodes.ACC_PUBLIC))));
assertThat(constructorStrategy.inject(methodRegistry), is(methodRegistry));
verify(methodRegistry).append(any(LatentMatcher.class),
any(MethodRegistry.Handler.class),
eq(methodAttributeAppenderFactory),
eq(Transformer.NoOp.<MethodDescription>make()));
verifyNoMoreInteractions(methodRegistry);
verify(instrumentedType).getSuperClass();
verifyNoMoreInteractions(instrumentedType);
}
@Test
@SuppressWarnings("unchecked")
public void testDefaultConstructorStrategyWithInheritedAnnotations() throws Exception {
when(methodDescription.getParameters()).thenReturn(new ParameterList.Empty<ParameterDescription.InGenericShape>());
ConstructorStrategy constructorStrategy = ConstructorStrategy.Default.DEFAULT_CONSTRUCTOR.withInheritedAnnotations();
assertThat(constructorStrategy.extractConstructors(instrumentedType),
is(Collections.singletonList(new MethodDescription.Token(Opcodes.ACC_PUBLIC))));
assertThat(constructorStrategy.inject(methodRegistry), is(methodRegistry));
verify(methodRegistry).append(any(LatentMatcher.class),
any(MethodRegistry.Handler.class),
eq(MethodAttributeAppender.ForInstrumentedMethod.EXCLUDING_RECEIVER),
eq(Transformer.NoOp.<MethodDescription>make()));
verifyNoMoreInteractions(methodRegistry);
verify(instrumentedType).getSuperClass();
verifyNoMoreInteractions(instrumentedType);
}
@Test(expected = IllegalArgumentException.class)
@SuppressWarnings("unchecked")
public void testDefaultConstructorStrategyNoDefault() throws Exception {
when(methodDescription.getParameters())
.thenReturn(new ParameterList.Explicit<ParameterDescription.InGenericShape>(mock(ParameterDescription.InGenericShape.class)));
ConstructorStrategy.Default.DEFAULT_CONSTRUCTOR.extractConstructors(instrumentedType);
}
@Test
@SuppressWarnings("unchecked")
public void testImitateSuperClassOpeningStrategyNonVisible() throws Exception {
when(methodDescription.isVisibleTo(instrumentedType)).thenReturn(false);
assertThat(ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING.extractConstructors(instrumentedType).isEmpty(), is(true));
}
@Test
@SuppressWarnings("unchecked")
public void testImitateSuperClassOpeningStrategy() throws Exception {
assertThat(ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING.extractConstructors(instrumentedType), is(Collections.singletonList(new MethodDescription.Token(FOO,
Opcodes.ACC_PUBLIC,
Collections.<TypeVariableToken>emptyList(),
typeDescription,
Collections.<ParameterDescription.Token>emptyList(),
Collections.<TypeDescription.Generic>emptyList(),
Collections.<AnnotationDescription>emptyList(),
defaultValue,
TypeDescription.Generic.UNDEFINED))));
assertThat(ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING.inject(methodRegistry), is(methodRegistry));
verify(methodRegistry).append(any(LatentMatcher.class),
any(MethodRegistry.Handler.class),
eq(MethodAttributeAppender.NoOp.INSTANCE),
eq(Transformer.NoOp.<MethodDescription>make()));
verifyNoMoreInteractions(methodRegistry);
verify(instrumentedType, atLeastOnce()).getSuperClass();
verifyNoMoreInteractions(instrumentedType);
}
@Test
public void testObjectProperties() throws Exception {
ObjectPropertyAssertion.of(ConstructorStrategy.Default.class).apply();
ObjectPropertyAssertion.of(ConstructorStrategy.Default.WithMethodAttributeAppenderFactory.class).apply();
}
}