package org.basex.query;
import static org.basex.core.Text.*;
import static org.basex.query.QueryError.*;
import static org.basex.util.Token.*;
import static org.junit.Assert.*;
import java.io.*;
import org.basex.core.*;
import org.basex.core.cmd.*;
import org.basex.data.*;
import org.basex.io.*;
import org.basex.io.serial.*;
import org.basex.query.util.*;
import org.basex.query.value.node.*;
import org.junit.*;
import org.junit.Test;
/**
* This class tests namespaces.
*
* @author BaseX Team 2005-17, BSD License
* @author Lukas Kircher
*/
public final class NamespaceTest extends AdvancedQueryTest {
/** Test documents. */
private static final String[][] DOCS = {
{ "d1", "<x/>" },
{ "d2", "<x xmlns='xx'/>" },
{ "d3", "<a:x xmlns:a='aa'><b:y xmlns:b='bb'/></a:x>" },
{ "d4", "<a:x xmlns:a='aa'><a:y xmlns:b='bb'/></a:x>" },
{ "d5", "<a:x xmlns:a='aa'/>" },
{ "d6", "<a:x xmlns='xx' xmlns:a='aa'><a:y xmlns:b='bb'/></a:x>" },
{ "d7", "<x xmlns='xx'><y/></x>" },
{ "d8", "<a><b xmlns='B'/><c/></a>" },
{ "d9", "<a xmlns='A'><b><c/><d xmlns='D'/></b><e/></a>" },
{ "d10", "<a xmlns='A'><b><c/><d xmlns='D'><g xmlns='G'/></d></b><e/></a>"},
{ "d11", "<a xmlns='A'><b xmlns:ns1='AA'><d/></b><c xmlns:ns1='AA'>" +
"<d/></c></a>" },
{ "d12", "<a><b/><c xmlns='B'/></a>" },
{ "d13", "<a><b xmlns='A'/></a>" },
{ "d14", "<a xmlns='A'><b xmlns='B'/><c xmlns='C'/></a>" },
{ "d15", "<a xmlns='A'><b xmlns='B'/><c xmlns='C'><d xmlns='D'/></c>" +
"<e xmlns='E'/></a>" },
{ "d16", "<a><b/></a>" },
{ "d17", "<ns:a xmlns:ns='NS'><b/></ns:a>" },
{ "d18", "<n xmlns:ns='ns'><a/></n>"},
{ "d19", "<x:n xmlns:x='X'/>"},
{ "d20", "<x:a xmlns:x='A'><x:b xmlns:x='B'/><x:c/></x:a>"},
{ "d21", "<n><a xmlns:p1='u1'><b xmlns:p2='u2'/></a><c/></n>"}
};
/**
* Checks if namespace hierarchy structure is updated correctly on the
* descendant axis after a NSNode has been inserted.
*/
@Test
public void insertIntoShiftPreValues() {
create(12);
query("insert node <b xmlns:ns='A'/> into db:open('d12')/*:a/*:b");
assertEquals(NL +
" Pre[3] xmlns:ns=\"A\"" + NL +
" Pre[4] xmlns=\"B\"",
context.data().nspaces.toString());
}
/**
* Checks if namespace hierarchy structure is updated correctly on the
* descendant axis after a NSNode has been inserted.
*/
@Test
public void insertIntoShiftPreValues2() {
create(13);
query("insert node <c/> as first into db:open('d13')/a");
assertEquals(NL +
" Pre[3] xmlns=\"A\"",
context.data().nspaces.toString());
}
/**
* Checks if namespace hierarchy structure is updated correctly on the
* descendant axis after a NSNode has been inserted.
*/
@Test
public void insertIntoShiftPreValues3() {
create(14);
query("insert node <n xmlns='D'/> into db:open('d14')/*:a/*:b");
assertEquals(NL +
" Pre[1] xmlns=\"A\"" + NL +
" Pre[2] xmlns=\"B\"" + NL +
" Pre[3] xmlns=\"D\"" + NL +
" Pre[4] xmlns=\"C\"",
context.data().nspaces.toString());
}
/**
* Checks if namespace hierarchy structure is updated correctly on the
* descendant axis after a NSNode has been deleted.
*/
@Test
public void deleteShiftPreValues() {
create(12);
query("delete node db:open('d12')/a/b");
assertEquals(NL +
" Pre[2] xmlns=\"B\"",
context.data().nspaces.toString());
}
/**
* Checks if namespace hierarchy structure is updated correctly on the
* descendant axis after a NSNode has been deleted.
*/
@Test
public void deleteShiftPreValues2() {
create(14);
query("delete node db:open('d14')/*:a/*:b");
assertEquals(NL +
" Pre[1] xmlns=\"A\"" + NL +
" Pre[2] xmlns=\"C\"",
context.data().nspaces.toString());
}
/**
* Checks if namespace hierarchy structure is updated correctly on the
* descendant axis after a NSNode has been deleted.
*/
@Test
public void deleteShiftPreValues3() {
create(15);
query("delete node db:open('d15')/*:a/*:c");
assertEquals(NL +
" Pre[1] xmlns=\"A\"" + NL +
" Pre[2] xmlns=\"B\"" + NL +
" Pre[3] xmlns=\"E\"",
context.data().nspaces.toString());
}
/**
* Checks if namespace hierarchy structure is updated correctly on the
* descendant axis after a NSNode has been deleted.
*/
@Test
public void deleteShiftPreValues4() {
create(16);
query("delete node db:open('d16')/a/b");
assertTrue(context.data().nspaces.toString().isEmpty());
}
/**
* Inserts an attribute with namespace.
*/
@Test
public void insertAttributeWithNs() {
create(1);
query("insert node attribute { QName('ns', 'pref:local') } { } into /*");
final Data data = context.data();
assertEquals(false, data.nsFlag(0));
assertEquals(true, data.nsFlag(1));
assertEquals(false, data.nsFlag(2));
assertEquals(0, data.uriId(1, data.kind(1)));
assertEquals(1, data.uriId(2, data.kind(2)));
assertEquals("ns", string(data.nspaces.uri(1)));
}
/**
* Tests for correct namespace hierarchy, esp. if namespace nodes
* on the following axis of an insert/delete operation are
* updated correctly.
*/
@Test
public void delete1() {
create(11);
query("delete node db:open('d11')/*:a/*:b",
"db:open('d11')/*:a",
"<a xmlns='A'><c xmlns:ns1='AA'><d/></c></a>");
}
/**
* Tests if a namespace node is deleted.
*/
@Test
public void delete2() {
create(21);
query("delete node //b");
assertEquals(NL +
" Pre[2] xmlns:p1=\"u1\"",
context.data().nspaces.toString());
}
/** Test query. */
@Test
public void copy1() {
query(
"copy $c := <x:a xmlns:x='xx'><b/></x:a>/b modify () return $c",
"<b xmlns:x='xx'/>");
}
/**
* Detects corrupt namespace hierarchy.
*/
@Test
public void copy2() {
create(4);
query(
"declare namespace a='aa';" +
"copy $c:=db:open('d4') modify () return $c//a:y",
"<a:y xmlns:a='aa' xmlns:b='bb'/>");
}
/**
* Detects missing prefix declaration.
*/
@Test
public void copy3() {
create(4);
query(
"declare namespace a='aa';" +
"copy $c:=db:open('d4')//a:y modify () return $c",
"<a:y xmlns:a='aa' xmlns:b='bb'/>");
}
/**
* Detects duplicate namespace declaration in MemData instance.
*/
@Test
public void copy4() {
query(
"copy $c := <a xmlns='test'><b><c/></b><d/></a> modify () return $c",
"<a xmlns='test'><b><c/></b><d/></a>");
}
/**
* Detects bogus namespace after insert.
*/
@Test
public void bogusDetector() {
create(1);
query(
"insert node <a xmlns='test'><b><c/></b><d/></a> into db:open('d1')/x",
"declare namespace na = 'test';db:open('d1')/x/na:a",
"<a xmlns='test'><b><c/></b><d/></a>");
}
/**
* Detects empty default namespace in serializer.
*/
@Test
public void emptyDefaultNamespace() {
query("<ns:x xmlns:ns='X'><y/></ns:x>",
"<ns:x xmlns:ns='X'><y/></ns:x>");
}
/**
* Detects duplicate default namespace in serializer.
*/
@Test
public void duplicateDefaultNamespace() {
query("<ns:x xmlns:ns='X'><y/></ns:x>",
"<ns:x xmlns:ns='X'><y/></ns:x>");
}
/**
* Detects malformed namespace hierarchy.
*/
@Test
public void nsHierarchy() {
create(9);
query("insert node <f xmlns='F'/> into db:open('d9')//*:e");
assertEquals(NL +
" Pre[1] xmlns=\"A\"" + NL +
" Pre[4] xmlns=\"D\"" + NL +
" Pre[6] xmlns=\"F\"",
context.data().nspaces.toString());
}
/**
* Detects malformed namespace hierarchy.
*/
@Test
public void nsHierarchy2() {
create(10);
query("insert node <f xmlns='F'/> into db:open('d10')//*:e");
assertEquals(NL +
" Pre[1] xmlns=\"A\"" + NL +
" Pre[4] xmlns=\"D\"" + NL +
" Pre[5] xmlns=\"G\"" + NL +
" Pre[7] xmlns=\"F\"",
context.data().nspaces.toString());
}
/**
* Detects malformed namespace hierarchy inserting an element.
*/
@Test
public void nsHierarchy3() {
query(transform(
"<a xmlns='x'/>",
"insert node <a xmlns='y'/> into $input"),
"<a xmlns='x'><a xmlns='y'/></a>");
// in-depth test
create(2);
query("insert node <a xmlns='y'/> into db:open('d2')//*:x");
assertEquals(NL +
" Pre[1] xmlns=\"xx\"" + NL +
" Pre[2] xmlns=\"y\"",
context.data().nspaces.toString());
}
/**
* Detects malformed namespace hierarchy adding a document to an empty DB.
*/
@Test
public void nsHierarchy4() {
execute(new CreateDB("d00x"));
execute(new Add("x", "<A xmlns='A'><B/><C/></A>"));
query("/", "<A xmlns='A'><B/><C/></A>");
}
/** Test query. */
@Test
public void copy5() {
query(
"copy $c := <n><a:y xmlns:a='aa'/><a:y xmlns:a='aa'/></n> " +
"modify () return $c",
"<n><a:y xmlns:a='aa'/><a:y xmlns:a='aa'/></n>");
}
/**
* Test query.
*/
@Test
public void insertD2intoD1() {
create(1, 2);
query(
"insert node db:open('d2') into db:open('d1')/x",
"db:open('d1')",
"<x><x xmlns='xx'/></x>");
}
/**
* Test query.
*/
@Test
public void insertD3intoD1() {
create(1, 3);
query(
"insert node db:open('d3') into db:open('d1')/x",
"db:open('d1')/x/*",
"<a:x xmlns:a='aa'><b:y xmlns:b='bb'/></a:x>");
}
/**
* Test query.
*/
@Test
public void insertD3intoD1b() {
create(1, 3);
query(
"insert node db:open('d3') into db:open('d1')/x",
"db:open('d1')/x/*/*",
"<b:y xmlns:b='bb' xmlns:a='aa'/>");
}
/**
* Detects missing prefix declaration.
*/
@Test
public void insertD4intoD1() {
create(1, 4);
query(
"declare namespace a='aa'; insert node db:open('d4')/a:x/a:y " +
"into db:open('d1')/x",
"db:open('d1')/x",
"<x><a:y xmlns:a='aa' xmlns:b='bb'/></x>");
}
/**
* Detects duplicate prefix declaration at pre=0 in MemData instance after insert.
* Though result correct, prefix
* a is declared twice. -> Solution?
*/
@Test
public void insertD4intoD5() {
create(4, 5);
query(
"declare namespace a='aa';insert node db:open('d4')//a:y " +
"into db:open('d5')/a:x",
"declare namespace a='aa';db:open('d5')//a:y",
"<a:y xmlns:a='aa' xmlns:b='bb'/>");
}
/**
* Detects duplicate namespace declarations in MemData instance.
*/
@Test
public void insertD7intoD1() {
create(1, 7);
query(
"declare namespace x='xx';insert node db:open('d7')/x:x into db:open('d1')/x",
"db:open('d1')/x",
"<x><x xmlns='xx'><y/></x></x>");
}
/**
* Detects general problems with namespace references.
*/
@Test
public void insertD6intoD4() {
create(4, 6);
query(
"declare namespace a='aa';insert node db:open('d6') into db:open('d4')/a:x",
"declare namespace a='aa';db:open('d4')/a:x/a:y",
"<a:y xmlns:a='aa' xmlns:b='bb'/>");
}
/**
* Detects general problems with namespace references.
*/
@Test
public void insertTransform1() {
query(
"declare default element namespace 'xyz';" +
"copy $foo := <foo/> modify insert nodes (<bar/>, <baz/>)" +
"into $foo return $foo",
"<foo xmlns='xyz'><bar/><baz/></foo>");
}
/**
* Detects general problems with namespace references.
*/
@Test
public void insertTransform2() {
query(
"copy $foo := <foo/> modify insert nodes (<bar/>)" +
"into $foo return $foo",
"<foo><bar/></foo>");
}
/**
* Tests, whether the PRE values of the namespace structure nodes are correctly adjusted after
* inserts.
*/
@Test
public void insertTransform3() {
query(transform("document { <X><C xmlns:c='NS'/></X> }",
"insert node <B><B b:b='B' xmlns:b='B'/></B> before $input/X/*:C"),
"<X><B><B xmlns:b='B' b:b='B'/></B><C xmlns:c='NS'/></X>");
}
/**
* Detects wrong namespace references.
*/
@Test
public void uriStack() {
create(8);
query(
"db:open('d8')",
"<a><b xmlns='B'/><c/></a>");
}
/**
* Deletes the document node and checks if namespace nodes of descendants
* are deleted as well. F.i. adding a document via REST/PUT deletes a
* document node if the given document/name is already stored in the target
* collection. If the test fails, this may lead to superfluous namespace nodes.
* @throws IOException I/O exception
*/
@Test
public void deleteDocumentNode() throws IOException {
create(2);
context.data().startUpdate(context.options);
context.data().delete(0);
context.data().finishUpdate(context.options);
final byte[] ns = context.data().nspaces.globalUri();
assertTrue(ns != null && ns.length == 0);
}
/**
* Checks a path optimization fix.
*/
@Test
public void queryPathOpt() {
create(17);
query("db:open('d17')/descendant::*:b", "<b xmlns:ns='NS'/>");
}
/**
* Checks a path optimization fix.
*/
@Test
public void queryPathOpt2() {
create(17);
query("db:open('d17')/*:a/*:b", "<b xmlns:ns='NS'/>");
}
/**
* GH-249: Inserts an element with a prefixed attribute and checks
* if there are superfluous namespace declarations for the element.
*/
@Test
public void superfluousPrefixDeclaration() {
create(18);
query(
"declare namespace ns='ns'; " +
"insert node <b ns:id='0'/> into /n/a");
query("//*:a", "<a xmlns:ns='ns'><b ns:id='0'/></a>");
}
/**
* Checks namespace declarations.
*/
@Test
public void renameNSCheck1() {
query(
"copy $copy := <a/> " +
"modify rename node $copy as QName('uri', 'e') " +
"return $copy",
"<e xmlns=\"uri\"/>");
}
/**
* Checks namespace declarations.
*/
@Test
public void renameNSCheck2() {
query(
"copy $n := <a><b/></a> " +
"modify rename node $n/b as QName('uri', 'e') " +
"return $n/*:e",
"<e xmlns=\"uri\"/>");
}
/**
* Checks namespace declarations.
*/
@Test
public void renameNSCheck3() {
query(
"copy $n := <a c='d'/> " +
"modify rename node $n as QName('uri', 'e') " +
"return $n",
"<e xmlns=\"uri\" c=\"d\"/>");
}
/**
* Checks namespace declarations.
*/
@Test
public void renameNSCheck4() {
query(
"copy $a := <a a='v'/> " +
"modify rename node $a/@a as QName('uri', 'p:a') " +
"return $a",
"<a xmlns:p='uri' p:a='v'/>");
}
/**
* Checks namespace declarations.
*/
@Test
public void renameNSCheck5() {
error(
"copy $a := <a xmlns:p='A' a='v'/> " +
"modify rename node $a/@a as QName('uri', 'p:a') " +
"return $a",
UPNSCONFL_X_X);
}
/**
* Checks if duplicate attributes are detected if a default namespace is declared.
*/
@Test
public void duplAttribute1() {
error(
"<e xmlns='URI' a=''/> update { insert node attribute a { } into . }",
UPATTDUPL_X);
}
/*
* Currently buggy (discovered via GH-1395).
* A new namespace declaration should be added.
*
@Test
public void renameDuplNSCheck() {
query("<a a='v'/> update rename node @a as QName('U', 'a')",
"<a xmlns:ns0=\"U\" ns0:a=''/><a xmlns=\"uri\" a=\"v\"/>");
}
*/
/**
* Checks namespace declarations.
*/
@Test
public void renameRemoveNS1() {
error(
"copy $a := <a xmlns='A'><b xmlns='B'/></a> " +
"modify for $el in $a/descendant-or-self::element() return " +
"rename node $el as QName('',local-name($el)) " +
"return $a",
UPNSCONFL_X_X);
}
/**
* Checks namespace declarations.
*/
@Test
public void renameRemoveNS2() {
query(
"copy $a := <a:a xmlns:a='A'><b:a xmlns:b='B'/></a:a> " +
"modify for $el in $a/descendant-or-self::element() return " +
"rename node $el as QName('',local-name($el)) " +
"return $a",
"<a xmlns:a='A'><a xmlns:b='B'/></a>");
}
/**
* Checks duplicate namespace declarations.
*/
@Test
public void avoidDuplicateNSDeclaration() {
create(19);
query(
"let $b := <a xmlns:x='X' x:id='0'/> " +
"return insert node $b//@*:id into /*:n");
assertEquals(1, context.data().namespaces(1).size());
}
/** Handles duplicate prefixes. */
@Test
public void duplicatePrefixes1() {
query(
"<e xmlns:p='u'>{ <a xmlns:p='u' p:a='v'/>/@* }</e>",
"<e xmlns:p='u' p:a='v'/>");
}
/** Handles duplicate prefixes. */
@Test
public void duplicatePrefixes2() {
query(
"<e xmlns:p='u1'>{ <a xmlns:p='u2' p:a='v'/>/@* }</e>",
"<e xmlns:p_1='u2' xmlns:p='u1' p_1:a='v'/>");
}
/** Handles duplicate prefixes. */
@Test
public void duplicatePrefixes3() {
query(
"<e xmlns:p='u' xmlns:p1='u1'>{ <a xmlns:p='u1' p:a='v'/>/@* }</e>",
"<e xmlns:p1='u1' xmlns:p='u' p1:a='v'/>");
}
/** Handles duplicate prefixes. */
@Test
public void duplicatePrefixes4() {
query(
"<e xmlns:p='u' xmlns:p1='u1'>{ <a xmlns:p='u2' p:a='v'/>/@* }</e>",
"<e xmlns:p_1='u2' xmlns:p1='u1' xmlns:p='u' p_1:a='v'/>");
}
/**
* Test query.
* Detects malformed namespace hierarchy.
*/
@Test
public void nsInAtt() {
query("data(<a a='{namespace-uri-for-prefix('x', <x:a/>)}' xmlns:x='X'/>/@a)",
"X");
}
/**
* Test query.
* Detects malformed namespace hierarchy.
*/
@Test
public void nsInBraces() {
query("<a xmlns:x='X'>{namespace-uri-for-prefix('x', <x:b/>)}</a>/text()",
"X");
}
/**
* Test query.
*/
@Test
public void defaultElementNamespaceTest() {
query("declare default element namespace 'a';" +
"let $x as element(a) := <a/> return $x",
"<a xmlns=\"a\"/>");
}
/**
* Test query.
* Detects malformed namespace hierarchy.
*/
@Test
public void newPrefix() {
query("<a>{ attribute {QName('U', 'a')} {} }</a>",
"<a xmlns:ns0='U' ns0:a=''/>");
}
/**
* Test query.
* Detects malformed namespace hierarchy.
*/
@Test
public void newPrefix2() {
query("<a xmlns:ns1='ns1'><b xmlns='ns1'>" +
"<c>{attribute {QName('ns1', 'att1')} {}," +
"attribute {QName('ns2', 'att2')} {}}</c></b></a>",
"<a xmlns:ns1='ns1'><b xmlns='ns1'>" +
"<c xmlns:ns0_1='ns2' xmlns:ns0='ns1' ns0:att1='' ns0_1:att2=''/>" +
"</b></a>");
}
/**
* Test query for stripping existing namespaces.
* @throws Exception exception
*/
@Test
public void stripNS() throws Exception {
final IO io = IO.get("<a xmlns:a='a'><b><c/><c/><c/></b></a>");
try(QueryProcessor qp = new QueryProcessor("/*:a/*:b", context).context(new DBNode(io))) {
final ANode sub = (ANode) qp.iter().next();
DataBuilder.stripNS(sub, token("a"), context);
}
}
/**
* Test query.
* Detects malformed namespace hierarchy.
*/
@Test
@Ignore
public void xuty0004() {
final String query = "declare variable $input-context external;" +
"let $source as node()* := (" +
" <status>on leave</status>," +
" <!-- for 6 months -->" +
" )," +
" $target := $input-context/works[1]/employee[1]" +
"return insert nodes $source into $target";
try(QueryProcessor qp = new QueryProcessor(query, context)) {
qp.value();
} catch(final QueryException ex) {
assertEquals("XUTY0004", ex.error().code);
}
fail("should throw XUTY0004");
}
/**
* Tests preserve, no-inherit for copy expression. Related to XQUTS
* id-insert-expr-081-no-inherit.xq. Tests if no-inherit has a persistent
* effect. Is it actually supposed to?
* The <new/> tag is inserted into a fragment f using no-inherit and copy.
* The resulting fragment is inserted into a database. The
* namespaces in scope with prefix 'ns' are finally checked for the
* inserted <new/> tag. If the result is non-empty we may have a problem -
* being not able propagate the no-inherit flag to our table.
*/
@Test
@Ignore
public void copyPreserveNoInheritPersistent() {
query("declare copy-namespaces preserve,no-inherit;" +
"declare namespace my = 'ns';" +
"let $v :=" +
"(copy $c := <my:n><my:a/></my:n>" +
"modify insert node <new/> into $c " +
"return $c)" +
"return insert node $v into db:open('d2')/n",
"namespace-uri-for-prefix('my', db:open('d2')//*:new)",
"");
}
/**
* Checks if a query uses the outer default namespace.
*/
@Test
public void defaultNS() {
create(1);
query("<h xmlns='U'>{ db:open('d1')/x }</h>/*", "");
}
/**
* Test query.
*/
@Test
public void precedingSiblingNsDecl() {
create(20);
query("//Q{A}a", "<x:a xmlns:x='A'><x:b xmlns:x='B'/><x:c/></x:a>");
query("//Q{A}b", "");
query("//Q{A}c", "<x:c xmlns:x='A'/>");
query("//Q{B}a", "");
query("//Q{B}b", "<x:b xmlns:x='B'/>");
query("//Q{B}c", "");
}
/**
* Test query.
*/
@Test
public void duplicateXMLNamespace() {
create(1);
query("insert node attribute xml:space { 'preserve' } into /x", "");
query(".", "<x xml:space='preserve'/>");
error("insert node attribute xml:space { 'preserve' } into /x", UPATTDUPL_X);
}
/**
* Test query.
*/
@Test
public void duplicateNamespaces() {
query("copy $c := <a xmlns='X'/> modify (" +
" rename node $c as QName('X','b')," +
" insert node attribute c{'a'} into $c" +
") return $c", "<b xmlns=\"X\" c=\"a\"/>");
error("copy $c := <a xmlns='X'/> modify (" +
" rename node $c as QName('Y','b')," +
" insert node attribute c{'a'} into $c" +
") return $c", UPNSCONFL_X_X);
query("copy $c := <a/> modify (" +
" rename node $c as QName('X','b')," +
" insert node attribute c{'a'} into $c" +
") return $c", "<b xmlns=\"X\" c=\"a\"/>");
}
/**
* Test query (#780).
*/
@Test
public void xmlNS() {
query("insert node (<w:a xmlns:w='X' xml:x=''><w:b/><w:c/><w:d/><w:e/><w:f/></w:a>," +
"<w:g xmlns:w='X' xml:y=''/>) into <w:h xmlns:w='X' xml:z=''/>");
query("insert node (<w:a xmlns:w='X' xmlns:a='a' a:x=''><w:b/><w:c/><w:d/><w:e/><w:f/></w:a>," +
"<w:g xmlns:w='X' xmlns:a='a' a:y=''/>) into <w:h xmlns:w='X' xmlns:a='a' a:z=''/>");
}
/**
* Creates the database context.
*/
@BeforeClass
public static void start() {
// turn off pretty printing
set(MainOptions.SERIALIZER, SerializerMode.NOINDENT.get());
}
/**
* Creates the specified test databases.
* @param db database numbers
*/
private static void create(final int... db) {
for(final int d : db) {
final String[] doc = DOCS[d - 1];
execute(new CreateDB(doc[0], doc[1]));
}
}
/**
* Runs a query and matches the result against the expected output.
* @param query query
* @param expected expected output
*/
private static void query(final String query, final String expected) {
query(null, query, expected);
}
/**
* Runs an updating query and matches the result of the second query
* against the expected output.
* @param first first query
* @param second second query
* @param expected expected output
*/
private static void query(final String first, final String second, final String expected) {
if(first != null) Sandbox.query(first);
final String result = Sandbox.query(second).trim();
// quotes are replaced by apostrophes to simplify comparison
final String res = result.replaceAll("\"", "'");
final String exp = expected.replaceAll("\"", "'");
if(!exp.equals(res)) fail("\n[E] " + exp + "\n[F] " + res);
}
}