| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to you under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.jmeter.util; |
| |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertNull; |
| import static org.junit.jupiter.api.Assertions.assertThrows; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.io.PrintStream; |
| import java.io.StringReader; |
| import java.nio.charset.StandardCharsets; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.stream.Stream; |
| |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.stream.FactoryConfigurationError; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.transform.TransformerException; |
| import javax.xml.transform.stream.StreamSource; |
| |
| import org.apache.jmeter.assertions.AssertionResult; |
| import org.hamcrest.CoreMatchers; |
| import org.junit.jupiter.api.Test; |
| import org.junit.jupiter.params.ParameterizedTest; |
| import org.junit.jupiter.params.provider.Arguments; |
| import org.junit.jupiter.params.provider.CsvSource; |
| import org.junit.jupiter.params.provider.MethodSource; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.SAXException; |
| |
| import net.sf.saxon.s9api.Processor; |
| import net.sf.saxon.s9api.SaxonApiException; |
| import net.sf.saxon.s9api.XPathCompiler; |
| import net.sf.saxon.s9api.XPathExecutable; |
| import net.sf.saxon.s9api.XPathSelector; |
| import net.sf.saxon.s9api.XdmItem; |
| import net.sf.saxon.s9api.XdmValue; |
| |
| public class XPathUtilTest { |
| private final String lineSeparator = System.getProperty("line.separator"); |
| |
| final String xmlDoc = JMeterUtils.getResourceFileAsText("XPathUtilTestXml.xml"); |
| |
| @Test |
| public void testBug63033() throws SaxonApiException { |
| Processor p = new Processor(false); |
| XPathCompiler c = p.newXPathCompiler(); |
| c.declareNamespace("age", "http://www.w3.org/2003/01/geo/wgs84_pos#"); |
| String xPathQuery="//Employees/Employee[1]/age:ag"; |
| XPathExecutable e = c.compile(xPathQuery); |
| XPathSelector selector = e.load(); |
| selector.setContextItem(p.newDocumentBuilder().build(new StreamSource(new StringReader(xmlDoc)))); |
| XdmValue nodes = selector.evaluate(); |
| XdmItem item = nodes.itemAt(0); |
| assertEquals("<age:ag xmlns:age=\"http://www.w3.org/2003/01/geo/wgs84_pos#\">29</age:ag>", item.toString()); |
| } |
| |
| @Test |
| public void testputValuesForXPathInListUsingSaxon() throws SaxonApiException, FactoryConfigurationError{ |
| String xPathQuery="//Employees/Employee/role"; |
| ArrayList<String> matchStrings = new ArrayList<>(); |
| boolean fragment = false; |
| String namespaces = "age=http://www.w3.org/2003/01/geo/wgs84_pos#"; |
| int matchNumber = 3; |
| |
| XPathUtil.putValuesForXPathInListUsingSaxon(xmlDoc, xPathQuery, matchStrings, fragment, matchNumber, namespaces); |
| assertEquals("Manager", matchStrings.get(0)); |
| |
| matchNumber = 0; |
| xPathQuery="//Employees/Employee[1]/age:ag"; |
| fragment = true; |
| matchStrings.clear(); |
| XPathUtil.putValuesForXPathInListUsingSaxon(xmlDoc, xPathQuery, matchStrings, fragment, matchNumber, namespaces); |
| assertEquals("<age:ag xmlns:age=\"http://www.w3.org/2003/01/geo/wgs84_pos#\">29</age:ag>", matchStrings.get(0)); |
| assertEquals(1, matchStrings.size()); |
| |
| matchNumber = -1; |
| xPathQuery="//Employees/Employee/age:ag"; |
| matchStrings.clear(); |
| XPathUtil.putValuesForXPathInListUsingSaxon(xmlDoc, xPathQuery, matchStrings, fragment, matchNumber, namespaces); |
| assertEquals("<age:ag xmlns:age=\"http://www.w3.org/2003/01/geo/wgs84_pos#\">29</age:ag>", matchStrings.get(0)); |
| assertEquals(4, matchStrings.size()); |
| |
| fragment = false; |
| matchStrings.clear(); |
| XPathUtil.putValuesForXPathInListUsingSaxon(xmlDoc, xPathQuery, matchStrings, fragment, matchNumber, namespaces); |
| assertEquals("29", matchStrings.get(0)); |
| assertEquals(4, matchStrings.size()); |
| |
| matchStrings.clear(); |
| xPathQuery="regtsgwsdfstgsdf"; |
| XPathUtil.putValuesForXPathInListUsingSaxon(xmlDoc, xPathQuery, matchStrings, fragment, matchNumber, namespaces); |
| assertEquals(new ArrayList<String>(), matchStrings); |
| assertEquals(0, matchStrings.size()); |
| |
| matchStrings.clear(); |
| xPathQuery="//Employees/Employee[1]/age:ag"; |
| matchNumber = 555; |
| XPathUtil.putValuesForXPathInListUsingSaxon(xmlDoc, xPathQuery, matchStrings, fragment, matchNumber, namespaces); |
| assertEquals(new ArrayList<String>(), matchStrings); |
| assertEquals(0, matchStrings.size()); |
| } |
| |
| static Stream<Arguments> namespaceData() { |
| return Stream.of( |
| Arguments.of("donald=duck", "donald", "duck", 0), |
| Arguments.of("donald=duck\nmickey=mouse", "donald", "duck", 0), |
| Arguments.of("donald=duck\nmickey=mouse", "mickey", "mouse", 1), |
| Arguments.of("donald=duck\n\n\nmickey=mouse", "mickey", "mouse", 1), |
| Arguments.of("donald=duck\n\n\nmickey=mouse", "donald", "duck", 0), |
| Arguments.of("donald=duck\n \n \nmickey=mouse\n \n\n", "donald", "duck", 0), |
| Arguments.of("donald=duck\n \n \nmickey=mouse\n \n\n", "mickey", "mouse", 1), |
| Arguments.of(" \n \ndonald=duck\n \n \nmickey=mouse\n \n\n", "donald", "duck", 0), |
| Arguments.of(" \n \ndonald=duck\n \n \nmickey=mouse\n \n\n", "mickey", "mouse", 1) |
| ); |
| } |
| @ParameterizedTest |
| @MethodSource("namespaceData") |
| public void testnamespacesParse(String namespaces, String key, String value, int position) { |
| List<String[]> test = XPathUtil.namespacesParse(namespaces); |
| assertEquals(key, test.get(position)[0]); |
| assertEquals(value, test.get(position)[1]); |
| } |
| |
| @Test |
| public void testFormatXmlSimple() { |
| assertThat(XPathUtil.formatXml("<one foo='bar'>Test</one>"), |
| CoreMatchers.is("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" |
| + "<one foo=\"bar\">Test</one>" + lineSeparator)); |
| } |
| |
| @Test |
| public void testFormatXmlComplex() { |
| assertThat( |
| XPathUtil.formatXml( |
| "<one foo='bar'><two/><three><four p=\"1\"/></three>...</one>"), |
| CoreMatchers.is(String.join(lineSeparator, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><one foo=\"bar\">", |
| " <two/>", |
| " <three>", |
| " <four p=\"1\"/>", |
| " </three>...</one>", |
| ""))); |
| } |
| |
| @Test |
| public void testFormatXmlInvalid() { |
| PrintStream origErr = System.err; |
| try { |
| // The parser will print an error, so let it go where we will not see it |
| System.setErr(new PrintStream(new OutputStream() { |
| @Override |
| public void write(int b) throws IOException { |
| // ignore output |
| } |
| })); |
| assertThat("No well formed xml here", CoreMatchers |
| .is(XPathUtil.formatXml("No well formed xml here"))); |
| } finally { |
| System.setErr(origErr); |
| } |
| } |
| |
| @ParameterizedTest |
| @CsvSource(value = { |
| "/book,false,false,false", |
| "/book/error,false,false,true", |
| "/book/error,true,false,false", |
| "/book/preface,true,false,true", |
| "count(/book/page)=2,false,false,false", |
| "count(/book/page)=2,true,false,true", |
| "count(/book/page)=1,false,false,true", |
| "count(/book/page)=1,true,false,false", |
| "///book,false,true,false" |
| }) |
| public void testMakeDocument(String xpathquery, boolean isNegated, boolean isError, boolean isFailure) |
| throws ParserConfigurationException, SAXException, IOException, TidyException { |
| String responseData = "<book><preface>zero</preface><page>one</page><page>two</page><empty></empty><a><b></b></a></book>"; |
| Document testDoc = XPathUtil.makeDocument( |
| new ByteArrayInputStream(responseData.getBytes(StandardCharsets.UTF_8)), |
| false, false, false, false, |
| false, false, false, false, false); |
| AssertionResult res = new AssertionResult("test"); |
| XPathUtil.computeAssertionResult(res, testDoc, xpathquery, isNegated); |
| assertEquals(isError, res.isError(), "test isError"); |
| assertEquals(isFailure, res.isFailure(), "test isFailure"); |
| } |
| |
| @Test |
| public void testGetNamespaces() throws XMLStreamException, FactoryConfigurationError { |
| String responseData = "<age:ag xmlns:age=\"http://www.w3.org/wgs84_pos#\">\n" |
| + "<hd:head xmlns:hd=\"http://www.w3.org/wgs85_pos#\"><title>test</title></hd:head></age:ag>"; |
| List<String[]> res = XPathUtil.getNamespaces(responseData); |
| assertEquals("age", res.get(0)[0]); |
| assertEquals("http://www.w3.org/wgs84_pos#", res.get(0)[1]); |
| assertEquals("hd", res.get(1)[0]); |
| assertEquals("http://www.w3.org/wgs85_pos#", res.get(1)[1]); |
| } |
| |
| @ParameterizedTest |
| @CsvSource(value = { |
| "/book,false,false,false", |
| "/book,true,false,true", |
| "/b,false,false,true", |
| "/b,true,false,false", |
| "count(//page)=2,false,false,false", |
| "count(//page)=2,true,false,true", |
| "count(//page)=3,false,false,true", |
| "count(//page)=3,true,false,false" |
| }) |
| public void testComputeAssertionResultUsingSaxon(String xpathquery, boolean isNegated, boolean isError, boolean isFailure) |
| throws SaxonApiException, FactoryConfigurationError { |
| //test xpath2 assertion |
| AssertionResult res = new AssertionResult("test"); |
| String responseData = "<book><page>one</page><page>two</page><empty></empty><a><b></b></a></book>"; |
| XPathUtil.computeAssertionResultUsingSaxon(res, responseData, xpathquery, "", isNegated); |
| assertEquals(isError, res.isError()); |
| assertEquals(isFailure, res.isFailure()); |
| } |
| |
| @Test |
| public void testPutValuesForXPathInList() |
| throws ParserConfigurationException, SAXException, IOException, TidyException, TransformerException { |
| String responseData = "<book><page>one</page><page>two</page><empty></empty><a><b></b></a></book>"; |
| Document testDoc = XPathUtil.makeDocument( |
| new ByteArrayInputStream( |
| responseData.getBytes(StandardCharsets.UTF_8)), |
| false, false, false, false, |
| false, false, false, false, false); |
| String xpathquery = "/book/page"; |
| List<String> matchs=new ArrayList<>(); |
| XPathUtil.putValuesForXPathInList(testDoc, xpathquery, matchs, true); |
| assertEquals("<page>one</page>", matchs.get(0)); |
| assertEquals("<page>two</page>", matchs.get(1)); |
| matchs=new ArrayList<>(); |
| XPathUtil.putValuesForXPathInList(testDoc, xpathquery, matchs, false); |
| assertEquals(2, matchs.size()); |
| assertEquals("one", matchs.get(0)); |
| assertEquals("two", matchs.get(1)); |
| matchs=new ArrayList<>(); |
| XPathUtil.putValuesForXPathInList(testDoc, "/book/a", matchs, false); |
| assertEquals(1, matchs.size()); |
| assertNull(matchs.get(0)); |
| } |
| |
| @Test |
| public void testSelectNodeList() throws ParserConfigurationException, SAXException, IOException, TidyException, TransformerException { |
| String responseData = "<book><page>one</page><page>two</page><empty></empty><a><b></b></a></book>"; |
| Document testDoc = XPathUtil.makeDocument( |
| new ByteArrayInputStream(responseData.getBytes(StandardCharsets.UTF_8)), false, false, false, false, |
| false, false, false, false, false); |
| String xpathquery = "/book/page"; |
| NodeList nodeList = XPathUtil.selectNodeList(testDoc, xpathquery); |
| assertEquals(2, nodeList.getLength()); |
| Element e0 = (Element) nodeList.item(0); |
| Element e1 = (Element) nodeList.item(1); |
| assertEquals("one", e0.getTextContent()); |
| assertEquals("two", e1.getTextContent()); |
| } |
| |
| @Test() |
| public void testSelectNodeListWithInvalidXPath() throws Exception { |
| String responseData = "<book><page>one</page><page>two</page><empty></empty><a><b></b></a></book>"; |
| Document testDoc = XPathUtil.makeDocument( |
| new ByteArrayInputStream(responseData.getBytes(StandardCharsets.UTF_8)), false, false, false, false, |
| false, false, false, false, false); |
| String xpathquery = "<"; |
| assertThrows(TransformerException.class, () -> XPathUtil.selectNodeList(testDoc, xpathquery)); |
| } |
| } |