/** * Initializes the input files, specified by the context nodes. * * @param nod variables * @param var documents * @param qp query processor * @param first call * @return string with input files * @throws Exception exception */ private byte[] file( final Nodes nod, final Nodes var, final QueryProcessor qp, final boolean first) throws Exception { final TokenBuilder tb = new TokenBuilder(); for (int c = 0; c < nod.size(); ++c) { final byte[] nm = data.atom(nod.list[c]); String src = srcs.get(string(nm)); if (tb.size() != 0) tb.add(", "); tb.add(nm); Expr expr = null; if (src == null) { // assign collection expr = coll(nm, qp); } else { // assign document final String dbname = new IOFile(src).dbname(); Function def = Function.DOC; // updates: drop updated document or open updated database if (updating()) { if (first) { new DropDB(dbname).execute(context); } else { def = Function.OPEN; src = dbname; } } expr = def.get(null, Str.get(src)); } if (var != null) qp.bind(string(data.atom(var.list[c])), expr); } return tb.finish(); }
/** * Assigns the nodes to the specified variables. * * @param nod nodes * @param var variables * @param qp query processor * @throws QueryException query exception */ private void var(final Nodes nod, final Nodes var, final QueryProcessor qp) throws QueryException { for (int c = 0; c < nod.size(); ++c) { final byte[] nm = data.atom(nod.list[c]); final String src = srcs.get(string(nm)); final Item it = src == null ? coll(nm, qp) : Str.get(src); qp.bind(string(data.atom(var.list[c])), it); } }
/** * Evaluates the the input files and assigns the result to the specified variables. * * @param nod variables * @param var documents * @param pth file path * @param qp query processor * @throws Exception exception */ private void eval(final Nodes nod, final Nodes var, final String pth, final QueryProcessor qp) throws Exception { for (int c = 0; c < nod.size(); ++c) { final String file = pth + string(data.atom(nod.list[c])) + IO.XQSUFFIX; final String in = read(new IOFile(queries + file)); final QueryProcessor xq = new QueryProcessor(in, context); final Value val = xq.value(); qp.bind(string(data.atom(var.list[c])), val); xq.close(); } }
/** * Returns the resulting query text (text node or attribute value). * * @param qu query * @param root root node * @return attribute value * @throws Exception exception */ protected String text(final String qu, final Nodes root) throws Exception { final Nodes n = nodes(qu, root); final TokenBuilder tb = new TokenBuilder(); for (int i = 0; i < n.size(); ++i) { if (i != 0) tb.add('/'); tb.add(data.atom(n.list[i])); } return tb.toString(); }
/** * Returns the value for the specified pre value. * * @param pre pre value * @return item value */ byte[] getValue(final int pre) { final Data data = plotData.context.data; final int limit = pre + data.size(pre, Data.ELEM); for (int p = pre; p < limit; ++p) { final int kind = data.kind(p); if ((kind == Data.ELEM && tag || kind == Data.ATTR && !tag) && attrID == data.name(p)) return data.atom(p); } return EMPTY; }
/** * Parses the specified test case. * * @param root root node * @throws Exception exception * @return true if the query, specified by {@link #single}, was evaluated */ private boolean parse(final Nodes root) throws Exception { final String pth = text("@FilePath", root); final String outname = text("@name", root); if (single != null && !outname.startsWith(single)) return true; final Performance perf = new Performance(); if (verbose) Util.out("- " + outname); boolean inspect = false; boolean correct = true; final Nodes nodes = states(root); for (int n = 0; n < nodes.size(); ++n) { final Nodes state = new Nodes(nodes.list[n], nodes.data); final String inname = text("*:query/@name", state); context.query = new IOFile(queries + pth + inname + IO.XQSUFFIX); final String in = read(context.query); String er = null; ItemCache iter = null; boolean doc = true; final Nodes cont = nodes("*:contextItem", state); Nodes curr = null; if (cont.size() != 0) { final Data d = Check.check(context, srcs.get(string(data.atom(cont.list[0])))); curr = new Nodes(d.doc(), d); curr.root = true; } context.prop.set(Prop.QUERYINFO, compile); final QueryProcessor xq = new QueryProcessor(in, curr, context); context.prop.set(Prop.QUERYINFO, false); // limit result sizes to 1MB final ArrayOutput ao = new ArrayOutput(); final TokenBuilder files = new TokenBuilder(); try { files.add( file(nodes("*:input-file", state), nodes("*:input-file/@variable", state), xq, n == 0)); files.add(file(nodes("*:defaultCollection", state), null, xq, n == 0)); var(nodes("*:input-URI", state), nodes("*:input-URI/@variable", state), xq); eval(nodes("*:input-query/@name", state), nodes("*:input-query/@variable", state), pth, xq); parse(xq, state); for (final int p : nodes("*:module", root).list) { final String uri = text("@namespace", new Nodes(p, data)); final String file = mods.get(string(data.atom(p))) + IO.XQSUFFIX; xq.module(file, uri); } // evaluate and serialize query final SerializerProp sp = new SerializerProp(); sp.set(SerializerProp.S_INDENT, context.prop.is(Prop.CHOP) ? DataText.YES : DataText.NO); final XMLSerializer xml = new XMLSerializer(ao, sp); iter = xq.value().cache(); for (Item it; (it = iter.next()) != null; ) { doc &= it.type == NodeType.DOC; it.serialize(xml); } xml.close(); } catch (final Exception ex) { if (!(ex instanceof QueryException || ex instanceof IOException)) { System.err.println("\n*** " + outname + " ***"); System.err.println(in + "\n"); ex.printStackTrace(); } er = ex.getMessage(); if (er.startsWith(STOPPED)) er = er.substring(er.indexOf('\n') + 1); if (er.startsWith("[")) er = er.replaceAll("\\[(.*?)\\] (.*)", "$1 $2"); // unexpected error - dump stack trace } // print compilation steps if (compile) { Util.errln("---------------------------------------------------------"); Util.err(xq.info()); Util.errln(in); } final Nodes expOut = nodes("*:output-file/text()", state); final TokenList result = new TokenList(); for (int o = 0; o < expOut.size(); ++o) { final String resFile = string(data.atom(expOut.list[o])); final IOFile exp = new IOFile(expected + pth + resFile); result.add(read(exp)); } final Nodes cmpFiles = nodes("*:output-file/@compare", state); boolean xml = false; boolean frag = false; boolean ignore = false; for (int o = 0; o < cmpFiles.size(); ++o) { final byte[] type = data.atom(cmpFiles.list[o]); xml |= eq(type, XML); frag |= eq(type, FRAGMENT); ignore |= eq(type, IGNORE); } String expError = text("*:expected-error/text()", state); final StringBuilder log = new StringBuilder(pth + inname + IO.XQSUFFIX); if (files.size() != 0) { log.append(" ["); log.append(files); log.append("]"); } log.append(NL); /** Remove comments. */ log.append(norm(in)); log.append(NL); final String logStr = log.toString(); // skip queries with variable results final boolean print = currTime || !logStr.contains("current-"); boolean correctError = false; if (er != null && (expOut.size() == 0 || !expError.isEmpty())) { expError = error(pth + outname, expError); final String code = er.substring(0, Math.min(8, er.length())); for (final String e : SLASH.split(expError)) { if (code.equals(e)) { correctError = true; break; } } } if (correctError) { if (print) { logOK.append(logStr); logOK.append("[Right] "); logOK.append(norm(er)); logOK.append(NL); logOK.append(NL); addLog(pth, outname + ".log", er); } ++ok; } else if (er == null) { int s = -1; final int rs = result.size(); while (!ignore && ++s < rs) { inspect |= s < cmpFiles.list.length && eq(data.atom(cmpFiles.list[s]), INSPECT); final byte[] res = result.get(s), actual = ao.toArray(); if (res.length == ao.size() && eq(res, actual)) break; if (xml || frag) { iter.reset(); try { final ItemCache ic = toIter(string(res).replaceAll("^<\\?xml.*?\\?>", "").trim(), frag); if (FNSimple.deep(null, iter, ic)) break; ic.reset(); final ItemCache ia = toIter(string(actual), frag); if (FNSimple.deep(null, ia, ic)) break; } catch (final Throwable ex) { System.err.println("\n" + outname + ":"); ex.printStackTrace(); } } } if ((rs > 0 || !expError.isEmpty()) && s == rs && !inspect) { if (print) { if (expOut.size() == 0) result.add(error(pth + outname, expError)); logErr.append(logStr); logErr.append("[" + testid + " ] "); logErr.append(norm(string(result.get(0)))); logErr.append(NL); logErr.append("[Wrong] "); logErr.append(norm(ao.toString())); logErr.append(NL); logErr.append(NL); addLog(pth, outname + (xml ? IO.XMLSUFFIX : ".txt"), ao.toString()); } correct = false; ++err; } else { if (print) { logOK.append(logStr); logOK.append("[Right] "); logOK.append(norm(ao.toString())); logOK.append(NL); logOK.append(NL); addLog(pth, outname + (xml ? IO.XMLSUFFIX : ".txt"), ao.toString()); } ++ok; } } else { if (expOut.size() == 0 || !expError.isEmpty()) { if (print) { logOK2.append(logStr); logOK2.append("[" + testid + " ] "); logOK2.append(norm(expError)); logOK2.append(NL); logOK2.append("[Rght?] "); logOK2.append(norm(er)); logOK2.append(NL); logOK2.append(NL); addLog(pth, outname + ".log", er); } ++ok2; } else { if (print) { logErr2.append(logStr); logErr2.append("[" + testid + " ] "); logErr2.append(norm(string(result.get(0)))); logErr2.append(NL); logErr2.append("[Wrong] "); logErr2.append(norm(er)); logErr2.append(NL); logErr2.append(NL); addLog(pth, outname + ".log", er); } correct = false; ++err2; } } if (curr != null) Close.close(curr.data, context); xq.close(); } if (reporting) { logReport.append(" <test-case name=\""); logReport.append(outname); logReport.append("\" result='"); logReport.append(correct ? "pass" : "fail"); if (inspect) logReport.append("' todo='inspect"); logReport.append("'/>"); logReport.append(NL); } // print verbose/timing information final long nano = perf.getTime(); final boolean slow = nano / 1000000 > timer; if (verbose) { if (slow) Util.out(": " + Performance.getTimer(nano, 1)); Util.outln(); } else if (slow) { Util.out(NL + "- " + outname + ": " + Performance.getTimer(nano, 1)); } return single == null || !outname.equals(single); }
/** * 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(); }