/** * Retrieves the specified value. Throws an error if value cannot be read. * * @param key key * @param c expected type * @return result */ private Object get(final Object[] key, final Class<?> c) { final Object entry = props.get(key[0].toString()); if (entry == null) Util.notexpected("Property " + key[0] + " not defined."); final Class<?> cc = entry.getClass(); if (c != cc) Util.notexpected("Property '" + key[0] + "' is a " + Util.name(cc)); return entry; }
@Override public String toString() { final TokenBuilder tb = new TokenBuilder(Util.name(this) + '['); for (int i = 0; i < size; ++i) { if (i != 0) tb.add(", "); tb.add(list[i]); } return tb.add(']').toString(); }
static { try { final Class<?>[] classes = Loader.load(IFileParser.class.getPackage(), IFileParser.class); for (final Class<?> c : classes) { final String name = Util.name(c); if (!REGISTRY.containsValue(c) && fallbackParser != c) Util.debug("Loading % ... FAILED", name); } } catch (final IOException ex) { Util.errln("Failed to load parsers (%)", ex.getMessage()); } }
/** * Gets a parser implementation for given file suffix. * * @param suffix the file suffix to get the parser for * @return the parser implementation or {@code null} if no implementation is available * @throws ParserException if the parser could not be loaded */ IFileParser getParser(final String suffix) throws ParserException { IFileParser instance = parserInstances.get(suffix); if (instance == null) { final Class<? extends IFileParser> clazz = REGISTRY.get(suffix); if (clazz != null) { instance = (IFileParser) Reflect.get(clazz); if (instance == null) { throw new ParserException("Failed to load " + Util.name(clazz) + " for suffix " + suffix); } } // put in hash map ... even if null parserInstances.put(suffix, instance); } return instance; }
/** * General tests of the XQuery Update Facility implementation. * * @author BaseX Team 2005-12, BSD License * @author Lukas Kircher */ public final class UpdateTest extends AdvancedQueryTest { /** Test database name. */ private static final String DB = Util.name(UpdateTest.class); /** Test document. */ private static final String DOC = "src/test/resources/xmark.xml"; /** * Creates a database. * * @param input input database string, if null, then use default. * @throws BaseXException database exception */ private void createDB(final String input) throws BaseXException { new CreateDB(DB, input == null ? DOC : input).execute(CONTEXT); } /** * Text merging for a simple insert into statement. * * @throws Exception exception */ @Test public void textMerging01() throws Exception { createDB(null); query("insert node 'foo' into //item[@id='item0']/location"); query("(//item[@id='item0']/location/text())[1]", "United Statesfoo"); } /** * Text merging for a simple insert into statement in combination with an insert before statement. * Checks if pre value shifts are taken into account. * * @throws Exception exception */ @Test public void textMerging02() throws Exception { createDB(null); query( "insert node 'foo' into //item[@id='item0']/location," + "insert node <a/> before //item[@id='item0']"); query("(//item[@id='item0']/location/text())[1]", "United Statesfoo"); } /** * Text merging test. Test 'insert into as first' and whether pre value shifts are taken into * account correctly. * * @throws Exception exception */ @Test public void textMerging03() throws Exception { createDB(null); query( "let $i := //item[@id='item0'] return (insert node 'foo' as " + "first into $i/location, insert node 'foo' before $i/location, " + "insert node 'foo' into $i/quantity)"); query( "let $i := //item[@id='item0'] return " + "(($i/location/text())[1], ($i/quantity/text())[1])", "fooUnited States1foo"); } /** * Text merging for a simple insert into statement. Checks if pre value shifts are taken into * account. * * @throws Exception exception */ @Test public void textMerging04() throws Exception { createDB(null); query("let $i := //item[@id='item0'] return insert node 'foo' " + "before $i/location/text()"); query("let $i := //item[@id='item0'] return " + "($i/location/text())[1]", "fooUnited States"); } /** * Text merging for a simple insert into statement. Checks if pre value shifts are taken into * account. * * @throws Exception exception */ @Test public void textMerging05() throws Exception { createDB(null); query( "let $i := //item[@id='item0']/location return " + "(insert node 'foo' into $i, delete node $i/text())"); query("//item[@id='item0']/location/text()", "foo"); } /** * Text merging test. * * @throws Exception exception */ @Test public void textMerging06() throws Exception { createDB(null); query( "let $i := //item[@id='item0']/location return " + "(insert node <n/> into $i, insert node 'foo' as last into $i)"); query("let $i := //item[@id='item0']/location return " + "delete node $i/n"); query("(//item[@id='item0']/location/text())[1]", "United Statesfoo"); } /** * Text merging test. * * @throws Exception exception */ @Test public void textMerging07() throws Exception { createDB(null); query("let $i := //item[@id='item0']/location return " + "insert node 'foo' after $i/text()"); query("(//item[@id='item0']/location/text())[1]", "United Statesfoo"); } /** * Text merging test. * * @throws Exception exception */ @Test public void textMerging08() throws Exception { createDB(null); query("let $i := //item[@id='item0'] return " + "(insert node 'foo' after $i/location)"); query( "let $i := //item[@id='item0']/location return " + "(insert node 'foo' after $i, insert node 'faa' before $i, insert " + "node 'faa' into $i, delete node $i/text())"); query( "let $i := //item[@id='item0']/location " + "return ($i/text(), ($i/../text())[2])", "faafoofoo"); } /** Text merging test for delete operation. */ @Test public void textMerging09() { query( "copy $c := <n>aa<d/><d/>cc</n> " + "modify (delete node $c//d, insert node 'bb' after ($c//d)[1]) " + "return (count($c//text()), $c//text())", "1aabbcc"); } /** Text merging test for delete operation. */ @Test public void textMerging10() { query( "copy $c := <n>aa<d/><d/>cc</n> " + "modify (delete node $c//d, insert node 'bb' before ($c//d)[2]) " + "return (count($c//text()), $c//text())", "1aabbcc"); } /** Text merging test for delete operation. */ @Test public void textMerging11() { query( "copy $c := <n>aa<d/><d/>cc</n> " + "modify (delete node $c//d, insert node 'bb' before ($c//d)[2]) " + "return (count($c//text()), $c//text())", "1aabbcc"); } /** Text merging test for delete operation. */ @Test public void treeAwareUpdates() { query( "copy $n := <a><b><c/></b></a> " + "modify (replace value of node $n/b with (), " + "insert node <d/> into $n/b, insert node <d/> after $n/b) return $n", "<a><b/><d/></a>"); } /** Delete last node of a data instance. Checks if table limits are crossed. */ @Test public void deleteLastNode() { query("copy $n := <a><b/><c/></a> modify (delete node $n//c) return $n", "<a><b/></a>"); } /** Replace last node of a data instance. Checks if table limits are crossed. */ @Test public void replaceLastNode() { query( "copy $n := <a><b/><c><d/><d/><d/></c></a> " + "modify (replace node $n//c with <c/>) return $n", "<a><b/><c/></a>"); } /** * Replaces the value of the documents root node. Related to github issue #141. * * @throws BaseXException database exception */ @Test public void replaceValueOfEmptyRoot() throws BaseXException { createDB("<a/>"); query("replace value of node /a with 'a'"); query("/", "<a>a</a>"); } /** Insertion into an empty element. */ @Test public void emptyInsert1() { query("copy $x := <X/> modify insert nodes <A/> into $x return $x", "<X><A/></X>"); } /** Insertion into an empty document. */ @Test public void emptyInsert2() { query("copy $x := document {()} modify insert nodes <X/> into $x return $x", "<X/>"); } /** * Insertion into an empty document. * * @throws BaseXException database exception */ @Test public void emptyInsert3() throws BaseXException { createDB("<a/>"); query("delete node /a"); query("insert nodes <X/> into doc('" + DB + "')"); query("/", "<X/>"); } /** * Tests a simple call of the optimize command. * * @throws BaseXException database exception */ @Test public void optimize() throws BaseXException { createDB(null); query( "let $w := //item[@id = 'item0'] " + "return (if($w/@id) " + "then (delete node $w/@id, db:optimize('" + DB + "')) else ())"); } /** Variable from the inner scope shouldn't be visible. */ @Test public void outOfScope() { error("let $d := copy $e := <a/> modify () return $e return $e", Err.VARUNDEF); } /** The new-namespace flag has to be set for the parent of an inserted attribute. */ @Test public void setNSFlag() { query( "declare namespace x='x';" + "copy $x := <x/> modify insert node attribute x:x {} into $x return $x", "<x xmlns:x=\"x\" x:x=\"\"/>"); } /** The new-namespace flag has to be set for the parent of an inserted attribute. */ @Test public void setNSFlag2() { query( "declare namespace x='x';" + "copy $x := <x><a/></x> " + "modify insert node attribute x:x {} into $x return $x/a", "<a xmlns:x=\"x\"/>"); } /** The new-namespace flag has to be set for the parent of an inserted attribute. */ @Test public void setNSFlag3() { query( "declare namespace x='x';" + "copy $x := <x><a/></x> " + "modify insert node attribute x:x {} into $x/a return $x/a", "<a xmlns:x=\"x\" x:x=\"\"/>"); } /** * Deletes the test db. * * @throws Exception exception */ @AfterClass public static void end() throws Exception { new DropDB(DB).execute(CONTEXT); CONTEXT.close(); } }
/** * Runs the test suite. * * @param args command-line arguments * @throws Exception exception */ void run(final String[] args) throws Exception { final Args arg = new Args( args, this, " Test Suite [options] [pat]" + NL + " [pat] perform only tests with the specified pattern" + NL + " -c print compilation steps" + NL + " -h show this help" + NL + " -m minimum conformance" + NL + " -g <test-group> test group to test" + NL + " -C run tests depending on current time" + NL + " -p change path" + NL + " -r create report" + NL + " -t[ms] list slowest queries" + NL + " -v verbose output"); while (arg.more()) { if (arg.dash()) { final char c = arg.next(); if (c == 'r') { reporting = true; currTime = true; } else if (c == 'C') { currTime = true; } else if (c == 'c') { compile = true; } else if (c == 'm') { minimum = true; } else if (c == 'g') { group = arg.string(); } else if (c == 'p') { path = arg.string() + "/"; } else if (c == 't') { timer = arg.num(); } else if (c == 'v') { verbose = true; } else { arg.check(false); } } else { single = arg.string(); maxout = Integer.MAX_VALUE; } } if (!arg.finish()) return; queries = path + "Queries/XQuery/"; expected = path + "ExpectedTestResults/"; results = path + "ReportingResults/Results/"; report = path + "ReportingResults/"; sources = path + "TestSources/"; final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); final String dat = sdf.format(Calendar.getInstance().getTime()); final Performance perf = new Performance(); context.prop.set(Prop.CHOP, false); // new Check(path + input).execute(context); data = CreateDB.xml(new IOFile(path + input), context); final Nodes root = new Nodes(0, data); Util.outln(NL + Util.name(this) + " Test Suite " + text("/*:test-suite/@version", root)); Util.outln(NL + "Caching Sources..."); for (final int s : nodes("//*:source", root).list) { final Nodes srcRoot = new Nodes(s, data); final String val = (path + text("@FileName", srcRoot)).replace('\\', '/'); srcs.put(text("@ID", srcRoot), val); } Util.outln("Caching Modules..."); for (final int s : nodes("//*:module", root).list) { final Nodes srcRoot = new Nodes(s, data); final String val = (path + text("@FileName", srcRoot)).replace('\\', '/'); mods.put(text("@ID", srcRoot), val); } Util.outln("Caching Collections..."); for (final int c : nodes("//*:collection", root).list) { final Nodes nodes = new Nodes(c, data); final String cname = text("@ID", nodes); final TokenList dl = new TokenList(); final Nodes doc = nodes("*:input-document", nodes); for (int d = 0; d < doc.size(); ++d) { dl.add(token(sources + string(data.atom(doc.list[d])) + IO.XMLSUFFIX)); } colls.put(cname, dl.toArray()); } init(root); if (reporting) { Util.outln("Delete old results..."); delete(new File[] {new File(results)}); } if (verbose) Util.outln(); final Nodes nodes = minimum ? nodes("//*:test-group[starts-with(@name, 'Minim')]//*:test-case", root) : group != null ? nodes("//*:test-group[@name eq '" + group + "']//*:test-case", root) : nodes("//*:test-case", root); long total = nodes.size(); Util.out("Parsing " + total + " Queries"); for (int t = 0; t < total; ++t) { if (!parse(new Nodes(nodes.list[t], data))) break; if (!verbose && t % 500 == 0) Util.out("."); } Util.outln(); total = ok + ok2 + err + err2; final String time = perf.getTimer(); Util.outln("Writing log file..." + NL); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + pathlog), UTF8)); bw.write("TEST RESULTS =================================================="); bw.write(NL + NL + "Total #Queries: " + total + NL); bw.write("Correct / Empty Results: " + ok + " / " + ok2 + NL); bw.write("Conformance (w/Empty Results): "); bw.write(pc(ok, total) + " / " + pc(ok + ok2, total) + NL); bw.write("Wrong Results / Errors: " + err + " / " + err2 + NL); bw.write("WRONG ========================================================="); bw.write(NL + NL + logErr + NL); bw.write("WRONG (ERRORS) ================================================"); bw.write(NL + NL + logErr2 + NL); bw.write("CORRECT? (EMPTY) =============================================="); bw.write(NL + NL + logOK2 + NL); bw.write("CORRECT ======================================================="); bw.write(NL + NL + logOK + NL); bw.write("==============================================================="); bw.close(); bw = new BufferedWriter(new FileWriter(path + pathhis, true)); bw.write(dat + "\t" + ok + "\t" + ok2 + "\t" + err + "\t" + err2 + NL); bw.close(); if (reporting) { bw = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(report + NAME + IO.XMLSUFFIX), UTF8)); write(bw, report + NAME + "Pre" + IO.XMLSUFFIX); bw.write(logReport.toString()); write(bw, report + NAME + "Pos" + IO.XMLSUFFIX); bw.close(); } Util.outln("Total #Queries: " + total); Util.outln("Correct / Empty results: " + ok + " / " + ok2); Util.out("Conformance (w/empty results): "); Util.outln(pc(ok, total) + " / " + pc(ok + ok2, total)); Util.outln("Total Time: " + time); context.close(); }
/** * This class tests namespaces. * * @author BaseX Team 2005-11, BSD License * @author Lukas Kircher */ public final class NamespaceTest { /** Database context. */ private static final Context CONTEXT = new Context(); /** Default database name. */ private static final String DBNAME = Util.name(NamespaceTest.class); /** Test documents. */ private static 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>"} }; /** * Checks if namespace hierarchy structure is updated correctly on the descendant axis after a * NSNode has been inserted. * * @throws Exception exception */ @Test public void insertIntoShiftPreValues() throws Exception { create(12); query("insert node <b xmlns:ns='A'/> into doc('d12')/*:a/*:b", ""); new Open("d12").execute(CONTEXT); assertEquals( NL + " Pre[3] xmlns:ns=\"A\" " + NL + " Pre[4] xmlns=\"B\" ", CONTEXT.data().ns.toString()); } /** * Checks if namespace hierarchy structure is updated correctly on the descendant axis after a * NSNode has been inserted. * * @throws Exception exception */ @Test public void insertIntoShiftPreValues2() throws Exception { create(13); query("insert node <c/> as first into doc('d13')/a", ""); new Open("d13").execute(CONTEXT); assertEquals(NL + " Pre[3] xmlns=\"A\" ", CONTEXT.data().ns.toString()); } /** * Checks if namespace hierarchy structure is updated correctly on the descendant axis after a * NSNode has been inserted. * * @throws Exception exception */ @Test public void insertIntoShiftPreValues3() throws Exception { create(14); query("insert node <n xmlns='D'/> into doc('d14')/*:a/*:b", ""); new Open("d14").execute(CONTEXT); assertEquals( NL + " Pre[1] xmlns=\"A\" " + NL + " Pre[2] xmlns=\"B\" " + NL + " Pre[3] xmlns=\"D\" " + NL + " Pre[4] xmlns=\"C\" ", CONTEXT.data().ns.toString()); } /** * Checks if namespace hierarchy structure is updated correctly on the descendant axis after a * NSNode has been deleted. * * @throws Exception exception */ @Test public void deleteShiftPreValues() throws Exception { create(12); query("delete node doc('d12')/a/b", ""); new Open("d12").execute(CONTEXT); assertEquals(NL + " Pre[2] xmlns=\"B\" ", CONTEXT.data().ns.toString()); } /** * Checks if namespace hierarchy structure is updated correctly on the descendant axis after a * NSNode has been deleted. * * @throws Exception exception */ @Test public void deleteShiftPreValues2() throws Exception { create(14); query("delete node doc('d14')/*:a/*:b", ""); new Open("d14").execute(CONTEXT); assertEquals( NL + " Pre[1] xmlns=\"A\" " + NL + " Pre[2] xmlns=\"C\" ", CONTEXT.data().ns.toString()); } /** * Checks if namespace hierarchy structure is updated correctly on the descendant axis after a * NSNode has been deleted. * * @throws Exception exception */ @Test public void deleteShiftPreValues3() throws Exception { create(15); query("delete node doc('d15')/*:a/*:c", ""); new Open("d15").execute(CONTEXT); assertEquals( NL + " Pre[1] xmlns=\"A\" " + NL + " Pre[2] xmlns=\"B\" " + NL + " Pre[3] xmlns=\"E\" ", CONTEXT.data().ns.toString()); } /** * Checks if namespace hierarchy structure is updated correctly on the descendant axis after a * NSNode has been deleted. * * @throws Exception exception */ @Test public void deleteShiftPreValues4() throws Exception { create(16); query("delete node doc('d16')/a/b", ""); new Open("d16").execute(CONTEXT); assertEquals("", CONTEXT.data().ns.toString()); } /** * Tests for correct namespace hierarchy, esp. if namespace nodes on the following axis of an * insert/delete operation are updated correctly. * * @throws Exception exception */ @Test public void delete1() throws Exception { create(11); query( "delete node doc('d11')/*:a/*:b", "doc('d11')/*:a", "<a xmlns='A'><c xmlns:ns1='AA'><d/></c></a>"); } /** 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. * * @throws Exception exception */ @Test public void copy2() throws Exception { create(4); query( "declare namespace a='aa'; copy $c:=doc('d4') modify () return $c//a:y", "<a:y xmlns:b='bb' xmlns:a='aa'/>"); } /** * Detects missing prefix declaration. * * @throws Exception exception */ @Test public void copy3() throws Exception { create(4); query( "declare namespace a='aa'; copy $c:=doc('d4')//a:y " + "modify () return $c", "<a:y xmlns:b='bb' xmlns:a='aa'/>"); } /** 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. * * @throws Exception exception */ @Test public void bogusDetector() throws Exception { create(1); query( "insert node <a xmlns='test'><b><c/></b><d/></a> into doc('d1')/x", "declare namespace na = 'test';doc('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. * * @throws Exception exception */ @Test public void nsHierarchy() throws Exception { create(9); query("insert node <f xmlns='F'/> into doc('d9')//*:e", ""); new Open("d9").execute(CONTEXT); assertEquals( NL + " Pre[1] xmlns=\"A\" " + NL + " Pre[4] xmlns=\"D\" " + NL + " Pre[6] xmlns=\"F\" ", CONTEXT.data().ns.toString()); } /** * Detects malformed namespace hierarchy. * * @throws Exception exception */ @Test public void nsHierarchy2() throws Exception { create(10); query("insert node <f xmlns='F'/> into doc('d10')//*:e", ""); new Open("d10").execute(CONTEXT); assertEquals( NL + " Pre[1] xmlns=\"A\" " + NL + " Pre[4] xmlns=\"D\" " + NL + " Pre[5] xmlns=\"G\" " + NL + " Pre[7] xmlns=\"F\" ", CONTEXT.data().ns.toString()); } /** 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. * * @throws Exception exception */ @Test public void insertD2intoD1() throws Exception { create(1, 2); query("insert node doc('d2') into doc('d1')/x", "doc('d1')", "<x><x xmlns='xx'/></x>"); } /** * Test query. * * @throws Exception exception */ @Test public void insertD3intoD1() throws Exception { create(1, 3); query( "insert node doc('d3') into doc('d1')/x", "doc('d1')/x/*", "<a:x xmlns:a='aa'><b:y xmlns:b='bb'/></a:x>"); } /** * Test query. * * @throws Exception exception */ @Test public void insertD3intoD1b() throws Exception { create(1, 3); query("insert node doc('d3') into doc('d1')/x", "doc('d1')/x/*/*", "<b:y xmlns:b='bb'/>"); } /** * Detects missing prefix declaration. * * @throws Exception exception */ @Test public void insertD4intoD1() throws Exception { create(1, 4); query( "declare namespace a='aa'; insert node doc('d4')/a:x/a:y " + "into doc('d1')/x", "doc('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? * * @throws Exception exception */ @Test public void insertD4intoD5() throws Exception { create(4, 5); query( "declare namespace a='aa';insert node doc('d4')//a:y " + "into doc('d5')/a:x", "declare namespace a='aa';doc('d5')//a:y", "<a:y xmlns:b='bb' xmlns:a='aa'/>"); } /** * Detects duplicate namespace declarations in MemData instance. * * @throws Exception exception */ @Test public void insertD7intoD1() throws Exception { create(1, 7); query( "declare namespace x='xx';insert node doc('d7')/x:x into doc('d1')/x", "doc('d1')/x", "<x><x xmlns='xx'><y/></x></x>"); } /** * Detects general problems with namespace references. * * @throws Exception exception */ @Test public void insertD6intoD4() throws Exception { create(4, 6); query( "declare namespace a='aa';insert node doc('d6') into doc('d4')/a:x", "declare namespace a='aa';doc('d4')/a:x/a:y", "<a:y xmlns:b='bb' xmlns:a='aa'/>"); } /** 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 insertTransformX() { query( "copy $foo := <foo/> modify insert nodes (<bar/>)" + "into $foo return $foo", "<foo><bar/></foo>"); } /** * Detects wrong namespace references. * * @throws Exception exception */ @Test public void uriStack() throws Exception { create(8); query("doc('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 JAX-RX/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 Exception exception */ @Test public void deleteDocumentNode() throws Exception { new Open("d2").execute(CONTEXT); CONTEXT.data().delete(0); assertEquals(true, CONTEXT.data().ns.rootEmpty()); } /** * Creates the database context. * * @throws BaseXException database exception */ @BeforeClass public static void start() throws BaseXException { // turn off pretty printing new Set(Prop.SERIALIZER, "indent=no").execute(CONTEXT); } /** * Creates the specified test databases. * * @param db database numbers * @throws BaseXException database exception */ public void create(final int... db) throws BaseXException { for (final int d : db) { final String[] doc = docs[d - 1]; new CreateDB(doc[0], doc[1]).execute(CONTEXT); } } /** * Removes test databases and closes the database context. * * @throws BaseXException database exception */ @AfterClass public static void finish() throws BaseXException { // drop all test databases for (final String[] db : docs) new DropDB(db[0]).execute(CONTEXT); new DropDB(DBNAME).execute(CONTEXT); CONTEXT.close(); } /** * Runs a query and matches the result against the expected output. * * @param query query * @param expected expected output */ private 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 void query(final String first, final String second, final String expected) { try { if (first != null) new XQuery(first).execute(CONTEXT); final String result = new XQuery(second).execute(CONTEXT); // quotes are replaced by apostrophes to simplify comparison final String res = result.replaceAll("\\\"", "'"); final String exp = expected.replaceAll("\\\"", "'"); if (!exp.equals(res)) fail("\nExpected: " + exp + "\nFound: " + res); } catch (final BaseXException ex) { fail(ex.getMessage()); } } }
/** * This class tests the database commands. * * @author BaseX Team 2005-11, BSD License * @author Christian Gruen */ public class CommandTest { /** Database context. */ protected static final Context CONTEXT = new Context(); /** Test file name. */ private static final String FN = "input.xml"; /** Test folder. */ private static final String FLDR = "etc/test"; /** Test file. */ private static final String FILE = FLDR + '/' + FN; /** Test name. */ private static final String NAME = Util.name(CommandTest.class); /** Test name. */ protected static final String NAME2 = NAME + '2'; /** Socket reference. */ static Session session; /** * Starts the server. * * @throws IOException I/O exception */ @BeforeClass public static void start() throws IOException { session = new LocalSession(CONTEXT); cleanUp(); } /** * Deletes the potentially already existing DBs. DBs & User {@link #NAME} and {@link #NAME2} * * @throws IOException I/O exception */ protected static void cleanUp() throws IOException { session.execute(new DropDB(NAME)); session.execute(new DropDB(NAME2)); session.execute(new DropUser(NAME)); session.execute(new DropUser(NAME2)); } /** Removes test databases and closes the database context. */ @AfterClass public static void finish() { CONTEXT.close(); } /** * Creates the database. * * @throws IOException I/O exception */ @After public final void after() throws IOException { cleanUp(); } /** Command test. */ @Test public final void add() { // database must be opened to add files no(new Add(FILE)); ok(new CreateDB(NAME)); ok(new Add(FILE, FN)); ok(new Add(FILE, FN, "target")); no(new Add(FILE, "/")); } /** Command test. */ @Test public final void alterDB() { ok(new CreateDB(NAME)); ok(new AlterDB(NAME, NAME2)); ok(new Close()); no(new AlterDB(NAME, NAME2)); no(new AlterDB(NAME2, "!")); no(new AlterDB("!", NAME2)); } /** Command test. */ @Test public final void alterUser() { ok(new CreateUser(NAME2, md5(NAME2))); ok(new AlterUser(NAME2, md5("test"))); no(new AlterUser(":", md5(NAME2))); } /** Command test. */ @Test public final void close() { // close is successful, even if no database is opened ok(new Close()); ok(new CreateDB(NAME, FILE)); ok(new Close()); } /** Create Backup Test. Using glob Syntax. */ @Test public final void createBackup() { no(new CreateBackup(NAME)); ok(new CreateDB(NAME)); ok(new CreateDB(NAME2)); ok(new CreateBackup(NAME)); ok(new Restore(NAME)); ok(new Close()); ok(new Restore(NAME)); ok(new CreateBackup(NAME)); ok(new Restore(NAME)); ok(new DropBackup(NAME)); ok(new CreateBackup(NAME + "*")); ok(new Restore(NAME2)); ok(new DropBackup(NAME + "*")); no(new Restore(":")); ok(new CreateBackup(NAME + "?," + NAME)); ok(new DropBackup(NAME2)); ok(new Restore(NAME)); no(new Restore(NAME + "?")); ok(new DropBackup(NAME)); } /** Command test. */ @Test public final void createDB() { ok(new CreateDB(NAME, FILE)); ok(new InfoDB()); ok(new CreateDB(NAME, FILE)); ok(new CreateDB("abcde")); ok(new DropDB("abcde")); // invalid database names no(new CreateDB("")); no(new CreateDB(" ")); no(new CreateDB(":")); no(new CreateDB("*?")); no(new CreateDB("/")); } /** Command test. */ @Test public final void createIndex() { no(new CreateIndex(null)); for (final CmdIndex cmd : CmdIndex.values()) no(new CreateIndex(cmd)); ok(new CreateDB(NAME, FILE)); for (final CmdIndex cmd : CmdIndex.values()) ok(new CreateIndex(cmd)); no(new CreateIndex("x")); } /** Command test. */ @Test public final void createUser() { ok(new CreateUser(NAME2, md5("test"))); no(new CreateUser(NAME2, md5("test"))); ok(new DropUser(NAME2)); no(new CreateUser("", "")); no(new CreateUser(":", "")); } /** Command test. */ @Test public final void cs() { no(new Cs("//li")); ok(new CreateDB(NAME, FILE)); ok(new Cs("// li")); ok(CONTEXT.current(), 2); ok(new Cs(".")); ok(CONTEXT.current(), 2); ok(new Cs("/")); ok(CONTEXT.current(), 1); } /** Command test. */ @Test public final void delete() { // database must be opened to add files no(new Delete(FILE)); ok(new CreateDB(NAME)); // target need not exist ok(new Delete(FILE)); ok(new Add(FILE)); ok(new Delete(FILE)); ok(new Delete(FILE)); } /** Command test. */ @Test public final void dropDB() { ok(new DropDB(NAME)); ok(new CreateDB(NAME, FILE)); ok(new DropDB(NAME2)); ok(new DropDB(NAME)); ok(new DropDB(NAME)); ok(new CreateDB(NAME)); ok(new CreateDB(NAME2)); ok(new DropDB(NAME + "*")); no(new Open(NAME2)); no(new DropDB(":")); no(new DropDB("")); ok(new CreateDB(NAME)); ok(new CreateDB(NAME2)); ok(new DropDB(NAME + "," + NAME2)); no(new DropDB(NAME + ", " + ":")); } /** Command test. */ @Test public final void dropIndex() { for (final CmdIndex cmd : CmdIndex.values()) no(new DropIndex(cmd)); ok(new CreateDB(NAME, FILE)); for (final CmdIndex cmd : CmdIndex.values()) ok(new DropIndex(cmd)); no(new DropIndex("x")); } /** Command test. */ @Test public final void dropUser() { ok(new CreateUser(NAME, md5(NAME))); ok(new CreateUser(NAME2, md5(NAME))); ok(new DropUser(NAME)); ok(new DropUser(NAME2)); no(new DropUser("")); no(new DropUser(NAME2, ":")); ok(new CreateDB(NAME)); ok(new CreateUser(NAME, md5(NAME))); ok(new CreateUser(NAME2, md5(NAME))); ok(new DropUser(NAME2, NAME + "*")); ok(new DropUser(NAME + "," + NAME2)); } /** Command test. */ @Test public final void export() { final IOFile io = new IOFile(FN); no(new Export(io.path())); ok(new CreateDB(NAME, FILE)); ok(new Export(".")); ok(io.exists()); ok(io.delete()); } /** Command test. */ @Test public final void find() { no(new Find("1")); ok(new CreateDB(NAME, FILE)); ok(new Find("1")); } /** Command test. */ @Test public final void flush() { no(new Flush()); ok(new CreateDB(NAME)); ok(new Flush()); ok(new Close()); no(new Flush()); } /** Command test. */ @Test public final void get() { ok(new Get(CmdSet.CHOP)); no(new Get(NAME2)); } /** Command test. */ @Test public final void grant() { ok(new CreateUser(NAME2, md5("test"))); ok(new CreateUser(NAME, md5("test"))); no(new Grant("something", NAME2)); ok(new CreateDB(NAME)); ok(new Grant("none", NAME + "*", NAME + "*")); no(new Grant("all", NAME2)); no(new Grant("all", ":*?", ":*:")); ok(new DropUser(NAME + "," + NAME2)); no(new Grant("all", NAME)); no(new Grant("all", NAME + "*", ":")); } /** Command test. */ @Test public final void help() { no(new Help("bla")); ok(new Help(null)); } /** Command test. */ @Test public final void info() { ok(new Info()); } /** Command test. */ @Test public final void infoDB() { no(new InfoDB()); ok(new CreateDB(NAME, FILE)); ok(new InfoDB()); } /** Command test. */ @Test public final void infoIndex() { no(new InfoIndex()); ok(new CreateDB(NAME, FILE)); ok(new InfoIndex()); no(new InfoIndex("x")); } /** Command test. */ @Test public final void infoTable() { no(new InfoStorage("1", "2")); ok(new CreateDB(NAME, FILE)); ok(new InfoStorage("1", "2")); ok(new InfoStorage("1", null)); ok(new InfoStorage("// li", null)); } /** Command test. */ @Test public final void list() { ok(new List()); ok(new CreateDB(NAME, FILE)); ok(new List()); } /** Command test. */ @Test public final void listdb() { no(new ListDB(NAME)); ok(new CreateDB(NAME, FILE)); ok(new ListDB(NAME)); } /** Command test. */ @Test public final void open() { no(new Open(NAME)); ok(new CreateDB(NAME, FILE)); ok(new Open(NAME)); ok(new Open(NAME)); no(new Open(":")); } /** Command test. */ @Test public final void optimize() { no(new Optimize()); no(new OptimizeAll()); ok(new CreateDB(NAME, FILE)); ok(new Optimize()); ok(new OptimizeAll()); } /** Command test. */ @Test public final void password() { ok(new Password(md5(Text.ADMIN))); no(new Password("")); } /** Command test. */ @Test public final void rename() { // database must be opened to rename paths no(new Rename(FILE, "xxx")); ok(new CreateDB(NAME, FILE)); // target path must not be empty no(new Rename(FN, "/")); no(new Rename(FN, "")); ok(new Rename(FILE, FILE)); ok(new Rename(FILE, "xxx")); // source need not exist ok(new Rename(FILE, "xxx")); } /** Command test. */ @Test public final void replace() { // query to count number of documents final String count = "count(db:open('" + NAME + "'))"; // database must be opened to replace resources no(new Replace(FILE, "xxx")); ok(new CreateDB(NAME, FILE)); assertEquals("1", ok(new XQuery(count))); // replace existing document ok(new Replace(FN, "<a/>")); assertEquals("1", ok(new XQuery(count))); // replace existing document (again) ok(new Replace(FN, "<a/>")); assertEquals("1", ok(new XQuery(count))); // invalid content no(new Replace(FN, "")); assertEquals("1", ok(new XQuery(count))); // create and replace binary file ok(new XQuery("db:store('" + NAME + "', 'a', 'a')")); ok(new Replace("a", "<b/>")); assertTrue(ok(new XQuery("db:open('" + NAME + "')")).length() != 0); ok(new XQuery("db:retrieve('" + NAME + "', 'a')")); // a failing replace should not remove existing documents no(new Replace(FN, "<a>")); assertEquals("1", ok(new XQuery(count))); } /** Command test. */ @Test public final void restore() { no(new Restore(NAME)); ok(new CreateDB(NAME)); ok(new CreateBackup(NAME)); ok(new Restore(NAME)); no(new Restore(":")); ok(new DropBackup(NAME)); no(new Restore(NAME)); ok(new Open(NAME)); no(new Restore(NAME)); ok(new XQuery(".")); ok(new CreateDB("test-1")); ok(new CreateBackup("test-1")); ok(new Restore("test-1")); ok(new DropBackup("test")); no(new Restore("test")); ok(new DropBackup("test-1")); ok(new DropDB("test-1")); ok(new Close()); } /** Retrieves raw data. */ @Test public final void retrieve() { ok(new CreateDB(NAME)); // retrieve non-existing file no(new Retrieve(NAME2)); // retrieve existing file ok(new Store(NAME2, FILE)); ok(new Retrieve(NAME2)); } /** Stores raw data. */ @Test public final void store() { ok(new CreateDB(NAME)); ok(new Store(NAME2, FILE)); // file can be overwritten ok(new Store(NAME2, FILE)); // reject invalid names no(new Store("", FILE)); no(new Store("../x", FILE)); } /** Command test. */ @Test public final void run() { final IOFile io = new IOFile("test.xq"); no(new Run(io.path())); try { io.write(token("// li")); } catch (final Exception ex) { fail(Util.message(ex)); } no(new Run(io.path())); ok(new CreateDB(NAME, FILE)); ok(new Run(io.path())); io.delete(); } /** Command test. */ @Test public final void set() { ok(new Set(CmdSet.CHOP, false)); ok(new Set(CmdSet.CHOP, true)); ok(new Set("chop", true)); ok(new Set("runs", 1)); no(new Set("runs", true)); no(new Set(NAME2, NAME2)); } /** Command test. */ @Test public final void showUsers() { ok(new ShowUsers()); no(new ShowUsers(NAME)); ok(new CreateDB(NAME)); ok(new ShowUsers(NAME)); no(new ShowUsers(":")); } /** Command test. */ @Test public final void xquery() { no(new XQuery("/")); ok(new CreateDB(NAME, FILE)); ok(new XQuery("/")); ok(new XQuery("1")); no(new XQuery("1+")); } /** * Assumes that the specified flag is successful. * * @param flag flag */ private static void ok(final boolean flag) { assertTrue(flag); } /** * Assumes that the nodes have the specified number of nodes. * * @param nodes context nodes * @param size expected size */ private static void ok(final Nodes nodes, final int size) { if (nodes != null) assertEquals(size, nodes.size()); } /** * Assumes that this command is successful. * * @param cmd command reference * @return result as string */ protected final String ok(final Command cmd) { try { return session.execute(cmd); } catch (final IOException ex) { fail(Util.message(ex)); return null; } } /** * Assumes that this command fails. * * @param cmd command reference */ protected final void no(final Command cmd) { try { session.execute(cmd); fail("\"" + cmd + "\" was supposed to fail."); } catch (final IOException ex) { } } }
/** * Generates a stop file for the specified port. * * @param port server port * @return stop file */ private static File stopFile(final int port) { return new File(Prop.TMP, Util.name(BaseXServer.class) + port); }
@Override public String toString() { return Util.name(this) + "[" + targetNode() + "]"; }