Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright (C) 2008 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.io.BufferedReader;
     18 import java.io.File;
     19 import java.io.FileInputStream;
     20 import java.io.FileReader;
     21 import java.io.IOException;
     22 import java.lang.annotation.Annotation;
     23 import java.lang.reflect.InvocationTargetException;
     24 import java.lang.reflect.Method;
     25 import java.util.ArrayList;
     26 import java.util.HashSet;
     27 import java.util.Iterator;
     28 import java.util.LinkedHashMap;
     29 import java.util.Map;
     30 import java.util.Set;
     31 
     32 import javax.xml.parsers.DocumentBuilderFactory;
     33 import javax.xml.parsers.ParserConfigurationException;
     34 
     35 import junit.framework.Test;
     36 import junit.framework.TestCase;
     37 import junit.framework.TestResult;
     38 import junit.textui.ResultPrinter;
     39 import junit.textui.TestRunner;
     40 
     41 import org.w3c.dom.Document;
     42 import org.w3c.dom.Element;
     43 import org.w3c.dom.Node;
     44 import org.w3c.dom.NodeList;
     45 
     46 public class CollectAllTests extends DescriptionGenerator {
     47 
     48     static final String ATTRIBUTE_RUNNER = "runner";
     49     static final String ATTRIBUTE_PACKAGE = "appPackageName";
     50     static final String ATTRIBUTE_NS = "appNameSpace";
     51     static final String ATTRIBUTE_TARGET = "targetNameSpace";
     52     static final String ATTRIBUTE_TARGET_BINARY = "targetBinaryName";
     53     static final String ATTRIBUTE_HOST_SIDE_ONLY = "hostSideOnly";
     54     static final String ATTRIBUTE_JAR_PATH = "jarPath";
     55 
     56     static final String JAR_PATH = "LOCAL_JAR_PATH :=";
     57     static final String TEST_TYPE = "LOCAL_TEST_TYPE :";
     58 
     59     static final int HOST_SIDE_ONLY = 1;
     60     static final int DEVICE_SIDE_ONLY = 2;
     61 
     62     private static String runner;
     63     private static String packageName;
     64     private static String target;
     65     private static String xmlName;
     66     private static int testType;
     67     private static String jarPath;
     68 
     69     private static Map<String,TestClass> testCases;
     70     private static Set<String> failed = new HashSet<String>();
     71 
     72     private static class MyXMLGenerator extends XMLGenerator {
     73 
     74         MyXMLGenerator(String outputPath) throws ParserConfigurationException {
     75             super(outputPath);
     76 
     77             Node testPackageElem = mDoc.getDocumentElement();
     78 
     79             setAttribute(testPackageElem, ATTRIBUTE_NAME, xmlName);
     80             setAttribute(testPackageElem, ATTRIBUTE_RUNNER, runner);
     81             setAttribute(testPackageElem, ATTRIBUTE_PACKAGE, packageName);
     82             setAttribute(testPackageElem, ATTRIBUTE_NS, packageName);
     83 
     84             if (testType == HOST_SIDE_ONLY) {
     85                 setAttribute(testPackageElem, ATTRIBUTE_HOST_SIDE_ONLY, "true");
     86                 setAttribute(testPackageElem, ATTRIBUTE_JAR_PATH, jarPath);
     87             }
     88 
     89             if (!packageName.equals(target)) {
     90                 setAttribute(testPackageElem, ATTRIBUTE_TARGET, target);
     91                 setAttribute(testPackageElem, ATTRIBUTE_TARGET_BINARY, target);
     92             }
     93         }
     94     }
     95 
     96     private static String OUTPUTFILE = "";
     97     private static String MANIFESTFILE = "";
     98     private static String TESTSUITECLASS = "";
     99     private static String ANDROID_MAKE_FILE = "";
    100 
    101     private static Test TESTSUITE;
    102 
    103     static XMLGenerator xmlGenerator;
    104 
    105     public static void main(String[] args) {
    106         if (args.length > 2) {
    107             OUTPUTFILE = args[0];
    108             MANIFESTFILE = args [1];
    109             TESTSUITECLASS = args[2];
    110             if (args.length > 3) {
    111                 ANDROID_MAKE_FILE = args[3];
    112             }
    113         } else {
    114             System.out.println("usage: \n" +
    115                 "\t... CollectAllTests <output-file> <manifest-file> <testsuite-class-name> <makefile-file>");
    116             System.exit(1);
    117         }
    118 
    119         if (ANDROID_MAKE_FILE.length() > 0) {
    120             testType = getTestType(ANDROID_MAKE_FILE);
    121         }
    122 
    123         Document manifest = null;
    124         try {
    125             manifest = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new FileInputStream(MANIFESTFILE));
    126         } catch (Exception e) {
    127             System.err.println("cannot open manifest");
    128             e.printStackTrace();
    129             System.exit(1);;
    130         }
    131 
    132         Element documentElement = manifest.getDocumentElement();
    133 
    134         documentElement.getAttribute("package");
    135 
    136         xmlName = new File(OUTPUTFILE).getName();
    137         runner = getElementAttribute(documentElement, "instrumentation", "android:name");
    138         packageName = documentElement.getAttribute("package");
    139         target = getElementAttribute(documentElement, "instrumentation", "android:targetPackage");
    140 
    141         Class<?> testClass = null;
    142         try {
    143             testClass = Class.forName(TESTSUITECLASS);
    144         } catch (ClassNotFoundException e) {
    145             System.err.println("test class not found");
    146             e.printStackTrace();
    147             System.exit(1);;
    148         }
    149 
    150         Method method = null;
    151         try {
    152             method = testClass.getMethod("suite", new Class<?>[0]);
    153         } catch (SecurityException e) {
    154             System.err.println("failed to get suite method");
    155             e.printStackTrace();
    156             System.exit(1);;
    157         } catch (NoSuchMethodException e) {
    158             System.err.println("failed to get suite method");
    159             e.printStackTrace();
    160             System.exit(1);;
    161         }
    162 
    163         try {
    164             TESTSUITE = (Test) method.invoke(null, (Object[])null);
    165         } catch (IllegalArgumentException e) {
    166             System.err.println("failed to get suite method");
    167             e.printStackTrace();
    168             System.exit(1);;
    169         } catch (IllegalAccessException e) {
    170             System.err.println("failed to get suite method");
    171             e.printStackTrace();
    172             System.exit(1);;
    173         } catch (InvocationTargetException e) {
    174             System.err.println("failed to get suite method");
    175             e.printStackTrace();
    176             System.exit(1);;
    177         }
    178 
    179         try {
    180             xmlGenerator = new MyXMLGenerator(OUTPUTFILE + ".xml");
    181         } catch (ParserConfigurationException e) {
    182             System.err.println("Can't initialize XML Generator");
    183             System.exit(1);
    184         }
    185 
    186         testCases = new LinkedHashMap<String, TestClass>();
    187         CollectAllTests cat = new CollectAllTests();
    188         cat.compose();
    189 
    190         if (!failed.isEmpty()) {
    191             System.err.println("The following classes have no default constructor");
    192             for (Iterator<String> iterator = failed.iterator(); iterator.hasNext();) {
    193                 String type = iterator.next();
    194                 System.err.println(type);
    195             }
    196             System.exit(1);
    197         }
    198 
    199         for (Iterator<TestClass> iterator = testCases.values().iterator(); iterator.hasNext();) {
    200             TestClass type = iterator.next();
    201             xmlGenerator.addTestClass(type);
    202         }
    203 
    204         try {
    205             xmlGenerator.dump();
    206         } catch (Exception e) {
    207             System.err.println("cannot dump xml");
    208             e.printStackTrace();
    209             System.exit(1);
    210         }
    211     }
    212 
    213     private static int getTestType(String makeFileName) {
    214 
    215         int type = DEVICE_SIDE_ONLY;
    216         try {
    217             BufferedReader reader = new BufferedReader(new FileReader(makeFileName));
    218             String line;
    219 
    220             while ((line =reader.readLine())!=null) {
    221                 if (line.startsWith(TEST_TYPE)) {
    222                     type = HOST_SIDE_ONLY;
    223                 } else if (line.startsWith(JAR_PATH)) {
    224                     jarPath = line.substring(JAR_PATH.length(), line.length()).trim();
    225                 }
    226             }
    227             reader.close();
    228         } catch (IOException e) {
    229         }
    230 
    231         return type;
    232     }
    233 
    234     private static Element getElement(Element element, String tagName) {
    235         NodeList elements = element.getElementsByTagName(tagName);
    236         if (elements.getLength() > 0) {
    237             return (Element) elements.item(0);
    238         } else {
    239             return null;
    240         }
    241     }
    242 
    243     private static String getElementAttribute(Element element, String elementName, String attributeName) {
    244         Element e = getElement(element, elementName);
    245         if (e != null) {
    246             return e.getAttribute(attributeName);
    247         } else {
    248             return "";
    249         }
    250     }
    251 
    252     public void compose() {
    253         TestRunner runner = new TestRunner() {
    254             @Override
    255             protected TestResult createTestResult() {
    256                 return new TestResult() {
    257                     @Override
    258                     protected void run(TestCase test) {
    259                         addToTests(test);
    260                     }
    261                 };
    262             }
    263 
    264             @Override
    265             public TestResult doRun(Test test) {
    266                 return super.doRun(test);
    267             }
    268 
    269 
    270 
    271         };
    272 
    273         runner.setPrinter(new ResultPrinter(System.out) {
    274             @Override
    275             protected void printFooter(TestResult result) {
    276             }
    277 
    278             @Override
    279             protected void printHeader(long runTime) {
    280             }
    281         });
    282         runner.doRun(TESTSUITE);
    283     }
    284 
    285     private String getKnownFailure(final Class<? extends TestCase> testClass,
    286             final String testName) {
    287         return getAnnotation(testClass, testName, KNOWN_FAILURE);
    288     }
    289 
    290     private boolean isKnownFailure(final Class<? extends TestCase> testClass,
    291             final String testName) {
    292         return getAnnotation(testClass, testName, KNOWN_FAILURE) != null;
    293     }
    294 
    295     private boolean isBrokenTest(final Class<? extends TestCase> testClass,
    296             final String testName)  {
    297         return getAnnotation(testClass, testName, BROKEN_TEST) != null;
    298     }
    299 
    300     private boolean isSuppressed(final Class<? extends TestCase> testClass,
    301             final String testName)  {
    302         return getAnnotation(testClass, testName, SUPPRESSED_TEST) != null;
    303     }
    304 
    305     private String getAnnotation(final Class<? extends TestCase> testClass,
    306             final String testName, final String annotationName) {
    307         try {
    308             Method testMethod = testClass.getMethod(testName, (Class[])null);
    309             Annotation[] annotations = testMethod.getAnnotations();
    310             for (Annotation annot : annotations) {
    311 
    312                 if (annot.annotationType().getName().equals(annotationName)) {
    313                     String annotStr = annot.toString();
    314                     String knownFailure = null;
    315                     if (annotStr.contains("(value=")) {
    316                         knownFailure =
    317                             annotStr.substring(annotStr.indexOf("=") + 1,
    318                                     annotStr.length() - 1);
    319 
    320                     }
    321 
    322                     if (knownFailure == null) {
    323                         knownFailure = "true";
    324                     }
    325 
    326                     return knownFailure;
    327                 }
    328 
    329             }
    330 
    331         } catch (java.lang.NoSuchMethodException e) {
    332         }
    333 
    334         return null;
    335     }
    336 
    337     private void addToTests(TestCase test) {
    338 
    339         String testClassName = test.getClass().getName();
    340         String testName = test.getName();
    341         String knownFailure = getKnownFailure(test.getClass(), testName);
    342 
    343         if (isKnownFailure(test.getClass(), testName)) {
    344             System.out.println("ignoring known failure: " + test);
    345             return;
    346         } else if (isBrokenTest(test.getClass(), testName)) {
    347             System.out.println("ignoring broken test: " + test);
    348             return;
    349         } else if (isSuppressed(test.getClass(), testName)) {
    350             System.out.println("ignoring suppressed test: " + test);
    351             return;
    352         }
    353 
    354         if (!testName.startsWith("test")) {
    355             try {
    356                 test.runBare();
    357             } catch (Throwable e) {
    358                 e.printStackTrace();
    359                 return;
    360             }
    361         }
    362         TestClass testClass = null;
    363         if (testCases.containsKey(testClassName)) {
    364             testClass = testCases.get(testClassName);
    365         } else {
    366             testClass = new TestClass(testClassName, new ArrayList<TestMethod>());
    367             testCases.put(testClassName, testClass);
    368         }
    369 
    370         testClass.mCases.add(new TestMethod(testName, "", "", knownFailure, false, false));
    371 
    372         try {
    373             test.getClass().getConstructor(new Class<?>[0]);
    374         } catch (SecurityException e) {
    375             failed.add(test.getClass().getName());
    376         } catch (NoSuchMethodException e) {
    377             failed.add(test.getClass().getName());
    378         }
    379     }
    380 }
    381