package com.googlecode.totallylazy.proxy; import com.googlecode.totallylazy.concurrent.NamedExecutors; import com.googlecode.totallylazy.concurrent.NamedThreadFactory; import org.junit.Test; import java.lang.reflect.Method; import java.util.Arrays; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicInteger; import static com.googlecode.totallylazy.Assert.assertThat; import static com.googlecode.totallylazy.Assert.assertTrue; import static com.googlecode.totallylazy.Sequences.sequence; import static com.googlecode.totallylazy.predicates.Predicates.is; import static com.googlecode.totallylazy.predicates.Predicates.nullValue; import static com.googlecode.totallylazy.proxy.Proxy.lazy; import static com.googlecode.totallylazy.proxy.Proxy.proxy; public class ProxyTest { abstract class VarArgs { public abstract int add(int a, int... b); } @Test public void marksVarArgsMethodsCorrectly() throws Exception { VarArgs instance = proxy(VarArgs.class, (proxy, method, args) -> 12); Method method = instance.getClass().getMethod("add", int.class, int[].class); assertThat(method.isVarArgs(), is(true)); } abstract class NonPublic { public abstract int add(int a, int b); } @Test public void canCreateProxyForNonPublicClass() throws Exception { NonPublic instance = proxy(NonPublic.class, (proxy, method, args) -> 12); assertThat(instance.add(1, 2), is(12)); } @Test public void supportsProxyClassForRestrictedPackage() throws Exception { proxy(Exception.class, (proxy, method, args) -> null ); } @Test public void canCreateALazyProxyWithReflectoMagic() throws Exception { User user = lazy(() -> new User("dan", "bod")); assertThat(user.firstName(), is("dan")); } @Test public void canCreateALazyProxy() throws Exception { AtomicInteger called = new AtomicInteger(); User user = lazy(User.class, () -> { called.incrementAndGet(); return new User("dan", "bod"); }); assertThat(called.get(), is(0)); assertThat(user.firstName(), is("dan")); assertThat(called.get(), is(1)); assertThat(user.lastName(), is("bod")); assertThat(called.get(), is(1)); } @Test(expected = UnsupportedOperationException.class) public void canNotCreateProxyForFinalClass() throws Exception { Proxy.proxy(Integer.class, null); } @Test public void canCreateAnAsyncProxy() throws Exception { ExecutorService executors = NamedExecutors.newCachedThreadPool(getClass()); CountDownLatch latch = new CountDownLatch(1); Sync async = Proxy.async(Sync.class, () -> { latch.await(); return () -> "done"; }, executors); Interface proxy = async.get(); // Would normally block latch.countDown(); assertThat(proxy.name(), is("done")); executors.shutdown(); } interface Sync{ Interface get() throws Exception; } interface Interface { String name(); } @Test public void canCreateProxyForInterface() throws Exception { Interface instance = proxy(Interface.class, (proxy, method, args) -> "Hello"); assertThat(instance.name(), is("Hello")); } public static abstract class CorrectMethod { public abstract Method theRightMethod(); } @Test public void passesCorrectMethod() throws Throwable { CorrectMethod instance = proxy(CorrectMethod.class, (proxy, method, args) -> method); assertThat(instance.theRightMethod(), is(CorrectMethod.class.getMethod("theRightMethod"))); } public static abstract class BooleanArguments { public abstract boolean add(boolean a, boolean b); } @Test public void supportsBoolean() throws Throwable { BooleanArguments instance = proxy(BooleanArguments.class, (proxy, method, args) -> true); assertThat(instance.add(false, false), is(true)); } public static abstract class IntegerArguments { public abstract int add(int a, int b); } @Test public void supportsInteger() throws Throwable { IntegerArguments instance = proxy(IntegerArguments.class, (proxy, method, args) -> 12); assertThat(instance.add(1, 2), is(12)); } public static abstract class LongArguments { public abstract long add(long a, long b); } @Test public void supportsLong() throws Throwable { LongArguments instance = proxy(LongArguments.class, (proxy, method, args) -> 12L); assertThat(instance.add(1L, 2L), is(12L)); } public static abstract class FloatArguments { public abstract float add(float a, float b); } @Test public void supportsFloat() throws Throwable { FloatArguments instance = proxy(FloatArguments.class, (proxy, method, args) -> 12F); assertThat(instance.add(1F, 2F), is(12F)); } public static abstract class DoubleArguments { public abstract double add(double a, double b); } @Test public void supportsDouble() throws Throwable { DoubleArguments instance = proxy(DoubleArguments.class, (proxy, method, args) -> 12D); assertThat(instance.add(1D, 2D), is(12D)); } public static abstract class ByteArguments { public abstract byte add(byte a, byte b); } @Test public void supportsByte() throws Throwable { ByteArguments instance = proxy(ByteArguments.class, (proxy, method, args) -> (byte)12); assertThat(instance.add((byte)1, (byte)2), is((byte)12)); } public static abstract class ShortArguments { public abstract short add(short a, short b); } @Test public void supportsShort() throws Throwable { ShortArguments instance = proxy(ShortArguments.class, (proxy, method, args) -> (short)12); assertThat(instance.add((short)1, (short)2), is((short)12)); } public static abstract class CharArguments { public abstract char add(char a, char b); } @Test public void supportsChar() throws Throwable { CharArguments instance = proxy(CharArguments.class, (proxy, method, args) -> (char)12); assertThat(instance.add((char)1, (char)2), is((char)12)); } public static abstract class ByteArrayArguments { public abstract byte[] add(byte[] a, byte[] b); } @Test public void supportsPrimativeArrays() throws Throwable { ByteArrayArguments instance = proxy(ByteArrayArguments.class, (proxy, method, args) -> new byte[]{12}); assertTrue(Arrays.equals(instance.add(new byte[]{1}, new byte[]{2}), new byte[]{12})); } public static abstract class BigByteArguments { public abstract Byte add(Byte a, Byte b); } @Test public void supportsBoxedPrimatives() throws Throwable { BigByteArguments instance = proxy(BigByteArguments.class, (proxy, method, args) -> (byte)12); assertThat(instance.add((byte) 1, (byte) 2), is((byte) 12)); } public static abstract class VoidArguments { public abstract void add(Void a, Void b); public abstract Void add(Void a); } @Test public void supportsVoid() throws Throwable { AtomicInteger count = new AtomicInteger(); VoidArguments instance = proxy(VoidArguments.class, (proxy, method, args) -> { count.incrementAndGet(); return null; }); instance.add(null, null); assertThat(instance.add(null), is(nullValue())); assertThat(count.intValue(), is(2)); } }