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, boolean checkCompiled)29 public TestCase(String testName, String testClass, String testMethodName, Object[] values, 30 Throwable expectedException, Object expectedReturn, 31 boolean checkCompiled) { 32 this.testName = testName; 33 this.testClass = testClass; 34 this.testMethodName = testMethodName; 35 this.values = values; 36 this.expectedException = expectedException; 37 this.expectedReturn = expectedReturn; 38 this.checkCompiled = checkCompiled; 39 } 40 TestCase(String testName, String testClass, String testMethodName, Object[] values, Throwable expectedException, Object expectedReturn)41 public TestCase(String testName, String testClass, String testMethodName, Object[] values, 42 Throwable expectedException, Object expectedReturn) { 43 this(testName, testClass, testMethodName, values, expectedException, 44 expectedReturn, false); 45 } 46 47 String testName; 48 String testClass; 49 String testMethodName; 50 Object[] values; 51 Throwable expectedException; 52 Object expectedReturn; 53 boolean checkCompiled; 54 } 55 56 private List<TestCase> testCases; 57 Main()58 public Main() { 59 // Create the test cases. 60 testCases = new LinkedList<TestCase>(); 61 testCases.add(new TestCase("PackedSwitch", "PackedSwitch", "packedSwitch", 62 new Object[]{123}, null, 123)); 63 testCases.add(new TestCase("PackedSwitch key INT_MAX", "PackedSwitch", 64 "packedSwitch_INT_MAX", new Object[]{123}, null, 123)); 65 testCases.add(new TestCase("PackedSwitch key overflow", "b_24399945", 66 "packedSwitch_overflow", new Object[]{123}, new VerifyError(), null)); 67 68 testCases.add(new TestCase("b/17790197", "B17790197", "getInt", null, null, 100)); 69 testCases.add(new TestCase("FloatBadArgReg", "FloatBadArgReg", "getInt", 70 new Object[]{100}, null, 100)); 71 testCases.add(new TestCase("negLong", "negLong", "negLong", null, null, 122142L)); 72 testCases.add(new TestCase("sameFieldNames", "sameFieldNames", "getInt", null, null, 7)); 73 testCases.add(new TestCase("b/18380491", "B18380491ConcreteClass", "foo", 74 new Object[]{42}, null, 42)); 75 testCases.add(new TestCase("invoke-super abstract", "B18380491ConcreteClass", "foo", 76 new Object[]{0}, new AbstractMethodError(), null)); 77 testCases.add(new TestCase("BadCaseInOpRegRegReg", "BadCaseInOpRegRegReg", "getInt", null, 78 null, 2)); 79 testCases.add(new TestCase("CmpLong", "CmpLong", "run", null, null, 0)); 80 testCases.add(new TestCase("FloatIntConstPassing", "FloatIntConstPassing", "run", null, 81 null, 2)); 82 testCases.add(new TestCase("b/18718277", "B18718277", "getInt", null, null, 0)); 83 testCases.add(new TestCase("b/18800943 (1)", "B18800943_1", "n_a", null, new VerifyError(), 84 0)); 85 testCases.add(new TestCase("b/18800943 (2)", "B18800943_2", "n_a", null, new VerifyError(), 86 0)); 87 testCases.add(new TestCase("MoveExc", "MoveExc", "run", null, new ArithmeticException(), 88 null)); 89 testCases.add(new TestCase("MoveExceptionOnEntry", "MoveExceptionOnEntry", 90 "moveExceptionOnEntry", new Object[]{0}, new VerifyError(), null)); 91 testCases.add(new TestCase("EmptySparseSwitch", "EmptySparseSwitch", "run", null, null, 92 null)); 93 testCases.add(new TestCase("b/20224106", "B20224106", "run", null, new VerifyError(), 94 0)); 95 testCases.add(new TestCase("b/17410612", "B17410612", "run", null, new VerifyError(), 96 0)); 97 testCases.add(new TestCase("b/21863767", "B21863767", "run", null, null, 98 null)); 99 testCases.add(new TestCase("b/21873167", "B21873167", "test", null, null, null)); 100 testCases.add(new TestCase("b/21614284", "B21614284", "test", new Object[] { null }, 101 new NullPointerException(), null)); 102 testCases.add(new TestCase("b/21902684", "B21902684", "test", null, null, null)); 103 testCases.add(new TestCase("b/22045582", "B22045582", "run", null, new VerifyError(), 104 0)); 105 testCases.add(new TestCase("b/22045582 (int)", "B22045582Int", "run", null, 106 new VerifyError(), 0)); 107 testCases.add(new TestCase("b/22045582 (wide)", "B22045582Wide", "run", null, 108 new VerifyError(), 0)); 109 testCases.add(new TestCase("b/21886894", "B21886894", "test", null, new VerifyError(), 110 null)); 111 testCases.add(new TestCase("b/22080519", "B22080519", "run", null, 112 new NullPointerException(), null)); 113 testCases.add(new TestCase("b/21645819", "B21645819", "run", new Object[] { null }, 114 null, null)); 115 testCases.add(new TestCase("b/22244733", "B22244733", "run", new Object[] { "abc" }, 116 null, "abc")); 117 testCases.add(new TestCase("b/22331663", "B22331663", "run", new Object[] { false }, 118 null, null)); 119 testCases.add(new TestCase("b/22331663 (pass)", "B22331663Pass", "run", 120 new Object[] { false }, null, null)); 121 testCases.add(new TestCase("b/22331663 (fail)", "B22331663Fail", "run", 122 new Object[] { false }, new VerifyError(), null)); 123 testCases.add(new TestCase("b/22411633 (1)", "B22411633_1", "run", new Object[] { false }, 124 null, null)); 125 testCases.add(new TestCase("b/22411633 (2)", "B22411633_2", "run", new Object[] { false }, 126 new VerifyError(), null)); 127 testCases.add(new TestCase("b/22411633 (3)", "B22411633_3", "run", new Object[] { false }, 128 null, null)); 129 testCases.add(new TestCase("b/22411633 (4)", "B22411633_4", "run", new Object[] { false }, 130 new VerifyError(), null)); 131 testCases.add(new TestCase("b/22411633 (5)", "B22411633_5", "run", new Object[] { false }, 132 null, null)); 133 testCases.add(new TestCase("b/22777307", "B22777307", "run", null, new InstantiationError(), 134 null)); 135 testCases.add(new TestCase("b/22881413", "B22881413", "run", null, null, null)); 136 testCases.add(new TestCase("b/20843113", "B20843113", "run", null, null, null)); 137 testCases.add(new TestCase("b/23201502 (float)", "B23201502", "runFloat", null, 138 new NullPointerException(), null)); 139 testCases.add(new TestCase("b/23201502 (double)", "B23201502", "runDouble", null, 140 new NullPointerException(), null)); 141 testCases.add(new TestCase("b/23300986", "B23300986", "runAliasAfterEnter", 142 new Object[] { new Object() }, null, null)); 143 testCases.add(new TestCase("b/23300986 (2)", "B23300986", "runAliasBeforeEnter", 144 new Object[] { new Object() }, null, null)); 145 testCases.add(new TestCase("b/23502994 (if-eqz)", "B23502994", "runIF_EQZ", 146 new Object[] { new Object() }, null, null)); 147 testCases.add(new TestCase("b/23502994 (check-cast)", "B23502994", "runCHECKCAST", 148 new Object[] { "abc" }, null, null)); 149 testCases.add(new TestCase("b/25494456", "B25494456", "run", null, new VerifyError(), 150 null)); 151 testCases.add(new TestCase("b/21869691", "B21869691A", "run", null, 152 new IncompatibleClassChangeError(), null)); 153 testCases.add(new TestCase("b/26143249", "B26143249", "run", null, 154 new AbstractMethodError(), null)); 155 testCases.add(new TestCase("b/26579108", "B26579108", "run", null, new VerifyError(), 156 null)); 157 testCases.add(new TestCase("b/26594149 (1)", "B26594149_1", "run", null, new VerifyError(), 158 null)); 159 testCases.add(new TestCase("b/26594149 (2)", "B26594149_2", "run", null, new VerifyError(), 160 null)); 161 testCases.add(new TestCase("b/26594149 (3)", "B26594149_3", "run", null, new VerifyError(), 162 null)); 163 testCases.add(new TestCase("b/26594149 (4)", "B26594149_4", "run", null, new VerifyError(), 164 null)); 165 testCases.add(new TestCase("b/26594149 (5)", "B26594149_5", "run", null, null, null)); 166 testCases.add(new TestCase("b/26594149 (6)", "B26594149_6", "run", null, new VerifyError(), 167 null)); 168 testCases.add(new TestCase("b/26594149 (7)", "B26594149_7", "run", null, new VerifyError(), 169 null)); 170 testCases.add(new TestCase("b/26594149 (8)", "B26594149_8", "run", null, new VerifyError(), 171 null)); 172 testCases.add(new TestCase("b/27148248", "B27148248", "run", null, new VerifyError(), 173 null)); 174 testCases.add(new TestCase("b/26965384", "B26965384", "run", null, new VerifyError(), 175 null)); 176 testCases.add(new TestCase("b/27799205 (1)", "B27799205Helper", "run1", null, null, null)); 177 testCases.add(new TestCase("b/27799205 (2)", "B27799205Helper", "run2", null, 178 new VerifyError(), null)); 179 testCases.add(new TestCase("b/27799205 (3)", "B27799205Helper", "run3", null, 180 new VerifyError(), null)); 181 testCases.add(new TestCase("b/27799205 (4)", "B27799205Helper", "run4", null, 182 new VerifyError(), null)); 183 testCases.add(new TestCase("b/27799205 (5)", "B27799205Helper", "run5", null, 184 new VerifyError(), null)); 185 testCases.add(new TestCase("b/27799205 (6)", "B27799205Helper", "run6", null, null, null)); 186 testCases.add(new TestCase("b/28187158", "B28187158", "run", new Object[] { null }, 187 new VerifyError(), null)); 188 testCases.add(new TestCase("b/29778499 (1)", "B29778499_1", "run", null, 189 new IncompatibleClassChangeError(), null)); 190 testCases.add(new TestCase("b/29778499 (2)", "B29778499_2", "run", null, 191 new IncompatibleClassChangeError(), null)); 192 testCases.add(new TestCase("b/30458218", "B30458218", "run", null, null, null)); 193 testCases.add(new TestCase("b/31313170", "B31313170", "run", null, null, 0)); 194 testCases.add(new TestCase("ConstClassAliasing", "ConstClassAliasing", "run", null, null, 195 null, true)); 196 testCases.add(new TestCase("b/121191566", "B121191566", "run", new Object[] { "a" }, null, 197 true, false)); 198 testCases.add(new TestCase("b/122501785", "B122501785", "run", null, new VerifyError(), 199 0)); 200 testCases.add(new TestCase("b/134061982", "B134061982", "run", new Object[] { 0 }, 201 new NullPointerException(), 0)); 202 testCases.add(new TestCase("b/134061982 (2)", "B134061982_2", "run", new Object[] { 0 }, 203 new VerifyError(), 0)); 204 testCases.add(new TestCase("b/121245951", "B121245951", "run", new Object[] { true, 205 new Object() }, new IllegalMonitorStateException(), 0)); 206 testCases.add(new TestCase("b/121245951 (2)", "B121245951_2", "run", new Object[] { true, 207 new Object() }, new VerifyError(), 0)); 208 testCases.add(new TestCase("b/121245951 (3)", "B121245951_3", "run", new Object[] { 209 new Object() }, new IllegalMonitorStateException(), 0)); 210 } 211 runTests()212 public void runTests() { 213 for (TestCase tc : testCases) { 214 System.out.println(tc.testName); 215 try { 216 runTest(tc); 217 } catch (Exception exc) { 218 exc.printStackTrace(System.out); 219 } 220 } 221 } 222 runTest(TestCase tc)223 private void runTest(TestCase tc) throws Exception { 224 Exception errorReturn = null; 225 try { 226 Class<?> c = Class.forName(tc.testClass); 227 228 Method[] methods = c.getDeclaredMethods(); 229 230 // For simplicity we assume that test methods are not overloaded. So searching by name 231 // will give us the method we need to run. 232 Method method = null; 233 for (Method m : methods) { 234 if (m.getName().equals(tc.testMethodName)) { 235 method = m; 236 break; 237 } 238 } 239 240 if (method == null) { 241 errorReturn = new IllegalArgumentException("Could not find test method " + 242 tc.testMethodName + " in class " + 243 tc.testClass + " for test " + 244 tc.testName); 245 } else { 246 Object retValue; 247 if (Modifier.isStatic(method.getModifiers())) { 248 retValue = method.invoke(null, tc.values); 249 } else { 250 retValue = method.invoke(method.getDeclaringClass().newInstance(), tc.values); 251 } 252 if (tc.expectedException != null) { 253 errorReturn = new IllegalStateException("Expected an exception in test " + 254 tc.testName); 255 } else if (tc.expectedReturn == null && retValue != null) { 256 errorReturn = new IllegalStateException("Expected a null result in test " + 257 tc.testName + " got " + retValue); 258 } else if (tc.expectedReturn != null && 259 (retValue == null || !tc.expectedReturn.equals(retValue))) { 260 errorReturn = new IllegalStateException("Expected return " + 261 tc.expectedReturn + 262 ", but got " + retValue); 263 } else if (tc.checkCompiled && compiledWithOptimizing() && !isAotVerified(c)) { 264 errorReturn = new IllegalStateException("Expected method " + method.getName() + 265 " of class " + c.getName() + 266 " be verified in compile-time in test " + tc.testName); 267 } else { 268 // Expected result, do nothing. 269 } 270 } 271 } catch (Throwable exc) { 272 if (tc.expectedException == null) { 273 errorReturn = new IllegalStateException("Did not expect exception", exc); 274 } else if (exc instanceof InvocationTargetException && exc.getCause() != null && 275 exc.getCause().getClass().equals(tc.expectedException.getClass())) { 276 // Expected exception is wrapped in InvocationTargetException. 277 } else if (!tc.expectedException.getClass().equals(exc.getClass())) { 278 errorReturn = new IllegalStateException("Expected " + 279 tc.expectedException.getClass().getName() + 280 ", but got " + exc.getClass(), exc); 281 } else { 282 // Expected exception, do nothing. 283 } 284 } finally { 285 if (errorReturn != null) { 286 throw errorReturn; 287 } 288 } 289 } 290 main(String[] args)291 public static void main(String[] args) throws Exception { 292 System.loadLibrary(args[0]); 293 294 Main main = new Main(); 295 296 main.runTests(); 297 298 System.out.println("Done!"); 299 } 300 isAotVerified(Class<?> cls)301 private native static boolean isAotVerified(Class<?> cls); compiledWithOptimizing()302 private native static boolean compiledWithOptimizing(); 303 } 304