package org.exist.xquery;
import org.exist.xmldb.DatabaseInstanceManager;
import org.exist.xmldb.XmldbURI;
import org.junit.*;
import org.xmldb.api.DatabaseManager;
import org.xmldb.api.base.*;
import org.xmldb.api.modules.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class DeepEqualTest {
private final static String URI = XmldbURI.LOCAL_DB;
private final static String DRIVER = "org.exist.xmldb.DatabaseImpl";
private static XPathQueryService query;
private static Collection c;
@Test
public void atomic1() throws XMLDBException {
assertQuery(true, "deep-equal('hello', 'hello')");
}
@Test
public void atomic2() throws XMLDBException {
assertQuery(false, "deep-equal('hello', 'goodbye')");
}
@Test
public void atomic3() throws XMLDBException {
assertQuery(true, "deep-equal(42, 42)");
}
@Test
public void atomic4() throws XMLDBException {
assertQuery(false, "deep-equal(42, 17)");
}
@Test
public void atomic5() throws XMLDBException {
assertQuery(false, "deep-equal(42, 'hello')");
}
@Test
public void atomic6() throws XMLDBException {
assertQuery(true, "deep-equal( 1. , xs:integer(1) )");
assertQuery(true, "deep-equal( xs:double(1) , xs:integer(1) )");
}
@Test
public void emptySeq() throws XMLDBException {
assertQuery(true, "deep-equal((), ())");
}
@Test
public void diffLengthSeq1() throws XMLDBException {
assertQuery(false, "deep-equal((), 42)");
}
@Test
public void diffLengthSeq2() throws XMLDBException {
assertQuery(false, "deep-equal((), (42, 'hello'))");
}
@Test
public void diffKindNodes1() throws XMLDBException {
createDocument("test", "<test key='value'>hello</test>");
assertQuery(false, "deep-equal(/test, /test/@key)");
}
@Test
public void diffKindNodes2() throws XMLDBException {
createDocument("test", "<test key='value'>hello</test>");
assertQuery(false, "deep-equal(/test, /test/text())");
}
@Test
public void diffKindNodes3() throws XMLDBException {
createDocument("test", "<test key='value'>hello</test>");
assertQuery(false, "deep-equal(/test/@key, /test/text())");
}
@Test
public void sameNode1() throws XMLDBException {
createDocument("test", "<test key='value'>hello</test>");
assertQuery(true, "deep-equal(/test, /test)");
}
@Test
public void sameNode2() throws XMLDBException {
createDocument("test", "<test key='value'>hello</test>");
assertQuery(true, "deep-equal(/test/@key, /test/@key)");
}
@Test
public void sameNode3() throws XMLDBException {
createDocument("test", "<test key='value'>hello</test>");
assertQuery(true, "deep-equal(/test/text(), /test/text())");
}
@Test
public void documents1() throws XMLDBException {
createDocument("test1", "<test key='value'>hello</test>");
createDocument("test2", "<test key='value'>hello</test>");
assertQuery(true, "deep-equal(xmldb:document('test1'), xmldb:document('test2'))");
}
@Test
public void documents2() throws XMLDBException {
createDocument("test1", "<test key='value'>hello</test>");
createDocument("test2", "<notatest/>");
assertQuery(false, "deep-equal(xmldb:document('test1'), xmldb:document('test2'))");
}
@Test
public void text1() throws XMLDBException {
createDocument("test", "<test><g1><a>1</a><b>2</b></g1><g2><c>1</c><d>2</d></g2></test>");
assertQuery(true, "deep-equal(//a/text(), //c/text())");
}
@Test
public void text2() throws XMLDBException {
createDocument("test", "<test><g1><a>1</a><b>2</b></g1><g2><c>1</c><d>2</d></g2></test>");
assertQuery(false, "deep-equal(//a/text(), //b/text())");
}
@Test
public void text3() throws XMLDBException {
createDocument("test", "<test><g1><a>1</a><b>2</b></g1><g2><c>1</c><d>2</d></g2></test>");
assertQuery(true, "deep-equal(//g1/text(), //g2/text())");
}
@Test
public void text4() throws XMLDBException {
createDocument("test", "<test><a>12</a><b>1<!--blah-->2</b></test>");
assertQuery(false, "deep-equal(//a/text(), //b/text())");
}
@Test
public void attributes1() throws XMLDBException {
createDocument("test", "<test><e1 a='1'/><e2 a='1' b='2' c='1'/><e3 a='2'/></test>");
assertQuery(true, "deep-equal(//e1/@a, //e2/@a)");
}
@Test
public void attributes2() throws XMLDBException {
createDocument("test", "<test><e1 a='1'/><e2 a='1' b='2' c='1'/><e3 a='2'/></test>");
assertQuery(false, "deep-equal(//e1/@a, //e2/@b)");
}
@Test
public void attributes3() throws XMLDBException {
createDocument("test", "<test><e1 a='1'/><e2 a='1' b='2' c='1'/><e3 a='2'/></test>");
assertQuery(false, "deep-equal(//e1/@a, //e2/@c)");
}
@Test
public void attributes4() throws XMLDBException {
createDocument("test", "<test><e1 a='1'/><e2 a='1' b='2' c='1'/><e3 a='2'/></test>");
assertQuery(false, "deep-equal(//e1/@a, //e3/@a)");
}
@Test
public void nsAttributes1() throws XMLDBException {
createDocument("test", "<test xmlns:n='urn:blah' xmlns:p='urn:foo' xmlns:q='urn:blah'><e1 n:a='1'/><e2 n:a='1' p:a='1' p:b='1'/><e3 n:a='2'/><e4 q:a='1'/></test>");
assertQuery(true, "declare namespace n = 'urn:blah'; declare namespace p = 'urn:foo'; declare namespace q = 'urn:blah'; deep-equal(//e1/@n:a, //e2/@n:a)");
}
@Test
public void nsAttributes2() throws XMLDBException {
createDocument("test", "<test xmlns:n='urn:blah' xmlns:p='urn:foo' xmlns:q='urn:blah'><e1 n:a='1'/><e2 n:a='1' p:a='1' p:b='1'/><e3 n:a='2'/><e4 q:a='1'/></test>");
assertQuery(true, "declare namespace n = 'urn:blah'; declare namespace p = 'urn:foo'; declare namespace q = 'urn:blah'; deep-equal(//e1/@q:a, //e4/@n:a)");
}
@Test
public void nsAttributes3() throws XMLDBException {
createDocument("test", "<test xmlns:n='urn:blah' xmlns:p='urn:foo' xmlns:q='urn:blah'><e1 n:a='1'/><e2 n:a='1' p:a='1' p:b='1'/><e3 n:a='2'/><e4 q:a='1'/></test>");
assertQuery(false, "declare namespace n = 'urn:blah'; declare namespace p = 'urn:foo'; declare namespace q = 'urn:blah'; deep-equal(//e1/@n:a, //e2/@p:a)");
}
@Test
public void nsAttributes4() throws XMLDBException {
createDocument("test", "<test xmlns:n='urn:blah' xmlns:p='urn:foo' xmlns:q='urn:blah'><e1 n:a='1'/><e2 n:a='1' p:a='1' p:b='1'/><e3 n:a='2'/><e4 q:a='1'/></test>");
assertQuery(false, "declare namespace n = 'urn:blah'; declare namespace p = 'urn:foo'; declare namespace q = 'urn:blah'; deep-equal(//e1/@n:a, //e2/@p:b)");
}
@Test
public void nsAttributes5() throws XMLDBException {
createDocument("test", "<test xmlns:n='urn:blah' xmlns:p='urn:foo' xmlns:q='urn:blah'><e1 n:a='1'/><e2 n:a='1' p:a='1' p:b='1'/><e3 n:a='2'/><e4 q:a='1'/></test>");
assertQuery(false, "declare namespace n = 'urn:blah'; declare namespace p = 'urn:foo'; declare namespace q = 'urn:blah'; deep-equal(//e1/@n:a, //e3/@n:a)");
}
@Test
public void elements1() throws XMLDBException {
createDocument("test", "<test><a/><a/></test>");
assertQuery(true, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void elements2() throws XMLDBException {
createDocument("test", "<test><a/><b/></test>");
assertQuery(false, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void elements3() throws XMLDBException {
createDocument("test", "<test><a a='1' b='2'/><a b='2' a='1'/></test>");
assertQuery(true, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void elements4() throws XMLDBException {
createDocument("test", "<test><a a='1'/><a b='2' a='1'/></test>");
assertQuery(false, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void elements5() throws XMLDBException {
createDocument("test", "<test><a a='1' c='2'/><a b='2' a='1'/></test>");
assertQuery(false, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void elements6() throws XMLDBException {
createDocument("test", "<test><a a='1' b='2'/><a a='2' b='2'/></test>");
assertQuery(false, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void elements7() throws XMLDBException {
createDocument("test", "<test><a>hello</a><a>hello</a></test>");
assertQuery(true, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void elements8() throws XMLDBException {
createDocument("test", "<test><a>hello</a><a>bye</a></test>");
assertQuery(false, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void elements9() throws XMLDBException {
createDocument("test", "<test><a><!--blah--></a><a/></test>");
assertQuery(true, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void elements10() throws XMLDBException {
createDocument("test", "<test><a><b/><!--blah-->hello</a><a><b/>hello</a></test>");
assertQuery(true, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void elements11() throws XMLDBException {
createDocument("test", "<test><a><b/>hello</a><a>hello</a></test>");
assertQuery(false, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void elements12() throws XMLDBException {
createDocument("test", "<test><a><b/></a><a>hello</a></test>");
assertQuery(false, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void elements13() throws XMLDBException {
createDocument("test", "<test><a><b/></a><a><b/>hello</a></test>");
assertQuery(false, "deep-equal(/test/*[1], /test/*[2])");
}
//Courtesy : Dizzz
@Test
public void elements14() throws XMLDBException {
//Includes a reference node
String query =
"let $parSpecs1 := <ParameterSpecifications/> " +
"let $funSpecs2 := " +
" <FunctionSpecifications>" +
" <FunctionName>Func2</FunctionName>" +
" { $parSpecs1 }" +
" </FunctionSpecifications>" +
"return " +
" deep-equal(" +
" <FunctionVerifications>" +
" <FunctionName>Func2</FunctionName>" +
" </FunctionVerifications>" +
"," +
" <FunctionVerifications>" +
" { $funSpecs2/FunctionName }" +
" </FunctionVerifications>" +
" )";
assertQuery(true, query);
}
@Test
public void elements15() throws XMLDBException {
String query = "let $funSpecs :=" +
"<FunctionSpecifications>" +
"<FunctionName>Func2</FunctionName>" +
"</FunctionSpecifications>" +
"let $funVers1 :=" +
"<FunctionVerifications>" +
"<FunctionName>Func2</FunctionName>" +
"</FunctionVerifications>" +
"let $funVers2 :=" +
"<FunctionVerifications>" +
"{$funSpecs/FunctionName}" +
"</FunctionVerifications>" +
"return " +
"deep-equal($funVers1, $funVers2)";
assertQuery(true, query);
}
@Test
public void elements16() throws XMLDBException {
// [ 1462061 ] Issue with deep-equal() "DeepestEqualBug"
String query =
"declare namespace ve = \"ournamespace\";" +
"declare function ve:functionVerifications($pars as element()*) as element() {" +
"<FunctionVerifications>" +
"<ParameterVerifications>{$pars[Name eq \"Par1\"]}</ParameterVerifications>" +
"</FunctionVerifications>" +
"};" +
"let $par1 := <Parameter><Name>Par1</Name></Parameter>" +
"let $funVers2 := " +
"<FunctionVerifications><ParameterVerifications> {$par1}" +
"</ParameterVerifications></FunctionVerifications> " +
"return " +
"deep-equal($funVers2, ve:functionVerifications($par1))";
assertQuery(true, query);
}
@Test
public void elements17() throws XMLDBException {
// Test deep-equal is used with in-memory nodes
String query =
"let $one := <foo/> " +
"let $two := <bar/> " +
"return " +
"deep-equal($one, $two)";
assertQuery(false, query);
}
@Test
public void referenceNode() throws XMLDBException {
String query =
"let $expr1 := <Value>Hello</Value> " +
"return " +
"deep-equal( <Result><Value>Hello</Value></Result>," +
"<Result><Value>{$expr1/node()}</Value></Result> )";
assertQuery(true, query);
}
@Test
public void referenceNode2() throws XMLDBException {
String query = "declare namespace dst = \"http://www.test.com/DeeperEqualTest\"; "
+ "declare function dst:value($value as element(Value), "
+ "$result as element(Result)) as element(Result) { "
+ "<Result><Value>{($result/Value/node(), $value/node())}</Value> </Result>}; "
+ "let $value1 := <Value>hello</Value> "
+ "let $result0 := <Result><Value/></Result> "
+ "let $result1 := dst:value($value1, $result0) "
+ "let $value2 := <Value/> "
+ "let $result2 := dst:value($value2, $result1) "
+ "return deep-equal($result1, $result2)";
assertQuery(true, query);
}
@Test
public void referenceNode3() throws XMLDBException {
createDocument("test", "<root><value>A</value><value>B</value></root>");
// two adjacent reference text nodes from another document should be merged into one
assertQuery(true,
"let $a := <v>{/root/value[1]/node(), /root/value[2]/node()}</v>" +
"let $b := <v>AB</v>" +
"return deep-equal($a, $b)");
// one reference node after a text node
assertQuery(true,
"let $a := <v>{/root/value[1]/node(), /root/value[2]/node()}</v>" +
"let $b := <v>A{/root/value[2]/node()}</v>" +
"return deep-equal($a, $b)");
// reference node before a text node
assertQuery(true,
"let $a := <v>{/root/value[1]/node(), /root/value[2]/node()}</v>" +
"let $b := <v>{/root/value[1]/node()}B</v>" +
"return deep-equal($a, $b)");
// reference node before an atomic value
assertQuery(true,
"let $a := <v>{/root/value[1]/node(), 'B'}</v>" +
"let $b := <v>AB</v>" +
"return deep-equal($a, $b)");
// reference node after an atomic value
assertQuery(true,
"let $a := <v>{'A', /root/value[2]/node()}</v>" +
"let $b := <v>AB</v>" +
"return deep-equal($a, $b)");
}
@Test
public void siblingCornerCase() throws XMLDBException {
String query = "declare namespace ve = 'http://www.test.com/deepestEqualError'; " +
"declare function ve:functionVerifications() as element(FunctionVerifications) { " +
"let $parVers := " +
"<ParameterVerifications> " +
" <Parameter/> " +
" <PassedLevel>ATP</PassedLevel> " +
" <PassedLevel>PE</PassedLevel> " +
" <PassedLevel>SPC</PassedLevel> " +
" <Specification>ATP</Specification> " +
" <Specification>PE</Specification> " +
" <Specification>SPC</Specification> " +
"</ParameterVerifications> " +
"let $dummy := $parVers/PassedLevel (: cause deep-equal bug!!! :) " +
"return " +
"<FunctionVerifications> " +
" <PassedLevel>ATP</PassedLevel> " +
" <PassedLevel>PE</PassedLevel> " +
" <PassedLevel>SPC</PassedLevel> " +
" {$parVers} " +
"</FunctionVerifications> " +
"}; " +
"let $expected := " +
" <FunctionVerifications> " +
" <PassedLevel>ATP</PassedLevel> " +
" <PassedLevel>PE</PassedLevel> " +
" <PassedLevel>SPC</PassedLevel> " +
" <ParameterVerifications> " +
" <Parameter/> " +
" <PassedLevel>ATP</PassedLevel> " +
" <PassedLevel>PE</PassedLevel> " +
" <PassedLevel>SPC</PassedLevel> " +
" <Specification>ATP</Specification> " +
" <Specification>PE</Specification> " +
" <Specification>SPC</Specification> " +
" </ParameterVerifications> " +
" </FunctionVerifications> " +
"let $got := ve:functionVerifications() " +
"return deep-equal($expected, $got)";
assertQuery(true, query);
}
@Test
public void sequenceError1() throws XMLDBException {
String query = "declare namespace ds = \"http://www.test.com/SequenceError\"; "
+ "declare function ds:result( $current as element(Result)?, "
+ "$value as element(Value)?) as element(Result) {"
+ "<Result> <Value>{ ($current/Value/node(), $value/node()) }</Value> </Result> };"
+ "let $v1 := <Value>1234</Value> "
+ "let $result1 := ds:result((), $v1) "
+ "let $v2 := <Value>abcd</Value> "
+ "let $expected := <Value>{($v1, $v2)/node()}</Value> "
+ "let $result2 := ds:result($result1, $v2) "
+ "return deep-equal($expected, $result2/Value)";
for (int i = 1; i < 20; i++) {
assertQuery(true, query);
}
}
;
@Test
public void nsElements1() throws XMLDBException {
createDocument("test", "<test xmlns:p='urn:foo' xmlns:q='urn:foo'><p:a/><q:a/></test>");
assertQuery(true, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void nsElements2() throws XMLDBException {
createDocument("test", "<test xmlns:p='urn:foo' xmlns:q='urn:bar'><p:a/><q:a/></test>");
assertQuery(false, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void nsElements3() throws XMLDBException {
createDocument("test", "<test><a/><a xmlns:z='foo'/></test>");
assertQuery(true, "deep-equal(/test/*[1], /test/*[2])");
}
@Test
public void forLoop() throws XMLDBException {
ResourceSet rs = query.query("let $set := <root><b>test</b><c><a>test</a></c><d><a>test</a></d></root>, $test := <c><a>test</a></c> for $node in $set/* return deep-equal($node, $test)");
assertEquals(3, rs.getSize());
assertEquals("false", rs.getResource(0).getContent());
assertEquals("true", rs.getResource(1).getContent());
assertEquals("false", rs.getResource(2).getContent());
}
private void assertQuery(boolean expected, String q) throws XMLDBException {
ResourceSet rs = query.query(q);
assertEquals(1, rs.getSize());
assertEquals(Boolean.toString(expected), rs.getResource(0).getContent());
}
private XMLResource createDocument(String name, String content) throws XMLDBException {
XMLResource res = (XMLResource) c.createResource(name, XMLResource.RESOURCE_TYPE);
res.setContent(content);
c.storeResource(res);
return res;
}
private static Collection setupTestCollection() throws XMLDBException {
Collection root = DatabaseManager.getCollection(URI, "admin", "");
CollectionManagementService rootcms = (CollectionManagementService) root.getService("CollectionManagementService", "1.0");
Collection cc = root.getChildCollection("test");
if (cc != null) rootcms.removeCollection("test");
rootcms.createCollection("test");
cc = DatabaseManager.getCollection(URI + "/test", "admin", "");
assertNotNull(cc);
return cc;
}
@BeforeClass
public static void setUp() throws ClassNotFoundException, XMLDBException, IllegalAccessException, InstantiationException {
// initialize driver
Database database = (Database) Class.forName(DRIVER).newInstance();
database.setProperty("create-database", "true");
DatabaseManager.registerDatabase(database);
c = setupTestCollection();
query = (XPathQueryService) c.getService("XPathQueryService", "1.0");
}
@AfterClass
public static void tearDown() throws XMLDBException {
if (c != null) {
DatabaseInstanceManager dim = (DatabaseInstanceManager) c.getService("DatabaseInstanceManager", "1.0");
c.close();
dim.shutdown();
}
c = null;
query = null;
}
}