Home | History | Annotate | Download | only in src
      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 {
     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 
     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 
     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     }
    199 
    200     public void runTests() {
    201         for (TestCase tc : testCases) {
    202             System.out.println(tc.testName);
    203             try {
    204                 runTest(tc);
    205             } catch (Exception exc) {
    206                 exc.printStackTrace(System.out);
    207             }
    208         }
    209     }
    210 
    211     private void runTest(TestCase tc) throws Exception {
    212         Exception errorReturn = null;
    213         try {
    214             Class<?> c = Class.forName(tc.testClass);
    215 
    216             Method[] methods = c.getDeclaredMethods();
    217 
    218             // For simplicity we assume that test methods are not overloaded. So searching by name
    219             // will give us the method we need to run.
    220             Method method = null;
    221             for (Method m : methods) {
    222                 if (m.getName().equals(tc.testMethodName)) {
    223                     method = m;
    224                     break;
    225                 }
    226             }
    227 
    228             if (method == null) {
    229                 errorReturn = new IllegalArgumentException("Could not find test method " +
    230                                                            tc.testMethodName + " in class " +
    231                                                            tc.testClass + " for test " +
    232                                                            tc.testName);
    233             } else {
    234                 Object retValue;
    235                 if (Modifier.isStatic(method.getModifiers())) {
    236                     retValue = method.invoke(null, tc.values);
    237                 } else {
    238                     retValue = method.invoke(method.getDeclaringClass().newInstance(), tc.values);
    239                 }
    240                 if (tc.expectedException != null) {
    241                     errorReturn = new IllegalStateException("Expected an exception in test " +
    242                                                             tc.testName);
    243                 } else if (tc.expectedReturn == null && retValue != null) {
    244                     errorReturn = new IllegalStateException("Expected a null result in test " +
    245                                                             tc.testName + " got " + retValue);
    246                 } else if (tc.expectedReturn != null &&
    247                            (retValue == null || !tc.expectedReturn.equals(retValue))) {
    248                     errorReturn = new IllegalStateException("Expected return " +
    249                                                             tc.expectedReturn +
    250                                                             ", but got " + retValue);
    251                 } else if (tc.checkCompiled && compiledWithOptimizing() && !isAotVerified(c)) {
    252                     errorReturn = new IllegalStateException("Expected method " + method.getName() +
    253                             " of class " + c.getName() +
    254                             " be verified in compile-time in test " + tc.testName);
    255                 } else {
    256                     // Expected result, do nothing.
    257                 }
    258             }
    259         } catch (Throwable exc) {
    260             if (tc.expectedException == null) {
    261                 errorReturn = new IllegalStateException("Did not expect exception", exc);
    262             } else if (exc instanceof InvocationTargetException && exc.getCause() != null &&
    263                        exc.getCause().getClass().equals(tc.expectedException.getClass())) {
    264                 // Expected exception is wrapped in InvocationTargetException.
    265             } else if (!tc.expectedException.getClass().equals(exc.getClass())) {
    266                 errorReturn = new IllegalStateException("Expected " +
    267                                                         tc.expectedException.getClass().getName() +
    268                                                         ", but got " + exc.getClass(), exc);
    269             } else {
    270                 // Expected exception, do nothing.
    271             }
    272         } finally {
    273             if (errorReturn != null) {
    274                 throw errorReturn;
    275             }
    276         }
    277     }
    278 
    279     public static void main(String[] args) throws Exception {
    280         System.loadLibrary(args[0]);
    281 
    282         Main main = new Main();
    283 
    284         main.runTests();
    285 
    286         System.out.println("Done!");
    287     }
    288 
    289     private native static boolean isAotVerified(Class<?> cls);
    290     private native static boolean compiledWithOptimizing();
    291 }
    292