package org.powermock.reflect.internal.proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.InvocationHandler;
import org.junit.Before;
import org.junit.Test;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.URLClassLoader;
import static org.assertj.core.api.Assertions.assertThat;
public class ProxyFrameworksTest {
private ProxyFrameworks proxyFrameworks;
@Before
public void setUp() throws Exception {
proxyFrameworks = new ProxyFrameworks();
}
@Test
public void should_throw_illegal_argument_exception_if_class_is_null() throws Exception {
assertThat(proxyFrameworks.getUnproxiedType(null)).isNull();
}
@Test
public void should_return_null_if_object_is_null() throws Exception {
assertThat(proxyFrameworks.getUnproxiedType((Object) null)).isNull();
}
@Test
public void should_return_original_class_if_object_not_proxy() throws Exception {
SomeClass someClass = new SomeClass();
UnproxiedType unproxiedType = proxyFrameworks.getUnproxiedType(someClass);
assertThatOriginalTypeInstanceOf(unproxiedType, SomeClass.class);
}
@Test
public void should_return_original_class_if_proxy_created_with_java() {
SomeInterface someInterface = createJavaProxy(new Class[]{ SomeInterface.class });
UnproxiedType unproxiedType = proxyFrameworks.getUnproxiedType(someInterface);
assertThatOriginalTypeInstanceOf(unproxiedType, SomeInterface.class);
}
@Test
public void should_return_original_class_if_proxy_created_with_cglib() {
SomeClass someClass = (SomeClass) createCglibProxy(SomeClass.class);
UnproxiedType unproxiedType = proxyFrameworks.getUnproxiedType(someClass);
assertThatOriginalTypeInstanceOf(unproxiedType, SomeClass.class);
}
@Test
public void should_not_detect_synthetic_classes_as_cglib_proxy() throws Exception {
String className = "Some$$SyntheticClass$$Lambda";
byte[] bytes = ClassFactory.create(className);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
CustomClassLoader customClassLoader = new CustomClassLoader(classLoader);
Class<?> defineClass = customClassLoader.defineClass(className, bytes);
UnproxiedType unproxiedType = proxyFrameworks.getUnproxiedType(defineClass.newInstance());
assertThatOriginalTypeInstanceOf(unproxiedType, defineClass);
}
@Test
public void should_return_object_as_original_class_if_no_non_no_mocking_interfaces() {
Factory someClass = (Factory) createCglibProxy(Factory.class);
UnproxiedType unproxiedType = proxyFrameworks.getUnproxiedType(someClass);
assertThatOriginalTypeInstanceOf(unproxiedType, Object.class);
}
@Test
public void should_return_interface_as_original_type_if_only_one_non_mocking_interface() {
Factory someClass = (Factory) createCglibProxy(Factory.class, SomeInterface.class);
UnproxiedType unproxiedType = proxyFrameworks.getUnproxiedType(someClass);
assertThatOriginalTypeInstanceOf(unproxiedType, SomeInterface.class);
}
@Test
public void should_return_interface_and_original_type_if_proxy_has_interface_and_superclass() {
SomeClass someClass = (SomeClass) createCglibProxy(SomeClass.class, SomeInterface.class, AnotherInterface.class);
UnproxiedType unproxiedType = proxyFrameworks.getUnproxiedType(someClass);
assertThatOriginalTypeInstanceOfAndInterfaces(unproxiedType, SomeClass.class, new Class[]{
SomeInterface.class,
AnotherInterface.class
});
}
@Test
public void should_return_interfaces_if_proxy_create_from_several_interfaces() {
Class[] interfaces = {SomeInterface.class, AnotherInterface.class};
SomeInterface someInterface = createJavaProxy(interfaces);
UnproxiedType unproxiedType = proxyFrameworks.getUnproxiedType(someInterface);
assertThatOriginalIsNullAndInterfaces(
unproxiedType, interfaces
);
}
private Object createCglibProxy(Class<?> superclass, Class... interfaces) {
if (interfaces.length == 0){
return Enhancer.create(
superclass,
new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(o, objects);
}
});
}else {
return Enhancer.create(
superclass,
interfaces,
new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(o, objects);
}
});
}
}
private SomeInterface createJavaProxy(Class[] interfaces) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return (SomeInterface) Proxy.newProxyInstance(
classLoader,
interfaces,
new java.lang.reflect.InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(proxy, args);
}
});
}
private void assertThatOriginalIsNullAndInterfaces(UnproxiedType unproxiedType, Class[] expectedInterfaces) {
assertThat(unproxiedType.getOriginalType()).isNull();
assertThat(unproxiedType.getInterfaces())
.containsExactlyInAnyOrder(expectedInterfaces);
}
private void assertThatOriginalTypeInstanceOf(UnproxiedType unproxiedType, Class<?> expectedClass) {
assertThat(unproxiedType.getOriginalType()).isEqualTo(expectedClass);
assertThat(unproxiedType.getInterfaces()).isEmpty();
}
private void assertThatOriginalTypeInstanceOfAndInterfaces(UnproxiedType unproxiedType, Class<?> expectedClass,Class[] expectedInterfaces ) {
assertThat(unproxiedType.getOriginalType()).isEqualTo(expectedClass);
assertThat(unproxiedType.getInterfaces())
.containsExactlyInAnyOrder(expectedInterfaces);
}
private static class CustomClassLoader extends URLClassLoader {
private CustomClassLoader(ClassLoader parent) {
super(((URLClassLoader) parent).getURLs(), parent);
}
Class<?> defineClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}
}