summaryrefslogtreecommitdiffstats
path: root/xml/src
diff options
context:
space:
mode:
authorJesse Wilson <jessewilson@google.com>2010-03-17 11:46:54 -0700
committerAndroid Git Automerger <android-git-automerger@android.com>2010-03-17 11:46:54 -0700
commit55b6240ddc4f221a2d925b8feda3ad8113a49187 (patch)
tree611c4a038aab2c8fd67103ecfbf15139243e315a /xml/src
parenteacb682a198cdaad72e90b1efa8532b5d7030db4 (diff)
parent1c5cae46e7b13df73a09504fbe43a78bb6ec41e2 (diff)
downloadlibcore-55b6240ddc4f221a2d925b8feda3ad8113a49187.zip
libcore-55b6240ddc4f221a2d925b8feda3ad8113a49187.tar.gz
libcore-55b6240ddc4f221a2d925b8feda3ad8113a49187.tar.bz2
am f6976780: Merge "Exercising our XPath implementation with 279 of Jaxen\'s tests."
Merge commit 'f6976780647c6b9bb168cc7a9c5c8f4ce1425caf' into dalvik-dev * commit 'f6976780647c6b9bb168cc7a9c5c8f4ce1425caf': Exercising our XPath implementation with 279 of Jaxen's tests.
Diffstat (limited to 'xml/src')
-rw-r--r--xml/src/test/java/org/apache/harmony/xml/JaxenXPathTestSuite.java317
-rw-r--r--xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java2
2 files changed, 318 insertions, 1 deletions
diff --git a/xml/src/test/java/org/apache/harmony/xml/JaxenXPathTestSuite.java b/xml/src/test/java/org/apache/harmony/xml/JaxenXPathTestSuite.java
new file mode 100644
index 0000000..e752fc0
--- /dev/null
+++ b/xml/src/test/java/org/apache/harmony/xml/JaxenXPathTestSuite.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package org.apache.harmony.xml;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import javax.xml.xpath.XPathVariableResolver;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The implementation-independent part of the <a
+ * href="http://jaxen.codehaus.org/">Jaxen</a> XPath test suite, adapted for use
+ * by JUnit. To run these tests on a device:
+ * <ul>
+ * <li>Obtain the Jaxen source from the project's website.
+ * <li>Copy the files to a device: <code>adb shell mkdir /data/jaxen ;
+ * adb push /home/dalvik-prebuild/jaxen /data/jaxen</code>
+ * <li>Invoke this class' main method, passing the on-device path to the test
+ * suite's root directory as an argument.
+ * </ul>
+ */
+public class JaxenXPathTestSuite {
+
+ private static final File DEFAULT_JAXEN_HOME
+ = new File("/home/dalvik-prebuild/jaxen");
+
+ public static void main(String[] args) throws Exception {
+ if (args.length != 1) {
+ System.out.println("Usage: JaxenXPathTestSuite <jaxen-home>");
+ return;
+ }
+
+ File jaxenHome = new File(args[0]);
+ TestRunner.run(suite(jaxenHome));
+ }
+
+ public static Test suite() throws Exception {
+ return suite(DEFAULT_JAXEN_HOME);
+ }
+
+ /**
+ * Creates a test suite from the Jaxen tests.xml catalog.
+ */
+ public static Test suite(File jaxenHome)
+ throws ParserConfigurationException, IOException, SAXException {
+
+ /*
+ * The tests.xml document has this structure:
+ *
+ * <tests>
+ * <document url="...">
+ * <context .../>
+ * <context .../>
+ * <context .../>
+ * </document>
+ * <document url="...">
+ * <context .../>
+ * </document>
+ * </tests>
+ */
+
+ File testsXml = new File(jaxenHome + "/xml/test/tests.xml");
+ Element tests = DocumentBuilderFactory.newInstance()
+ .newDocumentBuilder().parse(testsXml).getDocumentElement();
+
+ TestSuite result = new TestSuite();
+ for (Element document : elementsOf(tests.getElementsByTagName("document"))) {
+ String url = document.getAttribute("url");
+ InputSource inputSource = new InputSource("file:" + jaxenHome + "/" + url);
+ for (final Element context : elementsOf(document.getElementsByTagName("context"))) {
+ contextToTestSuite(result, url, inputSource, context);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Populates the test suite with tests from the given XML context element.
+ */
+ private static void contextToTestSuite(TestSuite suite, String url,
+ InputSource inputSource, Element element) {
+
+ /*
+ * Each context element has this structure:
+ *
+ * <context select="...">
+ * <test .../>
+ * <test .../>
+ * <test .../>
+ * <valueOf .../>
+ * <valueOf .../>
+ * <valueOf .../>
+ * </context>
+ */
+
+ String select = element.getAttribute("select");
+ Context context = new Context(inputSource, url, select);
+
+ XPath xpath = XPathFactory.newInstance().newXPath();
+ xpath.setXPathVariableResolver(new ElementVariableResolver(element));
+
+ for (Element test : elementsOf(element.getChildNodes())) {
+ if (test.getTagName().equals("test")) {
+ suite.addTest(createFromTest(xpath, context, test));
+
+ } else if (test.getTagName().equals("valueOf")) {
+ suite.addTest(createFromValueOf(xpath, context, test));
+
+ } else {
+ throw new UnsupportedOperationException("Unsupported test: " + context);
+ }
+ }
+ }
+
+ /**
+ * Returns the test described by the given {@code <test>} element. Such
+ * tests come in one of three varieties:
+ *
+ * <ul>
+ * <li>Expected failures.
+ * <li>String matches. These tests have a nested {@code <valueOf>} element
+ * that sub-selects an expected text.
+ * <li>Count matches. These tests specify how many nodes are expected to
+ * match.
+ * </ul>
+ */
+ private static TestCase createFromTest(
+ final XPath xpath, final Context context, final Element element) {
+ final String select = element.getAttribute("select");
+
+ /* Such as <test exception="true" select="..." count="0"/> */
+ if (element.getAttribute("exception").equals("true")) {
+ return new XPathTest(context, select) {
+ @Override void test(Node contextNode) {
+ try {
+ xpath.evaluate(select, contextNode);
+ fail("Expected exception!");
+ } catch (XPathExpressionException expected) {
+ }
+ }
+ };
+ }
+
+ /* a <test> with a nested <valueOf>, both of which have select attributes */
+ NodeList valueOfElements = element.getElementsByTagName("valueOf");
+ if (valueOfElements.getLength() == 1) {
+ final Element valueOf = (Element) valueOfElements.item(0);
+ final String valueOfSelect = valueOf.getAttribute("select");
+
+ return new XPathTest(context, select) {
+ @Override void test(Node contextNode) throws XPathExpressionException {
+ Node newContext = (Node) xpath.evaluate(
+ select, contextNode, XPathConstants.NODE);
+ assertEquals(valueOf.getTextContent(),
+ xpath.evaluate(valueOfSelect, newContext, XPathConstants.STRING));
+ }
+ };
+ }
+
+ /* Such as <test select="..." count="5"/> */
+ final String count = element.getAttribute("count");
+ if (count.length() > 0) {
+ return new XPathTest(context, select) {
+ @Override void test(Node contextNode) throws XPathExpressionException {
+ NodeList result = (NodeList) xpath.evaluate(
+ select, contextNode, XPathConstants.NODESET);
+ assertEquals(Integer.parseInt(count), result.getLength());
+ }
+ };
+ }
+
+ throw new UnsupportedOperationException("Unsupported test: " + context);
+ }
+
+ /**
+ * Returns the test described by the given {@code <valueOf>} element. These
+ * tests select an expected text.
+ */
+ private static TestCase createFromValueOf(
+ final XPath xpath, final Context context, final Element element) {
+ final String select = element.getAttribute("select");
+ return new XPathTest(context, select) {
+ @Override void test(Node contextNode) throws XPathExpressionException {
+ assertEquals(element.getTextContent(),
+ xpath.evaluate(select, contextNode, XPathConstants.STRING));
+ }
+ };
+ }
+
+ /**
+ * The subject of an XPath query. This is itself defined by an XPath query,
+ * so each test requires at least XPath expressions to be evaluated.
+ */
+ static class Context {
+ private final InputSource inputSource;
+ private final String url;
+ private final String select;
+
+ Context(InputSource inputSource, String url, String select) {
+ this.inputSource = inputSource;
+ this.url = url;
+ this.select = select;
+ }
+
+ Node getNode() {
+ XPath xpath = XPathFactory.newInstance().newXPath();
+ try {
+ return (Node) xpath.evaluate(select, inputSource, XPathConstants.NODE);
+ } catch (XPathExpressionException e) {
+ Error error = new AssertionFailedError("Failed to get context");
+ error.initCause(e);
+ throw error;
+ }
+ }
+
+ @Override public String toString() {
+ return url + " " + select;
+ }
+ }
+
+ /**
+ * This test evaluates an XPath expression against a context node and
+ * compares the result to a known expectation.
+ */
+ public abstract static class XPathTest extends TestCase {
+ private final Context context;
+ private final String select;
+
+ public XPathTest(Context context, String select) {
+ super("test");
+ this.context = context;
+ this.select = select;
+ }
+
+ abstract void test(Node contextNode) throws XPathExpressionException;
+
+ public final void test() throws XPathExpressionException {
+ try {
+ test(context.getNode());
+ } catch (XPathExpressionException e) {
+ if (isMissingFunction(e)) {
+ fail(e.getCause().getMessage());
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ private boolean isMissingFunction(XPathExpressionException e) {
+ return e.getCause() != null
+ && e.getCause().getMessage().startsWith("Could not find function");
+ }
+
+ @Override public String getName() {
+ return context + " " + select;
+ }
+ }
+
+ /**
+ * Performs XPath variable resolution by using {@code var:name="value"}
+ * attributes from the given element.
+ */
+ private static class ElementVariableResolver implements XPathVariableResolver {
+ private final Element element;
+ public ElementVariableResolver(Element element) {
+ this.element = element;
+ }
+ public Object resolveVariable(QName variableName) {
+ return element.getAttribute("var:" + variableName.getLocalPart());
+ }
+ }
+
+ private static List<Element> elementsOf(NodeList nodeList) {
+ List<Element> result = new ArrayList<Element>();
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ Node node = nodeList.item(i);
+ if (node instanceof Element) {
+ result.add((Element) node);
+ }
+ }
+ return result;
+ }
+}
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 0438e98..3f0d2cb 100644
--- a/xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java
+++ b/xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java
@@ -73,7 +73,7 @@ import java.util.List;
* 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>.
+ * 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>