Skip to content

Commit

Permalink
XPath for CHILD_LOOKUP differences was affected by NodeFilter
Browse files Browse the repository at this point in the history
  • Loading branch information
bodewig committed Mar 1, 2020
1 parent 06dd7b6 commit 33c5ea1
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 7 deletions.
5 changes: 5 additions & 0 deletions RELEASE_NOTES.md
Expand Up @@ -7,6 +7,11 @@
9 and later
Issue [#162](https://github.com/xmlunit/xmlunit/issues/162)

* the XPath values for comparisons resulting in `CHILD_LOOKUP`
differences could be wrong when `NodeFilter`s were present.
XMLUnit.NET Issue
[xmlunit/#29](https://github.com/xmlunit/xmlunit.net/issues/29)

## XMLUnit for Java 2.6.3 - /Released 2019-06-21/

* add a new `${xmlunit.isNumber}` placeholder
Expand Down
Expand Up @@ -587,18 +587,22 @@ public ComparisonState apply() {
}
}

return chain.andThen(new UnmatchedControlNodes(controlList, controlContext, seen, testContext))
.andThen(new UnmatchedTestNodes(testList, testContext, seen, controlContext));
return chain.andThen(new UnmatchedControlNodes(controlListForXpath, controlList, controlContext, seen,
testContext))
.andThen(new UnmatchedTestNodes(testListForXpath, testList, testContext, seen,
controlContext));
}

private class UnmatchedControlNodes implements DeferredComparison {
private final List<Node> controlListForXpath;
private final List<Node> controlList;
private final XPathContext controlContext;
private final Set<Node> seen;
private final XPathContext testContext;

private UnmatchedControlNodes(List<Node> controlList, XPathContext controlContext,
private UnmatchedControlNodes(List<Node> controlListForXpath, List<Node> controlList, XPathContext controlContext,
Set<Node> seen, XPathContext testContext) {
this.controlListForXpath = controlListForXpath;
this.controlList = controlList;
this.controlContext = controlContext;
this.seen = seen;
Expand All @@ -611,7 +615,7 @@ public ComparisonState apply() {
final int controlSize = controlList.size();
for (int i = 0; i < controlSize; i++) {
if (!seen.contains(controlList.get(i))) {
controlContext.navigateToChild(i);
controlContext.navigateToChild(controlListForXpath.indexOf(controlList.get(i)));
try {
chain =
chain.andThen(new Comparison(ComparisonType.CHILD_LOOKUP,
Expand All @@ -629,13 +633,15 @@ public ComparisonState apply() {
}

private class UnmatchedTestNodes implements DeferredComparison {
private final List<Node> testListForXpath;
private final List<Node> testList;
private final XPathContext testContext;
private final Set<Node> seen;
private final XPathContext controlContext;

private UnmatchedTestNodes(List<Node> testList, XPathContext testContext,
Set<Node> seen, XPathContext controlContext) {
private UnmatchedTestNodes(List<Node> testListForXpath, List<Node> testList, XPathContext testContext,
Set<Node> seen, XPathContext controlContext) {
this.testListForXpath = testListForXpath;
this.testList = testList;
this.testContext = testContext;
this.seen = seen;
Expand All @@ -648,7 +654,7 @@ public ComparisonState apply() {
final int testSize = testList.size();
for (int i = 0; i < testSize; i++) {
if (!seen.contains(testList.get(i))) {
testContext.navigateToChild(i);
testContext.navigateToChild(testListForXpath.indexOf(testList.get(i)));
try {
chain =
chain.andThen(new Comparison(ComparisonType.CHILD_LOOKUP,
Expand Down
Expand Up @@ -13,6 +13,8 @@
*/
package org.xmlunit.diff;

import java.util.Arrays;
import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.dom.DOMSource;
import org.xmlunit.NullNode;
Expand Down Expand Up @@ -1166,6 +1168,54 @@ public void attributesWithDifferentPrefixesAreSimilar() {
assertEquals(ComparisonType.NAMESPACE_PREFIX, diff.getDifferences().iterator().next().getComparison().getType());
}

@Test
public void xPathKnowsAboutNodeFiltersForUnmatchedControlNodes() {
final Diff diff = DiffBuilder.compare("<Document><Section><Binding /><Binding /><Finding /><Finding /><Finding /><Finding /><Finding /><Finding /><Finding /></Section></Document>")
.withTest("<Document><Section><Binding /><Binding /><Finding /><Finding /><Finding /><Finding /><Finding /><Finding /></Section></Document>")
.ignoreWhitespace()
.withNodeFilter(new Predicate<Node>() {
@Override
public boolean test(final Node node) {
return Arrays.asList("Document", "Section", "Finding").contains(node.getNodeName());
}
})
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))
.build();
final List<Difference> differences = Linqy.asList(diff.getDifferences());
assertEquals(2, differences.size());
assertEquals(ComparisonType.CHILD_NODELIST_LENGTH, differences.get(0).getComparison().getType());
assertEquals("/Document[1]/Section[1]", differences.get(0).getComparison().getControlDetails().getXPath());
assertEquals("/Document[1]/Section[1]", differences.get(0).getComparison().getTestDetails().getXPath());
assertEquals(ComparisonType.CHILD_LOOKUP, differences.get(1).getComparison().getType());
assertEquals("/Document[1]/Section[1]/Finding[7]", differences.get(1).getComparison().getControlDetails().getXPath());
assertNull(differences.get(1).getComparison().getTestDetails().getXPath());
assertEquals("/Document[1]/Section[1]", differences.get(1).getComparison().getTestDetails().getParentXPath());
}

@Test
public void xPathKnowsAboutNodeFiltersForUnmatchedTestNodes() {
final Diff diff = DiffBuilder.compare("<Document><Section><Binding /><Binding /><Finding /><Finding /><Finding /><Finding /><Finding /><Finding /></Section></Document>")
.withTest("<Document><Section><Binding /><Binding /><Finding /><Finding /><Finding /><Finding /><Finding /><Finding /><Finding /></Section></Document>")
.ignoreWhitespace()
.withNodeFilter(new Predicate<Node>() {
@Override
public boolean test(final Node node) {
return Arrays.asList("Document", "Section", "Finding").contains(node.getNodeName());
}
})
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))
.build();
final List<Difference> differences = Linqy.asList(diff.getDifferences());
assertEquals(2, differences.size());
assertEquals(ComparisonType.CHILD_NODELIST_LENGTH, differences.get(0).getComparison().getType());
assertEquals("/Document[1]/Section[1]", differences.get(0).getComparison().getControlDetails().getXPath());
assertEquals("/Document[1]/Section[1]", differences.get(0).getComparison().getTestDetails().getXPath());
assertEquals(ComparisonType.CHILD_LOOKUP, differences.get(1).getComparison().getType());
assertEquals("/Document[1]/Section[1]/Finding[7]", differences.get(1).getComparison().getTestDetails().getXPath());
assertNull(differences.get(1).getComparison().getControlDetails().getXPath());
assertEquals("/Document[1]/Section[1]", differences.get(1).getComparison().getControlDetails().getParentXPath());
}

private Document documentForString(String s) {
return Convert.toDocument(Input.fromString(s).build());
}
Expand Down

0 comments on commit 33c5ea1

Please sign in to comment.