8289509: Improve test coverage for XPath Axes: descendant, descendant-or-self, following, following-sibling

Reviewed-by: bhuang, joehw
This commit is contained in:
Mahendra Chhipa 2022-10-12 18:13:20 +00:00
parent 5699041adb
commit 1961e81e02
2 changed files with 358 additions and 0 deletions

View File

@ -0,0 +1,173 @@
/*
* 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 javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
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 org.w3c.dom.NodeList;
/*
* @test
* @bug 8289509
* @library /javax/xml/jaxp/unittest
* @run testng/othervm xpath.XPathExpDescendantTest
* @summary Tests for XPath descendant/descendant-or-self axis specifier.
*/
public class XPathExpDescendantTest extends XPathTestBase {
/*
* DataProvider: provides XPath Axis descendant expressions and equivalent xpath expression.
*/
@DataProvider(name = "descendantXpath")
public Object[][] getDescendantXpathExpression() {
return new Object[][] {
{"/Customers/descendant::*", "/Customers//*"},
{"/Customers/descendant::Customer", "//Customer"},
{"/Customers/descendant::foo:Customer", "//foo:Customer"},
{"/Customers/Customer[@id='x1']/descendant::Address",
"/Customers/Customer[@id='x1']/Address"},
{"/Customers/Customer[@id='x1']/descendant::*",
"/Customers/Customer[@id='x1']//*"},
{"/Customers/foo:Customer/foo:Address/descendant::*",
"/Customers/foo:Customer/foo:Address//*"},
{"/Customers/descendant::Name", "/Customers//Name"},
{"/Customers/descendant::Street", "/Customers//Street"},
{"/Customers/descendant::Street[2]", "Customers/Customer[@id='x2']/Address/Street"},
{"/Customers/descendant::Street[2]", "(Customers//Street)[2]"},
{"/Customers/descendant::Street[position() = 2]",
"Customers/Customer[@id='x2']/Address/Street"},
{"/Customers/descendant-or-self::*", "//*"},
{"/Customers/descendant-or-self::Customer", "/Customers/Customer"},
{"/Customers/descendant-or-self::foo:Customer", "/Customers/foo:Customer"},
{"/Customers/Customer[@id='x1']/descendant-or-self::Address",
"/Customers/Customer[@id = 'x1']/Address"},
{"/Customers/Customer[@id='x1']/descendant-or-self::*",
"/Customers/Customer[@id='x1'] | /Customers/Customer[@id = 'x1']//*"},
{"/Customers/foo:Customer/foo:Address/descendant-or-self::*",
"/Customers/foo:Customer/foo:Address | /Customers/foo:Customer/foo:Address//*"},
{"/Customers/Customer/*[descendant::Street]", "/Customers/Customer/Address"},
{"/Customers/Customer/*[not(descendant::Street)]", "/Customers/Customer/*[name() != \"Address\"]"},
{"/Customers/Customer/*[descendant-or-self::Street]", "/Customers/Customer/Address"},
{"/Customers/Customer/*[not(descendant-or-self::Street)]",
"/Customers/Customer/*[name() != \"Address\"]"}
};
}
/*
* DataProvider: provides XPath descendant expressions and expected number of descendant nodes returned
*/
@DataProvider(name = "descendantXpathNodeCount")
public Object[][] getDescendantXpathExpressionNodeCount() {
return new Object[][] {
{"/Customers/descendant::*", 40},
{"/Customers/descendant::Customer", 3},
{"/Customers/descendant::foo:Customer", 1},
{"/Customers/Customer[@id='x1']/descendant::Address", 1},
{"/Customers/Customer[@id='x1']/descendant::*", 9},
{"/Customers/foo:Customer/foo:Address/descendant::*", 3},
{"/Customers/Customer[@id='x1']/Address/descendant::Address", 0},
{"/Customers/descendant-or-self::*", 41},
{"/Customers/descendant-or-self::Customer", 3},
{"/Customers/descendant-or-self::foo:Customer", 1},
{"/Customers/Customer[@id='x1']/descendant-or-self::Address", 1},
{"/Customers/Customer[@id='x1']/Address/descendant-or-self::Address", 1},
{"/Customers/Customer[@id='x1']/descendant-or-self::*", 10},
{"/Customers/foo:Customer/foo:Address/descendant-or-self::*", 4},
{"/Customers/*[descendant::Name]", 3},
{"/Customers/foo:Customer/*[descendant-or-self::foo:Street]", 1}
};
}
/*
* DataProvider: provides XPath descendant expressions which should return null.
*/
@DataProvider(name = "descendantXpathEmpty")
public Object[][] getDescendantXpathExpressionEmpty() {
return new Object[][] {
{"/Customers/Customer/Name/descendant::*"},
{"/Customers/foo:Customer/descendant::Name"},
{"/Customers/Customer/descendant::foo:Name"},
{"/Customers/descendant::id"},
{"/Customers/Customer/Name/descendant-or-self::id"},
{"/Customers/foo:Customer/descendant-or-self::Name"},
{"/Customers/Customer/descendant-or-self::foo:Name"},
{"/Customers/descendant-or-self::id"}
};
}
/**
* Verifies descendant xpath expression returns same nodes as returns when used normal xpath expression
* @param descexp descendant XPath expression.
* @param expath normal xPath expression
* @throws XPathExpressionException
*/
@Test(dataProvider = "descendantXpath")
public void descendantExpTests(String descexp, String expath) throws XPathExpressionException {
Document doc = documentOf(DECLARATION + RAW_XML);
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList actualNodeList = (NodeList) xPath.evaluate(descexp, doc, XPathConstants.NODESET);
NodeList expectedNodeList = (NodeList) xPath.evaluate(expath, doc, XPathConstants.NODESET);
Assert.assertEquals(actualNodeList.getLength(), expectedNodeList.getLength());
for(int i = 0; i < actualNodeList.getLength(); i++) {
actualNodeList.item(i).equals(expectedNodeList.item(i));
}
}
/**
* Verifies descendant xpath expression return descendant nodes list with correct number of nodes.
* @param exp XPath expression.
* @param nodeCount number of descendant nodes in nodelist.
* @throws XPathExpressionException
*/
@Test(dataProvider = "descendantXpathNodeCount")
public void descendantNodesCountTests(String exp, int nodeCount) throws XPathExpressionException {
Document doc = documentOf(DECLARATION + RAW_XML);
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nodeList = (NodeList) xPath.evaluate(exp, doc, XPathConstants.NODESET);
Assert.assertEquals(nodeList.getLength(), nodeCount);
}
/**
* Verifies descendant xpath expression return no nodes if descendant expression context nodes don't have matching descendants
* @param exp XPath expression.
* @throws XPathExpressionException
*/
@Test(dataProvider = "descendantXpathEmpty")
public void DescendantScopeTests(String exp) throws XPathExpressionException {
Document doc = documentOf(DECLARATION + RAW_XML);
XPath xPath = XPathFactory.newInstance().newXPath();
Node node = xPath.evaluateExpression(exp, doc, Node.class);
Assert.assertNull(node);
}
}

