/*
* 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());
}
}
}