1e209b8615849755908f17053490e168051be97e0Jesse Wilson/* 2e209b8615849755908f17053490e168051be97e0Jesse Wilson * Copyright (C) 2010 The Android Open Source Project 3e209b8615849755908f17053490e168051be97e0Jesse Wilson * 4e209b8615849755908f17053490e168051be97e0Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5e209b8615849755908f17053490e168051be97e0Jesse Wilson * you may not use this file except in compliance with the License. 6e209b8615849755908f17053490e168051be97e0Jesse Wilson * You may obtain a copy of the License at 7e209b8615849755908f17053490e168051be97e0Jesse Wilson * 8e209b8615849755908f17053490e168051be97e0Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9e209b8615849755908f17053490e168051be97e0Jesse Wilson * 10e209b8615849755908f17053490e168051be97e0Jesse Wilson * Unless required by applicable law or agreed to in writing, software 11e209b8615849755908f17053490e168051be97e0Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12e209b8615849755908f17053490e168051be97e0Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e209b8615849755908f17053490e168051be97e0Jesse Wilson * See the License for the specific language governing permissions and 14e209b8615849755908f17053490e168051be97e0Jesse Wilson * limitations under the License. 15e209b8615849755908f17053490e168051be97e0Jesse Wilson */ 16e209b8615849755908f17053490e168051be97e0Jesse Wilson 17e209b8615849755908f17053490e168051be97e0Jesse Wilsonpackage org.apache.harmony.xml; 18e209b8615849755908f17053490e168051be97e0Jesse Wilson 19e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport junit.framework.AssertionFailedError; 20e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport junit.framework.Test; 21e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport junit.framework.TestCase; 22e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport junit.framework.TestSuite; 23e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport junit.textui.TestRunner; 24e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport org.w3c.dom.Element; 25e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport org.w3c.dom.Node; 26e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport org.w3c.dom.NodeList; 27e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport org.xml.sax.InputSource; 28e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport org.xml.sax.SAXException; 29e209b8615849755908f17053490e168051be97e0Jesse Wilson 30e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport javax.xml.namespace.QName; 31e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport javax.xml.parsers.DocumentBuilderFactory; 32e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport javax.xml.parsers.ParserConfigurationException; 33e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport javax.xml.xpath.XPath; 34e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport javax.xml.xpath.XPathConstants; 35e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport javax.xml.xpath.XPathExpressionException; 36e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport javax.xml.xpath.XPathFactory; 37e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport javax.xml.xpath.XPathVariableResolver; 38e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport java.io.File; 39e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport java.io.IOException; 40e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport java.util.ArrayList; 41e209b8615849755908f17053490e168051be97e0Jesse Wilsonimport java.util.List; 42e209b8615849755908f17053490e168051be97e0Jesse Wilson 43e209b8615849755908f17053490e168051be97e0Jesse Wilson/** 44e209b8615849755908f17053490e168051be97e0Jesse Wilson * The implementation-independent part of the <a 45e209b8615849755908f17053490e168051be97e0Jesse Wilson * href="http://jaxen.codehaus.org/">Jaxen</a> XPath test suite, adapted for use 46e209b8615849755908f17053490e168051be97e0Jesse Wilson * by JUnit. To run these tests on a device: 47e209b8615849755908f17053490e168051be97e0Jesse Wilson * <ul> 48e209b8615849755908f17053490e168051be97e0Jesse Wilson * <li>Obtain the Jaxen source from the project's website. 49e209b8615849755908f17053490e168051be97e0Jesse Wilson * <li>Copy the files to a device: <code>adb shell mkdir /data/jaxen ; 50e209b8615849755908f17053490e168051be97e0Jesse Wilson * adb push /home/dalvik-prebuild/jaxen /data/jaxen</code> 51e209b8615849755908f17053490e168051be97e0Jesse Wilson * <li>Invoke this class' main method, passing the on-device path to the test 52e209b8615849755908f17053490e168051be97e0Jesse Wilson * suite's root directory as an argument. 53e209b8615849755908f17053490e168051be97e0Jesse Wilson * </ul> 54e209b8615849755908f17053490e168051be97e0Jesse Wilson */ 55e209b8615849755908f17053490e168051be97e0Jesse Wilsonpublic class JaxenXPathTestSuite { 56e209b8615849755908f17053490e168051be97e0Jesse Wilson 57e209b8615849755908f17053490e168051be97e0Jesse Wilson private static final File DEFAULT_JAXEN_HOME 58e209b8615849755908f17053490e168051be97e0Jesse Wilson = new File("/home/dalvik-prebuild/jaxen"); 59e209b8615849755908f17053490e168051be97e0Jesse Wilson 60e209b8615849755908f17053490e168051be97e0Jesse Wilson public static void main(String[] args) throws Exception { 61e209b8615849755908f17053490e168051be97e0Jesse Wilson if (args.length != 1) { 62e209b8615849755908f17053490e168051be97e0Jesse Wilson System.out.println("Usage: JaxenXPathTestSuite <jaxen-home>"); 63e209b8615849755908f17053490e168051be97e0Jesse Wilson return; 64e209b8615849755908f17053490e168051be97e0Jesse Wilson } 65e209b8615849755908f17053490e168051be97e0Jesse Wilson 66e209b8615849755908f17053490e168051be97e0Jesse Wilson File jaxenHome = new File(args[0]); 67e209b8615849755908f17053490e168051be97e0Jesse Wilson TestRunner.run(suite(jaxenHome)); 68e209b8615849755908f17053490e168051be97e0Jesse Wilson } 69e209b8615849755908f17053490e168051be97e0Jesse Wilson 70e209b8615849755908f17053490e168051be97e0Jesse Wilson public static Test suite() throws Exception { 71e209b8615849755908f17053490e168051be97e0Jesse Wilson return suite(DEFAULT_JAXEN_HOME); 72e209b8615849755908f17053490e168051be97e0Jesse Wilson } 73e209b8615849755908f17053490e168051be97e0Jesse Wilson 74e209b8615849755908f17053490e168051be97e0Jesse Wilson /** 75e209b8615849755908f17053490e168051be97e0Jesse Wilson * Creates a test suite from the Jaxen tests.xml catalog. 76e209b8615849755908f17053490e168051be97e0Jesse Wilson */ 77e209b8615849755908f17053490e168051be97e0Jesse Wilson public static Test suite(File jaxenHome) 78e209b8615849755908f17053490e168051be97e0Jesse Wilson throws ParserConfigurationException, IOException, SAXException { 79e209b8615849755908f17053490e168051be97e0Jesse Wilson 80e209b8615849755908f17053490e168051be97e0Jesse Wilson /* 81e209b8615849755908f17053490e168051be97e0Jesse Wilson * The tests.xml document has this structure: 82e209b8615849755908f17053490e168051be97e0Jesse Wilson * 83e209b8615849755908f17053490e168051be97e0Jesse Wilson * <tests> 84e209b8615849755908f17053490e168051be97e0Jesse Wilson * <document url="..."> 85e209b8615849755908f17053490e168051be97e0Jesse Wilson * <context .../> 86e209b8615849755908f17053490e168051be97e0Jesse Wilson * <context .../> 87e209b8615849755908f17053490e168051be97e0Jesse Wilson * <context .../> 88e209b8615849755908f17053490e168051be97e0Jesse Wilson * </document> 89e209b8615849755908f17053490e168051be97e0Jesse Wilson * <document url="..."> 90e209b8615849755908f17053490e168051be97e0Jesse Wilson * <context .../> 91e209b8615849755908f17053490e168051be97e0Jesse Wilson * </document> 92e209b8615849755908f17053490e168051be97e0Jesse Wilson * </tests> 93e209b8615849755908f17053490e168051be97e0Jesse Wilson */ 94e209b8615849755908f17053490e168051be97e0Jesse Wilson 95e209b8615849755908f17053490e168051be97e0Jesse Wilson File testsXml = new File(jaxenHome + "/xml/test/tests.xml"); 96e209b8615849755908f17053490e168051be97e0Jesse Wilson Element tests = DocumentBuilderFactory.newInstance() 97e209b8615849755908f17053490e168051be97e0Jesse Wilson .newDocumentBuilder().parse(testsXml).getDocumentElement(); 98e209b8615849755908f17053490e168051be97e0Jesse Wilson 99e209b8615849755908f17053490e168051be97e0Jesse Wilson TestSuite result = new TestSuite(); 100e209b8615849755908f17053490e168051be97e0Jesse Wilson for (Element document : elementsOf(tests.getElementsByTagName("document"))) { 101e209b8615849755908f17053490e168051be97e0Jesse Wilson String url = document.getAttribute("url"); 102e209b8615849755908f17053490e168051be97e0Jesse Wilson InputSource inputSource = new InputSource("file:" + jaxenHome + "/" + url); 103e209b8615849755908f17053490e168051be97e0Jesse Wilson for (final Element context : elementsOf(document.getElementsByTagName("context"))) { 104e209b8615849755908f17053490e168051be97e0Jesse Wilson contextToTestSuite(result, url, inputSource, context); 105e209b8615849755908f17053490e168051be97e0Jesse Wilson } 106e209b8615849755908f17053490e168051be97e0Jesse Wilson } 107e209b8615849755908f17053490e168051be97e0Jesse Wilson 108e209b8615849755908f17053490e168051be97e0Jesse Wilson return result; 109e209b8615849755908f17053490e168051be97e0Jesse Wilson } 110e209b8615849755908f17053490e168051be97e0Jesse Wilson 111e209b8615849755908f17053490e168051be97e0Jesse Wilson /** 112e209b8615849755908f17053490e168051be97e0Jesse Wilson * Populates the test suite with tests from the given XML context element. 113e209b8615849755908f17053490e168051be97e0Jesse Wilson */ 114e209b8615849755908f17053490e168051be97e0Jesse Wilson private static void contextToTestSuite(TestSuite suite, String url, 115e209b8615849755908f17053490e168051be97e0Jesse Wilson InputSource inputSource, Element element) { 116e209b8615849755908f17053490e168051be97e0Jesse Wilson 117e209b8615849755908f17053490e168051be97e0Jesse Wilson /* 118e209b8615849755908f17053490e168051be97e0Jesse Wilson * Each context element has this structure: 119e209b8615849755908f17053490e168051be97e0Jesse Wilson * 120e209b8615849755908f17053490e168051be97e0Jesse Wilson * <context select="..."> 121e209b8615849755908f17053490e168051be97e0Jesse Wilson * <test .../> 122e209b8615849755908f17053490e168051be97e0Jesse Wilson * <test .../> 123e209b8615849755908f17053490e168051be97e0Jesse Wilson * <test .../> 124e209b8615849755908f17053490e168051be97e0Jesse Wilson * <valueOf .../> 125e209b8615849755908f17053490e168051be97e0Jesse Wilson * <valueOf .../> 126e209b8615849755908f17053490e168051be97e0Jesse Wilson * <valueOf .../> 127e209b8615849755908f17053490e168051be97e0Jesse Wilson * </context> 128e209b8615849755908f17053490e168051be97e0Jesse Wilson */ 129e209b8615849755908f17053490e168051be97e0Jesse Wilson 130e209b8615849755908f17053490e168051be97e0Jesse Wilson String select = element.getAttribute("select"); 131e209b8615849755908f17053490e168051be97e0Jesse Wilson Context context = new Context(inputSource, url, select); 132e209b8615849755908f17053490e168051be97e0Jesse Wilson 133e209b8615849755908f17053490e168051be97e0Jesse Wilson XPath xpath = XPathFactory.newInstance().newXPath(); 134e209b8615849755908f17053490e168051be97e0Jesse Wilson xpath.setXPathVariableResolver(new ElementVariableResolver(element)); 135e209b8615849755908f17053490e168051be97e0Jesse Wilson 136e209b8615849755908f17053490e168051be97e0Jesse Wilson for (Element test : elementsOf(element.getChildNodes())) { 137e209b8615849755908f17053490e168051be97e0Jesse Wilson if (test.getTagName().equals("test")) { 138e209b8615849755908f17053490e168051be97e0Jesse Wilson suite.addTest(createFromTest(xpath, context, test)); 139e209b8615849755908f17053490e168051be97e0Jesse Wilson 140e209b8615849755908f17053490e168051be97e0Jesse Wilson } else if (test.getTagName().equals("valueOf")) { 141e209b8615849755908f17053490e168051be97e0Jesse Wilson suite.addTest(createFromValueOf(xpath, context, test)); 142e209b8615849755908f17053490e168051be97e0Jesse Wilson 143e209b8615849755908f17053490e168051be97e0Jesse Wilson } else { 144e209b8615849755908f17053490e168051be97e0Jesse Wilson throw new UnsupportedOperationException("Unsupported test: " + context); 145e209b8615849755908f17053490e168051be97e0Jesse Wilson } 146e209b8615849755908f17053490e168051be97e0Jesse Wilson } 147e209b8615849755908f17053490e168051be97e0Jesse Wilson } 148e209b8615849755908f17053490e168051be97e0Jesse Wilson 149e209b8615849755908f17053490e168051be97e0Jesse Wilson /** 150e209b8615849755908f17053490e168051be97e0Jesse Wilson * Returns the test described by the given {@code <test>} element. Such 151e209b8615849755908f17053490e168051be97e0Jesse Wilson * tests come in one of three varieties: 152e209b8615849755908f17053490e168051be97e0Jesse Wilson * 153e209b8615849755908f17053490e168051be97e0Jesse Wilson * <ul> 154e209b8615849755908f17053490e168051be97e0Jesse Wilson * <li>Expected failures. 155e209b8615849755908f17053490e168051be97e0Jesse Wilson * <li>String matches. These tests have a nested {@code <valueOf>} element 156e209b8615849755908f17053490e168051be97e0Jesse Wilson * that sub-selects an expected text. 157e209b8615849755908f17053490e168051be97e0Jesse Wilson * <li>Count matches. These tests specify how many nodes are expected to 158e209b8615849755908f17053490e168051be97e0Jesse Wilson * match. 159e209b8615849755908f17053490e168051be97e0Jesse Wilson * </ul> 160e209b8615849755908f17053490e168051be97e0Jesse Wilson */ 161e209b8615849755908f17053490e168051be97e0Jesse Wilson private static TestCase createFromTest( 162e209b8615849755908f17053490e168051be97e0Jesse Wilson final XPath xpath, final Context context, final Element element) { 163e209b8615849755908f17053490e168051be97e0Jesse Wilson final String select = element.getAttribute("select"); 164e209b8615849755908f17053490e168051be97e0Jesse Wilson 165e209b8615849755908f17053490e168051be97e0Jesse Wilson /* Such as <test exception="true" select="..." count="0"/> */ 166e209b8615849755908f17053490e168051be97e0Jesse Wilson if (element.getAttribute("exception").equals("true")) { 167e209b8615849755908f17053490e168051be97e0Jesse Wilson return new XPathTest(context, select) { 168e209b8615849755908f17053490e168051be97e0Jesse Wilson @Override void test(Node contextNode) { 169e209b8615849755908f17053490e168051be97e0Jesse Wilson try { 170e209b8615849755908f17053490e168051be97e0Jesse Wilson xpath.evaluate(select, contextNode); 171e209b8615849755908f17053490e168051be97e0Jesse Wilson fail("Expected exception!"); 172e209b8615849755908f17053490e168051be97e0Jesse Wilson } catch (XPathExpressionException expected) { 173e209b8615849755908f17053490e168051be97e0Jesse Wilson } 174e209b8615849755908f17053490e168051be97e0Jesse Wilson } 175e209b8615849755908f17053490e168051be97e0Jesse Wilson }; 176e209b8615849755908f17053490e168051be97e0Jesse Wilson } 177e209b8615849755908f17053490e168051be97e0Jesse Wilson 178e209b8615849755908f17053490e168051be97e0Jesse Wilson /* a <test> with a nested <valueOf>, both of which have select attributes */ 179e209b8615849755908f17053490e168051be97e0Jesse Wilson NodeList valueOfElements = element.getElementsByTagName("valueOf"); 180e209b8615849755908f17053490e168051be97e0Jesse Wilson if (valueOfElements.getLength() == 1) { 181e209b8615849755908f17053490e168051be97e0Jesse Wilson final Element valueOf = (Element) valueOfElements.item(0); 182e209b8615849755908f17053490e168051be97e0Jesse Wilson final String valueOfSelect = valueOf.getAttribute("select"); 183e209b8615849755908f17053490e168051be97e0Jesse Wilson 184e209b8615849755908f17053490e168051be97e0Jesse Wilson return new XPathTest(context, select) { 185e209b8615849755908f17053490e168051be97e0Jesse Wilson @Override void test(Node contextNode) throws XPathExpressionException { 186e209b8615849755908f17053490e168051be97e0Jesse Wilson Node newContext = (Node) xpath.evaluate( 187e209b8615849755908f17053490e168051be97e0Jesse Wilson select, contextNode, XPathConstants.NODE); 188e209b8615849755908f17053490e168051be97e0Jesse Wilson assertEquals(valueOf.getTextContent(), 189e209b8615849755908f17053490e168051be97e0Jesse Wilson xpath.evaluate(valueOfSelect, newContext, XPathConstants.STRING)); 190e209b8615849755908f17053490e168051be97e0Jesse Wilson } 191e209b8615849755908f17053490e168051be97e0Jesse Wilson }; 192e209b8615849755908f17053490e168051be97e0Jesse Wilson } 193e209b8615849755908f17053490e168051be97e0Jesse Wilson 194e209b8615849755908f17053490e168051be97e0Jesse Wilson /* Such as <test select="..." count="5"/> */ 195e209b8615849755908f17053490e168051be97e0Jesse Wilson final String count = element.getAttribute("count"); 196e209b8615849755908f17053490e168051be97e0Jesse Wilson if (count.length() > 0) { 197e209b8615849755908f17053490e168051be97e0Jesse Wilson return new XPathTest(context, select) { 198e209b8615849755908f17053490e168051be97e0Jesse Wilson @Override void test(Node contextNode) throws XPathExpressionException { 199e209b8615849755908f17053490e168051be97e0Jesse Wilson NodeList result = (NodeList) xpath.evaluate( 200e209b8615849755908f17053490e168051be97e0Jesse Wilson select, contextNode, XPathConstants.NODESET); 201e209b8615849755908f17053490e168051be97e0Jesse Wilson assertEquals(Integer.parseInt(count), result.getLength()); 202e209b8615849755908f17053490e168051be97e0Jesse Wilson } 203e209b8615849755908f17053490e168051be97e0Jesse Wilson }; 204e209b8615849755908f17053490e168051be97e0Jesse Wilson } 205e209b8615849755908f17053490e168051be97e0Jesse Wilson 206e209b8615849755908f17053490e168051be97e0Jesse Wilson throw new UnsupportedOperationException("Unsupported test: " + context); 207e209b8615849755908f17053490e168051be97e0Jesse Wilson } 208e209b8615849755908f17053490e168051be97e0Jesse Wilson 209e209b8615849755908f17053490e168051be97e0Jesse Wilson /** 210e209b8615849755908f17053490e168051be97e0Jesse Wilson * Returns the test described by the given {@code <valueOf>} element. These 211e209b8615849755908f17053490e168051be97e0Jesse Wilson * tests select an expected text. 212e209b8615849755908f17053490e168051be97e0Jesse Wilson */ 213e209b8615849755908f17053490e168051be97e0Jesse Wilson private static TestCase createFromValueOf( 214e209b8615849755908f17053490e168051be97e0Jesse Wilson final XPath xpath, final Context context, final Element element) { 215e209b8615849755908f17053490e168051be97e0Jesse Wilson final String select = element.getAttribute("select"); 216e209b8615849755908f17053490e168051be97e0Jesse Wilson return new XPathTest(context, select) { 217e209b8615849755908f17053490e168051be97e0Jesse Wilson @Override void test(Node contextNode) throws XPathExpressionException { 218e209b8615849755908f17053490e168051be97e0Jesse Wilson assertEquals(element.getTextContent(), 219e209b8615849755908f17053490e168051be97e0Jesse Wilson xpath.evaluate(select, contextNode, XPathConstants.STRING)); 220e209b8615849755908f17053490e168051be97e0Jesse Wilson } 221e209b8615849755908f17053490e168051be97e0Jesse Wilson }; 222e209b8615849755908f17053490e168051be97e0Jesse Wilson } 223e209b8615849755908f17053490e168051be97e0Jesse Wilson 224e209b8615849755908f17053490e168051be97e0Jesse Wilson /** 225e209b8615849755908f17053490e168051be97e0Jesse Wilson * The subject of an XPath query. This is itself defined by an XPath query, 226e209b8615849755908f17053490e168051be97e0Jesse Wilson * so each test requires at least XPath expressions to be evaluated. 227e209b8615849755908f17053490e168051be97e0Jesse Wilson */ 228e209b8615849755908f17053490e168051be97e0Jesse Wilson static class Context { 229e209b8615849755908f17053490e168051be97e0Jesse Wilson private final InputSource inputSource; 230e209b8615849755908f17053490e168051be97e0Jesse Wilson private final String url; 231e209b8615849755908f17053490e168051be97e0Jesse Wilson private final String select; 232e209b8615849755908f17053490e168051be97e0Jesse Wilson 233e209b8615849755908f17053490e168051be97e0Jesse Wilson Context(InputSource inputSource, String url, String select) { 234e209b8615849755908f17053490e168051be97e0Jesse Wilson this.inputSource = inputSource; 235e209b8615849755908f17053490e168051be97e0Jesse Wilson this.url = url; 236e209b8615849755908f17053490e168051be97e0Jesse Wilson this.select = select; 237e209b8615849755908f17053490e168051be97e0Jesse Wilson } 238e209b8615849755908f17053490e168051be97e0Jesse Wilson 239e209b8615849755908f17053490e168051be97e0Jesse Wilson Node getNode() { 240e209b8615849755908f17053490e168051be97e0Jesse Wilson XPath xpath = XPathFactory.newInstance().newXPath(); 241e209b8615849755908f17053490e168051be97e0Jesse Wilson try { 242e209b8615849755908f17053490e168051be97e0Jesse Wilson return (Node) xpath.evaluate(select, inputSource, XPathConstants.NODE); 243e209b8615849755908f17053490e168051be97e0Jesse Wilson } catch (XPathExpressionException e) { 244e209b8615849755908f17053490e168051be97e0Jesse Wilson Error error = new AssertionFailedError("Failed to get context"); 245e209b8615849755908f17053490e168051be97e0Jesse Wilson error.initCause(e); 246e209b8615849755908f17053490e168051be97e0Jesse Wilson throw error; 247e209b8615849755908f17053490e168051be97e0Jesse Wilson } 248e209b8615849755908f17053490e168051be97e0Jesse Wilson } 249e209b8615849755908f17053490e168051be97e0Jesse Wilson 250e209b8615849755908f17053490e168051be97e0Jesse Wilson @Override public String toString() { 251e209b8615849755908f17053490e168051be97e0Jesse Wilson return url + " " + select; 252e209b8615849755908f17053490e168051be97e0Jesse Wilson } 253e209b8615849755908f17053490e168051be97e0Jesse Wilson } 254e209b8615849755908f17053490e168051be97e0Jesse Wilson 255e209b8615849755908f17053490e168051be97e0Jesse Wilson /** 256e209b8615849755908f17053490e168051be97e0Jesse Wilson * This test evaluates an XPath expression against a context node and 257e209b8615849755908f17053490e168051be97e0Jesse Wilson * compares the result to a known expectation. 258e209b8615849755908f17053490e168051be97e0Jesse Wilson */ 259e209b8615849755908f17053490e168051be97e0Jesse Wilson public abstract static class XPathTest extends TestCase { 260e209b8615849755908f17053490e168051be97e0Jesse Wilson private final Context context; 261e209b8615849755908f17053490e168051be97e0Jesse Wilson private final String select; 262e209b8615849755908f17053490e168051be97e0Jesse Wilson 263e209b8615849755908f17053490e168051be97e0Jesse Wilson public XPathTest(Context context, String select) { 264e209b8615849755908f17053490e168051be97e0Jesse Wilson super("test"); 265e209b8615849755908f17053490e168051be97e0Jesse Wilson this.context = context; 266e209b8615849755908f17053490e168051be97e0Jesse Wilson this.select = select; 267e209b8615849755908f17053490e168051be97e0Jesse Wilson } 268e209b8615849755908f17053490e168051be97e0Jesse Wilson 269e209b8615849755908f17053490e168051be97e0Jesse Wilson abstract void test(Node contextNode) throws XPathExpressionException; 270e209b8615849755908f17053490e168051be97e0Jesse Wilson 271e209b8615849755908f17053490e168051be97e0Jesse Wilson public final void test() throws XPathExpressionException { 272e209b8615849755908f17053490e168051be97e0Jesse Wilson try { 273e209b8615849755908f17053490e168051be97e0Jesse Wilson test(context.getNode()); 274e209b8615849755908f17053490e168051be97e0Jesse Wilson } catch (XPathExpressionException e) { 275e209b8615849755908f17053490e168051be97e0Jesse Wilson if (isMissingFunction(e)) { 276e209b8615849755908f17053490e168051be97e0Jesse Wilson fail(e.getCause().getMessage()); 277e209b8615849755908f17053490e168051be97e0Jesse Wilson } else { 278e209b8615849755908f17053490e168051be97e0Jesse Wilson throw e; 279e209b8615849755908f17053490e168051be97e0Jesse Wilson } 280e209b8615849755908f17053490e168051be97e0Jesse Wilson } 281e209b8615849755908f17053490e168051be97e0Jesse Wilson } 282e209b8615849755908f17053490e168051be97e0Jesse Wilson 283e209b8615849755908f17053490e168051be97e0Jesse Wilson private boolean isMissingFunction(XPathExpressionException e) { 284e209b8615849755908f17053490e168051be97e0Jesse Wilson return e.getCause() != null 285e209b8615849755908f17053490e168051be97e0Jesse Wilson && e.getCause().getMessage().startsWith("Could not find function"); 286e209b8615849755908f17053490e168051be97e0Jesse Wilson } 287e209b8615849755908f17053490e168051be97e0Jesse Wilson 288e209b8615849755908f17053490e168051be97e0Jesse Wilson @Override public String getName() { 289e209b8615849755908f17053490e168051be97e0Jesse Wilson return context + " " + select; 290e209b8615849755908f17053490e168051be97e0Jesse Wilson } 291e209b8615849755908f17053490e168051be97e0Jesse Wilson } 292e209b8615849755908f17053490e168051be97e0Jesse Wilson 293e209b8615849755908f17053490e168051be97e0Jesse Wilson /** 294e209b8615849755908f17053490e168051be97e0Jesse Wilson * Performs XPath variable resolution by using {@code var:name="value"} 295e209b8615849755908f17053490e168051be97e0Jesse Wilson * attributes from the given element. 296e209b8615849755908f17053490e168051be97e0Jesse Wilson */ 297e209b8615849755908f17053490e168051be97e0Jesse Wilson private static class ElementVariableResolver implements XPathVariableResolver { 298e209b8615849755908f17053490e168051be97e0Jesse Wilson private final Element element; 299e209b8615849755908f17053490e168051be97e0Jesse Wilson public ElementVariableResolver(Element element) { 300e209b8615849755908f17053490e168051be97e0Jesse Wilson this.element = element; 301e209b8615849755908f17053490e168051be97e0Jesse Wilson } 302e209b8615849755908f17053490e168051be97e0Jesse Wilson public Object resolveVariable(QName variableName) { 303e209b8615849755908f17053490e168051be97e0Jesse Wilson return element.getAttribute("var:" + variableName.getLocalPart()); 304e209b8615849755908f17053490e168051be97e0Jesse Wilson } 305e209b8615849755908f17053490e168051be97e0Jesse Wilson } 306e209b8615849755908f17053490e168051be97e0Jesse Wilson 307e209b8615849755908f17053490e168051be97e0Jesse Wilson private static List<Element> elementsOf(NodeList nodeList) { 308e209b8615849755908f17053490e168051be97e0Jesse Wilson List<Element> result = new ArrayList<Element>(); 309e209b8615849755908f17053490e168051be97e0Jesse Wilson for (int i = 0; i < nodeList.getLength(); i++) { 310e209b8615849755908f17053490e168051be97e0Jesse Wilson Node node = nodeList.item(i); 311e209b8615849755908f17053490e168051be97e0Jesse Wilson if (node instanceof Element) { 312e209b8615849755908f17053490e168051be97e0Jesse Wilson result.add((Element) node); 313e209b8615849755908f17053490e168051be97e0Jesse Wilson } 314e209b8615849755908f17053490e168051be97e0Jesse Wilson } 315e209b8615849755908f17053490e168051be97e0Jesse Wilson return result; 316e209b8615849755908f17053490e168051be97e0Jesse Wilson } 317e209b8615849755908f17053490e168051be97e0Jesse Wilson} 318