Skip to content

Commit

Permalink
Fixed Matcher.hasXpath against xml of multiple element of same path
Browse files Browse the repository at this point in the history
  • Loading branch information
HaoWang420 committed Apr 25, 2021
1 parent 8522353 commit 0a3bba0
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 6 deletions.
46 changes: 40 additions & 6 deletions hamcrest/src/main/java/org/hamcrest/xml/HasXPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.hamcrest.core.IsAnything;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.xpath.*;

import java.util.ArrayList;
import java.util.List;

import static javax.xml.xpath.XPathConstants.NODESET;
import static javax.xml.xpath.XPathConstants.STRING;
import static org.hamcrest.Condition.matched;
import static org.hamcrest.Condition.notMatched;
import static org.hamcrest.Condition.*;

/**
* Applies a Matcher to a given XML Node in an existing XML Node tree, specified by an XPath expression.
Expand Down Expand Up @@ -58,9 +62,22 @@ private HasXPath(String xPathExpression, NamespaceContext namespaceContext, Matc

@Override
public boolean matchesSafely(Node item, Description mismatch) {
return evaluated(item, mismatch)
.and(NODE_EXISTS)
.matching(valueMatcher);
if (this.evaluationMode == NODESET)
{
List<Condition<Object>> match_list = evaluatedList(item, mismatch);

for (Condition<Object> match: match_list) {
if (match.and(NODE_EXISTS).matching(valueMatcher)) {
return true;
}
}
return false;
}
else {
return evaluated(item, mismatch)
.and(NODE_EXISTS)
.matching(valueMatcher);
}
}

@Override
Expand All @@ -80,6 +97,23 @@ private Condition<Object> evaluated(Node item, Description mismatch) {
return notMatched();
}

private List<Condition<Object>> evaluatedList(Node item, Description mismatch) {
List<Condition<Object>> match_list = new ArrayList<>();
try {
NodeList list = (NodeList) compiledXPath.evaluate(item, evaluationMode);
Object obj = compiledXPath.evaluate(item, STRING);
for (int i = 0; i < list.getLength(); i++) {
Node node = list.item(i);
match_list.add((matched((Object)node.getTextContent(), mismatch)));
}
return match_list;
} catch (XPathExpressionException e) {
mismatch.appendText(e.getMessage());
}
match_list.add(notMatched());
return match_list;
}

private static Condition.Step<Object, String> nodeExists() {
return new Condition.Step<Object, String>() {
@Override
Expand Down Expand Up @@ -136,7 +170,7 @@ public static Matcher<Node> hasXPath(String xPath, Matcher<String> valueMatcher)
* matcher for the value at the specified xpath
*/
public static Matcher<Node> hasXPath(String xPath, NamespaceContext namespaceContext, Matcher<String> valueMatcher) {
return new HasXPath(xPath, namespaceContext, valueMatcher, STRING);
return new HasXPath(xPath, namespaceContext, valueMatcher, NODESET);
}

/**
Expand Down
35 changes: 35 additions & 0 deletions hamcrest/src/test/java/org/hamcrest/xml/HasXPathTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,41 @@ public Iterator<String> getPrefixes(String namespaceURI) {
assertMatches(hasXPath("//something[@id='b']/cheese"), xml);
}

/*
Test whether the multiple elements case works or not
*/
@Test public void
appliesMatcherToXPathInDocumentWithMultipleElement() {
Document multipleBookXml = parse("<books>\n"
+ "<book>\n"
+ "<isbn>A-ISBN</isbn>\n"
+ "</book>\n"
+ "<book>\n"
+ "<isbn>B-ISBN</isbn>\n"
+ "<name>B-Book></name>\n"
+ "</book>\n"
+ "</books>\n"
);

assertMatches(hasXPath("/books/book/isbn", equalTo("B-ISBN")), multipleBookXml);
assertMatches(hasXPath("/books/book/isbn", equalTo("A-ISBN")), multipleBookXml);
}

/*
Test whether the single element case still works or not
*/
@Test public void
appliesMatcherToPathInDocumentWithSingleElement() {
Document multipleBookXml = parse("<books>\n"
+ "<book>\n"
+ "<isbn>A-ISBN</isbn>\n"
+ "</book>\n"
+ "</books>\n"
);

assertMatches(hasXPath("/books/book/isbn", equalTo("A-ISBN")), multipleBookXml);
}

@Test public void
matchesEmptyElement() {
assertMatches(hasXPath("//emptySomething"), xml);
Expand Down

0 comments on commit 0a3bba0

Please sign in to comment.