/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestResult; import junit.textui.ResultPrinter; import junit.textui.TestRunner; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class CollectAllTests extends DescriptionGenerator { static final String ATTRIBUTE_RUNNER = "runner"; static final String ATTRIBUTE_PACKAGE = "appPackageName"; static final String ATTRIBUTE_NS = "appNameSpace"; static final String ATTRIBUTE_TARGET = "targetNameSpace"; static final String ATTRIBUTE_TARGET_BINARY = "targetBinaryName"; static final String ATTRIBUTE_HOST_SIDE_ONLY = "hostSideOnly"; static final String ATTRIBUTE_JAR_PATH = "jarPath"; static final String JAR_PATH = "LOCAL_JAR_PATH :="; static final String TEST_TYPE = "LOCAL_TEST_TYPE :"; static final int HOST_SIDE_ONLY = 1; static final int DEVICE_SIDE_ONLY = 2; private static String runner; private static String packageName; private static String target; private static String xmlName; private static int testType; private static String jarPath; private static Map<String,TestClass> testCases; private static Set<String> failed = new HashSet<String>(); private static class MyXMLGenerator extends XMLGenerator { MyXMLGenerator(String outputPath) throws ParserConfigurationException { super(outputPath); Node testPackageElem = mDoc.getDocumentElement(); setAttribute(testPackageElem, ATTRIBUTE_NAME, xmlName); setAttribute(testPackageElem, ATTRIBUTE_RUNNER, runner); setAttribute(testPackageElem, ATTRIBUTE_PACKAGE, packageName); setAttribute(testPackageElem, ATTRIBUTE_NS, packageName); if (testType == HOST_SIDE_ONLY) { setAttribute(testPackageElem, ATTRIBUTE_HOST_SIDE_ONLY, "true"); setAttribute(testPackageElem, ATTRIBUTE_JAR_PATH, jarPath); } if (!packageName.equals(target)) { setAttribute(testPackageElem, ATTRIBUTE_TARGET, target); setAttribute(testPackageElem, ATTRIBUTE_TARGET_BINARY, target); } } } private static String OUTPUTFILE = ""; private static String MANIFESTFILE = ""; private static String TESTSUITECLASS = ""; private static String ANDROID_MAKE_FILE = ""; private static Test TESTSUITE; static XMLGenerator xmlGenerator; public static void main(String[] args) { if (args.length > 2) { OUTPUTFILE = args[0]; MANIFESTFILE = args [1]; TESTSUITECLASS = args[2]; if (args.length > 3) { ANDROID_MAKE_FILE = args[3]; } } else { System.out.println("usage: \n" + "\t... CollectAllTests <output-file> <manifest-file> <testsuite-class-name> <makefile-file>"); System.exit(1); } if (ANDROID_MAKE_FILE.length() > 0) { testType = getTestType(ANDROID_MAKE_FILE); } Document manifest = null; try { manifest = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new FileInputStream(MANIFESTFILE)); } catch (Exception e) { System.err.println("cannot open manifest"); e.printStackTrace(); System.exit(1);; } Element documentElement = manifest.getDocumentElement(); documentElement.getAttribute("package"); xmlName = new File(OUTPUTFILE).getName(); runner = getElementAttribute(documentElement, "instrumentation", "android:name"); packageName = documentElement.getAttribute("package"); target = getElementAttribute(documentElement, "instrumentation", "android:targetPackage"); Class<?> testClass = null; try { testClass = Class.forName(TESTSUITECLASS); } catch (ClassNotFoundException e) { System.err.println("test class not found"); e.printStackTrace(); System.exit(1);; } Method method = null; try { method = testClass.getMethod("suite", new Class<?>[0]); } catch (SecurityException e) { System.err.println("failed to get suite method"); e.printStackTrace(); System.exit(1);; } catch (NoSuchMethodException e) { System.err.println("failed to get suite method"); e.printStackTrace(); System.exit(1);; } try { TESTSUITE = (Test) method.invoke(null, (Object[])null); } catch (IllegalArgumentException e) { System.err.println("failed to get suite method"); e.printStackTrace(); System.exit(1);; } catch (IllegalAccessException e) { System.err.println("failed to get suite method"); e.printStackTrace(); System.exit(1);; } catch (InvocationTargetException e) { System.err.println("failed to get suite method"); e.printStackTrace(); System.exit(1);; } try { xmlGenerator = new MyXMLGenerator(OUTPUTFILE + ".xml"); } catch (ParserConfigurationException e) { System.err.println("Can't initialize XML Generator"); System.exit(1); } testCases = new LinkedHashMap<String, TestClass>(); CollectAllTests cat = new CollectAllTests(); cat.compose(); if (!failed.isEmpty()) { System.err.println("The following classes have no default constructor"); for (Iterator<String> iterator = failed.iterator(); iterator.hasNext();) { String type = iterator.next(); System.err.println(type); } System.exit(1); } for (Iterator<TestClass> iterator = testCases.values().iterator(); iterator.hasNext();) { TestClass type = iterator.next(); xmlGenerator.addTestClass(type); } try { xmlGenerator.dump(); } catch (Exception e) { System.err.println("cannot dump xml"); e.printStackTrace(); System.exit(1); } } private static int getTestType(String makeFileName) { int type = DEVICE_SIDE_ONLY; try { BufferedReader reader = new BufferedReader(new FileReader(makeFileName)); String line; while ((line =reader.readLine())!=null) { if (line.startsWith(TEST_TYPE)) { type = HOST_SIDE_ONLY; } else if (line.startsWith(JAR_PATH)) { jarPath = line.substring(JAR_PATH.length(), line.length()).trim(); } } reader.close(); } catch (IOException e) { } return type; } private static Element getElement(Element element, String tagName) { NodeList elements = element.getElementsByTagName(tagName); if (elements.getLength() > 0) { return (Element) elements.item(0); } else { return null; } } private static String getElementAttribute(Element element, String elementName, String attributeName) { Element e = getElement(element, elementName); if (e != null) { return e.getAttribute(attributeName); } else { return ""; } } public void compose() { TestRunner runner = new TestRunner() { @Override protected TestResult createTestResult() { return new TestResult() { @Override protected void run(TestCase test) { addToTests(test); } }; } @Override public TestResult doRun(Test test) { return super.doRun(test); } }; runner.setPrinter(new ResultPrinter(System.out) { @Override protected void printFooter(TestResult result) { } @Override protected void printHeader(long runTime) { } }); runner.doRun(TESTSUITE); } private String getKnownFailure(final Class<? extends TestCase> testClass, final String testName) { return getAnnotation(testClass, testName, KNOWN_FAILURE); } private boolean isBrokenTest(final Class<? extends TestCase> testClass, final String testName) { return getAnnotation(testClass, testName, BROKEN_TEST) != null; } private String getAnnotation(final Class<? extends TestCase> testClass, final String testName, final String annotationName) { try { Method testMethod = testClass.getMethod(testName, (Class[])null); Annotation[] annotations = testMethod.getAnnotations(); for (Annotation annot : annotations) { if (annot.annotationType().getName().equals(annotationName)) { String annotStr = annot.toString(); String knownFailure = null; if (annotStr.contains("(value=")) { knownFailure = annotStr.substring(annotStr.indexOf("=") + 1, annotStr.length() - 1); } if (knownFailure == null) { knownFailure = "true"; } return knownFailure; } } } catch (java.lang.NoSuchMethodException e) { } return null; } private void addToTests(TestCase test) { String testClassName = test.getClass().getName(); String testName = test.getName(); String knownFailure = getKnownFailure(test.getClass(), testName); if (isBrokenTest(test.getClass(), testName)) { System.out.println("ignoring broken test: " + test); return; } if (!testName.startsWith("test")) { try { test.runBare(); } catch (Throwable e) { e.printStackTrace(); return; } } TestClass testClass = null; if (testCases.containsKey(testClassName)) { testClass = testCases.get(testClassName); } else { testClass = new TestClass(testClassName, new ArrayList<TestMethod>()); testCases.put(testClassName, testClass); } testClass.mCases.add(new TestMethod(testName, "", "", knownFailure, false)); try { test.getClass().getConstructor(new Class<?>[0]); } catch (SecurityException e) { failed.add(test.getClass().getName()); } catch (NoSuchMethodException e) { failed.add(test.getClass().getName()); } } }