Skip to content

Commit bef9cab

Browse files
committed
[refactor] Compare Nodes as Nodes rather than Strings.
* Removes Unnecessary calls and testing of fn:serialize * Promotes a more flexible testing framework via the incumbent Hamcrest
1 parent 0f76cf2 commit bef9cab

File tree

4 files changed

+232
-16
lines changed

4 files changed

+232
-16
lines changed

exist-core/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,12 +484,10 @@
484484
<dependency>
485485
<groupId>org.xmlunit</groupId>
486486
<artifactId>xmlunit-core</artifactId>
487-
<scope>test</scope>
488487
</dependency>
489488
<dependency>
490489
<groupId>org.xmlunit</groupId>
491490
<artifactId>xmlunit-matchers</artifactId>
492-
<scope>test</scope>
493491
</dependency>
494492
<dependency>
495493
<groupId>org.xmlunit</groupId>
@@ -665,6 +663,7 @@
665663
<exclude>src/test/java/org/exist/storage/txn/ReusableTxnTest.java</exclude>
666664
<exclude>src/test/java/org/exist/storage/txn/TransactionManagerTestHelper.java</exclude>
667665
<exclude>src/test/java/org/exist/storage/txn/TxnTest.java</exclude>
666+
<exclude>src/main/java/org/exist/test/DiffMatcher.java</exclude>
668667
<exclude>src/main/java/org/exist/util/CollectionOfArrayIterator.java</exclude>
669668
<exclude>src/test/java/org/exist/util/CollectionOfArrayIteratorTest.java</exclude>
670669
<exclude>src/main/java/org/exist/xquery/Cardinality.java</exclude>
@@ -802,6 +801,7 @@ The original license statement is also included below.]]></preamble>
802801
<include>src/test/java/org/exist/storage/txn/ReusableTxnTest.java</include>
803802
<include>src/test/java/org/exist/storage/txn/TransactionManagerTestHelper.java</include>
804803
<include>src/test/java/org/exist/storage/txn/TxnTest.java</include>
804+
<include>src/main/java/org/exist/test/DiffMatcher.java</include>
805805
<include>src/main/java/org/exist/util/CollectionOfArrayIterator.java</include>
806806
<include>src/test/java/org/exist/util/CollectionOfArrayIteratorTest.java</include>
807807
<include>src/main/java/org/exist/xquery/Cardinality.java</include>
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* Copyright (C) 2014, Evolved Binary Ltd
3+
*
4+
* This file was originally ported from FusionDB to eXist-db by
5+
* Evolved Binary, for the benefit of the eXist-db Open Source community.
6+
* Only the ported code as it appears in this file, at the time that
7+
* it was contributed to eXist-db, was re-licensed under The GNU
8+
* Lesser General Public License v2.1 only for use in eXist-db.
9+
*
10+
* This license grant applies only to a snapshot of the code as it
11+
* appeared when ported, it does not offer or infer any rights to either
12+
* updates of this source code or access to the original source code.
13+
*
14+
* The GNU Lesser General Public License v2.1 only license follows.
15+
*
16+
* ---------------------------------------------------------------------
17+
*
18+
* Copyright (C) 2014, Evolved Binary Ltd
19+
*
20+
* This library is free software; you can redistribute it and/or
21+
* modify it under the terms of the GNU Lesser General Public
22+
* License as published by the Free Software Foundation; version 2.1.
23+
*
24+
* This library is distributed in the hope that it will be useful,
25+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
26+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27+
* Lesser General Public License for more details.
28+
*
29+
* You should have received a copy of the GNU Lesser General Public
30+
* License along with this library; if not, write to the Free Software
31+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
32+
*/
33+
package org.exist.test;
34+
35+
import org.exist.xquery.value.Item;
36+
import org.exist.xquery.value.NodeValue;
37+
import org.exist.xquery.value.Sequence;
38+
import org.hamcrest.Description;
39+
import org.hamcrest.DiagnosingMatcher;
40+
import org.xmlunit.builder.DiffBuilder;
41+
import org.xmlunit.builder.Input;
42+
import org.xmlunit.diff.Diff;
43+
44+
import javax.xml.transform.Source;
45+
46+
/**
47+
* Implementation of a Hamcrest Matcher
48+
* which will compare XML nodes.
49+
*
50+
* @author <a href="mailto:[email protected]">Adam Retter</a>
51+
*/
52+
public class DiffMatcher extends DiagnosingMatcher<Sequence> {
53+
private final Source expectedSource;
54+
private final boolean identical;
55+
56+
private DiffMatcher(final Source expectedSource) {
57+
this(expectedSource, false);
58+
}
59+
60+
private DiffMatcher(final Source expectedSource, final boolean identical) {
61+
this.expectedSource = expectedSource;
62+
this.identical = identical;
63+
}
64+
65+
/**
66+
* Compares that the XML sources are similar.
67+
*
68+
* In this context "similar" is defined by {@link DiffBuilder#checkForSimilar()}.
69+
*
70+
* @param expectedSource the expected XML
71+
*
72+
* @return The Hamcrest Matcher
73+
*/
74+
public static DiffMatcher hasSimilarXml(final Source expectedSource) {
75+
return new DiffMatcher(expectedSource);
76+
}
77+
78+
/**
79+
* Compares that the XML sources are identical.
80+
*
81+
* In this context "similar" is defined by {@link DiffBuilder#checkForIdentical()} ()}.
82+
*
83+
* @param expectedSource the expected XML
84+
*
85+
* @return The Hamcrest Matcher
86+
*/
87+
public static DiffMatcher hasIdenticalXml(final Source expectedSource) {
88+
return new DiffMatcher(expectedSource, true);
89+
}
90+
91+
@Override
92+
public boolean matches(final Object item, final Description mismatch) {
93+
if (item == null) {
94+
mismatch.appendText("null");
95+
return false;
96+
}
97+
98+
final Item actualItem;
99+
if (item instanceof NodeValue) {
100+
actualItem = (NodeValue) item;
101+
102+
} else if (item instanceof Sequence) {
103+
final Sequence actual = ((Sequence) item);
104+
105+
if (actual.getItemCount() != 1) {
106+
mismatch.appendText("Sequence does not contain 1 item");
107+
return false;
108+
}
109+
110+
actualItem = actual.itemAt(0);
111+
if (!(actualItem instanceof NodeValue)) {
112+
mismatch.appendText("Sequence does not contain a Node");
113+
return false;
114+
}
115+
} else {
116+
mismatch.appendText("is not a Node");
117+
return false;
118+
}
119+
120+
final Source actualSource = Input.fromNode((org.w3c.dom.Node) actualItem).build();
121+
122+
DiffBuilder diffBuilder = DiffBuilder.compare(expectedSource)
123+
.withTest(actualSource);
124+
if (identical) {
125+
diffBuilder = diffBuilder.checkForIdentical();
126+
} else {
127+
diffBuilder = diffBuilder.checkForSimilar();
128+
}
129+
130+
final Diff diff = diffBuilder.build();
131+
if (diff.hasDifferences()) {
132+
mismatch.appendText("differences: " + diff.toString());
133+
return false;
134+
}
135+
136+
return true;
137+
}
138+
139+
@Override
140+
public void describeTo(final Description description) {
141+
description
142+
.appendText("nodes match ")
143+
.appendValue(expectedSource);
144+
}
145+
}

