Skip to content

Commit 2fa09bb

Browse files
Victor RudometovPaul Hohensee
Victor Rudometov
authored and
Paul Hohensee
committed
8290836: Improve test coverage for XPath functions: String Functions
8290837: Improve test coverage for XPath functions: Boolean Functions 8290838: Improve test coverage for XPath functions: Number Functions Backport-of: d889264c6123b6c28bdd6336f5ae547e4e441aa7
1 parent fe770e3 commit 2fa09bb

File tree

5 files changed

+818
-15
lines changed

5 files changed

+818
-15
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
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+
30+
import javax.xml.xpath.XPathExpressionException;
31+
32+
/*
33+
* @test
34+
* @bug 8290837
35+
* @library /javax/xml/jaxp/unittest
36+
* @run testng xpath.XPathBooleanFnTest
37+
* @summary Tests the XPath Boolean Functions
38+
*/
39+
public class XPathBooleanFnTest extends XPathTestBase {
40+
41+
private static final Document doc = getDtdDocument();
42+
43+
/*
44+
* DataProvider for testing the boolean, not, true, false and lang
45+
* functions.
46+
* Data columns:
47+
* see parameters of the test "testBooleanFn"
48+
*/
49+
@DataProvider(name = "booleanExpTestCases")
50+
public Object[][] getBooleanExp() {
51+
return new Object[][]{
52+
{"true()", true},
53+
{"false()", false},
54+
55+
{"boolean(true())", true},
56+
{"boolean(false())", false},
57+
{"boolean(1)", true},
58+
{"boolean(0)", false},
59+
{"boolean(-1)", true},
60+
{"boolean(1+1)", true},
61+
{"boolean(1-1)", false},
62+
{"boolean(1+'abc')", false},
63+
{"boolean('abc')", true},
64+
{"boolean('')", false},
65+
{"boolean(//Name)", true},
66+
{"boolean(//LastName)", false},
67+
{"boolean(//Customer[1]/ClubMember)", true},
68+
{"boolean(//Customer[2]/ClubMember)", true},
69+
{"boolean(//Customer[2]/ClubMember='true')", false},
70+
{"boolean(//Customer[1]/ClubMember or " +
71+
"//Customer[2]/ClubMember)", true},
72+
{"boolean(//Customer[1]/ClubMember and " +
73+
"//Customer[2]/ClubMember)", true},
74+
{"boolean(//*[boolean(.)=true()])", true},
75+
{"boolean(//*[boolean(.)=false()])", false},
76+
77+
{"not(1)", false},
78+
{"not(-1)", false},
79+
{"not(0)", true},
80+
{"not(true())", false},
81+
{"not(false())", true},
82+
{"not(//Customer[1]/ClubMember)", false},
83+
{"not(//Customer[2]/ClubMember)", false},
84+
{"not(//Customer[2]/ClubMember='true')", true},
85+
{"boolean(//*[not(.)=true()])", false},
86+
{"boolean(//*[not(.)=false()])", true},
87+
88+
{"boolean(//*[lang('en')])", true},
89+
{"boolean(//*[lang('es')])", false},
90+
};
91+
}
92+
93+
/*
94+
* DataProvider for testing XPathExpressionException being thrown on
95+
* invalid boolean function usage.
96+
* Data columns:
97+
* see parameters of the test "testExceptionOnEval"
98+
*/
99+
@DataProvider(name = "exceptionExpTestCases")
100+
public Object[][] getExceptionExp() {
101+
return new Object[][]{
102+
// Argument is required for these functions
103+
{"boolean()"},
104+
{"//*[boolean()=true()]"},
105+
{"not()"},
106+
{"//*[not()=true()]"},
107+
{"lang()"},
108+
{"/*[lang()=true()]"},
109+
110+
// No arguments should be passed to these functions
111+
{"true(1)"},
112+
{"false(0)"},
113+
{"//*[true(.)=true()]"},
114+
{"//*[false(.)=false()]"},
115+
};
116+
}
117+
118+
/**
119+
* Verifies that the result of evaluating the boolean, not, true, false
120+
* and lang functions matches the expected result.
121+
*
122+
* @param exp XPath expression
123+
* @param expected expected result
124+
* @throws Exception if test fails
125+
*/
126+
@Test(dataProvider = "booleanExpTestCases")
127+
void testBooleanFn(String exp, boolean expected) throws Exception {
128+
testExp(doc, exp, expected, Boolean.class);
129+
}
130+
131+
/**
132+
* Verifies that XPathExpressionException is thrown on xpath evaluation.
133+
*
134+
* @param exp XPath expression
135+
*/
136+
@Test(dataProvider = "exceptionExpTestCases")
137+
void testExceptionOnEval(String exp) {
138+
Assert.assertThrows(XPathExpressionException.class, () -> testEval(doc,
139+
exp));
140+
}
141+
}

