/*
* Copyright 2016 the original author or authors.
*
* Licensed 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 io.restassured.path.xml;
import io.restassured.path.xml.config.XmlPathConfig;
import io.restassured.path.xml.element.Node;
import io.restassured.path.xml.element.NodeChildren;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static io.restassured.path.xml.XmlPath.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
public class XmlPathTest {
private static final String XML = "<shopping>\n" +
" <category type=\"groceries\">\n" +
" <item>\n" +
"\t <name>Chocolate</name>\n" +
" <price>10</" +
"price>\n" +
"" +
" " +
"\t</item>\n" +
" <item>\n" +
"\t <name>Coffee</name>\n" +
" <price>20</price>\n" +
"\t</item>\n" +
" </category>\n" +
" <category type=\"supplies\">\n" +
" <item>\n" +
"\t <name>Paper</name>\n" +
" <price>5</price>\n" +
"\t</item>\n" +
" <item quantity=\"4\">\n" +
" <name>Pens</name>\n" +
" <price>15.5</price>\n" +
"\t</item>\n" +
" </category>\n" +
" <category type=\"present\">\n" +
" <item when=\"Aug 10\">\n" +
" <name>Kathryn's Birthday</name>\n" +
" <price>200</price>\n" +
" </item>\n" +
" </category>\n" +
"</shopping>";
private static final String GREETING = "<greeting><firstName>John</firstName>\n" +
" <lastName>Doe</lastName>\n" +
" </greeting>";
private static final String RECORDS = "<records>\n" +
" <car name='HSV Maloo' make='Holden' year='2006'>\n" +
" <country>Australia</country>\n" +
" <record type='speed'>Pickup Truck with speed of 271kph</record>\n" +
" </car>\n" +
" <car name='P50' make='Peel' year='1962'>\n" +
" <country>Isle of Man</country>\n" +
" <record type='size'>Street-Legal Car at 99cm wide, 59kg</record>\n" +
" </car>\n" +
" <car name='Royale' make='Bugatti' year='1931'>\n" +
" <country>France</country>\n" +
" <record type='price'>Most Valuable Car at $15 million</record>\n" +
" </car>\n" +
"</records>";
private static final String ATTR_WITH_MINUS = "<something has-a-name=\"some\" />";
private static final String XML_WITH_DOT_IN_NAME = "<something><com.mycompany.Filter>Hello</com.mycompany.Filter><some-value>Some value</some-value></something>";
private static final String RSS = "<?xml version=\"1.0\"?>\n" +
"<rss version=\"2.0\">\n" +
" <channel>\n" +
" <title>Some title</title>\n" +
" <link>http://www.google.com</link>\n" +
" <description>Description</description>\n" +
" <category domain=\"http://mycompany.com/category\">games</category>\n" +
" <item>\n" +
" <title>Item title</title>\n" +
" <link>http://www.somelink.org</link>\n" +
" <description>Some cool game</description>\n" +
" <enclosure length=\"58433\" type=\"image/jpeg\" url=\"https://mycompany.org/some.jpg\"/>\n" +
" <category domain=\"http://mycompany.com/rss/first\">First category</category>\n" +
" <category domain=\"http://mycompany.com/rss/second\">Second category</category>\n" +
" <pubDate>Sun, 04 Sep 2011 15:32:25 GMT</pubDate>\n" +
" <guid>1234</guid>\n" +
" </item>\n" +
" </channel>\n" +
"</rss>";
private static final String LIST_WITH_INTS = "<some>\n" +
" <thing id=\"1\">ikk</thing>\n" +
" <thing id=\"2\">ikk2</thing>\n" +
" <thing id=\"3\">ikk3</thing>\n" +
"</some>";
private static final String NOT_PRETTY_XML = "<some><thing id=\"1\">ikk</thing><thing id=\"2\">ikk2</thing><thing id=\"3\">3</thing></some>";
private static final String UUID_XML = "<some>\n" +
" <thing id=\"1\">db24eeeb-7fe5-41d3-8f06-986b793ecc91</thing>\n" +
" <thing id=\"2\">d69ded28-d75c-460f-9cbe-1412c60ed4cc</thing>\n" +
"</some>";
@Test
public void initializeUsingCtorAndGetList() throws Exception {
final NodeChildren categories = new XmlPath(XML).get("shopping.category");
assertThat(categories.size(), equalTo(3));
}
@Test
public void getNodeChildrenAsListWithTypeNodeReturnsAListOfNodes() throws Exception {
final List<Node> categories = new XmlPath(XML).getList("shopping.category", Node.class);
assertThat(categories.size(), equalTo(3));
}
@Test
public void initializeUsingGivenAndGetAttributes() throws Exception {
final List<String> categories = given(XML).get("shopping.category.@type");
assertThat(categories, hasItems("groceries", "supplies", "present"));
}
@Test
public void initializeUsingWithAndGetList() throws Exception {
final NodeChildren categories = with(XML).get("shopping.category");
assertThat(categories.size(), equalTo(3));
}
@Test
public void initializeUsingWithAndGetChildren() throws Exception {
final List<String> categories = with(XML).get("shopping.category.item.name.list()");
assertThat(categories, hasItems("Chocolate", "Coffee", "Paper", "Pens", "Kathryn's Birthday"));
}
@Test
public void returnItems() throws Exception {
final List<String> categories = with(XML).get("shopping.category.item.children().list()");
assertThat(categories, hasItems("Chocolate", "Coffee", "Paper", "Pens", "Kathryn's Birthday"));
}
@Test
public void itemsWithPriceBetweenTenAndTwenty() throws Exception {
final List<Node> itemsBetweenTenAndTwenty = with(XML).get("shopping.category.item.findAll { item -> def price = item.price.toFloat(); price >= 10 && price <= 20 }");
assertThat(itemsBetweenTenAndTwenty.size(), equalTo(3));
final Node category1 = itemsBetweenTenAndTwenty.get(0);
final NodeChildren categoryChildren = category1.children();
assertThat(categoryChildren, hasItems("Chocolate", "10"));
for (Node item : categoryChildren.nodeIterable()) {
assertThat(item.name(), anyOf(equalTo("name"), equalTo("price")));
}
}
@Test
public void multipleGetsWithOneInstanceOfXmlPath() throws Exception {
final XmlPath xmlPath = new XmlPath(XML);
assertThat(xmlPath.getInt("shopping.category.item.size()"), equalTo(5));
assertThat(xmlPath.getList("shopping.category.item.children().list()", String.class), hasItem("Pens"));
}
@Test
public void rootPathNotEndingWithDot() throws Exception {
final XmlPath xmlPath = new XmlPath(XML).setRoot("shopping.category.item");
assertThat(xmlPath.getInt("size()"), equalTo(5));
assertThat(xmlPath.getList("children().list()", String.class), hasItem("Pens"));
}
@Test
public void rootPathEndingWithDot() throws Exception {
final XmlPath xmlPath = new XmlPath(XML).setRoot("shopping.category.item.");
assertThat(xmlPath.getInt("size()"), equalTo(5));
assertThat(xmlPath.getList("children().list()", String.class), hasItem("Pens"));
}
@Test
public void convertsNonRootObjectGraphToJavaObjects() throws Exception {
NodeChildren categories = with(XML).get("shopping.category");
assertThat(categories.size(), equalTo(3));
assertThat(categories.toString(), equalTo("Chocolate10Coffee20Paper5Pens15.5Kathryn's Birthday200"));
}
@Test
public void convertsRootObjectGraphToJavaObjects() throws Exception {
Node objects = with(XML).get("shopping");
assertThat(objects.toString(), equalTo("Chocolate10Coffee20Paper5Pens15.5Kathryn's Birthday200"));
}
@Test
public void firstCategoryAttributeFromJava() throws Exception {
Node node = with(XML).get("shopping.category[0]");
assertThat(node.getAttribute("@type"), equalTo("groceries"));
assertThat(node.getAttribute("type"), equalTo("groceries"));
assertThat((String) node.get("@type"), equalTo("groceries"));
}
@Test
public void gettingChildrenFromJava() throws Exception {
Node category = with(XML).get("shopping.category[0]");
final NodeChildren categoryChildren = category.children();
assertThat(categoryChildren.size(), equalTo(2));
for (Node item : categoryChildren.nodeIterable()) {
assertThat(item.children().size(), equalTo(2));
final Node name = item.get("name");
final Node price = item.get("price");
assertThat(name.value(), anyOf(equalTo("Chocolate"), equalTo("Coffee")));
assertThat(price.value(), anyOf(equalTo("10"), equalTo("20")));
}
}
@Test
public void getFirstItemName() throws Exception {
final String name = with(XML).get("shopping.category.item[0].name");
assertThat(name, equalTo("Chocolate"));
assertThat(with(XML).getString("shopping.category.item[0].name"), equalTo("Chocolate"));
}
@Test
public void getSingleAttributes() throws Exception {
final Map<String, String> categoryAttributes = with(XML).get("shopping.category[0].attributes()");
assertThat(categoryAttributes.size(), equalTo(1));
assertThat(categoryAttributes.get("type"), equalTo("groceries"));
}
@Test
public void gettingLeafReturnsValueInsteadOfNode() throws Exception {
String firstName = with(GREETING).get("greeting.firstName");
String lastName = with(GREETING).get("greeting.lastName");
assertThat(firstName, equalTo("John"));
assertThat(lastName, equalTo("Doe"));
}
@Test
public void getAllItemNames() throws Exception {
final List<String> items = with(XML).get("shopping.depthFirst().grep { it.name() == 'item' }.name");
assertThat(items, hasItems("Chocolate", "Coffee", "Paper", "Pens", "Kathryn's Birthday"));
}
@Test
public void getEntireObjectGraph() throws Exception {
final Node node = with(XML).get();
assertThat(node.name(), is("shopping"));
}
@Test
public void getLocationOfRecords() throws Exception {
final List<String> list = from(RECORDS).getList("records.car.country.list()", String.class);
assertThat(list, hasItems("Australia", "Isle of Man", "France"));
}
@Test
public void getFirstTwoYearsOfRecords() throws Exception {
final List<String> list = from(RECORDS).getList("records.car[0..1].@year", String.class);
assertThat(list, hasItems("2006", "1962"));
}
@Test
public void getFirstTwoYearsOfRecordsAsIntegers() throws Exception {
final List<Integer> list = from(RECORDS).getList("records.car[0..1].@year", Integer.class);
assertThat(list, hasItems(2006, 1962));
}
@Test
public void getTheEarliestRecord() throws Exception {
final int earliest = from(RECORDS).getInt("records.car.@year.list()*.toInteger().min()");
assertThat(earliest , is(1931));
}
@Test
public void getFirstTwoYearsOfRecordsUsingEscapedAttributeGetter() throws Exception {
final List<String> list = from(RECORDS).getList("records.car[0..1].'@year'", String.class);
assertThat(list, hasItems("2006", "1962"));
}
@Test
public void getNameOfLastCountry() throws Exception {
final String country = from(RECORDS).getString("records.car[-1].country");
assertThat(country, equalTo("France"));
}
@Test
public void getNameOfFirstCar() throws Exception {
final String name = from(RECORDS).getString("records.car[0].@name");
assertThat(name, equalTo("HSV Maloo"));
}
@Test
public void getIntParsesAStringResultToInt() throws Exception {
final int price = from(XML).getInt("shopping.category[0].item[0].price");
assertThat(price, equalTo(10));
}
@Test
public void depthFirstSearchingUsingDoubleStarNotation() throws Exception {
final int chocolatePrice = from(XML).getInt("shopping.'**'.find { it.name == 'Chocolate' }.price");
assertThat(chocolatePrice, equalTo(10));
}
@Test
public void depthFirstSearchingUsingUnEscapedDoubleStarNotation() throws Exception {
final int chocolatePrice = from(XML).getInt("shopping.**.find { it.name == 'Chocolate' }.price");
assertThat(chocolatePrice, equalTo(10));
}
@Test
public void depthFirstSearchDoubleStarWithParam() throws Exception {
final int chocolatePrice = from(XML)
.param("itemName", "Chocolate")
.getInt("shopping.'**'.find { it.name == itemName }.price");
assertThat(chocolatePrice, equalTo(10));
}
@Test
public void getUUIDParsesAStringResultToUUID() throws Exception {
final UUID uuid = from(UUID_XML).getUUID("some.thing[0]");
assertThat(uuid, equalTo(UUID.fromString("db24eeeb-7fe5-41d3-8f06-986b793ecc91")));
}
@Test
public void getListReturnsListWhenNodeChildrenFound() {
final List<String> groceries = from(XML).getList("shopping.category[0].item.name");
assertThat(groceries, hasItems("Chocolate", "Coffee"));
}
@Test
public void getListReturnsListWhenListFound() {
final List<String> groceries = from(XML).getList("shopping.category[0].item.name.list()");
assertThat(groceries, hasItems("Chocolate", "Coffee"));
}
@Test
public void getListWhenUsingExplicitTypeConvertsTheListMembersToThatType() {
final List<Float> groceries = from(XML).getList("shopping.category.item.price", Float.class);
assertThat(groceries, hasItems(10.0f, 20.0f, 5.0f, 15.5f, 200.0f));
}
@Test
public void getListWhenNotUsingExplicitTypeDoesntConvertTheListMembersToAnyType() {
final List<String> groceries = from(XML).getList("shopping.category.item.price");
assertThat(groceries, hasItems("10", "20", "5", "15.5", "200"));
}
@Test
public void getListAutomaticallyTransformsSingleObjectResultsToAList() {
final List<String> groceries = from(XML).getList("shopping.category.item.price[0]");
assertThat(groceries, hasItems("10"));
}
@Test
public void getAutomaticallyTransformsSingleObjectResultsToAListWhenSpecifiedInPath() {
final List<String> groceries = from(XML).get("shopping.category.item.price[0].list()");
assertThat(groceries, hasItems("10"));
}
@Test
public void rootDepthFirstSearchingWhenUsingDoubleStarNotation() throws Exception {
final List<String> groceries = from(XML).getList("**.find { it.@type == 'groceries' }.item.name");
assertThat(groceries, hasItems("Chocolate", "Coffee"));
}
@Test
public void rootDepthFirstSearchingWhenUsingEscapedDoubleStarNotation() throws Exception {
final List<String> groceries = from(XML).getList("'**'.find { it.@type == 'groceries' }.item.name");
assertThat(groceries, hasItems("Chocolate", "Coffee"));
}
@Test
public void rootDepthFirstSearchingWhenUsingDoubleStarNotationWhenPathStartsWithDot() throws Exception {
final List<String> groceries = from(XML).getList(".**.find { it.@type == 'groceries' }.item.name");
assertThat(groceries, hasItems("Chocolate", "Coffee"));
}
@Test
public void rootDepthFirstMethodSearching() throws Exception {
final List<String> groceries = from(XML).getList("depthFirst().find { it.@type == 'groceries' }.item.name");
assertThat(groceries, hasItems("Chocolate", "Coffee"));
}
@Test
public void canParsePathWithDoubleEscapeChars() throws Exception {
final String name = from(ATTR_WITH_MINUS).getString("something.@has-a-name");
assertThat(name, equalTo("some"));
}
@Test
public void canParseTagsWithDotIfUsingEscaping() throws Exception {
final String message = from(XML_WITH_DOT_IN_NAME).get("something.'com.mycompany.Filter'");
assertThat(message, equalTo("Hello"));
}
@Test
public void canParseTagsWithEscapedMinus() throws Exception {
final String message = from(XML_WITH_DOT_IN_NAME).getString("something.'some-value'");
assertThat(message, equalTo("Some value"));
}
@Test
public void canParseClosuresWithEscapedDotsInEqualExpression() throws Exception {
final String firstCategory = from(RSS).get("rss.**.find { it.@domain == 'http://mycompany.com/rss/first' }");
assertThat(firstCategory, equalTo("First category"));
}
@Test
public void convertsListMembersToExplicitType() throws Exception {
List<Integer> ids = from(LIST_WITH_INTS).getList("some.thing.@id", int.class);
assertThat(ids, hasItems(1, 2, 3));
}
@Test
public void xmlPathSupportsPrettifiyingTheXML() throws Exception {
final String prettify = with(NOT_PRETTY_XML).prettify();
String lineSeparator = System.getProperty("line.separator");
assertThat(prettify, endsWith("<some>" + lineSeparator + " <thing id=\"1\">ikk</thing>" + lineSeparator + " <thing id=\"2\">ikk2</thing>" + lineSeparator + " <thing id=\"3\">3</thing>" + lineSeparator + "</some>"));
}
@Test
public void xmlPathSupportsPrettyPrintingTheXML() throws Exception {
final String prettify = with(NOT_PRETTY_XML).prettyPrint();
String lineSeparator = System.getProperty("line.separator");
assertThat(prettify, endsWith("<some>" + lineSeparator + " <thing id=\"1\">ikk</thing>" + lineSeparator + " <thing id=\"2\">ikk2</thing>" + lineSeparator + " <thing id=\"3\">3</thing>" + lineSeparator + "</some>"));
}
@Test
public void xmlPathSupportsPrettyPeekingTheXML() throws Exception {
final String thing = with(NOT_PRETTY_XML).prettyPeek().getString("some.thing[0]");
assertThat(thing, equalTo("ikk"));
}
@Test
public void xmlPathSupportsPeekingTheXML() throws Exception {
final String thing = with(NOT_PRETTY_XML).peek().getString("some.thing[0]");
assertThat(thing, equalTo("ikk"));
}
@Test
public void canParseXmlFilteredAttributes() throws Exception {
final List<Integer> list = with(getClass().getResourceAsStream("/jmeter.jtl")).getList("testResults.httpSample.@t.findAll { it.text().toInteger() < 60000 }", int.class);
assertThat(list.size(), is(171));
}
@Test
public void parsesXmlRootTagCalledProperties() throws Exception {
// Given
String xml = "<properties>prop</properties>";
// When
final String properties = from(xml).getString("properties");
// Then
assertThat(properties, equalTo("prop"));
}
@Test
public void parsesNonXmlRootTagCalledProperties() throws Exception {
// Given
String xml = "<root><properties>prop</properties></root>";
// When
final String properties = from(xml).getString("root.properties");
// Then
assertThat(properties, equalTo("prop"));
}
@Test
public void disableDtdValidationWorks() throws Exception {
// Given
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<!DOCTYPE LegacyService SYSTEM \"http://example.com/dtd/NonExistent.dtd\">\n" +
"<LegacyService>Text</LegacyService>";
// When
final XmlPath xmlPath = new XmlPath(xml).using(XmlPathConfig.xmlPathConfig().with().disableLoadingOfExternalDtd());
// Then
assertThat(xmlPath.getString("LegacyService"), equalTo("Text"));
}
@Test
public void setting_feature_works() throws Exception {
// Given
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<!DOCTYPE LegacyService SYSTEM \"http://example.com/dtd/NonExistent.dtd\">\n" +
"<LegacyService>Text</LegacyService>";
// When
final XmlPath xmlPath = new XmlPath(xml).using(XmlPathConfig.xmlPathConfig().with().
feature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false).
feature("http://apache.org/xml/features/disallow-doctype-decl", false));
// Then
assertThat(xmlPath.getString("LegacyService"), equalTo("Text"));
}
@Test
public void setting_features_works() throws Exception {
// Given
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<!DOCTYPE LegacyService SYSTEM \"http://example.com/dtd/NonExistent.dtd\">\n" +
"<LegacyService>Text</LegacyService>";
Map<String, Boolean> features = new HashMap<String, Boolean>();
features.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
features.put("http://apache.org/xml/features/disallow-doctype-decl", false);
features.put("http://xml.org/sax/features/namespaces", false);
// When
final XmlPath xmlPath = new XmlPath(xml).using(XmlPathConfig.xmlPathConfig().with().features(features));
// Then
assertThat(xmlPath.getString("LegacyService"), equalTo("Text"));
}
@Test
public void xmlPathWorksWithSoap() throws Exception {
// Given
String soap = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
"<env:Envelope \n" +
" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" \n" +
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" \n" +
" xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" \n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
" <env:Header/>\n" +
"\n" +
"<env:Body>\n" +
" <n1:importProjectResponse \n" +
" xmlns:n1=\"n1\" \n" +
" xmlns:n2=\"n2\" \n" +
" xsi:type=\"n2:ArrayOfProjectImportResultCode\">\n" +
" <n2:ProjectImportResultCode>\n" +
" <n2:code>1</n2:code>\n" +
" <n2:message>Project 'test1' import was successful.</n2:message>\n" +
" </n2:ProjectImportResultCode>\n" +
" </n1:importProjectResponse>\n" +
"</env:Body></env:Envelope>";
// When
XmlPath xmlPath = new XmlPath(soap);
// Then
assertThat(xmlPath.getString("Envelope.Body.importProjectResponse.ProjectImportResultCode.code"), equalTo("1"));
}
@Test
public void xmlPathCanExtractNodeFromSoap() throws Exception {
// Given
String soap = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
"<env:Envelope \n" +
" xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" \n" +
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" \n" +
" xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" \n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
" <env:Header/>\n" +
"\n" +
"<env:Body>\n" +
" <n1:importProjectResponse \n" +
" xmlns:n1=\"n1\" \n" +
" xmlns:n2=\"n2\" \n" +
" xsi:type=\"n2:ArrayOfProjectImportResultCode\">\n" +
" <n2:ProjectImportResultCode>\n" +
" <n2:code>1</n2:code>\n" +
" <n2:message>Project 'test1' import was successful.</n2:message>\n" +
" </n2:ProjectImportResultCode>\n" +
" </n1:importProjectResponse>\n" +
"</env:Body></env:Envelope>";
// When
XmlPath xmlPath = new XmlPath(soap);
Node node = xmlPath.getNode("Envelope");
// Then
assertThat(node.<String>getPath("Body.importProjectResponse.ProjectImportResultCode.code"), equalTo("1"));
}
@Test
public void doesntNeedToEscapeListsWithHyphenWithoutBrackets() throws Exception {
// Given
String xml = "<root><some-list>one</some-list><some-list>two</some-list></root>";
// When
XmlPath xmlPath = from(xml);
// Then
assertThat(xmlPath.getString("root.some-list[0]"), equalTo("one"));
}
@Test public void
trying_to_get_an_attribute_that_doesnt_exists_returns_null() {
// Given
String xml = " <root>" //
+ " <item type=\"normal\">item_1_content</item>"//
+ " <item type=\"special\">item_1_content</item>"//
+ " <item type=\"\">item_1_content</item>"//
+ " <item>item_2_content</item>"//
+ " </root>";
// When
XmlPath xmlPath = new XmlPath(xml).setRoot("root");
// Then
assertThat(xmlPath.getString("item[3].@type"), nullValue());
}
}