1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/* 2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2011 The Android Open Source Project 3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License. 6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at 7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software 11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and 14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License. 15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 171977585657cb304a9e1ffa8a2320fa8053a7383cJesse Wilsonpackage com.google.dexmaker.stock; 18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 19ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilsonimport com.google.dexmaker.DexMakerTest; 20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.File; 21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.IOException; 22fec7276299b950a8831ead9a9756d27e0fc60560Andrew Yousefimport java.lang.reflect.Field; 23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.InvocationHandler; 24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.Method; 25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.UndeclaredThrowableException; 261af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilsonimport java.util.Arrays; 27fec7276299b950a8831ead9a9756d27e0fc60560Andrew Yousefimport java.util.Map; 28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Random; 291af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilsonimport java.util.concurrent.Callable; 301af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilsonimport java.util.concurrent.atomic.AtomicInteger; 311977585657cb304a9e1ffa8a2320fa8053a7383cJesse Wilsonimport junit.framework.AssertionFailedError; 321977585657cb304a9e1ffa8a2320fa8053a7383cJesse Wilsonimport junit.framework.TestCase; 33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic class ProxyBuilderTest extends TestCase { 35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private FakeInvocationHandler fakeHandler = new FakeInvocationHandler(); 36054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef private File versionedDxDir = new File(DexMakerTest.getDataDirectory(), "v1"); 37054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 38054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public void setUp() throws Exception { 39054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef super.setUp(); 40054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef versionedDxDir.mkdirs(); 41054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef clearVersionedDxDir(); 42054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef getGeneratedProxyClasses().clear(); 43054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 44054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 45054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public void tearDown() throws Exception { 46054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef getGeneratedProxyClasses().clear(); 47054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef clearVersionedDxDir(); 48054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef super.tearDown(); 49054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 50054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 51054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef private void clearVersionedDxDir() { 52054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef for (File f : versionedDxDir.listFiles()) { 53054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef f.delete(); 54054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 55054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class SimpleClass { 58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public String simpleMethod() { 59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new AssertionFailedError(); 60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testExampleOperation() throws Throwable { 64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult("expected"); 65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson SimpleClass proxy = proxyFor(SimpleClass.class).build(); 66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("expected", proxy.simpleMethod()); 67054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals(2, versionedDxDir.listFiles().length); 68054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 69054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 70054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public void testExampleOperation_DexMakerCaching() throws Throwable { 71054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef fakeHandler.setFakeResult("expected"); 72054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef SimpleClass proxy = proxyFor(SimpleClass.class).build(); 73054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals(2, versionedDxDir.listFiles().length); 74054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals("expected", proxy.simpleMethod()); 75054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 76054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef // Force ProxyBuilder to create a DexMaker generator and call DexMaker.generateAndLoad(). 77054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef getGeneratedProxyClasses().clear(); 78054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 79054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef proxy = proxyFor(SimpleClass.class).build(); 80054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals(2, versionedDxDir.listFiles().length); 81054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals("expected", proxy.simpleMethod()); 82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class ConstructorTakesArguments { 85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private final String argument; 86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public ConstructorTakesArguments(String arg) { 88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson argument = arg; 89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public String method() { 92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new AssertionFailedError(); 93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testConstruction_SucceedsIfCorrectArgumentsProvided() throws Throwable { 97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson ConstructorTakesArguments proxy = proxyFor(ConstructorTakesArguments.class) 98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .constructorArgTypes(String.class) 99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .constructorArgValues("hello") 100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .build(); 101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("hello", proxy.argument); 102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxy.method(); 103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testConstruction_FailsWithWrongNumberOfArguments() throws Throwable { 106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(ConstructorTakesArguments.class).build(); 108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (IllegalArgumentException expected) {} 110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testClassIsNotAccessbile_FailsWithUnsupportedOperationException() throws Exception { 113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson class MethodVisibilityClass { 114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(MethodVisibilityClass.class).build(); 117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (UnsupportedOperationException expected) {} 119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private static class PrivateVisibilityClass { 122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testPrivateClass_FailsWithUnsupportedOperationException() throws Exception { 125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(PrivateVisibilityClass.class).build(); 127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (UnsupportedOperationException expected) {} 129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson protected static class ProtectedVisibilityClass { 132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public String foo() { 133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new AssertionFailedError(); 134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testProtectedVisibility_WorksFine() throws Exception { 138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("fake result", proxyFor(ProtectedVisibilityClass.class).build().foo()); 139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class HasFinalMethod { 142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public String nonFinalMethod() { 143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return "non-final method"; 144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public final String finalMethod() { 147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return "final method"; 148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testCanProxyClassesWithFinalMethods_WillNotCallTheFinalMethod() throws Throwable { 152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson HasFinalMethod proxy = proxyFor(HasFinalMethod.class).build(); 153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("final method", proxy.finalMethod()); 154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("fake result", proxy.nonFinalMethod()); 155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class HasPrivateMethod { 158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private String result() { 159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return "expected"; 160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testProxyingPrivateMethods_NotIntercepted() throws Throwable { 164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("expected", proxyFor(HasPrivateMethod.class).build().result()); 165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class HasPackagePrivateMethod { 168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson String result() { 169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new AssertionFailedError(); 170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testProxyingPackagePrivateMethods_AreIntercepted() throws Throwable { 174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("fake result", proxyFor(HasPackagePrivateMethod.class).build().result()); 175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class HasProtectedMethod { 178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson protected String result() { 179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new AssertionFailedError(); 180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testProxyingProtectedMethods_AreIntercepted() throws Throwable { 184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("fake result", proxyFor(HasProtectedMethod.class).build().result()); 185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class HasVoidMethod { 188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void dangerousMethod() { 189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testVoidMethod_ShouldNotThrowRuntimeException() throws Throwable { 194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(HasVoidMethod.class).build().dangerousMethod(); 195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testObjectMethodsAreAlsoProxied() throws Throwable { 198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson Object proxy = proxyFor(Object.class).build(); 199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult("mystring"); 200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("mystring", proxy.toString()); 201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult(-1); 202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(-1, proxy.hashCode()); 203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult(false); 204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(false, proxy.equals(proxy)); 205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 2071af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public static class AllReturnTypes { 208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public boolean getBoolean() { return true; } 209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public int getInt() { return 1; } 210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public byte getByte() { return 2; } 211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public long getLong() { return 3L; } 212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public short getShort() { return 4; } 213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public float getFloat() { return 5f; } 214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public double getDouble() { return 6.0; } 215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public char getChar() { return 'c'; } 2161af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public int[] getIntArray() { return new int[] { 8, 9 }; } 2171af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public String[] getStringArray() { return new String[] { "d", "e" }; } 218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 2201af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public void testAllReturnTypes() throws Throwable { 2211af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson AllReturnTypes proxy = proxyFor(AllReturnTypes.class).build(); 222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult(false); 223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(false, proxy.getBoolean()); 224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult(8); 225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(8, proxy.getInt()); 226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult((byte) 9); 227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(9, proxy.getByte()); 228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult(10L); 229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(10, proxy.getLong()); 230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult((short) 11); 231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(11, proxy.getShort()); 232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult(12f); 233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(12f, proxy.getFloat()); 234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult(13.0); 235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(13.0, proxy.getDouble()); 236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult('z'); 237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals('z', proxy.getChar()); 2381af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson fakeHandler.setFakeResult(new int[] { -1, -2 }); 2391af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals("[-1, -2]", Arrays.toString(proxy.getIntArray())); 2401af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson fakeHandler.setFakeResult(new String[] { "x", "y" }); 2411af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals("[x, y]", Arrays.toString(proxy.getStringArray())); 242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 2441af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public static class PassThroughAllTypes { 245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public boolean getBoolean(boolean input) { return input; } 246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public int getInt(int input) { return input; } 247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public byte getByte(byte input) { return input; } 248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public long getLong(long input) { return input; } 249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public short getShort(short input) { return input; } 250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public float getFloat(float input) { return input; } 251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public double getDouble(double input) { return input; } 252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public char getChar(char input) { return input; } 253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public String getString(String input) { return input; } 254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public Object getObject(Object input) { return input; } 255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void getNothing() {} 256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class InvokeSuperHandler implements InvocationHandler { 259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return ProxyBuilder.callSuper(proxy, method, args); 261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 2641af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public void testPassThroughWorksForAllTypes() throws Exception { 2651af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson PassThroughAllTypes proxy = proxyFor(PassThroughAllTypes.class) 266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .handler(new InvokeSuperHandler()) 267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .build(); 268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(false, proxy.getBoolean(false)); 269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(true, proxy.getBoolean(true)); 270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(0, proxy.getInt(0)); 271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(1, proxy.getInt(1)); 272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals((byte) 2, proxy.getByte((byte) 2)); 273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals((byte) 3, proxy.getByte((byte) 3)); 274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(4L, proxy.getLong(4L)); 275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(5L, proxy.getLong(5L)); 276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals((short) 6, proxy.getShort((short) 6)); 277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals((short) 7, proxy.getShort((short) 7)); 278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(8f, proxy.getFloat(8f)); 279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(9f, proxy.getFloat(9f)); 280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(10.0, proxy.getDouble(10.0)); 281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(11.0, proxy.getDouble(11.0)); 282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals('a', proxy.getChar('a')); 283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals('b', proxy.getChar('b')); 284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("asdf", proxy.getString("asdf")); 285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("qwer", proxy.getString("qwer")); 286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(null, proxy.getString(null)); 287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson Object a = new Object(); 288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(a, proxy.getObject(a)); 289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(null, proxy.getObject(null)); 290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxy.getNothing(); 291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 2931af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public static class ExtendsAllReturnTypes extends AllReturnTypes { 294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public int example() { return 0; } 295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testProxyWorksForSuperclassMethodsAlso() throws Throwable { 2981af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson ExtendsAllReturnTypes proxy = proxyFor(ExtendsAllReturnTypes.class).build(); 299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult(99); 300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(99, proxy.example()); 301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(99, proxy.getInt()); 302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(99, proxy.hashCode()); 303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class HasOddParams { 306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public long method(int first, Integer second) { 307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new AssertionFailedError(); 308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testMixingBoxedAndUnboxedParams() throws Throwable { 312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson HasOddParams proxy = proxyFor(HasOddParams.class).build(); 313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult(99L); 314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(99L, proxy.method(1, Integer.valueOf(2))); 315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 317579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class SingleInt { 318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public String getString(int value) { 319579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new AssertionFailedError(); 320579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 322579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 323579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testSinglePrimitiveParameter() throws Throwable { 324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson InvocationHandler handler = new InvocationHandler() { 325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 326579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return "asdf" + ((Integer) args[0]).intValue(); 327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson }; 329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("asdf1", proxyFor(SingleInt.class).handler(handler).build().getString(1)); 330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class TwoConstructors { 333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private final String string; 334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public TwoConstructors() { 336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson string = "no-arg"; 337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public TwoConstructors(boolean unused) { 340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson string = "one-arg"; 341579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 342579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 343579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 344579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testNoConstructorArguments_CallsNoArgConstructor() throws Throwable { 345579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson TwoConstructors twoConstructors = proxyFor(TwoConstructors.class).build(); 346579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("no-arg", twoConstructors.string); 347579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 348579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testWithoutInvocationHandler_ThrowsIllegalArgumentException() throws Throwable { 350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson ProxyBuilder.forClass(TwoConstructors.class) 352ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson .dexCache(DexMakerTest.getDataDirectory()) 353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .build(); 354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (IllegalArgumentException expected) {} 356579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 357579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 358579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class HardToConstructCorrectly { 359579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public HardToConstructCorrectly() { fail(); } 360579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public HardToConstructCorrectly(Runnable ignored) { fail(); } 361579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public HardToConstructCorrectly(Exception ignored) { fail(); } 362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public HardToConstructCorrectly(Boolean ignored) { /* safe */ } 363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public HardToConstructCorrectly(Integer ignored) { fail(); } 364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 365579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testHardToConstruct_WorksIfYouSpecifyTheConstructorCorrectly() throws Throwable { 367579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(HardToConstructCorrectly.class) 368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .constructorArgTypes(Boolean.class) 369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .constructorArgValues(true) 370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .build(); 371579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 373579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testHardToConstruct_EvenWorksWhenArgsAreAmbiguous() throws Throwable { 374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(HardToConstructCorrectly.class) 375579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .constructorArgTypes(Boolean.class) 376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .constructorArgValues(new Object[] { null }) 377579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .build(); 378579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 379579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 380579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testHardToConstruct_DoesNotInferTypesFromValues() throws Throwable { 381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(HardToConstructCorrectly.class) 383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .constructorArgValues(true) 384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .build(); 385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (IllegalArgumentException expected) {} 387579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testDefaultProxyHasSuperMethodToAccessOriginal() throws Exception { 390579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson Object objectProxy = proxyFor(Object.class).build(); 3911af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertNotNull(objectProxy.getClass().getMethod("super$hashCode$int")); 392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class PrintsOddAndValue { 395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public String method(int value) { 396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return "odd " + value; 397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testSometimesDelegateToSuper() throws Exception { 401579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson InvocationHandler delegatesOddValues = new InvocationHandler() { 402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 403579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (method.getName().equals("method")) { 404579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int intValue = ((Integer) args[0]).intValue(); 405579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (intValue % 2 == 0) { 406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return "even " + intValue; 407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return ProxyBuilder.callSuper(proxy, method, args); 410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson }; 412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson PrintsOddAndValue proxy = proxyFor(PrintsOddAndValue.class) 413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .handler(delegatesOddValues) 414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .build(); 415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("even 0", proxy.method(0)); 416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("odd 1", proxy.method(1)); 417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("even 2", proxy.method(2)); 418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("odd 3", proxy.method(3)); 419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 4201af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 4211af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public void testCallSuperThrows() throws Exception { 4221af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson InvocationHandler handler = new InvocationHandler() { 4231af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public Object invoke(Object o, Method method, Object[] objects) throws Throwable { 4241af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson return ProxyBuilder.callSuper(o, method, objects); 4251af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 4261af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson }; 4271af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 4281af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson FooThrows fooThrows = proxyFor(FooThrows.class) 4291af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .handler(handler) 4301af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .build(); 4311af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 4321af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson try { 4331af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson fooThrows.foo(); 4341af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson fail(); 4351af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } catch (IllegalStateException expected) { 4361af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals("boom!", expected.getMessage()); 4371af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 4381af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 4391af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 4401af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public static class FooThrows { 4411af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public void foo() { 4421af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson throw new IllegalStateException("boom!"); 4431af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 4441af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 445579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 446579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class DoubleReturn { 447579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public double getValue() { 448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return 2.0; 449579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 451579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 452579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testUnboxedResult() throws Exception { 453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.fakeResult = 2.0; 454579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals(2.0, proxyFor(DoubleReturn.class).build().getValue()); 455579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 456579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 457579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static void staticMethod() { 458579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 459579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 460579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testDoesNotOverrideStaticMethods() throws Exception { 461579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson // Method should exist on this test class itself. 462579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson ProxyBuilderTest.class.getDeclaredMethod("staticMethod"); 463579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson // Method should not exist on the subclass. 464579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 465579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(ProxyBuilderTest.class).build().getClass().getDeclaredMethod("staticMethod"); 466579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 467579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (NoSuchMethodException expected) {} 468579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 469579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 470579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testIllegalCacheDirectory() throws Exception { 471579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 4722e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson proxyFor(ProxyForIllegalCacheDirectory.class) 4732e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson .dexCache(new File("/poop/")) 4742e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson .build(); 475579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 4761977585657cb304a9e1ffa8a2320fa8053a7383cJesse Wilson } catch (IOException expected) { 4771977585657cb304a9e1ffa8a2320fa8053a7383cJesse Wilson } 478579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 479579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 4802e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson public static class ProxyForIllegalCacheDirectory { 4812e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson } 4822e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson 483579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testInvalidConstructorSpecification() throws Exception { 484579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 485579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(Object.class) 486579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .constructorArgTypes(String.class, Boolean.class) 487579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .constructorArgValues("asdf", true) 488579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .build(); 489579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 490579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (IllegalArgumentException expected) {} 491579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 492579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 493579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static abstract class AbstractClass { 494579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public abstract Object getValue(); 495579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 496579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 497579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testAbstractClassBehaviour() throws Exception { 498579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("fake result", proxyFor(AbstractClass.class).build().getValue()); 499579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 500579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 501579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class CtorHasDeclaredException { 502579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public CtorHasDeclaredException() throws IOException { 503579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new IOException(); 504579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 505579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 506579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 507579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class CtorHasRuntimeException { 508579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public CtorHasRuntimeException() { 509579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new RuntimeException("my message"); 510579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 511579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 512579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 513579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class CtorHasError { 514579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public CtorHasError() { 515579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new Error("my message again"); 516579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 517579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 518579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 519579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testParentConstructorThrowsDeclaredException() throws Exception { 520579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 521579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(CtorHasDeclaredException.class).build(); 522579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 523579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (UndeclaredThrowableException expected) { 524579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertTrue(expected.getCause() instanceof IOException); 525579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 526579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 527579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(CtorHasRuntimeException.class).build(); 528579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 529579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (RuntimeException expected) { 530579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("my message", expected.getMessage()); 531579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 532579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 533579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(CtorHasError.class).build(); 534579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 535579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (Error expected) { 536579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertEquals("my message again", expected.getMessage()); 537579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 538579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 539579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 540579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testGetInvocationHandler_NormalOperation() throws Exception { 541579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson Object proxy = proxyFor(Object.class).build(); 542579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertSame(fakeHandler, ProxyBuilder.getInvocationHandler(proxy)); 543579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 544579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 545579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testGetInvocationHandler_NotAProxy() { 546579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 547579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson ProxyBuilder.getInvocationHandler(new Object()); 548579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 549579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (IllegalArgumentException expected) {} 550579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 551579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 552579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class ReturnsObject { 553579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public Object getValue() { 554579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return new Object(); 555579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 556579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 557579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 558579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static class ReturnsString extends ReturnsObject { 559579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson @Override 560579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public String getValue() { 561579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return "a string"; 562579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 563579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 564579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 565579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testCovariantReturnTypes_NormalBehaviour() throws Exception { 566579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson String expected = "some string"; 567579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult(expected); 568579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertSame(expected, proxyFor(ReturnsObject.class).build().getValue()); 569579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson assertSame(expected, proxyFor(ReturnsString.class).build().getValue()); 570579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 571579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 572579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testCovariantReturnTypes_WrongReturnType() throws Exception { 573579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 574579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeHandler.setFakeResult(new Object()); 575579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(ReturnsString.class).build().getValue(); 576579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fail(); 577579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (ClassCastException expected) {} 578579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 579579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 5802e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson public void testCaching() throws Exception { 58131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson SimpleClass a = proxyFor(SimpleClass.class).build(); 58231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson SimpleClass b = proxyFor(SimpleClass.class).build(); 58331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson assertSame(a.getClass(), b.getClass()); 5842e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson } 5852e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson 5862e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson public void testCachingWithMultipleConstructors() throws Exception { 58731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson HasMultipleConstructors a = ProxyBuilder.forClass(HasMultipleConstructors.class) 58831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .constructorArgTypes() 58931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .constructorArgValues() 59031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .handler(fakeHandler) 59131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .dexCache(DexMakerTest.getDataDirectory()).build(); 59231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson assertEquals("no args", a.calledConstructor); 59331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson HasMultipleConstructors b = ProxyBuilder.forClass(HasMultipleConstructors.class) 59431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .constructorArgTypes(int.class) 59531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .constructorArgValues(2) 59631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .handler(fakeHandler) 59731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .dexCache(DexMakerTest.getDataDirectory()).build(); 59831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson assertEquals("int 2", b.calledConstructor); 59931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson assertEquals(a.getClass(), b.getClass()); 60031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson 60131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson HasMultipleConstructors c = ProxyBuilder.forClass(HasMultipleConstructors.class) 60231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .constructorArgTypes(Integer.class) 60331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .constructorArgValues(3) 60431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .handler(fakeHandler) 60531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .dexCache(DexMakerTest.getDataDirectory()).build(); 60631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson assertEquals("Integer 3", c.calledConstructor); 60731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson assertEquals(a.getClass(), c.getClass()); 6082e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson } 6092e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson 61031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson public static class HasMultipleConstructors { 61131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson private final String calledConstructor; 61231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson public HasMultipleConstructors() { 61331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson calledConstructor = "no args"; 61431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson } 61531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson public HasMultipleConstructors(int b) { 61631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson calledConstructor = "int " + b; 61731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson } 61831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson public HasMultipleConstructors(Integer c) { 61931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson calledConstructor = "Integer " + c; 62031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson } 62131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson } 62231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson 62331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson public void testClassNotCachedWithDifferentParentClassLoaders() throws Exception { 624b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson ClassLoader classLoaderA = newPathClassLoader(); 62531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson SimpleClass a = proxyFor(SimpleClass.class) 62631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .parentClassLoader(classLoaderA) 62731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .build(); 62831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson assertEquals(classLoaderA, a.getClass().getClassLoader().getParent()); 62931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson 630b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson ClassLoader classLoaderB = newPathClassLoader(); 63131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson SimpleClass b = proxyFor(SimpleClass.class) 63231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .parentClassLoader(classLoaderB) 63331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson .build(); 63431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson assertEquals(classLoaderB, b.getClass().getClassLoader().getParent()); 63531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson 63631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson assertTrue(a.getClass() != b.getClass()); 637579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 6381af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 6391af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public void testAbstractClassWithUndeclaredInterfaceMethod() throws Throwable { 6401af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson DeclaresInterface declaresInterface = proxyFor(DeclaresInterface.class) 6411af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .build(); 6421af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals("fake result", declaresInterface.call()); 6431af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson try { 6441af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson ProxyBuilder.callSuper(declaresInterface, Callable.class.getMethod("call")); 6451af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson fail(); 6461af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } catch (AbstractMethodError expected) { 6471af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 6481af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 6491af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 6501af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public static abstract class DeclaresInterface implements Callable<String> { 6511af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 6521af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 6531af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public void testImplementingInterfaces() throws Throwable { 6541af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson SimpleClass simpleClass = proxyFor(SimpleClass.class) 6551af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .implementing(Callable.class) 6561af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .implementing(Comparable.class) 6571af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .build(); 6581af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals("fake result", simpleClass.simpleMethod()); 6591af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 6601af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson Callable<?> asCallable = (Callable<?>) simpleClass; 6611af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals("fake result", asCallable.call()); 6621af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 6631af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson Comparable<?> asComparable = (Comparable<?>) simpleClass; 6641af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson fakeHandler.fakeResult = 3; 6651af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals(3, asComparable.compareTo(null)); 6661af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 6671af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 6681af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public void testCallSuperWithInterfaceMethod() throws Throwable { 6691af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson SimpleClass simpleClass = proxyFor(SimpleClass.class) 6701af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .implementing(Callable.class) 6711af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .build(); 6721af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson try { 6731af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson ProxyBuilder.callSuper(simpleClass, Callable.class.getMethod("call")); 6741af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson fail(); 6751af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } catch (AbstractMethodError expected) { 6761af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } catch (NoSuchMethodError expected) { 6771af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 6781af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 679579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 6801af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public void testImplementInterfaceCallingThroughConcreteClass() throws Throwable { 6811af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson InvocationHandler invocationHandler = new InvocationHandler() { 6821af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public Object invoke(Object o, Method method, Object[] objects) throws Throwable { 6831af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals("a", ProxyBuilder.callSuper(o, method, objects)); 6841af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson return "b"; 6851af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 6861af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson }; 6871af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson ImplementsCallable proxy = proxyFor(ImplementsCallable.class) 6881af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .implementing(Callable.class) 6891af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .handler(invocationHandler) 6901af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .build(); 6911af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals("b", proxy.call()); 6921af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals("a", ProxyBuilder.callSuper( 6931af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson proxy, ImplementsCallable.class.getMethod("call"))); 6941af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 6951af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 6961af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson /** 6971af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson * This test is a bit unintuitive because it exercises the synthetic methods 6981af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson * that support covariant return types. Calling 'Object call()' on the 6991af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson * interface bridges to 'String call()', and so the super method appears to 7001af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson * also be proxied. 7011af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson */ 7021af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public void testImplementInterfaceCallingThroughInterface() throws Throwable { 7031af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson final AtomicInteger count = new AtomicInteger(); 7041af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7051af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson InvocationHandler invocationHandler = new InvocationHandler() { 7061af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public Object invoke(Object o, Method method, Object[] objects) throws Throwable { 7071af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson count.incrementAndGet(); 7081af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson return ProxyBuilder.callSuper(o, method, objects); 7091af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 7101af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson }; 7111af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7121af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson Callable<?> proxy = proxyFor(ImplementsCallable.class) 7131af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .implementing(Callable.class) 7141af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .handler(invocationHandler) 7151af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .build(); 7161af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7171af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson // the invocation handler is called twice! 7181af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals("a", proxy.call()); 7191af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals(2, count.get()); 7201af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7211af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson // the invocation handler is called, even though this is a callSuper() call! 7221af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals("a", ProxyBuilder.callSuper(proxy, Callable.class.getMethod("call"))); 7231af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals(3, count.get()); 7241af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 7251af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7261af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public static class ImplementsCallable implements Callable<String> { 7271af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public String call() throws Exception { 7281af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson return "a"; 7291af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 7301af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 7311af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7321af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson /** 7331af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson * This test shows that our generated proxies follow the bytecode convention 7341af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson * where methods can have the same name but unrelated return types. This is 7351af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson * different from javac's convention where return types must be assignable 7361af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson * in one direction or the other. 7371af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson */ 7381af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public void testInterfacesSameNamesDifferentReturnTypes() throws Throwable { 7391af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson InvocationHandler handler = new InvocationHandler() { 7401af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public Object invoke(Object o, Method method, Object[] objects) throws Throwable { 7411af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson if (method.getReturnType() == void.class) { 7421af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson return null; 7431af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } else if (method.getReturnType() == String.class) { 7441af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson return "X"; 7451af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } else if (method.getReturnType() == int.class) { 7461af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson return 3; 7471af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } else { 7481af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson throw new AssertionFailedError(); 7491af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 7501af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 7511af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson }; 7521af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7531af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson Object o = proxyFor(Object.class) 7541af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .implementing(FooReturnsVoid.class, FooReturnsString.class, FooReturnsInt.class) 7551af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .handler(handler) 7561af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .build(); 7571af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7581af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson FooReturnsVoid a = (FooReturnsVoid) o; 7591af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson a.foo(); 7601af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7611af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson FooReturnsString b = (FooReturnsString) o; 7621af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals("X", b.foo()); 7631af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7641af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson FooReturnsInt c = (FooReturnsInt) o; 7651af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals(3, c.foo()); 7661af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 7671af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7681af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public void testInterfacesSameNamesSameReturnType() throws Throwable { 7691af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson Object o = proxyFor(Object.class) 7701af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .implementing(FooReturnsInt.class, FooReturnsInt2.class) 7711af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson .build(); 7721af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7731af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson fakeHandler.setFakeResult(3); 7741af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7751af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson FooReturnsInt a = (FooReturnsInt) o; 7761af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals(3, a.foo()); 7771af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7781af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson FooReturnsInt2 b = (FooReturnsInt2) o; 7791af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson assertEquals(3, b.foo()); 7801af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 7811af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7821af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public interface FooReturnsVoid { 7831af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson void foo(); 7841af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 7851af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7861af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public interface FooReturnsString { 7871af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson String foo(); 7881af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 7891af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7901af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public interface FooReturnsInt { 7911af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson int foo(); 7921af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 7931af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 7941af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson public interface FooReturnsInt2 { 7951af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson int foo(); 7961af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson } 7971af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson 798b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson private ClassLoader newPathClassLoader() throws Exception { 799b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson return (ClassLoader) Class.forName("dalvik.system.PathClassLoader") 800b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson .getConstructor(String.class, ClassLoader.class) 801b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson .newInstance("", getClass().getClassLoader()); 802b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson 803b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson } 804b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson 805579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void testSubclassOfRandom() throws Exception { 806579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson proxyFor(Random.class) 807579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .handler(new InvokeSuperHandler()) 808579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .build(); 809579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 810579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 81195689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy public static class FinalToString { 81295689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy @Override public final String toString() { 81395689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy return "no proxy"; 81495689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy } 81595689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy } 81695689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy 81795689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy // https://code.google.com/p/dexmaker/issues/detail?id=12 81895689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy public void testFinalToString() throws Throwable { 81995689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy assertEquals("no proxy", proxyFor(FinalToString.class).build().toString()); 82095689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy } 82195689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy 822579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** Simple helper to add the most common args for this test to the proxy builder. */ 823579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private <T> ProxyBuilder<T> proxyFor(Class<T> clazz) throws Exception { 824579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return ProxyBuilder.forClass(clazz) 825579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson .handler(fakeHandler) 826ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson .dexCache(DexMakerTest.getDataDirectory()); 827579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 828579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 829579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private static class FakeInvocationHandler implements InvocationHandler { 830579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private Object fakeResult = "fake result"; 831579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 832579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 833579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return fakeResult; 834579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 835579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 836579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void setFakeResult(Object result) { 837579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson fakeResult = result; 838579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 839579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 840054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 841054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public static class TestOrderingClass { 842054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public int returnsInt() { 843054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef return 0; 844054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 845054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 846054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public int returnsInt(int param1, int param2) { 847054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef return 1; 848054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 849054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 850054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public String returnsString() { 851054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef return "string"; 852054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 853054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 854054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public boolean returnsBoolean() { 855054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef return false; 856054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 857054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 858054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public double returnsDouble() { 859054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef return 1.0; 860054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 861054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 862054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public Object returnsObject() { 863054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef return new Object(); 864054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 865054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 866054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 867054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef @SuppressWarnings("unchecked") 868054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public void testMethodsGeneratedInDeterministicOrder() throws Exception { 869054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef // Grab the static methods array from the original class. 870054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef Method[] methods1 = getMethodsForProxyClass(TestOrderingClass.class); 871054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertNotNull(methods1); 872054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 873054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef // Clear ProxyBuilder's in-memory cache of classes. This will force 874054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef // it to rebuild the class and reset the static methods field. 875054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef Map<Class<?>, Class<?>> map = getGeneratedProxyClasses(); 876054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertNotNull(map); 877054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef map.clear(); 878054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 879054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef // Grab the static methods array from the rebuilt class. 880054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef Method[] methods2 = getMethodsForProxyClass(TestOrderingClass.class); 881054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertNotNull(methods2); 882054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 883054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef // Ensure that the two method arrays are equal. 884054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertTrue(Arrays.equals(methods1, methods2)); 885054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 886054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 887054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public void testOrderingClassWithDexMakerCaching() throws Exception { 888054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef doTestOrderClassWithDexMakerCaching(); 889054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 890054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef // Force ProxyBuilder to call DexMaker.generateAndLoad() 891054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef getGeneratedProxyClasses().clear(); 892054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 893054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef doTestOrderClassWithDexMakerCaching(); 894054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 895054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 896054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef private void doTestOrderClassWithDexMakerCaching() throws Exception { 897054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef TestOrderingClass proxy = ProxyBuilder.forClass(TestOrderingClass.class) 898054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef .handler(new InvokeSuperHandler()) 899054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef .dexCache(DexMakerTest.getDataDirectory()) 900054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef .build(); 901054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals(0, proxy.returnsInt()); 902054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals(1, proxy.returnsInt(1, 1)); 903054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals("string", proxy.returnsString()); 904054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertFalse(proxy.returnsBoolean()); 905054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals(1.0, proxy.returnsDouble()); 906054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertNotNull(proxy.returnsObject()); 907054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals(2, versionedDxDir.listFiles().length); 908054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 909054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 910054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef // Returns static methods array from a proxy class. 911054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef private Method[] getMethodsForProxyClass(Class<?> parentClass) throws Exception { 912054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef Class<?> proxyClass = proxyFor(parentClass).buildProxyClass(); 913054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef Method[] methods = null; 914054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef for (Field f : proxyClass.getDeclaredFields()) { 915054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef if (Method[].class.isAssignableFrom(f.getType())) { 916054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef f.setAccessible(true); 917054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef methods = (Method[]) f.get(null); 918054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef break; 919054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 920054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 921054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 922054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef return methods; 923054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 924054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 925054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef private Map<Class<?>, Class<?>> getGeneratedProxyClasses() throws Exception { 926054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef Field mapField = ProxyBuilder.class 927054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef .getDeclaredField("generatedProxyClasses"); 928054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef mapField.setAccessible(true); 929054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef return (Map<Class<?>, Class<?>>) mapField.get(null); 930054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 931054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 932054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public static class ConcreteClassA implements FooReturnsInt { 933054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef // from FooReturnsInt 934054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public int foo() { 935054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef return 1; 936054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 937054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 938054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef // not from FooReturnsInt 939054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public String bar() { 940054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef return "bar"; 941054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 942054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 943054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 944054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public static class ConcreteClassB implements FooReturnsInt { 945054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef // from FooReturnsInt 946054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public int foo() { 947054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef return 0; 948054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 949054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 950054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef // not from FooReturnsInt 951054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public String bar() { 952054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef return "bahhr"; 953054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 954054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 955054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 956054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef public void testTwoClassesWithIdenticalMethodSignatures_DexMakerCaching() throws Exception { 957054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef ConcreteClassA proxyA = ProxyBuilder.forClass(ConcreteClassA.class) 958054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef .handler(new InvokeSuperHandler()) 959054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef .dexCache(DexMakerTest.getDataDirectory()) 960054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef .build(); 961054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals(1, proxyA.foo()); 962054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals("bar", proxyA.bar()); 963054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals(2, versionedDxDir.listFiles().length); 964054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef 965054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef ConcreteClassB proxyB = ProxyBuilder.forClass(ConcreteClassB.class) 966054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef .handler(new InvokeSuperHandler()) 967054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef .dexCache(DexMakerTest.getDataDirectory()) 968054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef .build(); 969054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals(0, proxyB.foo()); 970054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals("bahhr", proxyB.bar()); 971054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef assertEquals(4, versionedDxDir.listFiles().length); 972054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef } 973579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson} 974