summaryrefslogtreecommitdiffstats
path: root/xml/src/test/java
diff options
context:
space:
mode:
authorJesse Wilson <jessewilson@google.com>2010-02-11 12:40:50 -0800
committerJesse Wilson <jessewilson@google.com>2010-02-11 12:51:17 -0800
commit2f4bbf1068869f45783608450731f83c523ded30 (patch)
tree18d2792632b50cae117b8f3ca1870a33e7406896 /xml/src/test/java
parent2b1267b8c87b3efd9ea75dd73bc82785ddcd4b82 (diff)
downloadlibcore-2f4bbf1068869f45783608450731f83c523ded30.zip
libcore-2f4bbf1068869f45783608450731f83c523ded30.tar.gz
libcore-2f4bbf1068869f45783608450731f83c523ded30.tar.bz2
Fixing problems with the test runner's ability to parse expected results files.
It appears that the original authors of this testing framework didn't really know whether these files were supposed to be XML or HTML, UTF-8 or UTF-16, and so there's quite a mess of processing in order to canonicalize them.
Diffstat (limited to 'xml/src/test/java')
-rw-r--r--xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java213
1 files changed, 179 insertions, 34 deletions
diff --git a/xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java b/xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java
index 443e415..7dbfaea 100644
--- a/xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java
+++ b/xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java
@@ -23,15 +23,16 @@ import junit.framework.TestCase;
import junit.framework.TestSuite;
import junit.textui.TestRunner;
import org.w3c.dom.Attr;
-import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.EntityReference;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
-import org.w3c.dom.Text;
+import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
@@ -39,17 +40,25 @@ import org.xmlpull.v1.XmlSerializer;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.ErrorListener;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
+import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -61,13 +70,23 @@ import java.util.List;
* XSLT conformance test suite</a>, adapted for use by JUnit. To run these tests
* on a device:
* <ul>
- * <li>Obtain the <a href="http://www.oasis-open.org/committees/download.php/12171/XSLT-testsuite-04.ZIP">test
- * suite zip file from the OASIS project site.</li>
- * <li>Unzip.
- * <li>Copy the files to a device: <code>adb shell mkdir /data/oasis ;
- * adb push ./XSLT-Conformance-TC /data/oasis</code>.
- * <li>Invoke this class' main method, passing the on-device path to the test
- * suite's <code>catalog.xml</code> file as an argument.
+ * <li>Obtain the <a href="http://www.oasis-open.org/committees/download.php/12171/XSLT-testsuite-04.ZIP">test
+ * suite zip file from the OASIS project site.</li>
+ * <li>Unzip.
+ * <li>Copy the files to a device: <code>adb shell mkdir /data/oasis ;
+ * adb push ./XSLT-Conformance-TC /data/oasis</code>.
+ * <li>Invoke this class' main method, passing the on-device path to the test
+ * suite's <code>catalog.xml</code> file as an argument.
+ * </ul>
+ *
+ * <p>Unfortunately, some of the tests in the OASIS suite will fail when
+ * executed outside of their original development environment:
+ * <ul>
+ * <li>The tests assume case insensitive filesystems. Some will fail with
+ * "Couldn't open file" errors due to a mismatch in file name casing.
+ * <li>The tests assume certain network hosts will exist and serve
+ * stylesheet files. In particular, "http://webxtest/" isn't generally
+ * available.
* </ul>
*/
public class XsltXPathConformanceTestSuite {
@@ -164,7 +183,7 @@ public class XsltXPathConformanceTestSuite {
/**
* Returns a JUnit test for the test described by the given element.
*/
- private Test create(File base, Element testCaseElement) {
+ private TestCase create(File base, Element testCaseElement) {
/*
* Extract the XSLT test from a DOM entity with the following structure:
@@ -291,7 +310,6 @@ public class XsltXPathConformanceTestSuite {
* the result to an expected output file.
*/
public class XsltTest extends TestCase {
- // TODO: include these in toString
private final String category;
private final String id;
private final String purpose;
@@ -304,7 +322,10 @@ public class XsltXPathConformanceTestSuite {
/** either "standard" or "execution-error" */
private final String operation;
- /** the syntax to compare the output file using, such as "XML" or "HTML" */
+ /**
+ * The syntax to compare the output file using, such as "XML", "HTML",
+ * "manual", or null for expected execution errors.
+ */
private final String compareAs;
XsltTest(String category, String id, String purpose, String spec,
@@ -335,37 +356,50 @@ public class XsltXPathConformanceTestSuite {
System.out.println("Spec: " + spec);
}
- Source xslt = new StreamSource(principalStylesheet);
- Source in = new StreamSource(principalData);
+ Result result;
+ if ("XML".equals(compareAs)) {
+ DOMResult domResult = new DOMResult();
+ domResult.setNode(documentBuilder.newDocument().createElementNS("", "result"));
+ result = domResult;
+ } else {
+ result = new StreamResult(new StringWriter());
+ }
+
+ ErrorRecorder errorRecorder = new ErrorRecorder();
+ transformerFactory.setErrorListener(errorRecorder);
Transformer transformer;
try {
+ Source xslt = new StreamSource(principalStylesheet);
transformer = transformerFactory.newTransformer(xslt);
- assertEquals("Transformer creation completed normally.",
- operation, "standard");
+ if (errorRecorder.error == null) {
+ transformer.setErrorListener(errorRecorder);
+ transformer.transform(new StreamSource(principalData), result);
+ }
} catch (TransformerConfigurationException e) {
- if (operation.equals("execution-error")) {
- return; // expected, such as in XSLT-Result-Tree.Attributes__78369
+ errorRecorder.fatalError(e);
+ }
+
+ if (operation.equals("standard")) {
+ if (errorRecorder.error != null) {
+ throw errorRecorder.error;
+ }
+ } else if (operation.equals("execution-error")) {
+ if (errorRecorder.error != null) {
+ return;
}
- AssertionFailedError failure = new AssertionFailedError();
- failure.initCause(e);
- throw failure;
+ fail("Expected " + operation + ", but transform completed normally."
+ + " (Warning=" + errorRecorder.warning + ")");
+ } else {
+ throw new UnsupportedOperationException("Unexpected operation: " + operation);
}
- Result result;
- if (compareAs.equals("XML")) {
- result = new DOMResult();
+ if ("XML".equals(compareAs)) {
+ assertNodesAreEquivalent(principal, ((DOMResult) result).getNode());
} else {
// TODO: implement support for comparing HTML etc.
throw new UnsupportedOperationException("Cannot compare as " + compareAs);
}
-
- transformer.transform(in, result);
-
- if (compareAs.equals("XML")) {
- DOMResult domResult = (DOMResult) result;
- assertNodesAreEquivalent(principal, domResult.getNode());
- }
}
@Override public String getName() {
@@ -376,19 +410,65 @@ public class XsltXPathConformanceTestSuite {
/**
* Ensures both XML documents represent the same semantic data. Non-semantic
* data such as namespace prefixes, comments, and whitespace is ignored.
+ *
+ * @param actual an XML document whose root is a {@code <result>} element.
+ * @param expected a file containing an XML document fragment.
*/
private void assertNodesAreEquivalent(File expected, Node actual)
throws ParserConfigurationException, IOException, SAXException,
XmlPullParserException {
- Document expectedDocument = documentBuilder.parse(new FileInputStream(expected));
- String expectedString = nodeToNormalizedString(expectedDocument);
+ Node expectedNode = fileToResultNode(expected);
+ String expectedString = nodeToNormalizedString(expectedNode);
String actualString = nodeToNormalizedString(actual);
Assert.assertEquals("Expected XML to match file " + expected,
expectedString, actualString);
}
+ /**
+ * Returns the given file's XML fragment as a single node, wrapped in
+ * {@code <result>} tags. This takes care of normalizing the following
+ * conditions:
+ *
+ * <ul>
+ * <li>Files containing XML document fragments with multiple elements:
+ * {@code <SPAN style="color=blue">Smurfs!</SPAN><br />}
+ *
+ * <li>Files containing XML document fragments with no elements:
+ * {@code Smurfs!}
+ *
+ * <li>Files containing proper XML documents with a single element and an
+ * XML declaration:
+ * {@code <?xml version="1.0"?><doc />}
+ *
+ * <li>Files prefixed with a byte order mark header, such as 0xEFBBBF.
+ * </ul>
+ */
+ private Node fileToResultNode(File file) throws IOException, SAXException {
+ String rawContents = fileToString(file);
+ String fragment = rawContents;
+
+ // If the file had an XML declaration, strip that. Otherwise wrapping
+ // it in <result> tags would result in a malformed XML document.
+ if (fragment.startsWith("<?xml")) {
+ int declarationEnd = fragment.indexOf("?>");
+ fragment = fragment.substring(declarationEnd + 2);
+ }
+
+ // Parse it as document fragment wrapped in <result> tags.
+ try {
+ fragment = "<result>" + fragment + "</result>";
+ return documentBuilder.parse(new InputSource(new StringReader(fragment)))
+ .getDocumentElement();
+ } catch (SAXParseException e) {
+ Error error = new AssertionFailedError(
+ "Failed to parse XML: " + file + "\n" + rawContents);
+ error.initCause(e);
+ throw error;
+ }
+ }
+
private String nodeToNormalizedString(Node node)
throws XmlPullParserException, IOException {
StringWriter writer = new StringWriter();
@@ -411,7 +491,8 @@ public class XsltXPathConformanceTestSuite {
emitChildren(serializer, element);
serializer.endTag(element.getNamespaceURI(), element.getLocalName());
- } else if (node.getNodeType() == Node.TEXT_NODE) {
+ } else if (node.getNodeType() == Node.TEXT_NODE
+ || node.getNodeType() == Node.CDATA_SECTION_NODE) {
// TODO: is it okay to trim whitespace in general? This may cause
// false positives for elements like HTML's <pre> tag
String trimmed = node.getTextContent().trim();
@@ -434,6 +515,10 @@ public class XsltXPathConformanceTestSuite {
} else if (node.getNodeType() == Node.COMMENT_NODE) {
// ignore!
+ } else if (node.getNodeType() == Node.ENTITY_REFERENCE_NODE) {
+ EntityReference entityReference = (EntityReference) node;
+ serializer.entityRef(entityReference.getNodeName());
+
} else {
throw new UnsupportedOperationException(
"Cannot emit " + node + " of type " + node.getNodeType());
@@ -488,4 +573,64 @@ public class XsltXPathConformanceTestSuite {
}
return result;
}
+
+ /**
+ * Reads the given file into a string. If the file contains a byte order
+ * mark, the corresponding character set will be used. Otherwise the system
+ * default charset will be used.
+ */
+ private String fileToString(File file) throws IOException {
+ InputStream in = new BufferedInputStream(new FileInputStream(file), 1024);
+
+ // Read the byte order mark to determine the charset.
+ // TODO: use a built-in API for this...
+ Reader reader;
+ in.mark(3);
+ int byte1 = in.read();
+ int byte2 = in.read();
+ if (byte1 == 0xFF && byte2 == 0xFE) {
+ reader = new InputStreamReader(in, "UTF-16LE");
+ } else if (byte1 == 0xFF && byte2 == 0xFF) {
+ reader = new InputStreamReader(in, "UTF-16BE");
+ } else {
+ int byte3 = in.read();
+ if (byte1 == 0xEF && byte2 == 0xBB && byte3 == 0xBF) {
+ reader = new InputStreamReader(in, "UTF-8");
+ } else {
+ in.reset();
+ reader = new InputStreamReader(in);
+ }
+ }
+
+ StringWriter out = new StringWriter();
+ char[] buffer = new char[1024];
+ int count;
+ while ((count = reader.read(buffer)) != -1) {
+ out.write(buffer, 0, count);
+ }
+ return out.toString();
+ }
+
+ static class ErrorRecorder implements ErrorListener {
+ Exception warning;
+ Exception error;
+
+ public void warning(TransformerException exception) {
+ if (this.warning == null) {
+ this.warning = exception;
+ }
+ }
+
+ public void error(TransformerException exception) {
+ if (this.error == null) {
+ this.error = exception;
+ }
+ }
+
+ public void fatalError(TransformerException exception) {
+ if (this.error == null) {
+ this.error = exception;
+ }
+ }
+ }
}