Package test

Source Code of test.XQueryTestSuiteDriver$MyErrorListener

package test;


import com.saxonica.codegen.QueryCompiler;
import com.saxonica.config.EnterpriseConfiguration;
import net.sf.saxon.*;
import net.sf.saxon.om.*;
import net.sf.saxon.pattern.NameTest;
import net.sf.saxon.query.DynamicQueryContext;
import net.sf.saxon.query.StaticQueryContext;
import net.sf.saxon.query.XQueryExpression;
import net.sf.saxon.sxpath.XPathEvaluator;
import net.sf.saxon.sxpath.XPathExpression;
import net.sf.saxon.tinytree.TinyBuilder;
import net.sf.saxon.trace.ExpressionPresenter;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.Type;
import net.sf.saxon.value.AnyURIValue;
import net.sf.saxon.value.DateTimeValue;
import net.sf.saxon.value.SequenceExtent;
import net.sf.saxon.value.StringValue;
import org.w3c.tidy.Tidy;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.regex.Pattern;

/**
* This class runs the W3C XQuery Test Suite, driven from the test catalog. It includes options to
* run the tests intepretively or by compilation.
*/
public class XQueryTestSuiteDriver {
    /**
     * Run the testsuite using Saxon.
     *
     * @param args Array of parameters passed to the application
     * via the command line.
     */
    public static void main(String[] args) throws Exception {
        if (args.length == 0 || args[0].equals("-?")) {
            System.err.println(
                    "XQueryTestSuiteDriver testsuiteDir saxonDir [testNamePattern] [-compile] [-runcomp] [-w] [-onwards] [-unfold] [-pull] [-indent:yes|no] [-spec:1.0|1.1]");
        }

        System.err.println("Testing Saxon " + Version.getProductVersion());
        new XQueryTestSuiteDriver().go(args);
    }

    private String testSuiteDir;
    private String saxonDir;
    private EnterpriseConfiguration saConfig;
    private XMLReader resultParser;
    private XMLReader fragmentParser;
    private boolean usePull = false;
    private Pattern testPattern = null;
    private boolean showWarnings = false;
    private boolean compile = false;
    private boolean onwards = false;
    private boolean unfolded = false;
    private boolean runCompiled = false;
    private HashMap documentCache = new HashMap(50);

    private TransformerFactory tfactory = new TransformerFactoryImpl();

    private Writer results;
    private Writer compileScript = null;
    private HashSet directories = new HashSet(200);
    private PrintStream monitor = System.err;
    private PrintStream log;
    private String indent = "yes";
    private String specVersion = "1.1";

    /**
     * Some tests use schemas that conflict with others, so they can't use the common schema cache.
     * These tests are run in a Configuration of their own. (Ideally we would put this list in a
     * catalogue file of some kind).
     */

    static HashSet noCacheTests = new HashSet(30);
    static {
        noCacheTests.add("schemainline20_005_01");

    }

    private NameTest elementNameTest(NamePool pool, String local) {
        int nameFP = pool.allocate("", "http://www.w3.org/2005/02/query-test-XQTSCatalog", local) & NamePool.FP_MASK;
        return new NameTest(Type.ELEMENT, nameFP, pool);
    }

    private NodeInfo getChildElement(NodeInfo parent, NameTest child) {
        return (NodeInfo)parent.iterateAxis(Axis.CHILD, child).next();
    }

