package net.bytebuddy.implementation;
import net.bytebuddy.ClassFileVersion;
import net.bytebuddy.description.field.FieldDescription;
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.description.type.TypeList;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.scaffold.TypeInitializer;
import net.bytebuddy.implementation.attribute.AnnotationValueFilter;
import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
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.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.Arrays;
import java.util.Collection;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.AdditionalMatchers.aryEq;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@RunWith(Parameterized.class)
public class ImplementationContextDefaultTest {
private static final String FOO = "foo", BAR = "bar", QUX = "qux", BAZ = "baz";
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{false, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_FINAL, Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_FINAL | Opcodes.ACC_PRIVATE},
{true, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_PUBLIC, Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC},
});
}
private final boolean interfaceType;
private final int accessorMethodModifiers;
private final int cacheFieldModifiers;
public ImplementationContextDefaultTest(boolean interfaceType, int accessorMethodModifiers, int cacheFieldModifiers) {
this.interfaceType = interfaceType;
this.accessorMethodModifiers = accessorMethodModifiers;
this.cacheFieldModifiers = cacheFieldModifiers;
}
@Rule
public TestRule mockitoRule = new MockitoRule(this);
@Mock
private TypeDescription instrumentedType, firstDescription, secondDescription;
@Mock
private TypeInitializer typeInitializer, otherTypeInitializer, thirdTypeInitializer;
@Mock
private ClassFileVersion classFileVersion, auxiliaryClassFileVersion;
@Mock
private ClassVisitor classVisitor;
@Mock
private MethodVisitor methodVisitor;
@Mock
private FieldVisitor fieldVisitor;
@Mock
private AuxiliaryType auxiliaryType, otherAuxiliaryType;
@Mock
private DynamicType firstDynamicType, secondDynamicType;
@Mock
private TypeDescription.Generic firstFieldType, secondFieldType;
@Mock
private TypeDescription firstRawFieldType, secondRawFieldType;
@Mock
private StackManipulation firstFieldValue, secondFieldValue;
@Mock
private TypeDescription.Generic firstSpecialReturnType, secondSpecialReturnType;
@Mock
private TypeDescription firstRawSpecialReturnType, secondRawSpecialReturnType;
@Mock
private TypeDescription.Generic firstSpecialParameterType, secondSpecialParameterType;
@Mock
private TypeDescription firstRawSpecialParameterType, secondRawSpecialParameterType;
@Mock
private TypeDescription.Generic firstSpecialExceptionType, secondSpecialExceptionType;
@Mock
private TypeDescription firstRawSpecialExceptionType, secondRawSpecialExceptionType;
@Mock
private ByteCodeAppender injectedCodeAppender, terminationAppender;
@Mock
private Implementation.SpecialMethodInvocation firstSpecialInvocation, secondSpecialInvocation;
@Mock
private MethodDescription.InDefinedShape firstSpecialMethod, secondSpecialMethod;
@Mock
private AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy;
@Mock
private TypeDescription firstSpecialType, secondSpecialType;
@Mock
private FieldDescription.InDefinedShape firstField, secondField;
@Mock
private TypeDescription firstFieldDeclaringType, secondFieldDeclaringType;
private TypeList.Generic firstSpecialExceptionTypes, secondSpecialExceptionTypes;
@Mock
private AnnotationValueFilter.Factory annotationValueFilterFactory;
@Mock
private TypeInitializer.Drain drain;
@Before
@SuppressWarnings("unchecked")
public void setUp() throws Exception {
firstSpecialExceptionTypes = new TypeList.Generic.Explicit(firstSpecialExceptionType);
secondSpecialExceptionTypes = new TypeList.Generic.Explicit(secondSpecialExceptionType);
when(instrumentedType.getInternalName()).thenReturn(BAZ);
when(instrumentedType.asErasure()).thenReturn(instrumentedType);
when(instrumentedType.isInterface()).thenReturn(interfaceType);
when(auxiliaryType.make(any(String.class), any(ClassFileVersion.class), any(MethodAccessorFactory.class)))
.thenReturn(firstDynamicType);
when(firstDynamicType.getTypeDescription()).thenReturn(firstDescription);
when(otherAuxiliaryType.make(any(String.class), any(ClassFileVersion.class), any(MethodAccessorFactory.class)))
.thenReturn(secondDynamicType);
when(secondDynamicType.getTypeDescription()).thenReturn(secondDescription);
when(classVisitor.visitMethod(any(int.class), any(String.class), any(String.class), Mockito.<String>any(), Mockito.<String[]>any()))
.thenReturn(methodVisitor);
when(classVisitor.visitField(any(int.class), any(String.class), any(String.class), Mockito.<String>any(), Mockito.any()))
.thenReturn(fieldVisitor);
when(firstFieldValue.apply(any(MethodVisitor.class), any(Implementation.Context.class))).thenReturn(new StackManipulation.Size(0, 0));
when(secondFieldValue.apply(any(MethodVisitor.class), any(Implementation.Context.class))).thenReturn(new StackManipulation.Size(0, 0));
when(firstFieldType.getStackSize()).thenReturn(StackSize.ZERO);
when(firstFieldType.getSort()).thenReturn(TypeDefinition.Sort.NON_GENERIC);
when(firstFieldType.accept(any(TypeDescription.Generic.Visitor.class))).thenReturn(firstFieldType);
when(firstFieldType.asErasure()).thenReturn(firstRawFieldType);
when(firstFieldType.asRawType()).thenReturn(firstFieldType);
when(firstFieldType.asGenericType()).thenReturn(firstFieldType);
when(firstFieldType.accept(any(TypeDescription.Generic.Visitor.class))).thenReturn(firstFieldType);
when(firstRawFieldType.asGenericType()).thenReturn(firstFieldType);
when(firstRawFieldType.getDescriptor()).thenReturn(BAR);
when(secondFieldType.getStackSize()).thenReturn(StackSize.ZERO);
when(secondFieldType.getSort()).thenReturn(TypeDefinition.Sort.NON_GENERIC);
when(secondFieldType.accept(any(TypeDescription.Generic.Visitor.class))).thenReturn(secondFieldType);
when(secondFieldType.asErasure()).thenReturn(secondRawFieldType);
when(secondFieldType.asRawType()).thenReturn(secondFieldType);
when(secondFieldType.asGenericType()).thenReturn(secondFieldType);
when(secondFieldType.accept(any(TypeDescription.Generic.Visitor.class))).thenReturn(secondFieldType);
when(secondRawFieldType.asGenericType()).thenReturn(secondFieldType);
when(secondRawFieldType.getDescriptor()).thenReturn(QUX);
when(injectedCodeAppender.apply(any(MethodVisitor.class), any(Implementation.Context.class), any(MethodDescription.class)))
.thenReturn(new ByteCodeAppender.Size(0, 0));
when(terminationAppender.apply(any(MethodVisitor.class), any(Implementation.Context.class), any(MethodDescription.class)))
.thenReturn(new ByteCodeAppender.Size(0, 0));
when(firstSpecialInvocation.getMethodDescription()).thenReturn(firstSpecialMethod);
when(firstSpecialInvocation.getTypeDescription()).thenReturn(firstSpecialType);
when(firstSpecialMethod.getReturnType()).thenReturn(firstSpecialReturnType);
when(firstSpecialMethod.getInternalName()).thenReturn(FOO);
when(firstSpecialMethod.getExceptionTypes()).thenReturn(firstSpecialExceptionTypes);
when(firstRawSpecialParameterType.getDescriptor()).thenReturn(BAZ);
when(firstSpecialParameterType.getSort()).thenReturn(TypeDefinition.Sort.NON_GENERIC);
when(firstRawSpecialReturnType.getDescriptor()).thenReturn(QUX);
when(firstSpecialReturnType.getSort()).thenReturn(TypeDefinition.Sort.NON_GENERIC);
when(firstSpecialReturnType.getStackSize()).thenReturn(StackSize.ZERO);
when(firstSpecialReturnType.asRawType()).thenReturn(firstSpecialReturnType);
when(firstRawSpecialExceptionType.getInternalName()).thenReturn(FOO);
when(firstSpecialExceptionType.getSort()).thenReturn(TypeDefinition.Sort.NON_GENERIC);
when(firstSpecialExceptionType.asGenericType()).thenReturn(firstSpecialExceptionType);
when(firstSpecialExceptionType.asRawType()).thenReturn(firstSpecialExceptionType);
when(firstSpecialParameterType.getStackSize()).thenReturn(StackSize.ZERO);
when(firstSpecialParameterType.asGenericType()).thenReturn(firstSpecialParameterType);
when(firstSpecialParameterType.asRawType()).thenReturn(firstSpecialParameterType);
when(firstSpecialInvocation.apply(any(MethodVisitor.class), any(Implementation.Context.class))).thenReturn(new StackManipulation.Size(0, 0));
when(firstSpecialMethod.getParameters()).thenReturn(new ParameterList.Explicit.ForTypes(firstSpecialMethod, firstSpecialParameterType));
when(secondSpecialInvocation.getMethodDescription()).thenReturn(secondSpecialMethod);
when(secondSpecialInvocation.getTypeDescription()).thenReturn(secondSpecialType);
when(secondSpecialMethod.getInternalName()).thenReturn(BAR);
when(secondSpecialMethod.getReturnType()).thenReturn(secondSpecialReturnType);
when(secondSpecialMethod.getExceptionTypes()).thenReturn(secondSpecialExceptionTypes);
when(secondRawSpecialParameterType.getDescriptor()).thenReturn(BAR);
when(secondRawSpecialReturnType.getDescriptor()).thenReturn(FOO);
when(secondRawSpecialExceptionType.getInternalName()).thenReturn(BAZ);
when(secondSpecialExceptionType.getSort()).thenReturn(TypeDefinition.Sort.NON_GENERIC);
when(secondSpecialExceptionType.asGenericType()).thenReturn(secondSpecialExceptionType);
when(secondSpecialExceptionType.asRawType()).thenReturn(secondSpecialExceptionType);
when(secondSpecialParameterType.getStackSize()).thenReturn(StackSize.ZERO);
when(secondSpecialParameterType.getSort()).thenReturn(TypeDefinition.Sort.NON_GENERIC);
when(secondSpecialParameterType.asGenericType()).thenReturn(secondSpecialParameterType);
when(secondSpecialParameterType.asRawType()).thenReturn(secondSpecialParameterType);
when(secondSpecialReturnType.getStackSize()).thenReturn(StackSize.ZERO);
when(secondSpecialReturnType.getSort()).thenReturn(TypeDefinition.Sort.NON_GENERIC);
when(secondSpecialReturnType.asRawType()).thenReturn(secondSpecialReturnType);
when(secondSpecialInvocation.apply(any(MethodVisitor.class), any(Implementation.Context.class))).thenReturn(new StackManipulation.Size(0, 0));
when(secondSpecialMethod.getParameters()).thenReturn(new ParameterList.Explicit.ForTypes(secondSpecialMethod, secondSpecialParameterType));
when(firstField.getType()).thenReturn(firstFieldType);
when(firstField.getName()).thenReturn(FOO);
when(firstField.getInternalName()).thenReturn(FOO);
when(firstField.getDescriptor()).thenReturn(BAR);
when(firstField.getDeclaringType()).thenReturn(firstFieldDeclaringType);
when(firstField.asDefined()).thenReturn(firstField);
when(firstFieldDeclaringType.getInternalName()).thenReturn(QUX);
when(secondField.getType()).thenReturn(secondFieldType);
when(secondField.getName()).thenReturn(BAR);
when(secondField.getInternalName()).thenReturn(BAR);
when(secondField.getDescriptor()).thenReturn(FOO);
when(secondField.getDeclaringType()).thenReturn(secondFieldDeclaringType);
when(secondField.asDefined()).thenReturn(secondField);
when(secondFieldDeclaringType.getInternalName()).thenReturn(BAZ);
when(firstSpecialReturnType.asErasure()).thenReturn(firstRawSpecialReturnType);
when(secondSpecialReturnType.asErasure()).thenReturn(secondRawSpecialReturnType);
when(firstSpecialExceptionType.asErasure()).thenReturn(firstRawSpecialExceptionType);
when(secondSpecialExceptionType.asErasure()).thenReturn(secondRawSpecialExceptionType);
when(firstSpecialParameterType.asErasure()).thenReturn(firstRawSpecialParameterType);
when(secondSpecialParameterType.asErasure()).thenReturn(secondRawSpecialParameterType);
when(firstSpecialParameterType.accept(any(TypeDescription.Generic.Visitor.class))).thenReturn(firstSpecialParameterType);
when(secondSpecialParameterType.accept(any(TypeDescription.Generic.Visitor.class))).thenReturn(secondSpecialParameterType);
when(firstFieldDeclaringType.asErasure()).thenReturn(firstFieldDeclaringType);
when(secondFieldDeclaringType.asErasure()).thenReturn(secondFieldDeclaringType);
when(firstSpecialMethod.getDeclaringType()).thenReturn(firstSpecialType);
when(firstSpecialType.asErasure()).thenReturn(firstSpecialType);
when(secondSpecialMethod.getDeclaringType()).thenReturn(secondSpecialType);
when(secondSpecialType.asErasure()).thenReturn(secondSpecialType);
when(auxiliaryTypeNamingStrategy.name(instrumentedType)).thenReturn(FOO);
}
@Test
public void testInitialContextIsEmpty() throws Exception {
Implementation.Context.ExtractableView implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
assertThat(implementationContext.getAuxiliaryTypes().size(), is(0));
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verifyZeroInteractions(classVisitor);
verify(drain).apply(classVisitor, typeInitializer, implementationContext);
verifyNoMoreInteractions(drain);
}
@Test
public void testAuxiliaryTypeRegistration() throws Exception {
Implementation.Context.ExtractableView implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
assertThat(implementationContext.getAuxiliaryTypes().size(), is(0));
assertThat(implementationContext.register(auxiliaryType), is(firstDescription));
assertThat(implementationContext.getAuxiliaryTypes().size(), is(1));
assertThat(implementationContext.getAuxiliaryTypes().contains(firstDynamicType), is(true));
assertThat(implementationContext.register(otherAuxiliaryType), is(secondDescription));
assertThat(implementationContext.getAuxiliaryTypes().size(), is(2));
assertThat(implementationContext.getAuxiliaryTypes().contains(firstDynamicType), is(true));
assertThat(implementationContext.getAuxiliaryTypes().contains(secondDynamicType), is(true));
assertThat(implementationContext.register(auxiliaryType), is(firstDescription));
assertThat(implementationContext.getAuxiliaryTypes().size(), is(2));
assertThat(implementationContext.getAuxiliaryTypes().contains(firstDynamicType), is(true));
assertThat(implementationContext.getAuxiliaryTypes().contains(secondDynamicType), is(true));
}
@Test
public void testDrainEmpty() throws Exception {
Implementation.Context.ExtractableView implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verifyZeroInteractions(classVisitor);
verify(drain).apply(classVisitor, typeInitializer, implementationContext);
verifyNoMoreInteractions(drain);
}
@Test
public void testDrainNoUserCodeNoInjectedCodeNoTypeInitializer() throws Exception {
Implementation.Context.ExtractableView implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verifyZeroInteractions(classVisitor);
verifyZeroInteractions(typeInitializer);
verify(drain).apply(classVisitor, typeInitializer, implementationContext);
verifyNoMoreInteractions(drain);
}
@Test
public void testDrainUserCodeNoInjectedCodeNoTypeInitializer() throws Exception {
Implementation.Context.ExtractableView implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verifyZeroInteractions(classVisitor);
verifyZeroInteractions(typeInitializer);
verify(drain).apply(classVisitor, typeInitializer, implementationContext);
verifyNoMoreInteractions(drain);
}
@Test
public void testDrainFieldCacheEntries() throws Exception {
Implementation.Context.ExtractableView implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
FieldDescription firstField = implementationContext.cache(firstFieldValue, firstRawFieldType);
assertThat(implementationContext.cache(firstFieldValue, firstRawFieldType), is(firstField));
FieldDescription secondField = implementationContext.cache(secondFieldValue, secondRawFieldType);
assertThat(implementationContext.cache(secondFieldValue, secondRawFieldType), is(secondField));
assertThat(firstField.getName(), not(secondField.getName()));
when(typeInitializer.expandWith(any(ByteCodeAppender.class))).thenReturn(otherTypeInitializer);
when(otherTypeInitializer.expandWith(any(ByteCodeAppender.class))).thenReturn(thirdTypeInitializer);
when(thirdTypeInitializer.isDefined()).thenReturn(true);
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verify(classVisitor).visitField(eq(cacheFieldModifiers),
Mockito.startsWith(Implementation.Context.Default.FIELD_CACHE_PREFIX),
eq(BAR),
Mockito.<String>isNull(),
Mockito.isNull());
verify(classVisitor).visitField(eq(cacheFieldModifiers),
Mockito.startsWith(Implementation.Context.Default.FIELD_CACHE_PREFIX),
eq(QUX),
Mockito.<String>isNull(),
Mockito.isNull());
verify(typeInitializer).expandWith(any(ByteCodeAppender.class));
verify(otherTypeInitializer).expandWith(any(ByteCodeAppender.class));
}
@Test(expected = IllegalStateException.class)
public void testCannotRegisterFieldAfterDraining() throws Exception {
Implementation.Context.ExtractableView implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verifyZeroInteractions(classVisitor);
verify(drain).apply(classVisitor, typeInitializer, implementationContext);
verifyNoMoreInteractions(drain);
implementationContext.cache(firstFieldValue, firstRawFieldType);
}
@Test
public void testAccessorMethodRegistration() throws Exception {
Implementation.Context.Default implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
MethodDescription.InDefinedShape firstMethodDescription = implementationContext.registerAccessorFor(firstSpecialInvocation, MethodAccessorFactory.AccessType.DEFAULT);
assertThat(firstMethodDescription.getParameters(), is((ParameterList) new ParameterList.Explicit.ForTypes(firstMethodDescription, firstSpecialParameterType)));
assertThat(firstMethodDescription.getReturnType(), is(firstSpecialReturnType));
assertThat(firstMethodDescription.getInternalName(), startsWith(FOO));
assertThat(firstMethodDescription.getModifiers(), is(accessorMethodModifiers));
assertThat(firstMethodDescription.getExceptionTypes(), is(firstSpecialExceptionTypes));
assertThat(implementationContext.registerAccessorFor(firstSpecialInvocation, MethodAccessorFactory.AccessType.DEFAULT), is(firstMethodDescription));
when(secondSpecialMethod.isStatic()).thenReturn(true);
MethodDescription.InDefinedShape secondMethodDescription = implementationContext.registerAccessorFor(secondSpecialInvocation, MethodAccessorFactory.AccessType.DEFAULT);
assertThat(secondMethodDescription.getParameters(), is((ParameterList) new ParameterList.Explicit.ForTypes(secondMethodDescription, secondSpecialParameterType)));
assertThat(secondMethodDescription.getReturnType(), is(secondSpecialReturnType));
assertThat(secondMethodDescription.getInternalName(), startsWith(BAR));
assertThat(secondMethodDescription.getModifiers(), is(accessorMethodModifiers | Opcodes.ACC_STATIC));
assertThat(secondMethodDescription.getExceptionTypes(), is(secondSpecialExceptionTypes));
assertThat(implementationContext.registerAccessorFor(firstSpecialInvocation, MethodAccessorFactory.AccessType.DEFAULT), is(firstMethodDescription));
assertThat(implementationContext.registerAccessorFor(secondSpecialInvocation, MethodAccessorFactory.AccessType.DEFAULT), is(secondMethodDescription));
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verify(classVisitor).visitMethod(eq(accessorMethodModifiers), Mockito.startsWith(FOO),
eq("(" + BAZ + ")" + QUX), Mockito.<String>isNull(), aryEq(new String[]{FOO}));
verify(classVisitor).visitMethod(eq(accessorMethodModifiers | Opcodes.ACC_STATIC), Mockito.startsWith(BAR),
eq("(" + BAR + ")" + FOO), Mockito.<String>isNull(), aryEq(new String[]{BAZ}));
}
@Test
public void testAccessorMethodRegistrationWritesFirst() throws Exception {
Implementation.Context.Default implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
MethodDescription firstMethodDescription = implementationContext.registerAccessorFor(firstSpecialInvocation, MethodAccessorFactory.AccessType.DEFAULT);
assertThat(implementationContext.registerAccessorFor(firstSpecialInvocation, MethodAccessorFactory.AccessType.DEFAULT), is(firstMethodDescription));
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verify(classVisitor).visitMethod(eq(accessorMethodModifiers), Mockito.startsWith(FOO),
eq("(" + BAZ + ")" + QUX), Mockito.<String>isNull(), aryEq(new String[]{FOO}));
verify(methodVisitor).visitCode();
verify(methodVisitor).visitVarInsn(Opcodes.ALOAD, 0);
verify(methodVisitor).visitVarInsn(Opcodes.ALOAD, 1);
verify(firstSpecialInvocation).apply(methodVisitor, implementationContext);
verify(methodVisitor).visitInsn(Opcodes.ARETURN);
verify(methodVisitor).visitMaxs(2, 1);
verify(methodVisitor).visitEnd();
}
@Test
public void testAccessorMethodRegistrationWritesSecond() throws Exception {
when(secondSpecialMethod.isStatic()).thenReturn(true);
Implementation.Context.Default implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
MethodDescription secondMethodDescription = implementationContext.registerAccessorFor(secondSpecialInvocation, MethodAccessorFactory.AccessType.DEFAULT);
assertThat(implementationContext.registerAccessorFor(secondSpecialInvocation, MethodAccessorFactory.AccessType.DEFAULT), is(secondMethodDescription));
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verify(classVisitor).visitMethod(eq(accessorMethodModifiers | Opcodes.ACC_STATIC), Mockito.startsWith(BAR),
eq("(" + BAR + ")" + FOO), Mockito.<String>isNull(), aryEq(new String[]{BAZ}));
verify(methodVisitor).visitCode();
verify(methodVisitor).visitVarInsn(Opcodes.ALOAD, 0);
verify(secondSpecialInvocation).apply(methodVisitor, implementationContext);
verify(methodVisitor).visitInsn(Opcodes.ARETURN);
verify(methodVisitor).visitMaxs(1, 0);
verify(methodVisitor).visitEnd();
}
@Test
public void testFieldGetterRegistration() throws Exception {
Implementation.Context.Default implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
MethodDescription firstFieldGetter = implementationContext.registerGetterFor(firstField, MethodAccessorFactory.AccessType.DEFAULT);
assertThat(firstFieldGetter.getParameters(), is((ParameterList) new ParameterList.Empty<ParameterDescription>()));
assertThat(firstFieldGetter.getReturnType(), is(firstFieldType));
assertThat(firstFieldGetter.getInternalName(), startsWith(FOO));
assertThat(firstFieldGetter.getModifiers(), is(accessorMethodModifiers));
assertThat(firstFieldGetter.getExceptionTypes(), is((TypeList.Generic) new TypeList.Generic.Empty()));
assertThat(implementationContext.registerGetterFor(firstField, MethodAccessorFactory.AccessType.DEFAULT), is(firstFieldGetter));
when(secondField.isStatic()).thenReturn(true);
MethodDescription secondFieldGetter = implementationContext.registerGetterFor(secondField, MethodAccessorFactory.AccessType.DEFAULT);
assertThat(secondFieldGetter.getParameters(), is((ParameterList) new ParameterList.Empty<ParameterDescription>()));
assertThat(secondFieldGetter.getReturnType(), is(secondFieldType));
assertThat(secondFieldGetter.getInternalName(), startsWith(BAR));
assertThat(secondFieldGetter.getModifiers(), is(accessorMethodModifiers | Opcodes.ACC_STATIC));
assertThat(secondFieldGetter.getExceptionTypes(), is((TypeList.Generic) new TypeList.Generic.Empty()));
assertThat(implementationContext.registerGetterFor(firstField, MethodAccessorFactory.AccessType.DEFAULT), is(firstFieldGetter));
assertThat(implementationContext.registerGetterFor(secondField, MethodAccessorFactory.AccessType.DEFAULT), is(secondFieldGetter));
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verify(classVisitor).visitMethod(eq(accessorMethodModifiers), Mockito.startsWith(FOO),
eq("()" + BAR), Mockito.<String>isNull(), Mockito.<String[]>isNull());
verify(classVisitor).visitMethod(eq(accessorMethodModifiers | Opcodes.ACC_STATIC), Mockito.startsWith(BAR),
eq("()" + QUX), Mockito.<String>isNull(), Mockito.<String[]>isNull());
}
@Test
public void testFieldGetterRegistrationWritesFirst() throws Exception {
Implementation.Context.Default implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
MethodDescription firstMethodDescription = implementationContext.registerGetterFor(firstField, MethodAccessorFactory.AccessType.DEFAULT);
assertThat(implementationContext.registerGetterFor(firstField, MethodAccessorFactory.AccessType.DEFAULT), is(firstMethodDescription));
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verify(classVisitor).visitMethod(eq(accessorMethodModifiers), Mockito.startsWith(FOO),
eq("()" + BAR), Mockito.<String>isNull(), Mockito.<String[]>isNull());
verify(methodVisitor).visitCode();
verify(methodVisitor).visitVarInsn(Opcodes.ALOAD, 0);
verify(methodVisitor).visitFieldInsn(Opcodes.GETFIELD, QUX, FOO, BAR);
verify(methodVisitor).visitInsn(Opcodes.ARETURN);
verify(methodVisitor).visitMaxs(1, 1);
verify(methodVisitor).visitEnd();
}
@Test
public void testFieldGetterRegistrationWritesSecond() throws Exception {
when(secondField.isStatic()).thenReturn(true);
Implementation.Context.Default implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
MethodDescription secondMethodDescription = implementationContext.registerGetterFor(secondField, MethodAccessorFactory.AccessType.DEFAULT);
assertThat(implementationContext.registerGetterFor(secondField, MethodAccessorFactory.AccessType.DEFAULT), is(secondMethodDescription));
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verify(classVisitor).visitMethod(eq(accessorMethodModifiers | Opcodes.ACC_STATIC), Mockito.startsWith(BAR),
eq("()" + QUX), Mockito.<String>isNull(), Mockito.<String[]>isNull());
verify(methodVisitor).visitCode();
verify(methodVisitor).visitFieldInsn(Opcodes.GETSTATIC, BAZ, BAR, FOO);
verify(methodVisitor).visitInsn(Opcodes.ARETURN);
verify(methodVisitor).visitMaxs(0, 0);
verify(methodVisitor).visitEnd();
}
@Test
public void testFieldSetterRegistration() throws Exception {
Implementation.Context.Default implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
MethodDescription.InDefinedShape firstFieldSetter = implementationContext.registerSetterFor(firstField, MethodAccessorFactory.AccessType.DEFAULT);
assertThat(firstFieldSetter.getParameters(), is((ParameterList) new ParameterList.Explicit.ForTypes(firstFieldSetter, firstFieldType)));
assertThat(firstFieldSetter.getReturnType(), is(TypeDescription.Generic.VOID));
assertThat(firstFieldSetter.getInternalName(), startsWith(FOO));
assertThat(firstFieldSetter.getModifiers(), is(accessorMethodModifiers));
assertThat(firstFieldSetter.getExceptionTypes(), is((TypeList.Generic) new TypeList.Generic.Empty()));
assertThat(implementationContext.registerSetterFor(firstField, MethodAccessorFactory.AccessType.DEFAULT), is(firstFieldSetter));
when(secondField.isStatic()).thenReturn(true);
MethodDescription.InDefinedShape secondFieldSetter = implementationContext.registerSetterFor(secondField, MethodAccessorFactory.AccessType.DEFAULT);
assertThat(secondFieldSetter.getParameters(), is((ParameterList) new ParameterList.Explicit.ForTypes(secondFieldSetter, secondFieldType)));
assertThat(secondFieldSetter.getReturnType(), is(TypeDescription.Generic.VOID));
assertThat(secondFieldSetter.getInternalName(), startsWith(BAR));
assertThat(secondFieldSetter.getModifiers(), is(accessorMethodModifiers | Opcodes.ACC_STATIC));
assertThat(secondFieldSetter.getExceptionTypes(), is((TypeList.Generic) new TypeList.Generic.Empty()));
assertThat(implementationContext.registerSetterFor(firstField, MethodAccessorFactory.AccessType.DEFAULT), is(firstFieldSetter));
assertThat(implementationContext.registerSetterFor(secondField, MethodAccessorFactory.AccessType.DEFAULT), is(secondFieldSetter));
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verify(classVisitor).visitMethod(eq(accessorMethodModifiers), Mockito.startsWith(FOO),
eq("(" + BAR + ")V"), Mockito.<String>isNull(), Mockito.<String[]>isNull());
verify(classVisitor).visitMethod(eq(accessorMethodModifiers | Opcodes.ACC_STATIC), Mockito.startsWith(BAR),
eq("(" + QUX + ")V"), Mockito.<String>isNull(), Mockito.<String[]>isNull());
}
@Test
public void testFieldSetterRegistrationWritesFirst() throws Exception {
Implementation.Context.Default implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
MethodDescription firstMethodDescription = implementationContext.registerSetterFor(firstField, MethodAccessorFactory.AccessType.DEFAULT);
assertThat(implementationContext.registerSetterFor(firstField, MethodAccessorFactory.AccessType.DEFAULT), is(firstMethodDescription));
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verify(classVisitor).visitMethod(eq(accessorMethodModifiers), Mockito.startsWith(FOO),
eq("(" + BAR + ")V"), Mockito.<String>isNull(), Mockito.<String[]>isNull());
verify(methodVisitor).visitCode();
verify(methodVisitor).visitVarInsn(Opcodes.ALOAD, 0);
verify(methodVisitor).visitVarInsn(Opcodes.ALOAD, 1);
verify(methodVisitor).visitFieldInsn(Opcodes.PUTFIELD, QUX, FOO, BAR);
verify(methodVisitor).visitInsn(Opcodes.RETURN);
verify(methodVisitor).visitMaxs(2, 1);
verify(methodVisitor).visitEnd();
}
@Test
public void testFieldSetterRegistrationWritesSecond() throws Exception {
when(secondField.isStatic()).thenReturn(true);
Implementation.Context.Default implementationContext = new Implementation.Context.Default(instrumentedType,
classFileVersion,
auxiliaryTypeNamingStrategy,
typeInitializer,
auxiliaryClassFileVersion);
MethodDescription secondMethodDescription = implementationContext.registerSetterFor(secondField, MethodAccessorFactory.AccessType.DEFAULT);
assertThat(implementationContext.registerSetterFor(secondField, MethodAccessorFactory.AccessType.DEFAULT), is(secondMethodDescription));
implementationContext.drain(drain, classVisitor, annotationValueFilterFactory);
verify(classVisitor).visitMethod(eq(accessorMethodModifiers | Opcodes.ACC_STATIC), Mockito.startsWith(BAR),
eq("(" + QUX + ")V"), Mockito.<String>isNull(), Mockito.<String[]>isNull());
verify(methodVisitor).visitCode();
verify(methodVisitor).visitVarInsn(Opcodes.ALOAD, 0);
verify(methodVisitor).visitFieldInsn(Opcodes.PUTSTATIC, BAZ, BAR, FOO);
verify(methodVisitor).visitInsn(Opcodes.RETURN);
verify(methodVisitor).visitMaxs(1, 0);
verify(methodVisitor).visitEnd();
}
}