1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 import java.lang.reflect.InvocationTargetException;
18 import java.lang.reflect.Method;
19 import java.lang.reflect.Modifier;
20 import java.util.LinkedList;
21 import java.util.List;
22 
23 /**
24  * Smali excercise.
25  */
26 public class Main {
27 
28     private static class TestCase {
TestCase(String testName, String testClass, String testMethodName, Object[] values, Throwable expectedException, Object expectedReturn)29         public TestCase(String testName, String testClass, String testMethodName, Object[] values,
30                         Throwable expectedException, Object expectedReturn) {
31             this.testName = testName;
32             this.testClass = testClass;
33             this.testMethodName = testMethodName;
34             this.values = values;
35             this.expectedException = expectedException;
36             this.expectedReturn = expectedReturn;
37         }
38 
39         String testName;
40         String testClass;
41         String testMethodName;
42         Object[] values;
43         Throwable expectedException;
44         Object expectedReturn;
45     }
46 
47     private List<TestCase> testCases;
48 
Main()49     public Main() {
50         // Create the test cases.
51         testCases = new LinkedList<TestCase>();
52         testCases.add(new TestCase("PackedSwitch", "PackedSwitch", "packedSwitch",
53                 new Object[]{123}, null, 123));
54 
55         testCases.add(new TestCase("b/17790197", "B17790197", "getInt", null, null, 100));
56         testCases.add(new TestCase("b/17978759", "B17978759", "test", null, new VerifyError(),
57                 null));
58         testCases.add(new TestCase("FloatBadArgReg", "FloatBadArgReg", "getInt",
59                 new Object[]{100}, null, 100));
60         testCases.add(new TestCase("negLong", "negLong", "negLong", null, null, 122142L));
61         testCases.add(new TestCase("sameFieldNames", "sameFieldNames", "getInt", null, null, 7));
62         testCases.add(new TestCase("b/18380491", "B18380491ConcreteClass", "foo",
63                 new Object[]{42}, null, 42));
64         testCases.add(new TestCase("invoke-super abstract", "B18380491ConcreteClass", "foo",
65                 new Object[]{0}, new AbstractMethodError(), null));
66         testCases.add(new TestCase("BadCaseInOpRegRegReg", "BadCaseInOpRegRegReg", "getInt", null,
67                 null, 2));
68         testCases.add(new TestCase("CmpLong", "CmpLong", "run", null, null, 0));
69         testCases.add(new TestCase("FloatIntConstPassing", "FloatIntConstPassing", "run", null,
70                 null, 2));
71         testCases.add(new TestCase("b/18718277", "B18718277", "getInt", null, null, 0));
72         testCases.add(new TestCase("b/18800943 (1)", "B18800943_1", "n_a", null, new VerifyError(),
73                 0));
74         testCases.add(new TestCase("b/18800943 (2)", "B18800943_2", "n_a", null, new VerifyError(),
75                 0));
76         testCases.add(new TestCase("MoveExc", "MoveExc", "run", null, new ArithmeticException(),
77                 null));
78         testCases.add(new TestCase("MoveExceptionOnEntry", "MoveExceptionOnEntry",
79             "moveExceptionOnEntry", new Object[]{0}, new VerifyError(), null));
80         testCases.add(new TestCase("EmptySparseSwitch", "EmptySparseSwitch", "run", null, null,
81                 null));
82         testCases.add(new TestCase("b/20224106", "B20224106", "run", null, new VerifyError(),
83                 0));
84         testCases.add(new TestCase("b/21873167", "B21873167", "test", null, null, null));
85         testCases.add(new TestCase("b/21614284", "B21614284", "test", new Object[] { null },
86                 new NullPointerException(), null));
87         testCases.add(new TestCase("b/21902684", "B21902684", "test", null, null, null));
88         testCases.add(new TestCase("b/21863767", "B21863767", "run", null, null,
89                 null));
90         testCases.add(new TestCase("b/21886894", "B21886894", "test", null, new VerifyError(),
91                 null));
92         testCases.add(new TestCase("b/22080519", "B22080519", "run", null,
93                 new NullPointerException(), null));
94         testCases.add(new TestCase("b/21645819", "B21645819", "run", new Object[] { null },
95                 null, null));
96         testCases.add(new TestCase("b/22244733", "B22244733", "run", new Object[] { "abc" },
97                 null, "abc"));
98         testCases.add(new TestCase("b/22331663", "B22331663", "run", new Object[] { false },
99                 null, null));
100         testCases.add(new TestCase("b/22331663 (pass)", "B22331663Pass", "run",
101                 new Object[] { false }, null, null));
102         testCases.add(new TestCase("b/22331663 (fail)", "B22331663Fail", "run",
103                 new Object[] { false }, new VerifyError(), null));
104         testCases.add(new TestCase("b/22881413", "B22881413", "run", null, null, null));
105         testCases.add(new TestCase("b/20843113", "B20843113", "run", null, null, null));
106         testCases.add(new TestCase("b/23201502 (float)", "B23201502", "runFloat", null,
107                 new NullPointerException(), null));
108         testCases.add(new TestCase("b/23201502 (double)", "B23201502", "runDouble", null,
109                 new NullPointerException(), null));
110     }
111 
runTests()112     public void runTests() {
113         for (TestCase tc : testCases) {
114             System.out.println(tc.testName);
115             try {
116                 runTest(tc);
117             } catch (Exception exc) {
118                 exc.printStackTrace(System.out);
119             }
120         }
121     }
122 
runTest(TestCase tc)123     private void runTest(TestCase tc) throws Exception {
124         Exception errorReturn = null;
125         try {
126             Class<?> c = Class.forName(tc.testClass);
127 
128             Method[] methods = c.getDeclaredMethods();
129 
130             // For simplicity we assume that test methods are not overloaded. So searching by name
131             // will give us the method we need to run.
132             Method method = null;
133             for (Method m : methods) {
134                 if (m.getName().equals(tc.testMethodName)) {
135                     method = m;
136                     break;
137                 }
138             }
139 
140             if (method == null) {
141                 errorReturn = new IllegalArgumentException("Could not find test method " +
142                                                            tc.testMethodName + " in class " +
143                                                            tc.testClass + " for test " +
144                                                            tc.testName);
145             } else {
146                 Object retValue;
147                 if (Modifier.isStatic(method.getModifiers())) {
148                     retValue = method.invoke(null, tc.values);
149                 } else {
150                     retValue = method.invoke(method.getDeclaringClass().newInstance(), tc.values);
151                 }
152                 if (tc.expectedException != null) {
153                     errorReturn = new IllegalStateException("Expected an exception in test " +
154                                                             tc.testName);
155                 }
156                 if (tc.expectedReturn == null && retValue != null) {
157                     errorReturn = new IllegalStateException("Expected a null result in test " +
158                                                             tc.testName);
159                 } else if (tc.expectedReturn != null &&
160                            (retValue == null || !tc.expectedReturn.equals(retValue))) {
161                     errorReturn = new IllegalStateException("Expected return " +
162                                                             tc.expectedReturn +
163                                                             ", but got " + retValue);
164                 } else {
165                     // Expected result, do nothing.
166                 }
167             }
168         } catch (Throwable exc) {
169             if (tc.expectedException == null) {
170                 errorReturn = new IllegalStateException("Did not expect exception", exc);
171             } else if (exc instanceof InvocationTargetException && exc.getCause() != null &&
172                        exc.getCause().getClass().equals(tc.expectedException.getClass())) {
173                 // Expected exception is wrapped in InvocationTargetException.
174             } else if (!tc.expectedException.getClass().equals(exc.getClass())) {
175                 errorReturn = new IllegalStateException("Expected " +
176                                                         tc.expectedException.getClass().getName() +
177                                                         ", but got " + exc.getClass(), exc);
178             } else {
179               // Expected exception, do nothing.
180             }
181         } finally {
182             if (errorReturn != null) {
183                 throw errorReturn;
184             }
185         }
186     }
187 
main(String[] args)188     public static void main(String[] args) throws Exception {
189         Main main = new Main();
190 
191         main.runTests();
192 
193         System.out.println("Done!");
194     }
195 }
196