8289948: Improve test coverage for XPath functions: Node Set Functions

Reviewed-by: joehw
This commit is contained in:
Bill Huang 2022-08-01 16:37:22 +00:00 committed by Joe Wang
parent 1df77ec137
commit 57bf603b73
4 changed files with 344 additions and 45 deletions

View File

@ -90,7 +90,8 @@ public class XPathAnyTypeTest extends XPathTestBase {
*/
@Test(dataProvider = "document")
public void test04(XPath xpath, Document doc) throws XPathExpressionException {
boolean result1 = xpath.evaluateExpression("boolean(/Customers/Customer[@id=3])", doc, Boolean.class);
boolean result1 = xpath.evaluateExpression("boolean" +
"(/Customers/Customer[@id=\"x3\"])", doc, Boolean.class);
assertTrue(result1);
}
@ -121,7 +122,8 @@ public class XPathAnyTypeTest extends XPathTestBase {
*/
@Test(dataProvider = "document")
public void test07(XPath xpath, Document doc) throws XPathExpressionException {
String result1 = xpath.evaluateExpression("string(/Customers/Customer[@id=3]/Phone/text())", doc, String.class);
String result1 = xpath.evaluateExpression("string(/Customers/Customer" +
"[@id=\"x3\"]/Phone/text())", doc, String.class);
assertTrue(result1.equals("3333333333"));
}
@ -142,7 +144,8 @@ public class XPathAnyTypeTest extends XPathTestBase {
*/
@Test(dataProvider = "document")
public void test09(XPath xpath, Document doc) throws XPathExpressionException {
Node n = xpath.evaluateExpression("/Customers/Customer[@id=3]", doc, Node.class);
Node n = xpath.evaluateExpression("/Customers/Customer[@id=\"x3\"]",
doc, Node.class);
assertEquals(n.getLocalName(), "Customer");
}
@ -151,7 +154,8 @@ public class XPathAnyTypeTest extends XPathTestBase {
*/
@Test(dataProvider = "document", expectedExceptions = IllegalArgumentException.class)
public void test10(XPath xpath, Document doc) throws XPathExpressionException {
File n = xpath.evaluateExpression("/Customers/Customer[@id=3]", doc, File.class);
File n = xpath.evaluateExpression("/Customers/Customer[@id=\"x3\"]",
doc, File.class);
}
/*
@ -159,7 +163,8 @@ public class XPathAnyTypeTest extends XPathTestBase {
*/
@Test(dataProvider = "document")
public void test11(XPath xpath, Document doc) throws XPathExpressionException {
XPathEvaluationResult<?> result = xpath.evaluateExpression("boolean(/Customers/Customer[@id=3])", doc);
XPathEvaluationResult<?> result = xpath.evaluateExpression(
"boolean(/Customers/Customer[@id=\"x3\"])", doc);
verifyResult(result, true);
}
@ -178,7 +183,7 @@ public class XPathAnyTypeTest extends XPathTestBase {
@Test(dataProvider = "document")
public void test13(XPath xpath, Document doc) throws XPathExpressionException {
XPathEvaluationResult<?> result = xpath.evaluateExpression(
"string(/Customers/Customer[@id=3]/Phone/text())", doc, XPathEvaluationResult.class);
"string(/Customers/Customer[@id=\"x3\"]/Phone/text())", doc, XPathEvaluationResult.class);
verifyResult(result, "3333333333");
}
@ -196,7 +201,8 @@ public class XPathAnyTypeTest extends XPathTestBase {
*/
@Test(dataProvider = "document")
public void test15(XPath xpath, Document doc) throws XPathExpressionException {
XPathEvaluationResult<?> result = xpath.evaluateExpression("/Customers/Customer[@id=3]", doc);
XPathEvaluationResult<?> result = xpath.evaluateExpression(
"/Customers/Customer[@id=\"x3\"]", doc);
verifyResult(result, "Customer");
}
}

View File

@ -76,7 +76,7 @@ public class XPathExpAnyTypeTest extends XPathTestBase {
*/
@Test(dataProvider = "document")
public void test04(XPath xpath, Document doc) throws XPathExpressionException {
XPathExpression exp = xpath.compile("boolean(/Customers/Customer[@id=3])");
XPathExpression exp = xpath.compile("boolean(/Customers/Customer[@id=\"x3\"])");
boolean result1 = exp.evaluateExpression(doc, Boolean.class);
assertTrue(result1);
}
@ -99,7 +99,7 @@ public class XPathExpAnyTypeTest extends XPathTestBase {
*/
@Test(dataProvider = "document")
public void test06(XPath xpath, Document doc) throws XPathExpressionException {
XPathExpression exp = xpath.compile("string(/Customers/Customer[@id=3]/Phone/text())");
XPathExpression exp = xpath.compile("string(/Customers/Customer[@id=\"x3\"]/Phone/text())");
String result1 = exp.evaluateExpression(doc, String.class);
assertTrue(result1.equals("3333333333"));
}
@ -122,7 +122,7 @@ public class XPathExpAnyTypeTest extends XPathTestBase {
*/
@Test(dataProvider = "document")
public void test08(XPath xpath, Document doc) throws XPathExpressionException {
XPathExpression exp = xpath.compile("/Customers/Customer[@id=3]");
XPathExpression exp = xpath.compile("/Customers/Customer[@id=\"x3\"]");
Node n = exp.evaluateExpression(doc, Node.class);
assertEquals(n.getLocalName(), "Customer");
}
@ -132,7 +132,7 @@ public class XPathExpAnyTypeTest extends XPathTestBase {
*/
@Test(dataProvider = "document", expectedExceptions = IllegalArgumentException.class)
public void test09(XPath xpath, Document doc) throws XPathExpressionException {
XPathExpression exp = xpath.compile("/Customers/Customer[@id=3]");
XPathExpression exp = xpath.compile("/Customers/Customer[@id=\"x3\"]");
File n = exp.evaluateExpression(doc, File.class);
}
@ -141,7 +141,7 @@ public class XPathExpAnyTypeTest extends XPathTestBase {
*/
@Test(dataProvider = "document")
public void test10(XPath xpath, Document doc) throws XPathExpressionException {
XPathExpression exp = xpath.compile("boolean(/Customers/Customer[@id=3])");
XPathExpression exp = xpath.compile("boolean(/Customers/Customer[@id=\"x3\"])");
XPathEvaluationResult<?> result = exp.evaluateExpression(doc);
verifyResult(result, true);
}
@ -161,7 +161,7 @@ public class XPathExpAnyTypeTest extends XPathTestBase {
*/
@Test(dataProvider = "document")
public void test12(XPath xpath, Document doc) throws XPathExpressionException {
XPathExpression exp = xpath.compile("string(/Customers/Customer[@id=3]/Phone/text())");
XPathExpression exp = xpath.compile("string(/Customers/Customer[@id=\"x3\"]/Phone/text())");
XPathEvaluationResult<?> result = exp.evaluateExpression(doc, XPathEvaluationResult.class);
verifyResult(result, "3333333333");
}
@ -181,7 +181,7 @@ public class XPathExpAnyTypeTest extends XPathTestBase {
*/
@Test(dataProvider = "document")
public void test14(XPath xpath, Document doc) throws XPathExpressionException {
XPathExpression exp = xpath.compile("/Customers/Customer[@id=3]");
XPathExpression exp = xpath.compile("/Customers/Customer[@id=\"x3\"]");
XPathEvaluationResult<?> result = exp.evaluateExpression(doc);
verifyResult(result, "Customer");
}

View File

@ -0,0 +1,222 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package xpath;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import javax.xml.xpath.*;
/*
* @test
* @bug 8289948
* @library /javax/xml/jaxp/unittest
* @run testng xpath.XPathNodeSetFnTest
* @summary Tests the XPath Node Set Functions
*/
public class XPathNodeSetFnTest extends XPathTestBase {
private static final Document doc = getDtdDocument();
/*
* DataProvider for testing the id function.
* Data columns:
* see parameters of the test "testIdFn"
*/
@DataProvider(name = "idExpTestCases")
public Object[][] getIdExp() {
return new Object[][]{
{"id('x3')", "Customer_x3"},
{"id('x1 x2 x3')[3]", "Customer_x3"},
{"id('x1 | x2 | x3')[3]", "Customer_x3"},
{"id('x')", "Email_x"},
{"id(//Customer[3]/@id)", "Customer_x3"},
{"id(//*[.='123@xyz.com']/@id)", "Email_x"},
};
}
/*
* DataProvider for testing the count function.
* Data columns:
* see parameters of the test "testCountFn"
*/
@DataProvider(name = "countExpTestCases")
public Object[][] getCountExp() {
return new Object[][]{
{"count(//Customer)", CUSTOMERS},
{"count(//@id)", ID_ATTRIBUTES},
{"count(//Customer/@id)", CUSTOMERS},
{"count(//@*)", ID_ATTRIBUTES + FOO_ID_ATTRIBUTES},
{"count(//*)",
ROOT + CUSTOMERS + FOO_CUSTOMERS +
(CUSTOMERS + FOO_CUSTOMERS) *
CUSTOMER_ELEMENTS},
{"count(//*[@id])", ID_ATTRIBUTES},
{"count(./*)", ROOT},
{"count(//Customer[1]/following::*)",
CUSTOMERS - 1 + FOO_CUSTOMERS +
(CUSTOMERS - 1 + FOO_CUSTOMERS) *
CUSTOMER_ELEMENTS},
{"count(//Customer[1]/following-sibling::*)",
CUSTOMERS - 1 + FOO_CUSTOMERS},
{"count(//Customer[3]/preceding::*)",
CUSTOMERS - 1 + (CUSTOMERS - 1) * CUSTOMER_ELEMENTS},
{"count(//Customer[3]/preceding-sibling::*)", CUSTOMERS - 1},
{"count(//Customer[1]/ancestor::*)", ROOT},
{"count(//Customer[1]/ancestor-or-self::*)", ROOT + 1},
{"count(//Customer[1]/descendant::*)", CUSTOMER_ELEMENTS},
{"count(//Customer[1]/descendant-or-self::*)",
CUSTOMER_ELEMENTS + 1},
{"count(//Customer/node())",
ID_ATTRIBUTES + CUSTOMERS * CUSTOMER_ELEMENTS},
};
}
/*
* DataProvider for testing the position function.
* Data columns:
* see parameters of the test "testPositionFn"
*/
@DataProvider(name = "positionExpTestCases")
public Object[][] getPositionExp() {
return new Object[][]{
{"//Customer[position()=1]", "Customer_x1"},
{"//Customer[position()=last()]", "Customer_x3"},
{"//Customer[position()>1 and position()<last()]",
"Customer_x2"},
{"//Customer[position() mod 2 =0]", "Customer_x2"},
{"//Customer[last()]", "Customer_x3"},
};
}
/*
* DataProvider for testing the name and local-name functions.
* Data columns:
* see parameters of the test "testNameFn"
*/
@DataProvider(name = "nameExpTestCases")
public Object[][] getNameExp() {
return new Object[][]{
{"local-name(//Customer)", "Customer"},
{"local-name(//foo:Customer)", "Customer"},
{"local-name(//Customer/@id)", "id"},
{"local-name(//foo:Customer/@foo:id)", "id"},
{"local-name(//*[local-name()='Customer'])", "Customer"},
{"namespace-uri(.)", ""},
{"namespace-uri(//Customers)", ""},
{"namespace-uri(//Customer)", ""},
{"namespace-uri(//foo:Customer)", "foo"},
{"namespace-uri(//@id)", ""},
{"namespace-uri(//@foo:id)", "foo"},
{"name(//*[namespace-uri()=\"foo\"])", "foo:Customer"},
{"name(//Customer)", "Customer"},
{"name(//foo:Customer)", "foo:Customer"},
{"name(//Customer/@id)", "id"},
{"name(//foo:Customer/@foo:id)", "foo:id"},
{"name(//*[name()='foo:Customer'])", "foo:Customer"},
};
}
/**
* Verifies that the result of evaluating the id function matches the
* expected result.
*
* @param exp XPath expression
* @param expected expected result
* @throws Exception if test fails
*/
@Test(dataProvider = "idExpTestCases")
void testIdFn(String exp, String expected) throws Exception {
XPath xPath = XPathFactory.newInstance().newXPath();
Node node = xPath.evaluateExpression(exp, doc, Node.class);
Node node2 = (Node) xPath.evaluate(exp, doc, XPathConstants.NODE);
Assert.assertEquals(node.getNodeName() + "_" +
node.getAttributes().item(0).getNodeValue()
, expected);
Assert.assertEquals(node2, node);
}
/**
* Verifies that the result of evaluating the count function matches the
* expected result.
*
* @param exp XPath expression
* @param expected expected result
* @throws Exception if test fails
*/
@Test(dataProvider = "countExpTestCases")
void testCountFn(String exp, int expected) throws Exception {
XPath xPath = XPathFactory.newInstance().newXPath();
double num = xPath.evaluateExpression(exp, doc, Double.class);
double num2 = (double) xPath.evaluate(exp, doc, XPathConstants.NUMBER);
Assert.assertEquals(num, expected);
Assert.assertEquals(num2, num);
}
/**
* Verifies that the result of evaluating the position function matches the
* expected result.
*
* @param exp XPath expression
* @param expected expected result
* @throws Exception if test fails
*/
@Test(dataProvider = "positionExpTestCases")
void testPositionFn(String exp, String expected) throws Exception {
XPath xPath = XPathFactory.newInstance().newXPath();
Node node = xPath.evaluateExpression(exp, doc, Node.class);
Node node2 = (Node) xPath.evaluate(exp, doc, XPathConstants.NODE);
Assert.assertEquals(node.getNodeName() + "_" +
node.getAttributes().item(0).getNodeValue()
, expected);
Assert.assertEquals(node2, node);
}
/**
* Verifies that the result of evaluating the name and local-name functions
* matches the expected result.
*
* @param exp XPath expression
* @param expected expected result
* @throws Exception if test fails
*/
@Test(dataProvider = "nameExpTestCases")
void testNameFn(String exp, String expected) throws Exception {
XPath xPath = XPathFactory.newInstance().newXPath();
String s = xPath.evaluateExpression(exp, doc, String.class);
String s2 = (String) xPath.evaluate(exp, doc, XPathConstants.STRING);
Assert.assertEquals(s, expected);
Assert.assertEquals(s2, s);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -31,11 +31,6 @@ import java.util.concurrent.atomic.AtomicLong;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import static javax.xml.xpath.XPathConstants.BOOLEAN;
import static javax.xml.xpath.XPathConstants.NUMBER;
import static javax.xml.xpath.XPathConstants.STRING;
import static javax.xml.xpath.XPathConstants.NODE;
import static javax.xml.xpath.XPathConstants.NODESET;
import javax.xml.xpath.XPathNodes;
import javax.xml.xpath.XPathEvaluationResult;
@ -51,42 +46,123 @@ import org.w3c.dom.Node;
* Base class for XPath test
*/
class XPathTestBase {
static final String DECLARATION = "<?xml version=\"1.0\" " +
"encoding=\"UTF-8\" standalone=\"yes\"?>";
static final String rawXML
= "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
+ "<Customers>"
+ " <Customer id=\"1\">"
static final String DTD = """
<!DOCTYPE Customers [
<!ELEMENT Customers (Customer*)>
<!ELEMENT Customer (Name, Phone, Email, Address)>
<!ELEMENT Name (#PCDATA)>
<!ELEMENT Phone (#PCDATA)>
<!ELEMENT Email (#PCDATA)>
<!ELEMENT Address (Street, City, State)>
<!ELEMENT Street (#PCDATA)>
<!ELEMENT City (#PCDATA)>
<!ELEMENT State (#PCDATA)>
<!ATTLIST Customer id ID #REQUIRED>
<!ATTLIST Email id ID #REQUIRED>
]>
""";
static final String RAW_XML
= "<Customers xmlns:foo=\"foo\">"
+ " <Customer id=\"x1\">"
+ " <Name>name1</Name>"
+ " <Phone>1111111111</Phone>"
+ " <Email>123@xyz.com</Email>"
+ " <Email id=\"x\">123@xyz.com</Email>"
+ " <Address>"
+ " <Street>1111 111st ave</Street>"
+ " <City>The City</City>"
+ " <State>The State</State>"
+ " </Address>"
+ " </Customer>"
+ " <Customer id=\"2\">"
+ " <Name>name1</Name>"
+ " <Customer id=\"x2\">"
+ " <Name>name2</Name>"
+ " <Phone>2222222222</Phone>"
+ " <Email>123@xyz.com</Email>"
+ " <Email id=\"y\">123@xyz.com</Email>"
+ " <Address>"
+ " <Street>2222 222nd ave</Street>"
+ " <City>The City</City>"
+ " <State>The State</State>"
+ " </Address>"
+ " </Customer>"
+ " <Customer id=\"3\">"
+ " <Name>name1</Name>"
+ " <Customer id=\"x3\">"
+ " <Name>name3</Name>"
+ " <Phone>3333333333</Phone>"
+ " <Email>123@xyz.com</Email>"
+ " <Email id=\"z\">123@xyz.com</Email>"
+ " <Address>"
+ " <Street>3333 333rd ave</Street>"
+ " <City>The City</City>"
+ " <State>The State</State>"
+ " </Address>"
+ " </Customer>"
+ " <foo:Customer foo:id=\"x1\">"
+ " <foo:Name>name1</foo:Name>"
+ " <foo:Phone>1111111111</foo:Phone>"
+ " <foo:Email foo:id=\"x\">123@xyz.com</foo:Email>"
+ " <foo:Address>"
+ " <foo:Street>1111 111st ave</foo:Street>"
+ " <foo:City>The City</foo:City>"
+ " <foo:State>The State</foo:State>"
+ " </foo:Address>"
+ " </foo:Customer>"
+ "</Customers>";
// Number of root element.
final int ROOT = 1;
// Number of Customer elements.
final int CUSTOMERS = 3;
// Number of id attributes.
final int ID_ATTRIBUTES = 6;
// Number of child elements of Customer.
final int CUSTOMER_ELEMENTS = 7;
// Number of Customer in the foo namespace.
final int FOO_CUSTOMERS = 1;
// Number of id attributes in the foo namespace.
final int FOO_ID_ATTRIBUTES = 2;
/**
* Returns a {@link org.w3c.dom.Document} for XML with DTD.
* @return a DOM Document
* @throws RuntimeException if any error occurred during document
* initialization.
*/
public static Document getDtdDocument() throws RuntimeException {
return documentOf(DECLARATION + DTD + RAW_XML);
}
/**
* Returns a {@link org.w3c.dom.Document} for raw XML.
* @return a DOM Document
* @throws RuntimeException if any error occurred during document
* initialization.
*/
public static Document getDocument() throws RuntimeException {
return documentOf(DECLARATION + RAW_XML);
}
/**
* Returns a {@link org.w3c.dom.Document} for input XML string.
* @param xml the input xml string.
* @return a DOM Document.
* @throws RuntimeException if any error occurred during document
* initialization.
*/
public static Document documentOf(String xml) throws RuntimeException {
try {
var dBF = DocumentBuilderFactory.newInstance();
dBF.setValidating(false);
dBF.setNamespaceAware(true);
return dBF.newDocumentBuilder().parse(
new ByteArrayInputStream(xml.getBytes("UTF-8")));
} catch (Exception e) {
System.out.println("Exception while initializing XML document");
throw new RuntimeException(e.getMessage());
}
}
void verifyResult(XPathEvaluationResult<?> result, Object expected) {
switch (result.type()) {
case BOOLEAN:
@ -126,13 +202,13 @@ class XPathTestBase {
public Object[][] getInvalidNumericTypes() {
XPath xpath = XPathFactory.newInstance().newXPath();
return new Object[][]{{xpath, AtomicInteger.class},
{xpath, AtomicInteger.class},
{xpath, AtomicLong.class},
{xpath, BigDecimal.class},
{xpath, BigInteger.class},
{xpath, Byte.class},
{xpath, Float.class},
{xpath, Short.class}
{xpath, AtomicInteger.class},
{xpath, AtomicLong.class},
{xpath, BigDecimal.class},
{xpath, BigInteger.class},
{xpath, Byte.class},
{xpath, Float.class},
{xpath, Short.class}
};
}
@ -140,13 +216,8 @@ class XPathTestBase {
* DataProvider: XPath and Document objects
*/
@DataProvider(name = "document")
public Object[][] getDocument() throws Exception {
DocumentBuilderFactory dBF = DocumentBuilderFactory.newInstance();
dBF.setValidating(false);
dBF.setNamespaceAware(true);
Document doc = dBF.newDocumentBuilder().parse(
new ByteArrayInputStream(rawXML.getBytes("UTF-8")));
public Object[][] getDocuments() throws RuntimeException {
Document doc = getDocument();
return new Object[][]{{XPathFactory.newInstance().newXPath(), doc}};
}
}