Skip to content

Commit 280f86e

Browse files
committed
8289511: Improve test coverage for XPath Axes: child
Backport-of: cfe9026fe0506488cc0f0557299cfa585811d194
1 parent 42acf50 commit 280f86e

File tree

1 file changed

+237
-0
lines changed

1 file changed

+237
-0
lines changed
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package xpath;
24+
25+
import org.testng.Assert;
26+
import org.testng.annotations.DataProvider;
27+
import org.testng.annotations.Test;
28+
import org.w3c.dom.Document;
29+
import org.w3c.dom.Node;
30+
import org.w3c.dom.NodeList;
31+
32+
import javax.xml.parsers.DocumentBuilderFactory;
33+
import javax.xml.xpath.XPath;
34+
import javax.xml.xpath.XPathConstants;
35+
import javax.xml.xpath.XPathExpressionException;
36+
import javax.xml.xpath.XPathFactory;
37+
import java.io.ByteArrayInputStream;
38+
import java.io.InputStream;
39+
40+
/*
41+
* @test
42+
* @bug 8289511
43+
* @run testng/othervm xpath.XPathExpChildTest
44+
* @summary Tests for XPath child axis specifier.
45+
*/
46+
public class XPathExpChildTest {
47+
48+
private static final String XML = """
49+
<store>
50+
<book id="1" lang="en">
51+
<title/>
52+
<author id="1"/>
53+
<isbn>1234</isbn>
54+
</book>
55+
<book id="2" lang="en">
56+
<title/>
57+
<author id="2"/>
58+
<isbn>5678</isbn>
59+
</book>
60+
</store>
61+
""";
62+
private static final String AUTHOR_1 = "author_1";
63+
private static final String AUTHOR_2 = "author_2";
64+
private static final Document doc;
65+
66+
static {
67+
try {
68+
var builder =
69+
DocumentBuilderFactory.newInstance().newDocumentBuilder();
70+
InputStream s = new ByteArrayInputStream(XML.getBytes());
71+
doc = builder.parse(s);
72+
} catch (Exception e) {
73+
System.out.println("Exception while initializing XML document");
74+
throw new RuntimeException(e.getMessage());
75+
}
76+
}
77+
78+
/*
79+
* DataProvider: provides XPath expression and expected result
80+
*/
81+
@DataProvider(name = "parameters")
82+
public Object[][] getXPathExpression() {
83+
return new Object[][]{
84+
// abbreviated text
85+
{"/store/book/author", AUTHOR_1},
86+
{"/child::store/child::book/child::author", AUTHOR_1},
87+
{"/store/child::book/author", AUTHOR_1},
88+
89+
// any nodes
90+
{"/store/book/child::*[2]", AUTHOR_1},
91+
{"/store/child::*[child::author]/author", AUTHOR_1},
92+
{"/store/child::*[child::author][2]/author", AUTHOR_2},
93+
{"/store/child::node()/child::author", AUTHOR_1},
94+
{"/store/child::node()[child::author]/author", AUTHOR_1},
95+
{"/store/child::node()[child::author][2]/author", AUTHOR_2},
96+
97+
// position
98+
{"/store/child::book[position()=1]/author", AUTHOR_1},
99+
{"/store/child::book[last()]/author", AUTHOR_2},
100+
101+
// descendant
102+
{"//book/child::*[2]", AUTHOR_1},
103+
{"//child::*[child::author]/author", AUTHOR_1},
104+
{"//child::*[child::author][2]/author", AUTHOR_2},
105+
{"//child::node()/child::author", AUTHOR_1},
106+
{"//child::node()[child::author]/author", AUTHOR_1},
107+
{"//child::node()[child::author][2]/author", AUTHOR_2},
108+
109+
// parent node
110+
{"//child::book/../child::book/child::author", AUTHOR_1},
111+
112+
// dot reference
113+
{"//child::book/./child::author", AUTHOR_1},
114+
{"//child::node()/./child::author", AUTHOR_1},
115+
{"//././/./child::author", AUTHOR_1},
116+
117+
// attributes
118+
{"/store/child::book[@id=1]/author", AUTHOR_1},
119+
{"/store/child::book[attribute::id=1]/author", AUTHOR_1},
120+
{"/store/child::book[@id]/author", AUTHOR_1},
121+
{"/store/child::book[@id=1][@lang='en']/author", AUTHOR_1},
122+
{"/store/child::book[@lang='en'][1]/author", AUTHOR_1},
123+
{"/store/child::book[child::isbn='1234']/author", AUTHOR_1},
124+
{"/store/child::book[@lang='en' and " +
125+
"child::isbn='1234']/author", AUTHOR_1},
126+
{"/store/child::*[@lang='en'][2]/author", AUTHOR_2},
127+
{"/store/child::node()[@id='1']/author", AUTHOR_1},
128+
{"/store/child::node()[@lang='en'][2]/author", AUTHOR_2},
129+
{"/store/child::*[child::author][child::title][@id='2']/author",
130+
AUTHOR_2},
131+
{"/store/child::*[child::author or child::ssn][@id='2']/author",
132+
AUTHOR_2},
133+
{"/store/child::*[child::*]/author", AUTHOR_1},
134+
{"/store/child::*[attribute::*]/author", AUTHOR_1},
135+
{"/store/*[*][*][*][*][*][*][*][*]/author", AUTHOR_1},
136+
{"/store/*[@*][@*][@*][@*][@*][@*][@*][@*]/author", AUTHOR_1},
137+
{"//author[@*]", AUTHOR_1},
138+
139+
// text node
140+
{"/store/book[1]/isbn/child::text()/../../author", AUTHOR_1},
141+
{"/store/book/isbn[child::text()='5678']/../author", AUTHOR_2},
142+
{"/store/book/isbn[.='5678']/../author", AUTHOR_2},
143+
144+
// count child nodes
145+
{"/store/book[count(./child::author)]/author", AUTHOR_1},
146+
{"/store/book[count(child::author)]/author", AUTHOR_1},
147+
{"/store/book[count(../child::book)]/author", AUTHOR_2},
148+
};
149+
}
150+
151+
/*
152+
* DataProvider: provides XPath expressions that return zero children
153+
*/
154+
@DataProvider(name = "zeroChildrenExp")
155+
public Object[][] getZeroChildrenExp() {
156+
return new Object[][]{
157+
{"/store/book[3]/author"},
158+
{"/store/book/author/ssn"},
159+
{"/store/child[book]/author"},
160+
{"/store/child[@id='1']/book/author"},
161+
{"/store/child::*[@category]/author"},
162+
{"//author[*]/../author"},
163+
{"//title[@*]/../author"},
164+
{"/store/book[-1]/author"},
165+
{"/store/child:book/author"},
166+
{"//book[.='1']/author"},
167+
};
168+
}
169+
170+
/*
171+
* DataProvider: provides invalid XPath expression and expected exception
172+
* to be thrown
173+
*/
174+
@DataProvider(name = "invalidExp")
175+
public Object[][] getInvalidExp() {
176+
return new Object[][]{
177+
// XPathExpressionException
178+
{"/store/*[child::author] and [child::title]/author",
179+
XPathExpressionException.class},
180+
{"//book[@id='en'] and book[@lang='en']/author",
181+
XPathExpressionException.class},
182+
{"/store/book[child::count()]/author",
183+
XPathExpressionException.class},
184+
{"//book[child::position()=1]", XPathExpressionException.class},
185+
};
186+
}
187+
188+
/**
189+
* Verifies XPath child axis specifier.
190+
*
191+
* @param exp XPath expression
192+
* @param expected expected result
193+
* @throws Exception
194+
*/
195+
@Test(dataProvider = "parameters")
196+
void testXPathEvaluate(String exp, String expected) throws Exception {
197+
XPath xPath = XPathFactory.newInstance().newXPath();
198+
NodeList nl = (NodeList) xPath.evaluate(exp, doc,
199+
XPathConstants.NODESET);
200+
Node node = xPath.evaluateExpression(exp, doc, Node.class);
201+
Assert.assertEquals(nl.item(0).getNodeName(), node.getNodeName());
202+
Assert.assertEquals(nl.item(0).getNodeValue(), node.getNodeValue());
203+
Assert.assertEquals(nl.item(0).getAttributes(), node.getAttributes());
204+
205+
Assert.assertEquals(node.getNodeName() + "_" +
206+
node.getAttributes().item(0).getNodeValue(),
207+
expected);
208+
}
209+
210+
/**
211+
* Verifies no child nodes returned from the XPath expression.
212+
*
213+
* @param exp XPath expression
214+
* @throws Exception
215+
*/
216+
@Test(dataProvider = "zeroChildrenExp")
217+
void testZeroChildrenExp(String exp) throws Exception {
218+
XPath xPath = XPathFactory.newInstance().newXPath();
219+
Node node = xPath.evaluateExpression(exp, doc, Node.class);
220+
Assert.assertNull(node);
221+
}
222+
223+
/**
224+
* Verifies exception thrown for invalid expression.
225+
*
226+
* @param exp XPath expression
227+
* @param throwableClass expected exception
228+
* @throws Exception
229+
*/
230+
@Test(dataProvider = "invalidExp")
231+
void testInvalidExp(String exp, Class throwableClass) throws Exception {
232+
XPath xPath = XPathFactory.newInstance().newXPath();
233+
Assert.assertThrows(throwableClass,
234+
() -> ((NodeList) xPath.evaluate(exp, doc,
235+
XPathConstants.NODESET)).item(0).getNodeName());
236+
}
237+
}

0 commit comments

Comments
 (0)