test/jaxp/javax/xml/jaxp/unittest/xpath/XPathNodeSetFnTest.java

+69-7
Original file line numberDiff line numberDiff line change
@@ -69,29 +69,35 @@ public Object[][] getCountExp() {
6969
{"count(//Customer)", CUSTOMERS},
7070
{"count(//@id)", ID_ATTRIBUTES},
7171
{"count(//Customer/@id)", CUSTOMERS},
72-
{"count(//@*)", ID_ATTRIBUTES + FOO_ID_ATTRIBUTES},
72+
{"count(//@*)",
73+
LANG_ATTRIBUTES + ID_ATTRIBUTES + FOO_ID_ATTRIBUTES},
7374
{"count(//*)",
7475
ROOT + CUSTOMERS + FOO_CUSTOMERS +
7576
(CUSTOMERS + FOO_CUSTOMERS) *
76-
CUSTOMER_ELEMENTS},
77+
(CUSTOMER_ELEMENTS + ADDRESS_ELEMENTS)},
7778
{"count(//*[@id])", ID_ATTRIBUTES},
7879
{"count(./*)", ROOT},
80+
{"count(.)", ROOT},
7981
{"count(//Customer[1]/following::*)",
8082
CUSTOMERS - 1 + FOO_CUSTOMERS +
8183
(CUSTOMERS - 1 + FOO_CUSTOMERS) *
82-
CUSTOMER_ELEMENTS},
84+
(CUSTOMER_ELEMENTS + ADDRESS_ELEMENTS)},
8385
{"count(//Customer[1]/following-sibling::*)",
8486
CUSTOMERS - 1 + FOO_CUSTOMERS},
8587
{"count(//Customer[3]/preceding::*)",
86-
CUSTOMERS - 1 + (CUSTOMERS - 1) * CUSTOMER_ELEMENTS},
88+
CUSTOMERS - 1 + (CUSTOMERS - 1) *
89+
(CUSTOMER_ELEMENTS + ADDRESS_ELEMENTS)},
8790
{"count(//Customer[3]/preceding-sibling::*)", CUSTOMERS - 1},
8891
{"count(//Customer[1]/ancestor::*)", ROOT},
8992
{"count(//Customer[1]/ancestor-or-self::*)", ROOT + 1},
90-
{"count(//Customer[1]/descendant::*)", CUSTOMER_ELEMENTS},
93+
{"count(//Customer[1]/descendant::*)",
94+
CUSTOMER_ELEMENTS + ADDRESS_ELEMENTS},
9195
{"count(//Customer[1]/descendant-or-self::*)",
92-
CUSTOMER_ELEMENTS + 1},
96+
CUSTOMER_ELEMENTS + ADDRESS_ELEMENTS + 1},
97+
// node() returns all children of the context node including
98+
// element nodes and text nodes.
9399
{"count(//Customer/node())",
94-
ID_ATTRIBUTES + CUSTOMERS * CUSTOMER_ELEMENTS},
100+
CUSTOMERS + CUSTOMERS * (CUSTOMER_ELEMENTS * 2)},
95101
};
96102
}
97103

