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