package net.bytebuddy.implementation;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.implementation.bytecode.assign.Assigner;
import net.bytebuddy.test.utility.MockitoRule;
import org.hamcrest.CoreMatchers;
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 java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.when;
@RunWith(Parameterized.class)
public class MethodCallTypeTest {
private static final String FOO = "foo";
private static final String STRING_VALUE = "foo";
private static final Bar ENUM_VALUE = Bar.INSTANCE;
private static final Class<?> CLASS_VALUE = Object.class;
private static final boolean BOOLEAN_VALUE = true;
private static final byte BYTE_VALUE = 42;
private static final short SHORT_VALUE = 42;
private static final char CHAR_VALUE = '@';
private static final int INT_VALUE = 42;
private static final long LONG_VALUE = 42L;
private static final float FLOAT_VALUE = 42f;
private static final double DOUBLE_VALUE = 42d;
private static final Object NULL_CONSTANT = null;
private static final Object REFERENCE_VALUE = new Object();
private final Object value;
private final boolean definesFieldReference;
private final boolean definesFieldConstantPool;
@Rule
public TestRule methodRule = new MockitoRule(this);
@Mock
private Assigner nonAssigner;
public MethodCallTypeTest(Object value, boolean definesFieldReference, boolean definesFieldConstantPool) {
this.value = value;
this.definesFieldReference = definesFieldReference;
this.definesFieldConstantPool = definesFieldConstantPool;
}
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{BOOLEAN_VALUE, true, false},
{BYTE_VALUE, true, false},
{SHORT_VALUE, true, false},
{CHAR_VALUE, true, false},
{INT_VALUE, true, false},
{LONG_VALUE, true, false},
{FLOAT_VALUE, true, false},
{DOUBLE_VALUE, true, false},
{NULL_CONSTANT, false, false},
{STRING_VALUE, true, false},
{CLASS_VALUE, true, false},
{ENUM_VALUE, true, false},
{REFERENCE_VALUE, true, true}
});
}
@Before
public void setUp() throws Exception {
when(nonAssigner.assign(Mockito.any(TypeDescription.Generic.class), Mockito.any(TypeDescription.Generic.class), Mockito.any(Assigner.Typing.class)))
.thenReturn(StackManipulation.Illegal.INSTANCE);
}
@Test
public void testFieldConstantPool() throws Exception {
DynamicType.Loaded<Foo> loaded = new ByteBuddy()
.subclass(Foo.class)
.method(isDeclaredBy(Foo.class))
.intercept(MethodCall.invokeSuper().with(value))
.make()
.load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0));
assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1));
assertThat(loaded.getLoaded().getDeclaredMethod(FOO, Object.class), not(nullValue(Method.class)));
assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1));
assertThat(loaded.getLoaded().getDeclaredFields().length, is(definesFieldConstantPool ? 1 : 0));
Foo instance = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(Foo.class)));
assertThat(instance, instanceOf(Foo.class));
assertThat(instance.foo(new Object()), is(value));
}
@Test
public void testFieldReference() throws Exception {
DynamicType.Loaded<Foo> loaded = new ByteBuddy()
.subclass(Foo.class)
.method(isDeclaredBy(Foo.class))
.intercept(MethodCall.invokeSuper().withReference(value))
.make()
.load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0));
assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1));
assertThat(loaded.getLoaded().getDeclaredMethod(FOO, Object.class), not(nullValue(Method.class)));
assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1));
assertThat(loaded.getLoaded().getDeclaredFields().length, is(definesFieldReference ? 1 : 0));
Foo instance = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(Foo.class)));
assertThat(instance, instanceOf(Foo.class));
assertThat(instance.foo(new Object()), sameInstance(value));
}
@Test(expected = IllegalStateException.class)
public void testNonAssignable() throws Exception {
new ByteBuddy()
.subclass(Foo.class)
.method(isDeclaredBy(Foo.class))
.intercept(MethodCall.invokeSuper().with(value).withAssigner(nonAssigner, Assigner.Typing.STATIC))
.make();
}
public enum Bar {
INSTANCE;
}
public static class Foo {
public Object foo(Object value) {
return value;
}
}
}