    public void go(String[] args) throws SAXException, ParserConfigurationException {


        testSuiteDir = args[0];
        saxonDir = args[1];
        HashSet exceptions = new HashSet();

        for (int i=2; i<args.length; i++) {
            if (args[i].startsWith("-")) {
                if (args[i].equals("-w")) {
                    showWarnings = true;
                } else if (args[i].equals("-compile")) {
                    compile = true;
                } else if (args[i].equals("-onwards")) {
                    onwards = true;
                } else if (args[i].equals("-runcomp")) {
                    runCompiled = true;
                } else if (args[i].equals("-unfold")) {
                    unfolded = true;
                } else if (args[i].equals("-pull")) {
                    usePull = true;
                } else if (args[i].startsWith("-indent")) {
                    indent = args[i].substring(8);
                } else if (args[i].startsWith("-spec")) {
                    specVersion = args[i].substring(6);
                }
            } else {
                testPattern = Pattern.compile(args[i]);
            }
        }


        try {
//            parser = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
//            if (!parser.getFeature("http://xml.org/sax/features/xml-1.1")) {
//                System.err.println("Warning: XML parser does not support XML 1.1 - " + parser.getClass());
//            };
            NamePool pool = new NamePool();
            saConfig = new EnterpriseConfiguration();
            saConfig.setNamePool(pool);
            saConfig.setHostLanguage(Configuration.XQUERY);
            //saConfig.setSourceParserClass("com.sun.org.apache.xerces.internal.parsers.SAXParser");
            XMLReader parser = saConfig.getSourceParser();

            boolean supports11 = false;
            try {
                supports11 = parser.getFeature("http://xml.org/sax/features/xml-1.1");
            } catch (Exception err) {}

            if (!supports11) {
                monitor.println("Warning: XML parser does not support XML 1.1 - " + parser.getClass());
            }
            resultParser = saConfig.getSourceParser();
            resultParser.setEntityResolver(
                    new EntityResolver() {
                        public InputSource resolveEntity(String publicId, String systemId) {
                            return new InputSource(new StringReader(""));
                        }
                    }
            );
            fragmentParser = saConfig.getSourceParser();

            //Configuration config11 = new Configuration();
            //config11.setXMLVersion(Configuration.XML11);
            //config11.setNamePool(pool);

            results = new FileWriter(
                    new File(saxonDir + "/results" + Version.getProductVersion() + ".xml"));
            log = new PrintStream(new FileOutputStream(
                    new File(saxonDir + "/results" + Version.getProductVersion() + ".log")));

            MyErrorListener errorListener = new MyErrorListener(log);
            saConfig.setErrorListener(errorListener);

            NameTest testCaseNT = elementNameTest(pool, "test-case");
            NameTest inputUriNT = elementNameTest(pool, "input-URI");
            NameTest inputFileNT = elementNameTest(pool, "input-file");
            NameTest queryNT = elementNameTest(pool, "query");
            NameTest inputQueryNT = elementNameTest(pool, "input-query");
            NameTest contextItemNT = elementNameTest(pool, "contextItem");
            NameTest outputFileNT = elementNameTest(pool, "output-file");
            NameTest sourceNT = elementNameTest(pool, "source");
            NameTest schemaNT = elementNameTest(pool, "schema");
            NameTest expectedErrorNT = elementNameTest(pool, "expected-error");
            NameTest collectionNT = elementNameTest(pool, "collection");
            NameTest defaultCollectionNT = elementNameTest(pool, "defaultCollection");
            NameTest optimizationNT = elementNameTest(pool, "optimization");


            int schemaAtt = pool.allocate("", "", "schema") & NamePool.FP_MASK;
            int nameAtt = pool.allocate("", "", "name") & NamePool.FP_MASK;
            int filePathAtt = pool.allocate("", "", "FilePath") & NamePool.FP_MASK;
            int fileNameAtt = pool.allocate("", "", "FileName") & NamePool.FP_MASK;
            int idAtt = pool.allocate("", "", "ID") & NamePool.FP_MASK;
            int compareAtt = pool.allocate("", "", "compare") & NamePool.FP_MASK;
            int variableAtt = pool.allocate("", "", "variable") & NamePool.FP_MASK;
            int scenarioAtt = pool.allocate("", "", "scenario") & NamePool.FP_MASK;
            int explainAtt = pool.allocate("", "", "explain") & NamePool.FP_MASK;
            int assertAtt = pool.allocate("", "", "assert") & NamePool.FP_MASK;
            int versionAtt = pool.allocate("", "", "version") & NamePool.FP_MASK;
            int specVersionAtt = pool.allocate("", "", "spec-version") & NamePool.FP_MASK;

            /**
             * Look for an exceptions.xml document with the general format:
             *
             * <exceptions>
             *   <exception>
             *     <tests>testname1 testname2 ...</tests>
             *     <decription>text explanation</description>
             *   </exception>
             * </exceptions>
             *
             * Tests listed in this file will not be run.
             */

            DocumentInfo exceptionsDoc = saConfig.buildDocument(
                    new StreamSource(new File(saxonDir + "/exceptions.xml"))
            );

            NameTest exceptionTestsNT = new NameTest(Type.ELEMENT, pool.allocate("", "", "tests"), pool);
            AxisIterator exceptionTestCases = exceptionsDoc.iterateAxis(Axis.DESCENDANT, exceptionTestsNT);
            while (true) {
                NodeInfo testCase = (NodeInfo)exceptionTestCases.next();
                if (testCase == null) {
                    break;
                }
                String name = testCase.getStringValue();
                StringTokenizer tok = new StringTokenizer(name);
                while (tok.hasMoreElements()) {
                    exceptions.add(tok.nextElement());
                }
            }


            DocumentInfo catalog = saConfig.buildDocument(
                    new StreamSource(new File(testSuiteDir + "/XQTScatalog.xml"))
            );



            /**
             * If compiling tests to Java, generate a batch script to perform the Java compilations
             */

            if (compile) {
                compileScript = new FileWriter(
                        new File(saxonDir + "compile.cmd"));
                compileScript.write("set JAVA=\"c:\\Program Files\\java\\jdk1.6.0_05\"\n");
                //compileScript.write("set CLASSPATH=\"C:\\Documents and Settings\\Mike\\IdeaProjects\\Saxon 8.x\\Saxon\\classes\";c:\\Javalib\\jsdk2.1\\servlet.jar\n");
                compileScript.write("set CLASSPATH=e:\\saxon-build\\9.2.0.1\\eej\\saxon9ee.jar;e:\\Javalib\\jsdk2.1\\servlet.jar\n");
            }

            String dateTime = DateTimeValue.getCurrentDateTime(null).getStringValue();
            Properties outputProps = new Properties();
            outputProps.setProperty("method", "xml");
            outputProps.setProperty("indent", indent);
            results.write("<test-suite-result xmlns='http://www.w3.org/2005/02/query-test-XQTSResult'>");
            results.write(" <implementation name='Saxon-EE' version='" + Version.getProductVersion() +
                    "' anonymous-result-column='false'>\n");
            results.write("  <organization name='Saxonica' website='http://www.saxonica.com/' anonymous='false'/>\n");
            results.write("  <submittor name='Michael Kay' title='Director' email='mike@saxonica.com'/>\n");
            outputDiscretionaryItems();
            results.write(" </implementation>\n");
            results.write(" <syntax>XQuery</syntax>");
            results.write(" <test-run dateRun='" + dateTime + "'>");
            results.write("   <test-suite version='1.0.4'/>");
            results.write("   <transformation/>");
            results.write("   <comparison/>");
            results.write("   <otherComments/>");
            results.write(" </test-run>");

            /**
             * Load all the schemas
             */

            AxisIterator schemas = catalog.iterateAxis(Axis.DESCENDANT, schemaNT);
            while (true) {
                NodeInfo schemaElement = (NodeInfo)schemas.next();
                if (schemaElement == null) {
                    break;
                }
                String fileName = schemaElement.getAttributeValue(fileNameAtt);
                monitor.println("Loading schema " + fileName);
                StreamSource ss = new StreamSource(new File(testSuiteDir + fileName));
                saConfig.addSchemaSource(ss);

            }

            /**
             * Unless we are compiling tests to Java, load the source documents
             */

            if (!compile) {
                AxisIterator sources = catalog.iterateAxis(Axis.DESCENDANT, sourceNT);
                while (true) {
                    NodeInfo sourceElement = (NodeInfo)sources.next();
                    if (sourceElement == null) {
                        break;
                    }
                    String schema = sourceElement.getAttributeValue(schemaAtt);
                    String id = sourceElement.getAttributeValue(idAtt);
                    String fileName = sourceElement.getAttributeValue(fileNameAtt);
                    monitor.println("Loading source " + fileName);
                    Source ss = new StreamSource(new File(testSuiteDir + fileName));
                    if (schema != null) {
                        ss = AugmentedSource.makeAugmentedSource(ss);
                        ((AugmentedSource)ss).setSchemaValidationMode(Validation.STRICT);
                    }
                    try {
                        DocumentInfo doc = saConfig.buildDocument(ss);
                        documentCache.put(id, doc) ;
                    } catch (XPathException e) {
                        monitor.println("** invalid source document");
                    }

                }
            }

            AxisIterator testCases = catalog.iterateAxis(Axis.DESCENDANT, testCaseNT);
            int groupsize = 0;
            String prevGroup = null;
            while (true) {
                NodeInfo testCase = (NodeInfo)testCases.next();
                if (testCase == null) {
                    break;
                }

                String testName = testCase.getAttributeValue(nameAtt);
                boolean optimizationOK = true;
                if (testPattern != null && !testPattern.matcher(testName).matches()) {
                    continue;
                }
                if (onwards) {
                    testPattern = null;
                }
                if (exceptions.contains(testName)) {
                    continue;
                }
                if (isExcluded(testName)) {
                    continue;
                }
                monitor.println("Test " + testName);
                log.println("Test " + testName);

                String filePath = testCase.getAttributeValue(filePathAtt);
                if (filePath.startsWith("StaticTyping")) {
                    continue;
                }
                //NodeInfo testInput = getChildElement(testCase, inputFileNT);

                NodeInfo query = getChildElement(testCase, queryNT);
                String queryName = query.getAttributeValue(nameAtt);
                String languageVersion = query.getAttributeValue(versionAtt);
                if (languageVersion == null) {
                    languageVersion = specVersion;
                }

                String absQueryName = testSuiteDir + "/Queries/" +
                        (unfolded ? "XQUnfolded/" : "XQuery/") +
                        filePath + queryName + ".xq";

                String outputFile;

                if (compile) {
                    if ("parse-error".equals(testCase.getAttributeValue(scenarioAtt))) {
                        continue;
                    }
                    QueryCompiler qc = new QueryCompiler(saConfig);
                    qc.setBaseURI(new File(absQueryName).toURI().toString());
                    String groupName = testCase.getParent().getAttributeValue(nameAtt);
                    groupName = lowercase(groupName);
                    if (groupName.equals(prevGroup)) {
                        groupsize++;
                        int tome = groupsize / 500;
                        if (tome != 0) {
                            groupName += tome;
                        }
                    } else {
                        groupsize = 0;
                        prevGroup = groupName;
                    }
                    queryName = lowercase(queryName);
                    qc.setClassName(makeClassName(groupName, queryName));
                    File dir = new File(saxonDir + "/java/");
                    dir.mkdir();
                    qc.setOutputDirectory(dir);
                    //qc.setClassPath(classPath);

                    try {

                        qc.compileQueryToJava(new FileInputStream(absQueryName), "utf8");
                        log.println("Java source code written "/* + qc.getJavaFile()*/);
                        String finaldir = dir + "/" + groupName;
                        if (!directories.contains(finaldir)) {
                            compileScript.write("%JAVA%\\bin\\javac -classpath %CLASSPATH% " + finaldir + "/*.java\n");
                            directories.add(finaldir);
                        }
                    } catch (XPathException err) {
                        log.println("Query compilation failed");
                        continue;
                    } catch (FileNotFoundException err) {
                        log.println("Query file not found");
                    } catch (Exception err2) {
                        err2.printStackTrace();
                        continue;
                    }
                    continue;


                } else {
                    if (runCompiled) {
                        if ("parse-error".equals(testCase.getAttributeValue(scenarioAtt))) {
                            continue;
                        }
                        QueryCompiler qc = new QueryCompiler(saConfig);
                        qc.setBaseURI(new File(absQueryName).toURI().toString());
                        String groupName = testCase.getParent().getAttributeValue(nameAtt);
                        groupName = lowercase(groupName);

                        if (groupName.equals(prevGroup)) {
                            groupsize++;
                            int tome = groupsize / 500;
                            if (tome != 0) {
                                groupName += tome;
                            }
                        } else {
                            groupsize = 0;
                            prevGroup = groupName;
                        }
                        queryName = lowercase(queryName);
                        qc.setClassName(makeClassName(groupName, queryName));
                        File dir = new File(saxonDir + "/java/");
                        dir.mkdir();
                        qc.setOutputDirectory(dir);

                        DynamicQueryContext dqc = new DynamicQueryContext(saConfig);
                        dqc.setParameterValue("zlsJJ", StringValue.EMPTY_STRING);
                        NodeInfo contextItemElement = getChildElement(testCase, contextItemNT);
                        if (contextItemElement != null) {
                            DocumentInfo contextNode = loadDocument(contextItemElement.getStringValue());
                            dqc.setContextItem(contextNode);
                        }

                        processInputDocuments(testCase, inputFileNT, variableAtt, dqc);

                        setQueryParameters(catalog, testCase, dqc, inputUriNT, variableAtt, collectionNT, idAtt);

                        NodeInfo defaultCollection = getChildElement(testCase, defaultCollectionNT);
                        if (defaultCollection != null) {
                            String docName = defaultCollection.getStringValue();
                            NodeInfo collectionElement = getCollectionElement(catalog, docName, collectionNT, idAtt);
                            CollectionURIResolver r =
                                            new XQTSCollectionURIResolver(catalog, collectionElement, true);
                            saConfig.setCollectionURIResolver(r);
                        }

                        processInputQueries(testCase, inputQueryNT, variableAtt, nameAtt, filePath, dqc);

                        String outputDir = saxonDir + "/results/" + filePath;
                        new File(outputDir).mkdirs();
                        outputFile = outputDir + "/" + testName + ".out";
                        File outputFileF = new File(outputFile);
                        outputFileF.createNewFile();
                        StreamResult result = new StreamResult(outputFileF);
                        try {
                            qc.runQuery(dqc, result, outputProps);
                        } catch (XPathException err) {
                            if (!err.hasBeenReported()) {
                                log.println(err.getMessage());
                            }
                            processError(err, testCase, testName, filePath + queryName + ".xq", expectedErrorNT, specVersionAtt);
                            continue;
                        } catch (ClassNotFoundException err) {
                            // means the query had a static error
                            continue;
                        } catch (Exception err2) {
                            err2.printStackTrace();
                            continue;
                        }
                    } else {
                        StaticQueryContext env = saConfig.newStaticQueryContext();
                        env.setModuleURIResolver(new XQTSModuleURIResolver(testCase));
                        env.setBaseURI(new File(absQueryName).toURI().toString());
                        env.setLanguageVersion(languageVersion);
                        XQueryExpression xqe;

                        try {
                            xqe = env.compileQuery(new FileInputStream(absQueryName), "UTF-8");
                        } catch (XPathException err) {
                            processError(err, testCase, testName, filePath + queryName + ".xq", expectedErrorNT, specVersionAtt);
                            continue;
                        }

                        NodeInfo optElement = getChildElement(testCase, optimizationNT);
                        if (optElement != null) {
                            String explain = optElement.getAttributeValue(explainAtt);
                            if ("true".equals(explain) || "1".equals(explain)) {
                                ExpressionPresenter presenter = new ExpressionPresenter(saConfig);
                                xqe.explain(presenter);
                                presenter.close();
                            }
                            String assertion = optElement.getAttributeValue(assertAtt);
                            if (assertion != null) {
                                TinyBuilder builder = new TinyBuilder();
                                builder.setPipelineConfiguration(saConfig.makePipelineConfiguration());
                                ExpressionPresenter presenter = new ExpressionPresenter(saConfig, builder);
                                xqe.explain(presenter);
                                presenter.close();
                                NodeInfo expressionTree = builder.getCurrentRoot();
                                XPathEvaluator xpe = new XPathEvaluator(saConfig);
                                XPathExpression exp = xpe.createExpression(assertion);
                                try {
                                    Boolean bv = (Boolean)exp.evaluateSingle(expressionTree);
                                    if (bv == null || !bv.booleanValue()) {
                                        log.println("** Optimization assertion failed");
                                        optimizationOK = false;
                                    }
                                } catch (Exception e) {
                                    log.println("** Optimization assertion result is not a boolean: " + assertion +
                                            "(" + e.getMessage() + ")");

                                }
                            }
                        }

                        DynamicQueryContext dqc = new DynamicQueryContext(saConfig);

                        NodeInfo contextItemElement = getChildElement(testCase, contextItemNT);
                        if (contextItemElement != null) {
                            DocumentInfo contextNode = loadDocument(contextItemElement.getStringValue());
                            dqc.setContextItem(contextNode);
                        }

                        processInputQueries(testCase, inputQueryNT, variableAtt, nameAtt, filePath, dqc);

                        processInputDocuments(testCase, inputFileNT, variableAtt, dqc);

                        setQueryParameters(catalog, testCase, dqc, inputUriNT, variableAtt, collectionNT, idAtt);

                        NodeInfo defaultCollection = getChildElement(testCase, defaultCollectionNT);
                        if (defaultCollection != null) {
                            String docName = defaultCollection.getStringValue();
                            NodeInfo collectionElement = getCollectionElement(catalog, docName, collectionNT, idAtt);
                            CollectionURIResolver r =
                                            new XQTSCollectionURIResolver(catalog, collectionElement, true);
                            saConfig.setCollectionURIResolver(r);
                        }


                        // Run the query

                        String outputDir = saxonDir + "/results/" + filePath;
                        if (outputDir.endsWith("/")) {
                            outputDir = outputDir.substring(0, outputDir.length()-1);
                        }
                        new File(outputDir).mkdirs();
                        outputFile = outputDir + "/" + testName + ".out";
                        File outputFileF = new File(outputFile);
                        outputFileF.createNewFile();
                        StreamResult result = new StreamResult(outputFileF);
                        try {
                            if (usePull) {
                                xqe.pull(dqc, result, outputProps);
                            } else {
                                xqe.run(dqc, result, outputProps);
                            }
                        } catch (XPathException err) {
                            processError(err, testCase, testName, filePath + queryName + ".xq", expectedErrorNT, specVersionAtt);
                            continue;
                        }
                    }
                }

                // Compare the results

                boolean resultsMatched = false;
                String possibleMatch = null;
                SequenceIterator expectedResults = testCase.iterateAxis(Axis.CHILD, outputFileNT);
                boolean multipleResults = false;
                SequenceIterator ccc = expectedResults.getAnother();
                ccc.next();
                if (ccc.next() != null) {
                    multipleResults = true;
                }
                while (true) {
                    NodeInfo outputFileElement = (NodeInfo)expectedResults.next();
                    if (outputFileElement == null) {
                        break;
                    }
                    String appliesTo = outputFileElement.getAttributeValue(specVersionAtt);
                    if (appliesTo != null && !appliesTo.contains(specVersion)) {
                        continue; // results apply to a different version
                    }
                    String resultsDir = testSuiteDir + "/ExpectedTestResults/" + filePath;
                    String resultsPath = resultsDir + outputFileElement.getStringValue();
                    String comparisonMethod = outputFileElement.getAttributeValue(compareAtt);
                    String comparisonResult;
                    if (comparisonMethod.equals("Ignore")) {
                        comparisonResult = "true";
                    } else {
                        comparisonResult = compare(outputFile, resultsPath, comparisonMethod, multipleResults);
                    }
                    if (comparisonResult.equals("true")) {
                        // exact match
                        results.write("  <test-case name='" + testName + "' result='pass'" +
                                (optimizationOK ? "" : " comment='check optimization'") +
                                "/>\n");
                        resultsMatched = true;
                        break;
                    } else if (comparisonResult.equals("false")) {
                        //continue;
                    } else {
                        possibleMatch = comparisonResult;
                        //continue;
                    }
                }

                if (!resultsMatched) {
                    if (multipleResults) {
                        log.println("*** Failed to match any of the permitted results");
                    }
                    NodeInfo expectedError = null;
                    SequenceIterator eit = testCase.iterateAxis(Axis.CHILD, expectedErrorNT);
                    while (true) {
                        NodeInfo e = (NodeInfo)eit.next();
                        if (e == null) {
                            break;
                        }
                        String appliesTo = e.getAttributeValue(specVersionAtt);
                        if (appliesTo != null && !appliesTo.contains(specVersion)) {
                            continue; // results apply to a different version
                        }
                        expectedError = e;
                        break;
                    }

                    if (possibleMatch != null) {
                        results.write("  <test-case name='" + testName + "' result='pass' comment='" +
                                possibleMatch + "'/>\n");
                    } else if (expectedError != null) {
                        results.write("  <test-case name='" + testName + "' result='fail' comment='" +
                                "expected " + expectedError.getStringValue() + ", got success'/>\n");
                    } else {
                        results.write("  <test-case name='" + testName + "' result='fail'/>\n");
                    }
                    results.write("  <?file " + filePath + queryName + ".xq ?>\n");
                }
            }

            results.write("</test-suite-result>");
            results.close();
            if (compile) {
                compileScript.close();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void setQueryParameters(DocumentInfo catalog, NodeInfo testCase, DynamicQueryContext dqc, NameTest inputUriNT, int variableAtt, NameTest collectionNT, int idAtt) throws XPathException {
        SequenceIterator inputURIs = testCase.iterateAxis(Axis.CHILD, inputUriNT);
        while (true) {
            NodeInfo inputURI = (NodeInfo)inputURIs.next();
            if (inputURI == null) {
                break;
            }
            String variableName = inputURI.getAttributeValue(variableAtt);
            variableName = toClarkName(variableName);
            if (variableName != null) {
                String docName = inputURI.getStringValue();
                if (docName.startsWith("collection")) {
                    NodeInfo collectionElement = getCollectionElement(catalog, docName, collectionNT, idAtt);
                    CollectionURIResolver r =
                            new XQTSCollectionURIResolver(catalog, collectionElement, false);
                    saConfig.setCollectionURIResolver(r);
                    dqc.setParameterValue(variableName, new AnyURIValue(docName));
                } else {
                    DocumentInfo doc = loadDocument(docName);
                    if (doc == null) {
                        dqc.setParameterValue(variableName, new AnyURIValue("error-document" + docName));
                    } else {
                        String uri = doc.getSystemId();
                        dqc.setParameterValue(variableName, new AnyURIValue(uri));
                    }
                }
            }
        }
    }

    private void processInputDocuments(NodeInfo testCase, NameTest inputFileNT, int variableAtt, DynamicQueryContext dqc) throws XPathException {
        SequenceIterator inputFiles = testCase.iterateAxis(Axis.CHILD, inputFileNT);
        while (true) {
            NodeInfo inputFile = (NodeInfo)inputFiles.next();
            if (inputFile == null) {
                break;
            }
            String variableName = inputFile.getAttributeValue(variableAtt);
            variableName = toClarkName(variableName);
            if (variableName != null) {
                DocumentInfo inputDoc = loadDocument(inputFile.getStringValue());
                dqc.setParameterValue(variableName, inputDoc);
                //System.err.println("Set parameter " + variableName + " := " + inputDoc.getSystemId());
            }
        }
    }

    private void processInputQueries(NodeInfo testCase, NameTest inputQueryNT, int variableAtt, int nameAtt, String filePath, DynamicQueryContext dqc) throws XPathException, IOException {
        SequenceIterator inputQueries = testCase.iterateAxis(Axis.CHILD, inputQueryNT);
        while (true) {
            NodeInfo inputQuery = (NodeInfo)inputQueries.next();
            if (inputQuery == null) {
                break;
            }
            String variableName = inputQuery.getAttributeValue(variableAtt);
            variableName = toClarkName(variableName);
            if (variableName != null) {
                String preQueryName = inputQuery.getAttributeValue(nameAtt);
                String subQueryFile = testSuiteDir + "/Queries/XQuery/" + filePath + preQueryName + ".xq";
                StaticQueryContext sqc2 = saConfig.newStaticQueryContext();
                XQueryExpression subQuery = sqc2.compileQuery(new FileReader(subQueryFile));
                SequenceIterator subQueryResult = subQuery.iterator(new DynamicQueryContext(saConfig));
                dqc.setParameterValue(variableName, SequenceExtent.makeSequenceExtent(subQueryResult));
            }
        }
    }

    private NodeInfo getCollectionElement(DocumentInfo catalog, String docName, NameTest collectionNT, int idAtt) {
        NodeInfo collectionElement = null;
        AxisIterator colls = catalog.iterateAxis(Axis.DESCENDANT, collectionNT);
        while (true) {
            NodeInfo coll = (NodeInfo)colls.next();
            if (coll == null) {
                break;
            }
            if (docName.equals(coll.getAttributeValue(idAtt))) {
                collectionElement = coll;
            }
        }
        return collectionElement;
    }

//    protected String getResultDirectoryName() {
//        return "SaxonDriver";
//    }

    protected boolean isExcluded(String testName) {
        return testName.startsWith("dotnet");
    }

    private static String toClarkName(String variableName) {
        // Crude handling of QName-valued variables (there aren't many in the catalog!)
        if (variableName == null) {
            return null;
        }
        if (variableName.startsWith("local:")) {
            return "{http://www.w3.org/2005/xquery-local-functions}" + variableName.substring(6);
        } else {
            return variableName;
        }

    }


    /**
     * Construct source object. This method allows subclassing e.g. to build a DOM or XOM source.
     * @param xml
     */

    private DocumentInfo loadDocument(String xml) {
        return (DocumentInfo)documentCache.get(xml);
    }

    /**
     * Process a static or dynamic error
     */

    private void processError(XPathException err, NodeInfo testCase, String testName, String queryPath, NameTest expectedErrorNT, int specVersionAtt)
    throws java.io.IOException {
        String actualError = err.getErrorCodeLocalPart();
        AxisIterator expectedErrors = testCase.iterateAxis(Axis.CHILD, expectedErrorNT);
        FastStringBuffer expected = new FastStringBuffer(20);
        while (true) {
            NodeInfo expectedError = (NodeInfo)expectedErrors.next();
            if (expectedError == null) {
                break;
            }
            String appliesTo = expectedError.getAttributeValue(specVersionAtt);
            if (appliesTo != null && !appliesTo.contains(specVersion)) {
                continue; // results apply to a different version
            }
            if (expectedError.getStringValue().equals(actualError) ||
                    expectedError.getStringValue().equals("*")) {
                results.write("  <test-case name='" + testName + "' result='pass'/>\n");
                return;
            }
            expected.append(expectedError.getStringValue());
            expected.append(" ");
        }
        if (expected.length() > 0) {
            results.write("  <test-case name='" + testName + "' result='pass'" +
                    " comment='expected " + expected + ", got " + actualError + "'/>\n");
        } else {
            results.write("  <test-case name='" + testName + "' result='fail'" +
                    " comment='expected success, got " + actualError + "'/>\n");
        }
        results.write("  <?file " + queryPath + " ?>\n");

    }


    static CanonicalXML canon = new CanonicalXML();

    private String compare(String outfile, String reffile, String comparator, boolean silent) {
        if (reffile == null) {
            log.println("*** No reference results available");
            return "false";
        }
        File outfileFile = new File(outfile);
        File reffileFile = new File(reffile);

        if (!reffileFile.exists()) {
            log.println("*** No reference results available");
            return "false";
        }

        // try direct comparison first

        String refResult = null;
        String actResult = null;

        try {
            // This is decoding bytes assuming the platform default encoding
            FileReader reader1 = new FileReader(outfileFile);
            FileReader reader2 = new FileReader(reffileFile);
            char[] contents1 = new char[(int)outfileFile.length()];
            char[] contents2 = new char[(int)reffileFile.length()];
            int size1 = reader1.read(contents1, 0, (int)outfileFile.length());
            int size2 = reader2.read(contents2, 0, (int)reffileFile.length());
            int offset1 = 0;
            int offset2 = 0;
            if (contents1[0]=='\u00ef' && contents1[1]=='\u00bb' && contents1[2]=='\u00bf') {
                offset1 += 3;
            }
            if (contents2[0]=='\u00ef' && contents2[1]=='\u00bb' && contents2[2]=='\u00bf') {
                offset2 += 3;
            }
            actResult = (size1==-1 ? "" : new String(contents1, offset1, size1-offset1));
            refResult = (size2==-1 ? "" : new String(contents2, offset2, size2-offset2));

            actResult = normalizeNewlines(actResult);
            refResult = normalizeNewlines(refResult);
            if (actResult.equals(refResult)) {
                return "true";
            }
            if (size1 == 0) {
                if (!silent) {
                    log.println("** ACTUAL RESULTS EMPTY; REFERENCE RESULTS LENGTH " + size2);
                }
                return "false";
            }
            if (size2 == 0) {
                if (!silent) {
                    log.println("** REFERENCED RESULTS EMPTY; ACTUAL RESULTS LENGTH " + size2);
                }
                return "false";
            }
        } catch (Exception e) {
        }

        // HTML: can't do logical comparison

        if (comparator.equals("html-output")) {
            // TODO: Tidy gets upset by byte-order-marks. Use the strings constructed above as input.
            try {
                Tidy tidy = new Tidy();
                tidy.setXmlOut(true);
                tidy.setQuiet(true);
                tidy.setShowWarnings(false);
                tidy.setCharEncoding(org.w3c.tidy.Configuration.UTF8);
                InputStream in1 = new FileInputStream(outfile);
                File xml1 = new File(outfile + ".xml");
                xml1.createNewFile();
                OutputStream out1 = new FileOutputStream(xml1);
                tidy.parse(in1, out1);
                InputStream in2 = new FileInputStream(reffile);
                File xml2 = new File(reffile + ".xml");
                xml2.createNewFile();
                OutputStream out2 = new FileOutputStream(xml2);
                tidy.parse(in2, out2);
                return compare(xml1.toString(), xml2.toString(), "xml", silent);
            } catch (IOException e) {
                e.printStackTrace();
                return "false";
            }
        } else if (comparator.equals("xhtml-output")) {
            refResult = canonizeXhtml(refResult);
            actResult = canonizeXhtml(actResult);
            return Boolean.toString((actResult.equals(refResult)));

        } else if (comparator.equals("Fragment") || comparator.equals("Text")) {
            try {
                // try two comparison techniques hoping one will work...
                boolean b = false;
                try {
                    b = compareFragments2(actResult, refResult, outfile, silent);
                } catch (Exception err1) {
                    log.println("XQTS: First comparison attempt failed " + err1.getMessage() + ", trying again");
                }
                if (!b) {
                    log.println("XQTS: First comparison attempt failed, trying again");
                    b = compareFragments(outfileFile, reffileFile, outfile, silent);
                }
                return Boolean.toString(b);
            } catch (Exception err2) {
                log.println("Failed to compare results for: " + outfile);
                err2.printStackTrace();
                return "false";
            }
        } else if (comparator.equals("Inspect")) {
            log.println("** Inspect results by hand");
            return "true";
        } else {
            // convert both files to Canonical XML and compare them again
            try {
                InputSource out = new InputSource(outfileFile.toURL().toString());
                InputSource ref = new InputSource(reffileFile.toURL().toString());
                String outxml = canon.toCanonicalXML2(resultParser, out, false);
                String refxml = canon.toCanonicalXML2(resultParser, ref, false);
//                String outxml = canon.toCanonicalXML3(factory, resultParser, actResult, false);
//                String refxml = canon.toCanonicalXML3(factory, resultParser, refResult, false);
                if (!outxml.equals(refxml)) {
                    // try comparing again, this time without whitespace nodes
                    outxml = canon.toCanonicalXML2(resultParser, out, true);
                    refxml = canon.toCanonicalXML2(resultParser, ref, true);
//                    outxml = canon.toCanonicalXML3(factory, resultParser, actResult, true);
//                    refxml = canon.toCanonicalXML3(factory, resultParser, refResult, true);
                    if (outxml.equals(refxml)) {
                        log.println("*** Match after stripping whitespace nodes: " + outfile);
                        return "*** Match after stripping whitespace nodes";
                    } else {
                        if (!silent) {
                            log.println("Mismatch with reference results: " + outfile);
                            log.println("REFERENCE RESULTS:");
                            log.println(truncate(refxml));
                            log.println("ACTUAL RESULTS:");
                            log.println(truncate(outxml));
                            findDiff(refxml, outxml);
                        }
                        return "false";
                    }
                } else {
                    return "true";
                }
            } catch (Exception err) {
                try {
                    log.println("Failed to compare results for: " + outfile + ": " + err.getMessage());
                    log.println("** Attempting XML Fragment comparison");
                    //boolean b = compareFragments(outfileFile, reffileFile, outfile, silent);
                    boolean b = compareFragments2(actResult, refResult, outfile, silent);
                    log.println("** " + (b ? "Success" : "Still different"));
                    return Boolean.toString(b);
                } catch (Exception err2) {
                    log.println("Again failed to compare results for: " + outfile);
                    err2.printStackTrace();
                }
                return "false";
            }
        }
    }

    Templates xhtmlCanonizer;

    private String canonizeXhtml(String input) {
        try {
            Templates canonizer = getXhtmlCanonizer();
            Transformer t = canonizer.newTransformer();
            StringWriter sw = new StringWriter();
            StreamResult r = new StreamResult(sw);
            InputSource is = new InputSource(new StringReader(input));
            SAXSource ss = new SAXSource(resultParser, is);
            t.transform(ss, r);
            return sw.toString();
        } catch (TransformerConfigurationException err) {
            log.println("*** Failed to compile XHTML canonicalizer stylesheet");
        } catch (TransformerException err) {
            log.println("*** Failed while running XHTML canonicalizer stylesheet");
        }
        return "";
    }

    private Templates getXhtmlCanonizer() throws TransformerConfigurationException {
        if (xhtmlCanonizer == null) {
            Source source = new StreamSource(new File(saxonDir + "/canonizeXhtml.xsl"));
            xhtmlCanonizer = tfactory.newTemplates(source);
        }
        return xhtmlCanonizer;
    }

    private boolean compareFragments(File outfileFile, File reffileFile, String outfile, boolean silent) {
        // if we can't parse the output as a document, try it as an external entity, with space stripping
        String outurl = outfileFile.toURI().toString();
        String refurl = reffileFile.toURI().toString();
        String outdoc = "<?xml version='1.1'?><!DOCTYPE doc [ <!ENTITY e SYSTEM '" + outurl + "'>]><doc>&e;</doc>";
        String refdoc = "<?xml version='1.1'?><!DOCTYPE doc [ <!ENTITY e SYSTEM '" + refurl + "'>]><doc>&e;</doc>";
        InputSource out2 = new InputSource(new StringReader(outdoc));
        InputSource ref2 = new InputSource(new StringReader(refdoc));
        String outxml2 = canon.toCanonicalXML(fragmentParser, out2, true);
        String refxml2 = canon.toCanonicalXML(fragmentParser, ref2, true);
        if (outxml2 != null && refxml2 != null && !outxml2.equals(refxml2)) {
            if (!silent) {
                log.println("Mismatch with reference results: " + outfile);
                log.println("REFERENCE RESULTS:");
                log.println(truncate(refxml2));
                log.println("ACTUAL RESULTS:");
                log.println(truncate(outxml2));
                findDiff(refxml2, outxml2);
            }
            return false;
        } else if (outxml2 == null) {
            log.println("Cannot canonicalize actual results");
            return false;
        } else if (refxml2 == null) {
            log.println("Cannot canonicalize reference results");
            return false;
        }
        return true;
    }

    /**
     * With this method of fragment comparison we build the wrapper document ourselves. This is
     * mainly to circumvent a Java XML parsing bug
     * @param outFragment
     * @param refFragment
     * @param outfile
     * @param silent
     * @return
     */

    private boolean compareFragments2(String outFragment, String refFragment, String outfile, boolean silent) {
        if (outFragment == null) {
            outFragment = "";
        }
        if (outFragment.startsWith("<?xml")) {
            int x = outFragment.indexOf("?>");
            outFragment = outFragment.substring(x+2);
        }
        if (refFragment == null) {
            refFragment = "";
        }
        if (refFragment.startsWith("<?xml")) {
            int x = refFragment.indexOf("?>");
            refFragment = refFragment.substring(x+2);
        }

        String outdoc = "<?xml version='1.1'?><doc>" + outFragment.trim() + "</doc>";
        String refdoc = "<?xml version='1.1'?><doc>" + refFragment.trim() + "</doc>";
        InputSource out2 = new InputSource(new StringReader(outdoc));
        InputSource ref2 = new InputSource(new StringReader(refdoc));
        String outxml2 = canon.toCanonicalXML(fragmentParser, out2, false);
        String refxml2 = canon.toCanonicalXML(fragmentParser, ref2, false);
        if (outxml2 != null && refxml2 != null && !outxml2.equals(refxml2)) {
            // Try again with whitespace stripping
            InputSource out3 = new InputSource(new StringReader(outdoc));
            InputSource ref3 = new InputSource(new StringReader(refdoc));
            String outxml3 = canon.toCanonicalXML(fragmentParser, out3, true);
            String refxml3 = canon.toCanonicalXML(fragmentParser, ref3, true);
            if (outxml3 != null && refxml3 != null && !outxml3.equals(refxml3)) {
                if (!silent) {
                    log.println("Mismatch with reference results: " + outfile);
                    log.println("REFERENCE RESULTS:");
                    log.println(truncate(refxml2));
                    log.println("ACTUAL RESULTS:");
                    log.println(truncate(outxml2));
                    findDiff(refxml2, outxml2);
                }
                return false;
            } else {
                log.println("Matches after stripping whitespace");
                return true;
            }

        } else if (outxml2 == null) {
            log.println("Cannot canonicalize actual results");
            return false;
        } else if (refxml2 == null) {
            log.println("Cannot canonicalize reference results");
            return false;
        }
        return true;
    }


    private static String truncate(String s) {
        if (s.length() > 200) return s.substring(0, 200);
        return s;
    }

    private void findDiff(String s1, String s2) {
        FastStringBuffer sb1 = new FastStringBuffer(s1.length());
        sb1.append(s1);
        FastStringBuffer sb2 = new FastStringBuffer(s2.length());
        sb2.append(s2);
        int i = 0;
        while (true) {
            if (s1.charAt(i) != s2.charAt(i)) {
                int j = (i < 50 ? 0 : i - 50);
                int k = (i + 50 > s1.length() || i + 50 > s2.length() ? i + 1 : i + 50);
                log.println("Different at char " + i + "\n+" + s1.substring(j, k) +
                                   "\n+" + s2.substring(j, k));
                break;
            }
            if (i >= s1.length()) break;
            if (i >= s2.length()) break;
            i++;
        }
    }

    private void outputDiscretionaryItems() throws IOException {
        results.write("  <discretionary-items/>\n");
    }


    private class MyErrorListener extends StandardErrorListener {

        public String errorCode;

        public MyErrorListener(PrintStream log) {
            setErrorOutput(log);
        }

        /**
         * Receive notification of a recoverable error.
         */

        public void error(TransformerException exception) throws TransformerException {
            if (exception instanceof XPathException) {
                String code = ((XPathException)exception).getErrorCodeLocalPart();
                if (code != null) {
                    errorCode = code;
                }
                if ("FODC0005".equals(errorCode)) {
                    fatalError(exception);
                }
            }
            super.error(exception);
        }

        /**
         * Receive notification of a non-recoverable error.
         */

        public void fatalError(TransformerException exception) throws TransformerException {
            if (exception instanceof XPathException) {
                String code = ((XPathException)exception).getErrorCodeLocalPart();
                if (code != null) {
                    errorCode = code;
                }
            }
            super.fatalError(exception);
        }

        /**
         * Receive notification of a warning.
         */

        public void warning(TransformerException exception) throws TransformerException {
            if (showWarnings) {
                super.warning(exception);
            }
        }

        /**
         * Make a clean copy of this ErrorListener. This is necessary because the
         * standard error listener is stateful (it remembers how many errors there have been)
         */

        public StandardErrorListener makeAnother(int hostLanguage) {
            return new MyErrorListener(log);
        }

    }

    private String lowercase(String name) {
        FastStringBuffer sb = new FastStringBuffer(name.length());
        name = name.toLowerCase();
        for (int p=0; p<name.length(); p++) {
            char c = name.charAt(p);
            if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    private String makeClassName(String groupName, String mainName) {
        FastStringBuffer sb = new FastStringBuffer(mainName.length());
        sb.append(groupName);
        sb.append(".");
        mainName = mainName.substring(0,1).toUpperCase() + mainName.substring(1).toLowerCase();
        sb.append(mainName);
        return sb.toString();
    }

    private String normalizeNewlines(String in) {
        return in.replace("\r\n", "\n");
    }
//        int cr = in.indexOf('\r');
//        if (cr >= 0 && in.charAt(cr + 1) == '\n') {
//            return in.substring(0, cr) + normalizeNewlines(in.substring(cr + 1));
//        } else {
//            return in;
//        }
//    }


}
TOP

Related Classes of test.XQueryTestSuiteDriver$MyErrorListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.