exist-core/src/main/java/org/exist/test/XQueryAssertions.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,22 @@
2626
import org.exist.xquery.ErrorCodes;
2727
import org.exist.xquery.XPathException;
2828
import org.exist.xquery.value.Sequence;
29+
import org.hamcrest.Matcher;
30+
import javax.xml.transform.Source;
2931

30-
import static org.junit.Assert.*;
32+
import static org.exist.test.DiffMatcher.hasIdenticalXml;
33+
import static org.exist.test.DiffMatcher.hasSimilarXml;
34+
import static org.hamcrest.MatcherAssert.assertThat;
35+
import static org.junit.Assert.fail;
36+
import static org.junit.Assert.assertTrue;
37+
import static org.junit.Assert.assertEquals;
3138

3239
/**
3340
* This set of assertions are meant to help when testing XQuery compilation, execution and errors
3441
* Especially useful, if the testsuite inherits from/ extends XQueryCompilationTest class
42+
*
3543
* @author <a href="mailto:[email protected]">Juri Leino</a>
44+
* @author <a href="mailto:[email protected]">Adam Retter</a>
3645
*/
3746
public class XQueryAssertions {
3847
public static void assertXQStaticError(final ErrorCodes.ErrorCode expectedCode, final int line, final int column, final String expectedMessage, final Either<XPathException, CompiledXQuery> actual) {
@@ -61,10 +70,20 @@ public static void assertXQDynamicError(final ErrorCodes.ErrorCode expectedCode,
6170
assertXQErrorCode(expectedCode, xpe);
6271
}
6372

64-
public static void assertXQResultToStringEquals(final String expectedSerializedString, final Either<XPathException, Sequence> actual) {
65-
assertTrue("Expected: " + expectedSerializedString + ", but got result: " + actual.toString(), actual.isRight());
73+
public static void assertThatXQResult(final Either<XPathException, Sequence> actual, final Matcher<Sequence> expectedMatcher) {
74+
if (actual.isLeft()) {
75+
fail("Expected result, but found XPathException: " + actual.left().get().toString());
76+
}
6677
final Sequence sequence = actual.right().get();
67-
assertEquals(expectedSerializedString, sequence.toString());
78+
assertThat(sequence, expectedMatcher);
79+
}
80+
81+
public static void assertXQResultSimilar(final Source expectedSource, final Either<XPathException, Sequence> actual) {
82+
assertThatXQResult(actual, hasSimilarXml(expectedSource));
83+
}
84+
85+
public static void assertXQResultIdentical(final Source expectedSource, final Either<XPathException, Sequence> actual) {
86+
assertThatXQResult(actual, hasIdenticalXml(expectedSource));
6887
}
6988

7089
public static void assertXQErrorCode(final ErrorCodes.ErrorCode expectedCode, final XPathException exception) {
@@ -86,5 +105,4 @@ public static void assertXQErrorMessage(final String expectedMessage, final XPat
86105
assertEquals("Expected message to be " + expectedMessage + ", but got " + exception.getMessage(),
87106
expectedMessage, exception.getDetailMessage());
88107
}
89-
90108
}

exist-core/src/test/java/org/exist/xquery/AbsolutePathTests.java

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,29 @@
2121
*/
2222
package org.exist.xquery;
2323

24+
import com.evolvedbinary.j8fu.Either;
2425
import org.exist.EXistException;
2526
import org.exist.security.PermissionDeniedException;
2627
import org.exist.test.XQueryCompilationTest;
28+
import org.exist.xquery.value.IntegerValue;
29+
import org.exist.xquery.value.Sequence;
2730
import org.junit.Test;
31+
import org.w3c.dom.Node;
32+
import org.xmlunit.builder.Input;
33+
import org.xmlunit.util.Convert;
2834

29-
import static org.exist.test.XQueryAssertions.assertXQResultToStringEquals;
35+
import javax.xml.transform.Source;
36+
37+
import static org.exist.test.XQueryAssertions.assertThatXQResult;
3038
import static org.exist.test.XQueryAssertions.assertXQStaticError;
39+
import static org.exist.test.XQueryAssertions.assertXQResultSimilar;
40+
import static org.hamcrest.Matchers.equalTo;
3141

3242
/**
33-
* Ensure absolute XPath expression will raise a static error
43+
* Ensure absolute XPath expression will raise a static error.
3444
*
3545
* @author <a href="mailto:[email protected]">Juri Leino</a>
46+
* @author <a href="mailto:[email protected]">Adam Retter</a>
3647
*/
3748
public class AbsolutePathTests extends XQueryCompilationTest {
3849
@Test
@@ -76,32 +87,74 @@ public void immediateLambdaContainsDoubleSlash() throws EXistException, Permissi
7687

7788
@Test
7889
public void immediateLambdaWithDocumentAndDoubleSlash() throws EXistException, PermissionDeniedException {
90+
final Source expected = elemSource("<result><x/><x/><x/></result>");
91+
7992
final String query = "let $f := function($d) { $d ! //x }\n" +
8093
"let $d := document { <root><x/><x/><y><x/></y></root> }\n" +
81-
"return serialize($f($d))";
82-
assertXQResultToStringEquals("<x/><x/><x/>", executeQuery(query));
94+
"return\n" +
95+
" <result>{ $f($d) }</result>";
96+
final Either<XPathException, Sequence> actual = executeQuery(query);
97+
98+
assertXQResultSimilar(expected, actual);
8399
}
84100

85101
@Test
86102
public void immediateLambdaWithDocumentAndSlash() throws EXistException, PermissionDeniedException {
103+
final Source expected = elemSource("<root/>");
104+
87105
final String query = "let $f := function($d) { $d ! /root }\n" +
88106
"let $d := document { <root/> }\n" +
89-
"return serialize($f($d))";
90-
assertXQResultToStringEquals("<root/>", executeQuery(query));
107+
"return\n" +
108+
" $f($d)";
109+
final Either<XPathException, Sequence> actual = executeQuery(query);
110+
111+
assertXQResultSimilar(expected, actual);
91112
}
92113

93114
@Test
94115
public void immediateLambdaWithDocumentAndLoneSlash() throws EXistException, PermissionDeniedException {
116+
final Source expected = docSource("<root/>");
117+
95118
final String query = "let $f := function($d) { $d ! / }\n" +
96119
"let $d := document { <root/> }\n" +
97-
"return serialize($f($d))";
98-
assertXQResultToStringEquals("<root/>", executeQuery(query));
120+
"return\n" +
121+
" $f($d)";
122+
final Either<XPathException, Sequence> actual = executeQuery(query);
123+
124+
assertXQResultSimilar(expected, actual);
99125
}
100126

101127
@Test
102128
public void topLevelAbsolutePath() throws EXistException, PermissionDeniedException {
129+
final Sequence expected = new IntegerValue(1);
130+
103131
final String query = "count(//*)";
104-
assertXQResultToStringEquals("1", executeQuery(query));
132+
final Either<XPathException, Sequence> actual = executeQuery(query);
133+
134+
assertThatXQResult(actual, equalTo(expected));
105135
}
106136

137+
/**
138+
* Creates an Document6 Source form an XML String.
139+
*
140+
* @param str a string representation of XML.
141+
*
142+
* @return a Document Source.
143+
*/
144+
private static Source docSource(final String str) {
145+
return Input.fromString(str).build();
146+
}
147+
148+
/**
149+
* Creates an Element Source form an XML String.
150+
*
151+
* @param str a string representation of XML.
152+
*
153+
* @return an Element Source.
154+
*/
155+
private static Source elemSource(final String str) {
156+
final Node documentNode = Convert.toNode(docSource(str));
157+
final Node firstElement = documentNode.getFirstChild();
158+
return Input.fromNode(firstElement).build();
159+
}
107160
}

0 commit comments

Comments
 (0)