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
17b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinpackage com.android.dx.stock;
18b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
19b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport com.android.dx.DexMakerTest;
20b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport junit.framework.AssertionFailedError;
21b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport org.junit.After;
22b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport org.junit.Before;
23b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport org.junit.Test;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.File;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.IOException;
278d53a06d10c6e2b96be6857aede5e4661804611eAndrew Yousefimport java.lang.reflect.Field;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.InvocationHandler;
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.Method;
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.UndeclaredThrowableException;
311af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilsonimport java.util.Arrays;
328d53a06d10c6e2b96be6857aede5e4661804611eAndrew Yousefimport java.util.Map;
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Random;
341af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilsonimport java.util.concurrent.Callable;
351af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilsonimport java.util.concurrent.atomic.AtomicInteger;
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
37b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static com.android.dx.util.TestUtil.DELTA_DOUBLE;
38b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static com.android.dx.util.TestUtil.DELTA_FLOAT;
39b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static junit.framework.Assert.assertFalse;
40b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static junit.framework.Assert.assertNotNull;
41b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static junit.framework.Assert.assertSame;
42b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static junit.framework.Assert.assertTrue;
43b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static junit.framework.Assert.fail;
44b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static org.junit.Assert.assertEquals;
45b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
46b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinpublic class ProxyBuilderTest {
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private FakeInvocationHandler fakeHandler = new FakeInvocationHandler();
48054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private File versionedDxDir = new File(DexMakerTest.getDataDirectory(), "v1");
49054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
50b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Before
51054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void setUp() throws Exception {
52b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        versionedDxDir.mkdirs();
53054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        clearVersionedDxDir();
54054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        getGeneratedProxyClasses().clear();
55054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
56054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
57b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @After
58054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void tearDown() throws Exception {
59054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        getGeneratedProxyClasses().clear();
60054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        clearVersionedDxDir();
61054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
62054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
63054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private void clearVersionedDxDir() {
64b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        for (File file : versionedDxDir.listFiles()) {
65b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin            file.delete();
66054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
67054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class SimpleClass {
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String simpleMethod() {
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
75b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    public static class ExampleClass {
76b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        public String exampleMethod() {
77b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin            throw new AssertionFailedError();
78b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        }
79b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    }
80b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
81b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    public static class ExampleOperationClass {
82b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        public String exampleMethod() {
83b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin            throw new AssertionFailedError();
84b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        }
85b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    }
86b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
87b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testExampleOperation() throws Throwable {
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult("expected");
90b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        ExampleClass proxy = proxyFor(ExampleClass.class).build();
91b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals("expected", proxy.exampleMethod());
92054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(2, versionedDxDir.listFiles().length);
93054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
94054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
95b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
96054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testExampleOperation_DexMakerCaching() throws Throwable {
97054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        fakeHandler.setFakeResult("expected");
98b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        ExampleOperationClass proxy = proxyFor(ExampleOperationClass.class).build();
99054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(2, versionedDxDir.listFiles().length);
100b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals("expected", proxy.exampleMethod());
101054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
102054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Force ProxyBuilder to create a DexMaker generator and call DexMaker.generateAndLoad().
103054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        getGeneratedProxyClasses().clear();
104054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
105b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxy = proxyFor(ExampleOperationClass.class).build();
106054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(2, versionedDxDir.listFiles().length);
107b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals("expected", proxy.exampleMethod());
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class ConstructorTakesArguments {
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final String argument;
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public ConstructorTakesArguments(String arg) {
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            argument = arg;
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String method() {
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
122b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testConstruction_SucceedsIfCorrectArgumentsProvided() throws Throwable {
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ConstructorTakesArguments proxy = proxyFor(ConstructorTakesArguments.class)
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgTypes(String.class)
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgValues("hello")
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("hello", proxy.argument);
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxy.method();
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
132b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = IllegalArgumentException.class)
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testConstruction_FailsWithWrongNumberOfArguments() throws Throwable {
134b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxyFor(ConstructorTakesArguments.class).build();
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
137b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = UnsupportedOperationException.class)
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testClassIsNotAccessbile_FailsWithUnsupportedOperationException() throws Exception {
139b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        class MethodVisibilityClass {}
140b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxyFor(MethodVisibilityClass.class).build();
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
143b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    private static class PrivateVisibilityClass {}
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
145b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = UnsupportedOperationException.class)
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testPrivateClass_FailsWithUnsupportedOperationException() throws Exception {
147b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxyFor(PrivateVisibilityClass.class).build();
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected static class ProtectedVisibilityClass {
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String foo() {
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
156b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testProtectedVisibility_WorksFine() throws Exception {
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("fake result", proxyFor(ProtectedVisibilityClass.class).build().foo());
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasFinalMethod {
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String nonFinalMethod() {
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "non-final method";
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public final String finalMethod() {
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "final method";
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
171b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCanProxyClassesWithFinalMethods_WillNotCallTheFinalMethod() throws Throwable {
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        HasFinalMethod proxy = proxyFor(HasFinalMethod.class).build();
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("final method", proxy.finalMethod());
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("fake result", proxy.nonFinalMethod());
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasPrivateMethod {
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private String result() {
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "expected";
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
184b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testProxyingPrivateMethods_NotIntercepted() throws Throwable {
186a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        HasPrivateMethod proxy = proxyFor(HasPrivateMethod.class).build();
187a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        try {
188a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            proxy.getClass().getDeclaredMethod("result");
189a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            fail();
190a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        } catch (NoSuchMethodException expected) {
191a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
192a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
193a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
194a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        assertEquals("expected", proxy.result());
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasPackagePrivateMethod {
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        String result() {
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
203a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public void testProxyingPackagePrivateMethods_NotIntercepted()
204a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            throws Throwable {
205a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        HasPackagePrivateMethod proxy = proxyFor(HasPackagePrivateMethod.class)
206a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin                .build();
207a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        try {
208a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            proxy.getClass().getDeclaredMethod("result");
209a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            fail();
210a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        } catch (NoSuchMethodException expected) {
211a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
212a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
213a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
214a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        try {
215a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            proxy.result();
216a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            fail();
217a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        } catch (AssertionFailedError expected) {
218a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
219a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasProtectedMethod {
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        protected String result() {
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
228b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testProxyingProtectedMethods_AreIntercepted() throws Throwable {
230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("fake result", proxyFor(HasProtectedMethod.class).build().result());
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
233a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public static class MyParentClass {
234a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        String someMethod() {
235a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            return "package";
236a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
237a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
238a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
239a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public static class MyChildClassWithProtectedMethod extends MyParentClass {
240a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        @Override
241a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        protected String someMethod() {
242a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            return "protected";
243a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
244a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
245a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
246a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public static class MyChildClassWithPublicMethod extends MyParentClass {
247a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        @Override
248a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        public String someMethod() {
249a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin            return "public";
250a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        }
251a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
252a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
253b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
254a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    public void testProxying_ClassHierarchy() throws Throwable {
255a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        assertEquals("package", proxyFor(MyParentClass.class).build().someMethod());
256a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        assertEquals("fake result", proxyFor(MyChildClassWithProtectedMethod.class).build().someMethod());
257a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin        assertEquals("fake result", proxyFor(MyChildClassWithPublicMethod.class).build().someMethod());
258a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin    }
259a13e8e98b64e3f5271759dac44967f1c24c76995Paul Duffin
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasVoidMethod {
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void dangerousMethod() {
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
266b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testVoidMethod_ShouldNotThrowRuntimeException() throws Throwable {
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxyFor(HasVoidMethod.class).build().dangerousMethod();
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
271b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
272b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @SuppressWarnings("EqualsWithItself")
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testObjectMethodsAreAlsoProxied() throws Throwable {
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object proxy = proxyFor(Object.class).build();
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult("mystring");
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("mystring", proxy.toString());
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(-1);
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, proxy.hashCode());
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(false);
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, proxy.equals(proxy));
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
2831af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class AllReturnTypes {
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean getBoolean() { return true; }
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int getInt() { return 1; }
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public byte getByte() { return 2; }
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public long getLong() { return 3L; }
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public short getShort() { return 4; }
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public float getFloat() { return 5f; }
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public double getDouble() { return 6.0; }
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public char getChar() { return 'c'; }
2921af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        public int[] getIntArray() { return new int[] { 8, 9 }; }
2931af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        public String[] getStringArray() { return new String[] { "d", "e" }; }
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
296b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
2971af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testAllReturnTypes() throws Throwable {
2981af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        AllReturnTypes proxy = proxyFor(AllReturnTypes.class).build();
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(false);
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, proxy.getBoolean());
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(8);
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(8, proxy.getInt());
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult((byte) 9);
304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(9, proxy.getByte());
305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(10L);
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(10, proxy.getLong());
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult((short) 11);
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(11, proxy.getShort());
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(12f);
310b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(12f, proxy.getFloat(), DELTA_FLOAT);
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(13.0);
312b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(13.0, proxy.getDouble(), DELTA_FLOAT);
313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult('z');
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals('z', proxy.getChar());
3151af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        fakeHandler.setFakeResult(new int[] { -1, -2 });
3161af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("[-1, -2]", Arrays.toString(proxy.getIntArray()));
3171af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        fakeHandler.setFakeResult(new String[] { "x", "y" });
3181af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("[x, y]", Arrays.toString(proxy.getStringArray()));
319579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
320579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
3211af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class PassThroughAllTypes {
322579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean getBoolean(boolean input) { return input; }
323579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int getInt(int input) { return input; }
324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public byte getByte(byte input) { return input; }
325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public long getLong(long input) { return input; }
326579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public short getShort(short input) { return input; }
327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public float getFloat(float input) { return input; }
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public double getDouble(double input) { return input; }
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public char getChar(char input) { return input; }
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String getString(String input) { return input; }
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Object getObject(Object input) { return input; }
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void getNothing() {}
333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class InvokeSuperHandler implements InvocationHandler {
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return ProxyBuilder.callSuper(proxy, method, args);
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
341b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
3421af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testPassThroughWorksForAllTypes() throws Exception {
3431af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        PassThroughAllTypes proxy = proxyFor(PassThroughAllTypes.class)
344579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .handler(new InvokeSuperHandler())
345579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
346579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, proxy.getBoolean(false));
347579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(true, proxy.getBoolean(true));
348579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, proxy.getInt(0));
349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, proxy.getInt(1));
350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((byte) 2, proxy.getByte((byte) 2));
351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((byte) 3, proxy.getByte((byte) 3));
352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(4L, proxy.getLong(4L));
353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(5L, proxy.getLong(5L));
354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((short) 6, proxy.getShort((short) 6));
355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((short) 7, proxy.getShort((short) 7));
356b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(8f, proxy.getFloat(8f), DELTA_FLOAT);
357b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(9f, proxy.getFloat(9f), DELTA_FLOAT);
358b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(10.0, proxy.getDouble(10.0), DELTA_DOUBLE);
359b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(11.0, proxy.getDouble(11.0), DELTA_DOUBLE);
360579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals('a', proxy.getChar('a'));
361579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals('b', proxy.getChar('b'));
362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("asdf", proxy.getString("asdf"));
363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("qwer", proxy.getString("qwer"));
364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(null, proxy.getString(null));
365579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object a = new Object();
366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(a, proxy.getObject(a));
367579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(null, proxy.getObject(null));
368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxy.getNothing();
369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
3711af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class ExtendsAllReturnTypes extends AllReturnTypes {
372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int example() { return 0; }
373579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
375b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testProxyWorksForSuperclassMethodsAlso() throws Throwable {
3771af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        ExtendsAllReturnTypes proxy = proxyFor(ExtendsAllReturnTypes.class).build();
378579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(99);
379579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(99, proxy.example());
380579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(99, proxy.getInt());
381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(99, proxy.hashCode());
382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HasOddParams {
385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public long method(int first, Integer second) {
386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
387579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
390b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
391579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testMixingBoxedAndUnboxedParams() throws Throwable {
392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        HasOddParams proxy = proxyFor(HasOddParams.class).build();
393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(99L);
394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(99L, proxy.method(1, Integer.valueOf(2)));
395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class SingleInt {
398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String getString(int value) {
399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionFailedError();
400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
401579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
403b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
404579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testSinglePrimitiveParameter() throws Throwable {
405579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        InvocationHandler handler = new InvocationHandler() {
406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return "asdf" + ((Integer) args[0]).intValue();
408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        };
410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("asdf1", proxyFor(SingleInt.class).handler(handler).build().getString(1));
411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class TwoConstructors {
414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final String string;
415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public TwoConstructors() {
417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            string = "no-arg";
418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
420579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public TwoConstructors(boolean unused) {
421579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            string = "one-arg";
422579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
423579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
424579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
425b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
426579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testNoConstructorArguments_CallsNoArgConstructor() throws Throwable {
427579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TwoConstructors twoConstructors = proxyFor(TwoConstructors.class).build();
428579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("no-arg", twoConstructors.string);
429579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
430579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
431b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
432579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testWithoutInvocationHandler_ThrowsIllegalArgumentException() throws Throwable {
433579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
434579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            ProxyBuilder.forClass(TwoConstructors.class)
435ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson                    .dexCache(DexMakerTest.getDataDirectory())
436579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    .build();
437579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
438579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IllegalArgumentException expected) {}
439579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
440579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
441579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class HardToConstructCorrectly {
442579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly() { fail(); }
443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly(Runnable ignored) { fail(); }
444579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly(Exception ignored) { fail(); }
445579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly(Boolean ignored) { /* safe */ }
446579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public HardToConstructCorrectly(Integer ignored) { fail(); }
447579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
449b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testHardToConstruct_WorksIfYouSpecifyTheConstructorCorrectly() throws Throwable {
451579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxyFor(HardToConstructCorrectly.class)
452579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgTypes(Boolean.class)
453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgValues(true)
454579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
455579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
456579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
457b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
458579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testHardToConstruct_EvenWorksWhenArgsAreAmbiguous() throws Throwable {
459579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxyFor(HardToConstructCorrectly.class)
460579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgTypes(Boolean.class)
461579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .constructorArgValues(new Object[] { null })
462579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
463579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
464579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
465b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = IllegalArgumentException.class)
466579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testHardToConstruct_DoesNotInferTypesFromValues() throws Throwable {
467b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxyFor(HardToConstructCorrectly.class)
468b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .constructorArgValues(true)
469b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .build();
470579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
471579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
472b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
473579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testDefaultProxyHasSuperMethodToAccessOriginal() throws Exception {
474579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object objectProxy = proxyFor(Object.class).build();
4751af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertNotNull(objectProxy.getClass().getMethod("super$hashCode$int"));
476579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
477579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
478579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class PrintsOddAndValue {
479579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String method(int value) {
480579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "odd " + value;
481579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
482579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
483579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
484b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
485579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testSometimesDelegateToSuper() throws Exception {
486579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        InvocationHandler delegatesOddValues = new InvocationHandler() {
487579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
488579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (method.getName().equals("method")) {
489579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int intValue = ((Integer) args[0]).intValue();
490579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if (intValue % 2 == 0) {
491579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        return "even " + intValue;
492579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
493579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
494579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return ProxyBuilder.callSuper(proxy, method, args);
495579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
496579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        };
497579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        PrintsOddAndValue proxy = proxyFor(PrintsOddAndValue.class)
498579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .handler(delegatesOddValues)
499579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
500579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("even 0", proxy.method(0));
501579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("odd 1", proxy.method(1));
502579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("even 2", proxy.method(2));
503579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("odd 3", proxy.method(3));
504579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
505b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
506b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
5071af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testCallSuperThrows() throws Exception {
5081af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        InvocationHandler handler = new InvocationHandler() {
5091af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
5101af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                return ProxyBuilder.callSuper(o, method, objects);
5111af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            }
5121af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        };
5131af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
5141af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooThrows fooThrows = proxyFor(FooThrows.class)
5151af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .handler(handler)
5161af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
5171af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
5181af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        try {
5191af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            fooThrows.foo();
5201af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            fail();
5211af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        } catch (IllegalStateException expected) {
5221af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            assertEquals("boom!", expected.getMessage());
5231af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
5241af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
525b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
5261af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class FooThrows {
5271af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        public void foo() {
5281af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            throw new IllegalStateException("boom!");
5291af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
5301af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
531579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
532579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class DoubleReturn {
533579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public double getValue() {
534579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return 2.0;
535579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
536579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
537579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
538b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
539579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testUnboxedResult() throws Exception {
540579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.fakeResult = 2.0;
541b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(2.0, proxyFor(DoubleReturn.class).build().getValue(), DELTA_DOUBLE);
542579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
543579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
544b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    public static void staticMethod() {}
545579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
546b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
547579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testDoesNotOverrideStaticMethods() throws Exception {
548579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Method should exist on this test class itself.
549579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ProxyBuilderTest.class.getDeclaredMethod("staticMethod");
550579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Method should not exist on the subclass.
551579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
552579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(ProxyBuilderTest.class).build().getClass().getDeclaredMethod("staticMethod");
553579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
554579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (NoSuchMethodException expected) {}
555579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
556579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
557b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = IOException.class)
558579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testIllegalCacheDirectory() throws Exception {
559b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxyFor(ProxyForIllegalCacheDirectory.class)
560b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .dexCache(new File("/poop/"))
561b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .build();
562579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
563579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
564b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    public static class ProxyForIllegalCacheDirectory {}
5652e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson
566b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = IllegalArgumentException.class)
567579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testInvalidConstructorSpecification() throws Exception {
568b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        proxyFor(Object.class)
569b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .constructorArgTypes(String.class, Boolean.class)
570b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .constructorArgValues("asdf", true)
571b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin                .build();
572579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
573579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
574579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static abstract class AbstractClass {
575579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public abstract Object getValue();
576579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
577579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
578b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
579579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testAbstractClassBehaviour() throws Exception {
580579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("fake result", proxyFor(AbstractClass.class).build().getValue());
581579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
582579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
583579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class CtorHasDeclaredException {
584579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public CtorHasDeclaredException() throws IOException {
585579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IOException();
586579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
587579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
588579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
589579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class CtorHasRuntimeException {
590579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public CtorHasRuntimeException() {
591579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException("my message");
592579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
593579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
594579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
595579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class CtorHasError {
596579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public CtorHasError() {
597579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new Error("my message again");
598579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
599579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
600579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
601b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
602579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testParentConstructorThrowsDeclaredException() throws Exception {
603579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
604579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(CtorHasDeclaredException.class).build();
605579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
606579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (UndeclaredThrowableException expected) {
607579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertTrue(expected.getCause() instanceof IOException);
608579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
609579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
610579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(CtorHasRuntimeException.class).build();
611579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
612579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (RuntimeException expected) {
613579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertEquals("my message", expected.getMessage());
614579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
615579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
616579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(CtorHasError.class).build();
617579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
618579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (Error expected) {
619579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertEquals("my message again", expected.getMessage());
620579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
621579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
622579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
623b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
624579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testGetInvocationHandler_NormalOperation() throws Exception {
625579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object proxy = proxyFor(Object.class).build();
626579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertSame(fakeHandler, ProxyBuilder.getInvocationHandler(proxy));
627579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
628579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
629b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test(expected = IllegalArgumentException.class)
630579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testGetInvocationHandler_NotAProxy() {
631b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        ProxyBuilder.getInvocationHandler(new Object());
632579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
633579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
634579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class ReturnsObject {
635579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Object getValue() {
636579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return new Object();
637579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
638579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
639579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
640579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class ReturnsString extends ReturnsObject {
641579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        @Override
642579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String getValue() {
643579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return "a string";
644579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
645579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
646579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
647b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
648579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCovariantReturnTypes_NormalBehaviour() throws Exception {
649579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        String expected = "some string";
650579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        fakeHandler.setFakeResult(expected);
651579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertSame(expected, proxyFor(ReturnsObject.class).build().getValue());
652579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertSame(expected, proxyFor(ReturnsString.class).build().getValue());
653579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
654579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
655b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
656579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCovariantReturnTypes_WrongReturnType() throws Exception {
657579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
658579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fakeHandler.setFakeResult(new Object());
659579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            proxyFor(ReturnsString.class).build().getValue();
660579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
661579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (ClassCastException expected) {}
662579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
663579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
664b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
6652e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    public void testCaching() throws Exception {
66631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        SimpleClass a = proxyFor(SimpleClass.class).build();
66731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        SimpleClass b = proxyFor(SimpleClass.class).build();
66831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertSame(a.getClass(), b.getClass());
6692e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    }
6702e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson
671b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
6722e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    public void testCachingWithMultipleConstructors() throws Exception {
67331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        HasMultipleConstructors a = ProxyBuilder.forClass(HasMultipleConstructors.class)
67431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgTypes()
67531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgValues()
67631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .handler(fakeHandler)
67731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .dexCache(DexMakerTest.getDataDirectory()).build();
67831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals("no args", a.calledConstructor);
67931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        HasMultipleConstructors b = ProxyBuilder.forClass(HasMultipleConstructors.class)
68031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgTypes(int.class)
68131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgValues(2)
68231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .handler(fakeHandler)
68331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .dexCache(DexMakerTest.getDataDirectory()).build();
68431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals("int 2", b.calledConstructor);
68531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals(a.getClass(), b.getClass());
68631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson
68731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        HasMultipleConstructors c = ProxyBuilder.forClass(HasMultipleConstructors.class)
68831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgTypes(Integer.class)
68931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .constructorArgValues(3)
69031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .handler(fakeHandler)
69131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .dexCache(DexMakerTest.getDataDirectory()).build();
69231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals("Integer 3", c.calledConstructor);
69331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals(a.getClass(), c.getClass());
6942e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson    }
6952e28a229885e9ba7fec9ef42cbf30fdcf8a0c939Jesse Wilson
69631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson    public static class HasMultipleConstructors {
69731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        private final String calledConstructor;
69831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        public HasMultipleConstructors() {
69931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson            calledConstructor = "no args";
70031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        }
70131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        public HasMultipleConstructors(int b) {
70231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson            calledConstructor = "int " + b;
70331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        }
70431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        public HasMultipleConstructors(Integer c) {
70531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson            calledConstructor = "Integer " + c;
70631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        }
70731c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson    }
70831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson
709b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
71031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson    public void testClassNotCachedWithDifferentParentClassLoaders() throws Exception {
711b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson        ClassLoader classLoaderA = newPathClassLoader();
71231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        SimpleClass a = proxyFor(SimpleClass.class)
71331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .parentClassLoader(classLoaderA)
71431c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .build();
71531c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals(classLoaderA, a.getClass().getClassLoader().getParent());
71631c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson
717b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson        ClassLoader classLoaderB = newPathClassLoader();
71831c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        SimpleClass b = proxyFor(SimpleClass.class)
71931c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .parentClassLoader(classLoaderB)
72031c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson                .build();
72131c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertEquals(classLoaderB, b.getClass().getClassLoader().getParent());
72231c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson
72331c34ef392ca364c845f71b4cc8f84de2739426bJesse Wilson        assertTrue(a.getClass() != b.getClass());
724579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
725b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
726b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
7271af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testAbstractClassWithUndeclaredInterfaceMethod() throws Throwable {
7281af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        DeclaresInterface declaresInterface = proxyFor(DeclaresInterface.class)
7291af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
7301af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("fake result", declaresInterface.call());
7311af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        try {
7321af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            ProxyBuilder.callSuper(declaresInterface, Callable.class.getMethod("call"));
7331af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            fail();
734b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        } catch (IncompatibleClassChangeError expected) {
7351af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
7361af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
7371af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
738b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    public static abstract class DeclaresInterface implements Callable<String> {}
739b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
740b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
7411af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testImplementingInterfaces() throws Throwable {
7421af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        SimpleClass simpleClass = proxyFor(SimpleClass.class)
7431af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Callable.class)
7441af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Comparable.class)
7451af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
7461af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("fake result", simpleClass.simpleMethod());
7471af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7481af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Callable<?> asCallable = (Callable<?>) simpleClass;
7491af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("fake result", asCallable.call());
7501af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7511af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Comparable<?> asComparable = (Comparable<?>) simpleClass;
7521af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        fakeHandler.fakeResult = 3;
7531af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, asComparable.compareTo(null));
7541af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
7551af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
756b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
7571af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testCallSuperWithInterfaceMethod() throws Throwable {
7581af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        SimpleClass simpleClass = proxyFor(SimpleClass.class)
7591af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Callable.class)
7601af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
7611af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        try {
7621af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            ProxyBuilder.callSuper(simpleClass, Callable.class.getMethod("call"));
7631af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            fail();
7641af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        } catch (AbstractMethodError expected) {
7651af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        } catch (NoSuchMethodError expected) {
7661af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
7671af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
768579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
769b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
7701af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testImplementInterfaceCallingThroughConcreteClass() throws Throwable {
7711af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        InvocationHandler invocationHandler = new InvocationHandler() {
7721af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
7731af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                assertEquals("a", ProxyBuilder.callSuper(o, method, objects));
7741af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                return "b";
7751af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            }
7761af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        };
7771af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        ImplementsCallable proxy = proxyFor(ImplementsCallable.class)
7781af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Callable.class)
7791af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .handler(invocationHandler)
7801af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
7811af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("b", proxy.call());
7821af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("a", ProxyBuilder.callSuper(
7831af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                proxy, ImplementsCallable.class.getMethod("call")));
7841af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
785b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
7861af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    /**
7871af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * This test is a bit unintuitive because it exercises the synthetic methods
7881af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * that support covariant return types. Calling 'Object call()' on the
7891af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * interface bridges to 'String call()', and so the super method appears to
7901af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * also be proxied.
7911af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     */
792b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
7931af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testImplementInterfaceCallingThroughInterface() throws Throwable {
7941af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        final AtomicInteger count = new AtomicInteger();
7951af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
7961af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        InvocationHandler invocationHandler = new InvocationHandler() {
7971af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
7981af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                count.incrementAndGet();
7991af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                return ProxyBuilder.callSuper(o, method, objects);
8001af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            }
8011af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        };
8021af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8031af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Callable<?> proxy = proxyFor(ImplementsCallable.class)
8041af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(Callable.class)
8051af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .handler(invocationHandler)
8061af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
8071af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8081af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        // the invocation handler is called twice!
8091af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("a", proxy.call());
8101af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(2, count.get());
8111af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8121af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        // the invocation handler is called, even though this is a callSuper() call!
8131af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("a", ProxyBuilder.callSuper(proxy, Callable.class.getMethod("call")));
8141af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, count.get());
8151af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
816b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8171af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public static class ImplementsCallable implements Callable<String> {
8181af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        public String call() throws Exception {
8191af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            return "a";
8201af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        }
8211af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
8221af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8231af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    /**
8241af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * This test shows that our generated proxies follow the bytecode convention
8251af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * where methods can have the same name but unrelated return types. This is
8261af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * different from javac's convention where return types must be assignable
8271af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     * in one direction or the other.
8281af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson     */
829b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
8301af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testInterfacesSameNamesDifferentReturnTypes() throws Throwable {
8311af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        InvocationHandler handler = new InvocationHandler() {
8321af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
8331af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                if (method.getReturnType() == void.class) {
8341af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                    return null;
8351af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                } else if (method.getReturnType() == String.class) {
8361af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                    return "X";
8371af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                } else if (method.getReturnType() == int.class) {
8381af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                    return 3;
8391af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                } else {
8401af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                    throw new AssertionFailedError();
8411af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                }
8421af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson            }
8431af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        };
844b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8451af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Object o = proxyFor(Object.class)
8461af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(FooReturnsVoid.class, FooReturnsString.class, FooReturnsInt.class)
8471af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .handler(handler)
8481af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
849b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8501af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsVoid a = (FooReturnsVoid) o;
8511af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        a.foo();
852b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8531af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsString b = (FooReturnsString) o;
8541af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals("X", b.foo());
855b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8561af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsInt c = (FooReturnsInt) o;
8571af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, c.foo());
8581af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
859b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
860b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
8611af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public void testInterfacesSameNamesSameReturnType() throws Throwable {
8621af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        Object o = proxyFor(Object.class)
8631af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .implementing(FooReturnsInt.class, FooReturnsInt2.class)
8641af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson                .build();
865b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8661af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        fakeHandler.setFakeResult(3);
8671af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8681af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsInt a = (FooReturnsInt) o;
8691af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, a.foo());
8701af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8711af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        FooReturnsInt2 b = (FooReturnsInt2) o;
8721af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        assertEquals(3, b.foo());
8731af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
874b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8751af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public interface FooReturnsVoid {
8761af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        void foo();
8771af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
8781af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8791af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public interface FooReturnsString {
8801af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        String foo();
8811af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
8821af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson
8831af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public interface FooReturnsInt {
8841af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        int foo();
8851af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
886b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
8871af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    public interface FooReturnsInt2 {
8881af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson        int foo();
8891af1da6af1f59f0bc1f9d048f31279ce5e614c3dJesse Wilson    }
890b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
891b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson    private ClassLoader newPathClassLoader() throws Exception {
892b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson        return (ClassLoader) Class.forName("dalvik.system.PathClassLoader")
893b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson                .getConstructor(String.class, ClassLoader.class)
894b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson                .newInstance("", getClass().getClassLoader());
895b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson
896b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson    }
897b4fdb175545f178c642194bc43a3fad31af3f0e9Jesse Wilson
898b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
899579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testSubclassOfRandom() throws Exception {
900579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        proxyFor(Random.class)
901579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .handler(new InvokeSuperHandler())
902579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .build();
903579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
904579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
90595689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    public static class FinalToString {
906b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        @Override
907b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        public final String toString() {
90895689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy            return "no proxy";
90995689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        }
91095689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    }
91195689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy
91295689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    // https://code.google.com/p/dexmaker/issues/detail?id=12
913b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
91495689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    public void testFinalToString() throws Throwable {
91595689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        assertEquals("no proxy", proxyFor(FinalToString.class).build().toString());
91695689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    }
91795689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy
918ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    public static class FinalInterfaceImpl implements FooReturnsString {
919b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        @Override
920b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        public final String foo() {
921ab38abdf175554643d40b889d58d283d358218c3Samuel Tan          return "no proxy";
922ab38abdf175554643d40b889d58d283d358218c3Samuel Tan        }
923ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    }
924ab38abdf175554643d40b889d58d283d358218c3Samuel Tan
925ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    public static class ExtenstionOfFinalInterfaceImpl extends FinalInterfaceImpl
926ab38abdf175554643d40b889d58d283d358218c3Samuel Tan            implements FooReturnsString {
927ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    }
928ab38abdf175554643d40b889d58d283d358218c3Samuel Tan
929b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
930ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    public void testFinalInterfaceImpl() throws Throwable {
931ab38abdf175554643d40b889d58d283d358218c3Samuel Tan        assertEquals("no proxy", proxyFor(ExtenstionOfFinalInterfaceImpl.class).build().foo());
932ab38abdf175554643d40b889d58d283d358218c3Samuel Tan    }
933ab38abdf175554643d40b889d58d283d358218c3Samuel Tan
934cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    // https://code.google.com/p/dexmaker/issues/detail?id=9
935cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    public interface DeclaresMethodLate {
936cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin        void thisIsTheMethod();
937cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    }
938cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin
939cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    public static class MakesMethodFinalEarly {
940cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin        public final void thisIsTheMethod() {}
941cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    }
942cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin
943cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    public static class YouDoNotChooseYourFamily
944cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin            extends MakesMethodFinalEarly implements DeclaresMethodLate {}
945cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin
946b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
947cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    public void testInterfaceMethodMadeFinalBeforeActualInheritance() throws Exception {
948cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin        proxyFor(YouDoNotChooseYourFamily.class).build();
949cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin    }
950cb6e5223823f9f9ad04da51c63548659062a4f43Paul Duffin
951309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin    public interface ExtendsAnotherInterface extends FooReturnsString {
952309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin
953309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin    }
954309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin
955309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin    @Test
956309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin    public void testExtraInterfaceExtendsInterface() throws Exception {
957309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin        ExtendsAnotherInterface proxy = (ExtendsAnotherInterface)
958309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin                proxyFor(SimpleClass.class)
959309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin                        .implementing(ExtendsAnotherInterface.class)
960309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin                        .build();
961309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin        fakeHandler.setFakeResult(ExtendsAnotherInterface.class.getName());
962309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin        assertEquals(ExtendsAnotherInterface.class.getName(), proxy.foo());
963309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin    }
964309cc66e50aaac713a5c2c72e3ea6b236716b036Paul Duffin
965579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** Simple helper to add the most common args for this test to the proxy builder. */
966579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private <T> ProxyBuilder<T> proxyFor(Class<T> clazz) throws Exception {
967579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return ProxyBuilder.forClass(clazz)
968579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                .handler(fakeHandler)
969ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson                .dexCache(DexMakerTest.getDataDirectory());
970579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
971579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
972579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static class FakeInvocationHandler implements InvocationHandler {
973579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private Object fakeResult = "fake result";
974579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
975579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
976579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return fakeResult;
977579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
978579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
979579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void setFakeResult(Object result) {
980579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fakeResult = result;
981579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
982579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
983054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
984054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public static class TestOrderingClass {
985054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public int returnsInt() {
986054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 0;
987054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
988054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
989054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public int returnsInt(int param1, int param2) {
990054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 1;
991054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
992054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
993054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public String returnsString() {
994054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return "string";
995054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
996054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
997054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public boolean returnsBoolean() {
998054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return false;
999054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1000054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1001054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public double returnsDouble() {
1002054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 1.0;
1003054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1004054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1005054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public Object returnsObject() {
1006054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return new Object();
1007054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1008054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1009054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1010b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
1011054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    @SuppressWarnings("unchecked")
1012054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testMethodsGeneratedInDeterministicOrder() throws Exception {
1013054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Grab the static methods array from the original class.
1014054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Method[] methods1 = getMethodsForProxyClass(TestOrderingClass.class);
1015054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertNotNull(methods1);
1016054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1017054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Clear ProxyBuilder's in-memory cache of classes. This will force
1018054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // it to rebuild the class and reset the static methods field.
1019054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Map<Class<?>, Class<?>> map = getGeneratedProxyClasses();
1020054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertNotNull(map);
1021054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        map.clear();
1022054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1023054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Grab the static methods array from the rebuilt class.
1024054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Method[] methods2 = getMethodsForProxyClass(TestOrderingClass.class);
1025054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertNotNull(methods2);
1026054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1027054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Ensure that the two method arrays are equal.
1028054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertTrue(Arrays.equals(methods1, methods2));
1029054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1030054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1031b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
1032054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testOrderingClassWithDexMakerCaching() throws Exception {
1033054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        doTestOrderClassWithDexMakerCaching();
1034054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1035054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Force ProxyBuilder to call DexMaker.generateAndLoad()
1036054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        getGeneratedProxyClasses().clear();
1037054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1038054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        doTestOrderClassWithDexMakerCaching();
1039054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1040054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1041054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private void doTestOrderClassWithDexMakerCaching() throws Exception {
1042054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        TestOrderingClass proxy = ProxyBuilder.forClass(TestOrderingClass.class)
1043054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .handler(new InvokeSuperHandler())
1044054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .dexCache(DexMakerTest.getDataDirectory())
1045054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .build();
1046054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(0, proxy.returnsInt());
1047054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(1, proxy.returnsInt(1, 1));
1048054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals("string", proxy.returnsString());
1049054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertFalse(proxy.returnsBoolean());
1050b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertEquals(1.0, proxy.returnsDouble(), DELTA_DOUBLE);
1051054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertNotNull(proxy.returnsObject());
1052b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        assertTrue(versionedDxDir.listFiles().length != 0);
1053054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1054054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1055054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    // Returns static methods array from a proxy class.
1056054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private Method[] getMethodsForProxyClass(Class<?> parentClass) throws Exception {
1057054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Class<?> proxyClass = proxyFor(parentClass).buildProxyClass();
1058054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Method[] methods = null;
1059054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        for (Field f : proxyClass.getDeclaredFields()) {
1060054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            if (Method[].class.isAssignableFrom(f.getType())) {
1061054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                f.setAccessible(true);
1062054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                methods = (Method[]) f.get(null);
1063054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                break;
1064054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            }
1065054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1066054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1067054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        return methods;
1068054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1069054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1070054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private Map<Class<?>, Class<?>> getGeneratedProxyClasses() throws Exception {
1071054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Field mapField = ProxyBuilder.class
1072054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .getDeclaredField("generatedProxyClasses");
1073054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        mapField.setAccessible(true);
1074054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        return (Map<Class<?>, Class<?>>) mapField.get(null);
1075054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1076054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1077054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public static class ConcreteClassA implements FooReturnsInt {
1078054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // from FooReturnsInt
1079054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public int foo() {
1080054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 1;
1081054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1082054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1083054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // not from FooReturnsInt
1084054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public String bar() {
1085054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return "bar";
1086054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1087054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1088054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1089054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public static class ConcreteClassB implements FooReturnsInt {
1090054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // from FooReturnsInt
1091054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public int foo() {
1092054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return 0;
1093054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1094054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1095054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // not from FooReturnsInt
1096054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        public String bar() {
1097054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            return "bahhr";
1098054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1099054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1100054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1101b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    @Test
1102054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testTwoClassesWithIdenticalMethodSignatures_DexMakerCaching() throws Exception {
1103054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        ConcreteClassA proxyA = ProxyBuilder.forClass(ConcreteClassA.class)
1104054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .handler(new InvokeSuperHandler())
1105054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .dexCache(DexMakerTest.getDataDirectory())
1106054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .build();
1107054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(1, proxyA.foo());
1108054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals("bar", proxyA.bar());
1109054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(2, versionedDxDir.listFiles().length);
1110054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1111054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        ConcreteClassB proxyB = ProxyBuilder.forClass(ConcreteClassB.class)
1112054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .handler(new InvokeSuperHandler())
1113054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .dexCache(DexMakerTest.getDataDirectory())
1114054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                .build();
1115054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(0, proxyB.foo());
1116054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals("bahhr", proxyB.bar());
1117054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(4, versionedDxDir.listFiles().length);
1118054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
1120