View File

@ -0,0 +1,185 @@
/*
* 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 javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
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 org.w3c.dom.NodeList;
/*
* @test
* @bug 8289509
* @library /javax/xml/jaxp/unittest
* @run testng/othervm xpath.XPathExpFollowingTest
* @summary Tests for XPath following/following-sibling axis specifier.
*/
public class XPathExpFollowingTest extends XPathTestBase {
/*
* DataProvider: provides XPath Axis following expressions and equivalent xpath expression.
*/
@DataProvider(name = "followingXpath")
public Object[][] getFollowingXpathExpression() {
return new Object[][] {
{"/Customers/following::*", "/None"},
{"/Customers/Customer/following::Customer", "//Customer[@id != 'x1']"},
{"/Customers/Customer/following::foo:Customer", "//foo:Customer"},
{"/Customers/Customer[@id='x1']/following::Address",
"/Customers/Customer[@id != 'x1']/Address"},
{"/Customers/Customer[@id='x1']/following::Street",
"/Customers/Customer[@id != 'x1']/Address/Street"},
{"/Customers/Customer[@id='x1']/following::Street[2]",
"/Customers/Customer[@id='x2']/Address/Street"},
{"/Customers/Customer[@id='x1']/following::*",
"/Customers/Customer[@id != 'x1']/descendant-or-self::*" +
" | /Customers/foo:Customer/descendant-or-self::*"},
{"/Customers/foo:Customer/foo:Address/following::*",
"/Customers/foo:Customer/foo:Age | /Customers/foo:Customer/foo:ClubMember"},
{"/Customers/Customer[@id = 'x1']/*[following::Street]", "/Customers/Customer[@id = 'x1']/*"},
{"/Customers/foo:Customer/*[following::foo:Name]", "/None"},
{"/Customers/foo:Customer/*[not(following::foo:Name)]", "/Customers/foo:Customer/*"},
{"/Customers/following-sibling::*", "/None"},
{"/Customers/Customer/following-sibling::Customer",
"/Customers/Customer[@id != 'x1']"},
{"/Customers/Customer/following-sibling::foo:Customer",
"/Customers/foo:Customer"},
{"/Customers/Customer[@id='x1']/Name/following-sibling::Address",
"/Customers/Customer[@id='x1']/Address"},
{"/Customers/Customer/Name/following-sibling::Address",
"/Customers//Address"},
{"(/Customers/Customer/Address/Street/following-sibling::State)[3]",
"/Customers/Customer[@id='x3']/Address/State"},
{"/Customers/Customer[@id='x1']/Address/Street/following-sibling::*[2]",
"/Customers/Customer[@id='x3']/Address/State"},
{"/Customers/Customer[@id='x1']/following-sibling::*",
"/Customers/Customer[@id != 'x1'] | /Customers/foo:Customer"},
{"/Customers/foo:Customer/foo:Address/following-sibling::*",
"/Customers/foo:Customer/foo:Age | /Customers/foo:Customer/foo:ClubMember"},
{"/Customers/Customer[@id = 'x1']/*[following-sibling::Street]", "/None"},
{"/Customers/foo:Customer/*[following-sibling::foo:Address]", "/Customers/foo:Customer/foo:Name |" +
"/Customers/foo:Customer/foo:Phone | /Customers/foo:Customer/foo:Email"},
{"/Customers/foo:Customer/*[not(following-sibling::foo:Address)]", "/Customers/foo:Customer/foo:Age | " +
"/Customers/foo:Customer/foo:ClubMember | /Customers/foo:Customer/foo:Address"}
};
}
/*
* DataProvider: provides XPath following expressions and expected number of following nodes returned
*/
@DataProvider(name = "followingXpathNodeCount")
public Object[][] getFollowingXpathExpressionNodeCount() {
return new Object[][] {
{"/Customers/following::*", 0},
{"/Customers/Customer/following::*", 30},
{"/Customers/Customer/following::Customer", 2},
{"/Customers/Customer/following::foo:Customer", 1},
{"/Customers/Customer[@id='x1']/Name/following::*", 38},
{"/Customers/Customer/Address/following::*", 32},
{"/Customers/foo:Customer/foo:Address/following::*", 2},
{"/Customers/foo:Customer/foo:Name/following::*", 8},
{"/Customers/foo:Customer/*[following::foo:Name]", 0},
{"/Customers/foo:Customer/*[not(following::foo:Name)]", 6},
{"/Customers/following-sibling::*", 0},
{"/Customers/Customer/following-sibling::*", 3},
{"/Customers/Customer/following-sibling::Customer", 2},
{"/Customers/Customer/following-sibling::foo:Customer", 1},
{"/Customers/Customer[@id='x1']/Name/following-sibling::*", 5},
{"/Customers/Customer/Address/following-sibling::*", 6},
{"/Customers/Customer[@id='x1']/Address/following-sibling::*", 2},
{"/Customers/foo:Customer/foo:Address/following-sibling::*", 2},
{"/Customers/Customer[@id = 'x1']/*[following-sibling::Street]", 0},
{"/Customers/foo:Customer/*[following-sibling::foo:Address]", 3},
{"/Customers/foo:Customer/*[not(following-sibling::foo:Address)]", 3}
};
}
/*
* DataProvider: provides XPath following expressions which should not return any node.
*/
@DataProvider(name = "followingXpathEmpty")
public Object[][] getFollowingXpathExpressionEmpty() {
return new Object[][] {
{"/Customers/following::*"},
{"/Customers/foo:Customer/following::*"},
{"/Customers/Customer[@id = 'x3' ]/following::Customer"},
{"/Customers/following::id"},
{"/Customers/Customer[@id = 'x3' ]/following-sibling::Customer"},
{"/Customers/foo:Customer/following-sibling::*"},
{"/Customers/Customer/following-sibling::foo:Name"},
{"/Customers/following-sibling::id"}
};
}
/**
* Verifies Axis following xpath expression returns same nodes as returns when used normal xpath expression
* @param descexp Axis following XPath expression.
* @param expath normal xPath expression
* @throws XPathExpressionException
*/
@Test(dataProvider = "followingXpath")
public void followingExpTests(String descexp, String expath) throws XPathExpressionException {
Document doc = documentOf(DECLARATION + RAW_XML);
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList actualNodeList = (NodeList) xPath.evaluate(descexp, doc, XPathConstants.NODESET);
NodeList expectedNodeList = (NodeList) xPath.evaluate(expath, doc, XPathConstants.NODESET);
Assert.assertEquals(actualNodeList.getLength(), expectedNodeList.getLength());
for(int i = 0; i < actualNodeList.getLength(); i++) {
actualNodeList.item(i).equals(expectedNodeList.item(i));
}
}
/**
* Verifies following xpath expression return following nodes list with correct number of nodes.
* @param exp XPath expression.
* @param nodeCount number of following nodes in nodelist.
* @throws XPathExpressionException
*/
@Test(dataProvider = "followingXpathNodeCount")
public void followingNodesCountTests(String exp, int nodeCount) throws XPathExpressionException {
Document doc = documentOf(DECLARATION + RAW_XML);
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nodeList = (NodeList) xPath.evaluate(exp, doc, XPathConstants.NODESET);
Assert.assertEquals(nodeList.getLength(), nodeCount);
}
/**
* Verifies following xpath expression return no nodes if following expression context nodes don't have matching following elements.
* @param exp XPath expression.
* @throws XPathExpressionException
*/
@Test(dataProvider = "followingXpathEmpty")
public void FollowingScopeTests(String exp) throws XPathExpressionException {
Document doc = documentOf(DECLARATION + RAW_XML);
XPath xPath = XPathFactory.newInstance().newXPath();
Node node = xPath.evaluateExpression(exp, doc, Node.class);
Assert.assertNull(node);
}
}