package net.bytebuddy.implementation;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.test.utility.CallTraceable;
import org.hamcrest.CoreMatchers;
import org.hamcrest.Matcher;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
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;
@RunWith(Parameterized.class)
public class SuperMethodCallTest {
private static final String OBJECT_METHOD = "reference";
private static final String BOOLEAN_METHOD = "aBoolean";
private static final String BYTE_METHOD = "aByte";
private static final String SHORT_METHOD = "aShort";
private static final String CHAR_METHOD = "aChar";
private static final String INT_METHOD = "aInt";
private static final String LONG_METHOD = "aLong";
private static final String FLOAT_METHOD = "aFloat";
private static final String DOUBLE_METHOD = "aDouble";
private static final String VOID_METHOD = "aVoid";
private static final String PARAMETERS_METHOD = "parameters";
private static final String STRING_VALUE = "foo";
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 final Matcher<?> matcher;
private final String methodName;
private final Class<?>[] methodParameterTypes;
private final Object[] methodArguments;
public SuperMethodCallTest(Matcher<?> matcher,
String methodName,
Class<?>[] methodParameterTypes,
Object[] methodArguments) {
this.matcher = matcher;
this.methodName = methodName;
this.methodParameterTypes = methodParameterTypes;
this.methodArguments = methodArguments;
}
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{is(STRING_VALUE), OBJECT_METHOD, new Class<?>[0], new Object[0]},
{is(BOOLEAN_VALUE), BOOLEAN_METHOD, new Class<?>[0], new Object[0]},
{is(BYTE_VALUE), BYTE_METHOD, new Class<?>[0], new Object[0]},
{is(SHORT_VALUE), SHORT_METHOD, new Class<?>[0], new Object[0]},
{is(CHAR_VALUE), CHAR_METHOD, new Class<?>[0], new Object[0]},
{is(INT_VALUE), INT_METHOD, new Class<?>[0], new Object[0]},
{is(LONG_VALUE), LONG_METHOD, new Class<?>[0], new Object[0]},
{is(FLOAT_VALUE), FLOAT_METHOD, new Class<?>[0], new Object[0]},
{is(DOUBLE_VALUE), DOUBLE_METHOD, new Class<?>[0], new Object[0]},
{nullValue(), VOID_METHOD, new Class<?>[0], new Object[0]},
{nullValue(), PARAMETERS_METHOD,
new Class<?>[]{long.class, float.class, int.class, double.class, Object.class},
new Object[]{LONG_VALUE, FLOAT_VALUE, INT_VALUE, DOUBLE_VALUE, STRING_VALUE}}
});
}
@Test
@SuppressWarnings("unchecked")
public void testInstrumentedMethod() throws Exception {
DynamicType.Loaded<Foo> loaded = new ByteBuddy()
.subclass(Foo.class)
.method(isDeclaredBy(Foo.class))
.intercept(SuperMethodCall.INSTANCE)
.make()
.load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0));
assertThat(loaded.getLoaded().getDeclaredMethods().length, is(11));
Foo instance = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(Foo.class)));
assertThat(instance, instanceOf(Foo.class));
assertThat(loaded.getLoaded().getDeclaredMethod(methodName, methodParameterTypes)
.invoke(instance, methodArguments), (Matcher) matcher);
instance.assertOnlyCall(methodName, methodArguments);
}
@SuppressWarnings("unused")
public static class Foo extends CallTraceable {
public Object reference() {
register(OBJECT_METHOD);
return STRING_VALUE;
}
public boolean aBoolean() {
register(BOOLEAN_METHOD);
return BOOLEAN_VALUE;
}
public byte aByte() {
register(BYTE_METHOD);
return BYTE_VALUE;
}
public short aShort() {
register(SHORT_METHOD);
return SHORT_VALUE;
}
public char aChar() {
register(CHAR_METHOD);
return CHAR_VALUE;
}
public int aInt() {
register(INT_METHOD);
return INT_VALUE;
}
public long aLong() {
register(LONG_METHOD);
return LONG_VALUE;
}
public float aFloat() {
register(FLOAT_METHOD);
return FLOAT_VALUE;
}
public double aDouble() {
register(DOUBLE_METHOD);
return DOUBLE_VALUE;
}
public void aVoid() {
register(VOID_METHOD);
}
public void parameters(long l, float f, int i, double d, Object o) {
register(PARAMETERS_METHOD, l, f, i, d, o);
}
}
}