Skip to content

Commit fafd082

Browse files
committedMay 8, 2023
8289509: Improve test coverage for XPath Axes: descendant, descendant-or-self, following, following-sibling
Backport-of: 1961e81e02e707cd0c8241aa3af6ddabf7668589
1 parent 2aaf3c5 commit fafd082

File tree

2 files changed

+358
-0
lines changed

2 files changed

+358
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
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+
24+
package xpath;
25+
26+
27+
import javax.xml.xpath.XPath;
28+
import javax.xml.xpath.XPathConstants;
29+
import javax.xml.xpath.XPathExpressionException;
30+
import javax.xml.xpath.XPathFactory;
31+
32+
import org.testng.Assert;
33+
import org.testng.annotations.DataProvider;
34+
import org.testng.annotations.Test;
35+
import org.w3c.dom.Document;
36+
import org.w3c.dom.Node;
37+
import org.w3c.dom.NodeList;
38+
39+
/*
40+
* @test
41+
* @bug 8289509
42+
* @library /javax/xml/jaxp/unittest
43+
* @run testng/othervm xpath.XPathExpDescendantTest
44+
* @summary Tests for XPath descendant/descendant-or-self axis specifier.
45+
*/
46+
public class XPathExpDescendantTest extends XPathTestBase {
47+
48+
/*
49+
* DataProvider: provides XPath Axis descendant expressions and equivalent xpath expression.
50+
*/
51+
@DataProvider(name = "descendantXpath")
52+
public Object[][] getDescendantXpathExpression() {
53+
return new Object[][] {
54+
{"/Customers/descendant::*", "/Customers//*"},
55+
{"/Customers/descendant::Customer", "//Customer"},
56+
{"/Customers/descendant::foo:Customer", "//foo:Customer"},
57+
{"/Customers/Customer[@id='x1']/descendant::Address",
58+
"/Customers/Customer[@id='x1']/Address"},
59+
{"/Customers/Customer[@id='x1']/descendant::*",
60+
"/Customers/Customer[@id='x1']//*"},
61+
{"/Customers/foo:Customer/foo:Address/descendant::*",
62+
"/Customers/foo:Customer/foo:Address//*"},
63+
{"/Customers/descendant::Name", "/Customers//Name"},
64+
{"/Customers/descendant::Street", "/Customers//Street"},
65+
{"/Customers/descendant::Street[2]", "Customers/Customer[@id='x2']/Address/Street"},
66+
{"/Customers/descendant::Street[2]", "(Customers//Street)[2]"},
67+
{"/Customers/descendant::Street[position() = 2]",
68+
"Customers/Customer[@id='x2']/Address/Street"},
69+
{"/Customers/descendant-or-self::*", "//*"},
70+
{"/Customers/descendant-or-self::Customer", "/Customers/Customer"},
71+
{"/Customers/descendant-or-self::foo:Customer", "/Customers/foo:Customer"},
72+
{"/Customers/Customer[@id='x1']/descendant-or-self::Address",
73+
"/Customers/Customer[@id = 'x1']/Address"},
74+
{"/Customers/Customer[@id='x1']/descendant-or-self::*",
75+
"/Customers/Customer[@id='x1'] | /Customers/Customer[@id = 'x1']//*"},
76+
{"/Customers/foo:Customer/foo:Address/descendant-or-self::*",
77+
"/Customers/foo:Customer/foo:Address | /Customers/foo:Customer/foo:Address//*"},
78+
{"/Customers/Customer/*[descendant::Street]", "/Customers/Customer/Address"},
79+
{"/Customers/Customer/*[not(descendant::Street)]", "/Customers/Customer/*[name() != \"Address\"]"},
80+
{"/Customers/Customer/*[descendant-or-self::Street]", "/Customers/Customer/Address"},
81+
{"/Customers/Customer/*[not(descendant-or-self::Street)]",
82+
"/Customers/Customer/*[name() != \"Address\"]"}
83+
};
84+
}
85+
86+
/*
87+
* DataProvider: provides XPath descendant expressions and expected number of descendant nodes returned
88+
*/
89+
@DataProvider(name = "descendantXpathNodeCount")
90+
public Object[][] getDescendantXpathExpressionNodeCount() {
91+
return new Object[][] {
92+
{"/Customers/descendant::*", 40},
93+
{"/Customers/descendant::Customer", 3},
94+
{"/Customers/descendant::foo:Customer", 1},
95+
{"/Customers/Customer[@id='x1']/descendant::Address", 1},
96+
{"/Customers/Customer[@id='x1']/descendant::*", 9},
97+
{"/Customers/foo:Customer/foo:Address/descendant::*", 3},
98+
{"/Customers/Customer[@id='x1']/Address/descendant::Address", 0},
99+
{"/Customers/descendant-or-self::*", 41},
100+
{"/Customers/descendant-or-self::Customer", 3},
101+
{"/Customers/descendant-or-self::foo:Customer", 1},
102+
{"/Customers/Customer[@id='x1']/descendant-or-self::Address", 1},
103+
{"/Customers/Customer[@id='x1']/Address/descendant-or-self::Address", 1},
104+
{"/Customers/Customer[@id='x1']/descendant-or-self::*", 10},
105+
{"/Customers/foo:Customer/foo:Address/descendant-or-self::*", 4},
106+
{"/Customers/*[descendant::Name]", 3},
107+
{"/Customers/foo:Customer/*[descendant-or-self::foo:Street]", 1}
108+
};
109+
}
110+
111+
/*
112+
* DataProvider: provides XPath descendant expressions which should return null.
113+
*/
114+
@DataProvider(name = "descendantXpathEmpty")
115+
public Object[][] getDescendantXpathExpressionEmpty() {
116+
return new Object[][] {
117+
{"/Customers/Customer/Name/descendant::*"},
118+
{"/Customers/foo:Customer/descendant::Name"},
119+
{"/Customers/Customer/descendant::foo:Name"},
120+
{"/Customers/descendant::id"},
121+
{"/Customers/Customer/Name/descendant-or-self::id"},
122+
{"/Customers/foo:Customer/descendant-or-self::Name"},
123+
{"/Customers/Customer/descendant-or-self::foo:Name"},
124+
{"/Customers/descendant-or-self::id"}
125+
};
126+
}
127+
128+
/**
129+
* Verifies descendant xpath expression returns same nodes as returns when used normal xpath expression
130+
* @param descexp descendant XPath expression.
131+
* @param expath normal xPath expression
132+
* @throws XPathExpressionException
133+
*/
134+
@Test(dataProvider = "descendantXpath")
135+
public void descendantExpTests(String descexp, String expath) throws XPathExpressionException {
136+
Document doc = documentOf(DECLARATION + RAW_XML);
137+
XPath xPath = XPathFactory.newInstance().newXPath();
138+
NodeList actualNodeList = (NodeList) xPath.evaluate(descexp, doc, XPathConstants.NODESET);
139+
NodeList expectedNodeList = (NodeList) xPath.evaluate(expath, doc, XPathConstants.NODESET);
140+
Assert.assertEquals(actualNodeList.getLength(), expectedNodeList.getLength());
141+
142+
for(int i = 0; i < actualNodeList.getLength(); i++) {
143+
actualNodeList.item(i).equals(expectedNodeList.item(i));
144+
}
145+
}
146+
147+
/**
148+
* Verifies descendant xpath expression return descendant nodes list with correct number of nodes.
149+
* @param exp XPath expression.
150+
* @param nodeCount number of descendant nodes in nodelist.
151+
* @throws XPathExpressionException
152+
*/
153+
@Test(dataProvider = "descendantXpathNodeCount")
154+
public void descendantNodesCountTests(String exp, int nodeCount) throws XPathExpressionException {
155+
Document doc = documentOf(DECLARATION + RAW_XML);
156+
XPath xPath = XPathFactory.newInstance().newXPath();
157+
NodeList nodeList = (NodeList) xPath.evaluate(exp, doc, XPathConstants.NODESET);
158+
Assert.assertEquals(nodeList.getLength(), nodeCount);
159+
}
160+
161+
/**
162+
* Verifies descendant xpath expression return no nodes if descendant expression context nodes don't have matching descendants
163+
* @param exp XPath expression.
164+
* @throws XPathExpressionException
165+
*/
166+
@Test(dataProvider = "descendantXpathEmpty")
167+
public void DescendantScopeTests(String exp) throws XPathExpressionException {
168+
Document doc = documentOf(DECLARATION + RAW_XML);
169+
XPath xPath = XPathFactory.newInstance().newXPath();
170+
Node node = xPath.evaluateExpression(exp, doc, Node.class);
171+
Assert.assertNull(node);
172+
}
173+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
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 javax.xml.xpath.XPath;
26+
import javax.xml.xpath.XPathConstants;
27+
import javax.xml.xpath.XPathExpressionException;
28+
import javax.xml.xpath.XPathFactory;
29+
30+
import org.testng.Assert;
31+
import org.testng.annotations.DataProvider;
32+
import org.testng.annotations.Test;
33+
import org.w3c.dom.Document;
34+
import org.w3c.dom.Node;
35+
import org.w3c.dom.NodeList;
36+
37+
/*
38+
* @test
39+
* @bug 8289509
40+
* @library /javax/xml/jaxp/unittest
41+
* @run testng/othervm xpath.XPathExpFollowingTest
42+
* @summary Tests for XPath following/following-sibling axis specifier.
43+
*/
44+
public class XPathExpFollowingTest extends XPathTestBase {
45+
/*
46+
* DataProvider: provides XPath Axis following expressions and equivalent xpath expression.
47+
*/
48+
@DataProvider(name = "followingXpath")
49+
public Object[][] getFollowingXpathExpression() {
50+
return new Object[][] {
51+
{"/Customers/following::*", "/None"},
52+
{"/Customers/Customer/following::Customer", "//Customer[@id != 'x1']"},
53+
{"/Customers/Customer/following::foo:Customer", "//foo:Customer"},
54+
{"/Customers/Customer[@id='x1']/following::Address",
55+
"/Customers/Customer[@id != 'x1']/Address"},
56+
{"/Customers/Customer[@id='x1']/following::Street",
57+
"/Customers/Customer[@id != 'x1']/Address/Street"},
58+
{"/Customers/Customer[@id='x1']/following::Street[2]",
59+
"/Customers/Customer[@id='x2']/Address/Street"},
60+
{"/Customers/Customer[@id='x1']/following::*",
61+
"/Customers/Customer[@id != 'x1']/descendant-or-self::*" +
62+
" | /Customers/foo:Customer/descendant-or-self::*"},
63+
{"/Customers/foo:Customer/foo:Address/following::*",
64+
"/Customers/foo:Customer/foo:Age | /Customers/foo:Customer/foo:ClubMember"},
65+
{"/Customers/Customer[@id = 'x1']/*[following::Street]", "/Customers/Customer[@id = 'x1']/*"},
66+
{"/Customers/foo:Customer/*[following::foo:Name]", "/None"},
67+
{"/Customers/foo:Customer/*[not(following::foo:Name)]", "/Customers/foo:Customer/*"},
68+
{"/Customers/following-sibling::*", "/None"},
69+
{"/Customers/Customer/following-sibling::Customer",
70+
"/Customers/Customer[@id != 'x1']"},
71+
{"/Customers/Customer/following-sibling::foo:Customer",
72+
"/Customers/foo:Customer"},
73+
{"/Customers/Customer[@id='x1']/Name/following-sibling::Address",
74+
"/Customers/Customer[@id='x1']/Address"},
75+
{"/Customers/Customer/Name/following-sibling::Address",
76+
"/Customers//Address"},
77+
{"(/Customers/Customer/Address/Street/following-sibling::State)[3]",
78+
"/Customers/Customer[@id='x3']/Address/State"},
79+
{"/Customers/Customer[@id='x1']/Address/Street/following-sibling::*[2]",
80+
"/Customers/Customer[@id='x3']/Address/State"},
81+
{"/Customers/Customer[@id='x1']/following-sibling::*",
82+
"/Customers/Customer[@id != 'x1'] | /Customers/foo:Customer"},
83+
{"/Customers/foo:Customer/foo:Address/following-sibling::*",
84+
"/Customers/foo:Customer/foo:Age | /Customers/foo:Customer/foo:ClubMember"},
85+
{"/Customers/Customer[@id = 'x1']/*[following-sibling::Street]", "/None"},
86+
{"/Customers/foo:Customer/*[following-sibling::foo:Address]", "/Customers/foo:Customer/foo:Name |" +
87+
"/Customers/foo:Customer/foo:Phone | /Customers/foo:Customer/foo:Email"},
88+
{"/Customers/foo:Customer/*[not(following-sibling::foo:Address)]", "/Customers/foo:Customer/foo:Age | " +
89+
"/Customers/foo:Customer/foo:ClubMember | /Customers/foo:Customer/foo:Address"}
90+
};
91+
}
92+
93+
/*
94+
* DataProvider: provides XPath following expressions and expected number of following nodes returned
95+
*/
96+
@DataProvider(name = "followingXpathNodeCount")
97+
public Object[][] getFollowingXpathExpressionNodeCount() {
98+
return new Object[][] {
99+
{"/Customers/following::*", 0},
100+
{"/Customers/Customer/following::*", 30},
101+
{"/Customers/Customer/following::Customer", 2},
102+
{"/Customers/Customer/following::foo:Customer", 1},
103+
{"/Customers/Customer[@id='x1']/Name/following::*", 38},
104+
{"/Customers/Customer/Address/following::*", 32},
105+
{"/Customers/foo:Customer/foo:Address/following::*", 2},
106+
{"/Customers/foo:Customer/foo:Name/following::*", 8},
107+
{"/Customers/foo:Customer/*[following::foo:Name]", 0},
108+
{"/Customers/foo:Customer/*[not(following::foo:Name)]", 6},
109+
{"/Customers/following-sibling::*", 0},
110+
{"/Customers/Customer/following-sibling::*", 3},
111+
{"/Customers/Customer/following-sibling::Customer", 2},
112+
{"/Customers/Customer/following-sibling::foo:Customer", 1},
113+
{"/Customers/Customer[@id='x1']/Name/following-sibling::*", 5},
114+
{"/Customers/Customer/Address/following-sibling::*", 6},
115+
{"/Customers/Customer[@id='x1']/Address/following-sibling::*", 2},
116+
{"/Customers/foo:Customer/foo:Address/following-sibling::*", 2},
117+
{"/Customers/Customer[@id = 'x1']/*[following-sibling::Street]", 0},
118+
{"/Customers/foo:Customer/*[following-sibling::foo:Address]", 3},
119+
{"/Customers/foo:Customer/*[not(following-sibling::foo:Address)]", 3}
120+
};
121+
}
122+
123+
/*
124+
* DataProvider: provides XPath following expressions which should not return any node.
125+
*/
126+
@DataProvider(name = "followingXpathEmpty")
127+
public Object[][] getFollowingXpathExpressionEmpty() {
128+
return new Object[][] {
129+
{"/Customers/following::*"},
130+
{"/Customers/foo:Customer/following::*"},
131+
{"/Customers/Customer[@id = 'x3' ]/following::Customer"},
132+
{"/Customers/following::id"},
133+
{"/Customers/Customer[@id = 'x3' ]/following-sibling::Customer"},
134+
{"/Customers/foo:Customer/following-sibling::*"},
135+
{"/Customers/Customer/following-sibling::foo:Name"},
136+
{"/Customers/following-sibling::id"}
137+
};
138+
}
139+
140+
/**
141+
* Verifies Axis following xpath expression returns same nodes as returns when used normal xpath expression
142+
* @param descexp Axis following XPath expression.
143+
* @param expath normal xPath expression
144+
* @throws XPathExpressionException
145+
*/
146+
@Test(dataProvider = "followingXpath")
147+
public void followingExpTests(String descexp, String expath) throws XPathExpressionException {
148+
Document doc = documentOf(DECLARATION + RAW_XML);
149+
XPath xPath = XPathFactory.newInstance().newXPath();
150+
NodeList actualNodeList = (NodeList) xPath.evaluate(descexp, doc, XPathConstants.NODESET);
151+
NodeList expectedNodeList = (NodeList) xPath.evaluate(expath, doc, XPathConstants.NODESET);
152+
Assert.assertEquals(actualNodeList.getLength(), expectedNodeList.getLength());
153+
154+
for(int i = 0; i < actualNodeList.getLength(); i++) {
155+
actualNodeList.item(i).equals(expectedNodeList.item(i));
156+
}
157+
}
158+
159+
/**
160+
* Verifies following xpath expression return following nodes list with correct number of nodes.
161+
* @param exp XPath expression.
162+
* @param nodeCount number of following nodes in nodelist.
163+
* @throws XPathExpressionException
164+
*/
165+
@Test(dataProvider = "followingXpathNodeCount")
166+
public void followingNodesCountTests(String exp, int nodeCount) throws XPathExpressionException {
167+
Document doc = documentOf(DECLARATION + RAW_XML);
168+
XPath xPath = XPathFactory.newInstance().newXPath();
169+
NodeList nodeList = (NodeList) xPath.evaluate(exp, doc, XPathConstants.NODESET);
170+
Assert.assertEquals(nodeList.getLength(), nodeCount);
171+
}
172+
173+
/**
174+
* Verifies following xpath expression return no nodes if following expression context nodes don't have matching following elements.
175+
* @param exp XPath expression.
176+
* @throws XPathExpressionException
177+
*/
178+
@Test(dataProvider = "followingXpathEmpty")
179+
public void FollowingScopeTests(String exp) throws XPathExpressionException {
180+
Document doc = documentOf(DECLARATION + RAW_XML);
181+
XPath xPath = XPathFactory.newInstance().newXPath();
182+
Node node = xPath.evaluateExpression(exp, doc, Node.class);
183+
Assert.assertNull(node);
184+
}
185+
}

0 commit comments

Comments
 (0)
Please sign in to comment.