@@ -104,6 +110,7 @@ public Object[][] getCountExp() {
104110
public Object[][] getPositionExp() {
105111
return new Object[][]{
106112
{"//Customer[position()=1]", "Customer_x1"},
113+
{"//Customer[position()]", "Customer_x1"},
107114
{"//Customer[position()=last()]", "Customer_x3"},
108115
{"//Customer[position()>1 and position()<last()]",
109116
"Customer_x2"},
@@ -125,18 +132,62 @@ public Object[][] getNameExp() {
125132
{"local-name(//Customer/@id)", "id"},
126133
{"local-name(//foo:Customer/@foo:id)", "id"},
127134
{"local-name(//*[local-name()='Customer'])", "Customer"},
135+
{"local-name(//*[local-name(.)='Customer'])", "Customer"},
128136
{"namespace-uri(.)", ""},
129137
{"namespace-uri(//Customers)", ""},
130138
{"namespace-uri(//Customer)", ""},
131139
{"namespace-uri(//foo:Customer)", "foo"},
132140
{"namespace-uri(//@id)", ""},
133141
{"namespace-uri(//@foo:id)", "foo"},
134142
{"name(//*[namespace-uri()=\"foo\"])", "foo:Customer"},
143+
{"name(//*[namespace-uri(.)=\"foo\"])", "foo:Customer"},
135144
{"name(//Customer)", "Customer"},
136145
{"name(//foo:Customer)", "foo:Customer"},
137146
{"name(//Customer/@id)", "id"},
138147
{"name(//foo:Customer/@foo:id)", "foo:id"},
139148
{"name(//*[name()='foo:Customer'])", "foo:Customer"},
149+
{"name(//*[name(.)='foo:Customer'])", "foo:Customer"},
150+
};
151+
}
152+
153+
/*
154+
* DataProvider for testing XPathExpressionException being thrown on
155+
* invalid node set function usage.
156+
* Data columns:
157+
* see parameters of the test "testExceptionOnEval"
158+
*/
159+
@DataProvider(name = "exceptionExpTestCases")
160+
public Object[][] getExceptionExp() {
161+
return new Object[][]{
162+
// Argument is required for these functions
163+
{"//Customer[id()]"},
164+
{"//Customer[id()='x1']"},
165+
{"//Customer[count()]"},
166+
{"//*[count()=3]"},
167+
168+
// No argument should be passed to these functions
169+
{"//Customer[position(.)]"},
170+
{"//*[position(//Customer[1])]"},
171+
{"//Customer[last(.)]"},
172+
{"//*[last(//Customer[1])]"},
173+
174+
// Node-set argument is required for these functions
175+
{"count(1)"},
176+
{"count(true())"},
177+
{"count('')"},
178+
{"count('abc')"},
179+
{"local-name(1)"},
180+
{"local-name(true())"},
181+
{"local-name('')"},
182+
{"local-name('abc')"},
183+
{"name(1)"},
184+
{"name(true())"},
185+
{"name('')"},
186+
{"name('abc')"},
187+
{"namespace-uri(1)"},
188+
{"namespace-uri(true())"},
189+
{"namespace-uri('')"},
190+
{"namespace-uri('abc')"},
140191
};
141192
}
142193

@@ -219,4 +270,15 @@ void testNameFn(String exp, String expected) throws Exception {
219270
Assert.assertEquals(s, expected);
220271
Assert.assertEquals(s2, s);
221272
}
273+
274+
/**
275+
* Verifies that XPathExpressionException is thrown on xpath evaluation.
276+
*
277+
* @param exp XPath expression
278+
*/
279+
@Test(dataProvider = "exceptionExpTestCases")
280+
void testExceptionOnEval(String exp) {
281+
Assert.assertThrows(XPathExpressionException.class, () -> testEval(doc,
282+
exp));
283+
}
222284
}

0 commit comments

Comments
 (0)