blob: 4cd006828c40d3b8beb371765d4ed551a22634a5 [file] [log] [blame]
package android.icu.cts.tools;
import com.google.common.base.Joiner;
import com.android.compatibility.common.util.AbiUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
/**
* Generates an XML file suitable for CTS version 1.
*
* <p>A lot of this code is copied from {@code tools/utils/DescriptionGenerator.java} and
* {@code tools/utils/CollectAllTests.java}. Ideally, that code should have been refactored to make
* it usable in this case but that would have taken quite a lot of time and given that CTS version 1
* is going away anyway and CTS version 2 doesn't need an XML file this seemed like the best
* approach.
*/
public class GenerateTestCaseXML {
private static final String ATTRIBUTE_RUNNER = "runner";
private static final String ATTRIBUTE_PACKAGE = "appPackageName";
private static final String ATTRIBUTE_NS = "appNameSpace";
static final String TAG_PACKAGE = "TestPackage";
static final String TAG_SUITE = "TestSuite";
static final String TAG_CASE = "TestCase";
static final String TAG_TEST = "Test";
static final String ATTRIBUTE_NAME_VERSION = "version";
static final String ATTRIBUTE_VALUE_VERSION = "1.0";
static final String ATTRIBUTE_NAME_FRAMEWORK = "AndroidFramework";
static final String ATTRIBUTE_VALUE_FRAMEWORK = "Android 1.0";
static final String ATTRIBUTE_NAME = "name";
static final String ATTRIBUTE_ABIS = "abis";
public static void main(String[] args) throws Exception {
if (args.length != 3) {
throw new IllegalStateException(
"... <test-list-path> <architecture> <output-file-path");
}
String testListPath = args[0];
String architecture = args[1];
String outputFilePath = args[2];
File testListFile = new File(testListPath);
String abis = Joiner.on(" ").join(AbiUtils.getAbisForArch(architecture));
File testCaseXML = new File(outputFilePath);
TestSuite root = new TestSuite("");
try (FileReader fileReader = new FileReader(testListFile);
BufferedReader reader = new BufferedReader(fileReader)) {
String line;
while ((line = reader.readLine()) != null) {
int index = line.indexOf('#');
String className = line.substring(0, index);
String methodName = line.substring(index + 1);
root.addTest(className, methodName);
}
}
Document mDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element testPackageElem = mDoc.createElement(TAG_PACKAGE);
mDoc.appendChild(testPackageElem);
setAttribute(testPackageElem, ATTRIBUTE_NAME_VERSION, ATTRIBUTE_VALUE_VERSION);
setAttribute(testPackageElem, ATTRIBUTE_NAME_FRAMEWORK, ATTRIBUTE_VALUE_FRAMEWORK);
setAttribute(testPackageElem, ATTRIBUTE_NAME, "CtsIcuTestCases");
setAttribute(testPackageElem, ATTRIBUTE_RUNNER, "android.icu.cts.IcuTestRunnerForCtsV1");
setAttribute(testPackageElem, ATTRIBUTE_PACKAGE, "android.icu.dev.test");
setAttribute(testPackageElem, ATTRIBUTE_NS, "android.icu.cts");
root.addChildInformation(testPackageElem, abis);
Transformer t = TransformerFactory.newInstance().newTransformer();
// enable indent in result file
t.setOutputProperty("indent", "yes");
t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
File directory = testCaseXML.getParentFile();
if (!directory.exists() && !directory.mkdirs()) {
throw new IOException("Could not create directory: " + directory);
}
t.transform(new DOMSource(mDoc), new StreamResult(new FileOutputStream(testCaseXML)));
}
/**
* Set the attribute of element.
*
* @param elem The element to be set attribute.
* @param name The attribute name.
* @param value The attribute value.
*/
protected static void setAttribute(Node elem, String name, String value) {
Attr attr = elem.getOwnerDocument().createAttribute(name);
attr.setNodeValue(value);
elem.getAttributes().setNamedItem(attr);
}
/**
* The contents of a {@link TestSuite}, may be a {@link TestSuite} or a {@link TestCase}.
*/
private static abstract class SuiteContent {
private final String name;
private SuiteContent(String name) {
this.name = name;
}
public String getName() {
return name;
}
public abstract void addInformation(Element parent, String abis);
}
public static class TestSuite extends SuiteContent {
private Map<String, SuiteContent> name2Content = new TreeMap<>();
public TestSuite(String name) {
super(name);
}
public TestSuite getSuite(String name) {
return getSuiteContent(TestSuite.class, name);
}
public TestCase getTestCase(String name) {
return getSuiteContent(TestCase.class, name);
}
private <S extends SuiteContent> S getSuiteContent(Class<? extends S> contentClass,
String name) {
SuiteContent content = name2Content.get(name);
S s;
if (content == null) {
try {
s = contentClass.getConstructor(String.class).newInstance(name);
} catch (Exception e) {
throw new RuntimeException("Could not create instance of " + contentClass, e);
}
name2Content.put(name, s);
} else if (contentClass.isInstance(content)) {
s = contentClass.cast(content);
} else {
throw new IllegalStateException("Expected " + this
+ " to have a TestSuite called '" + name + "' but has "
+ content + " instead");
}
return s;
}
public void addTest(String className, String methodName) {
int index = className.indexOf('.');
if (index == -1) {
TestCase testCase = getTestCase(className);
testCase.addMethod(methodName);
} else {
String suiteName = className.substring(0, index);
TestSuite childSuite = getSuite(suiteName);
childSuite.addTest(className.substring(index + 1), methodName);
}
}
@Override
public void addInformation(Element parent, String abis) {
Element suiteElement = appendElement(parent, TAG_SUITE);
setAttribute(suiteElement, ATTRIBUTE_NAME, getName());
addChildInformation(suiteElement, abis);
}
public void addChildInformation(Element parent, String abis) {
for (SuiteContent suiteContent : name2Content.values()) {
suiteContent.addInformation(parent, abis);
}
}
}
public static class TestCase extends SuiteContent {
private final Set<String> methods = new TreeSet<>();
public TestCase(String name) {
super(name);
}
@Override
public void addInformation(Element parent, String abis) {
Element testCaseElement = appendElement(parent, TAG_CASE);
setAttribute(testCaseElement, ATTRIBUTE_NAME, getName());
setAttribute(testCaseElement, ATTRIBUTE_ABIS, abis);
for (String method : methods) {
Element testElement = appendElement(testCaseElement, TAG_TEST);
setAttribute(testElement, ATTRIBUTE_NAME, method);
}
}
public void addMethod(String methodName) {
methods.add(methodName);
}
}
private static Element appendElement(Element parent, String tagName) {
Element testCaseElement = parent.getOwnerDocument().createElement(tagName);
parent.appendChild(testCaseElement);
return testCaseElement;
}
}