tests/auto/xmlpatterns/tst_xmlpatterns.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 #include <QFile>
       
    44 #include <QtTest/QtTest>
       
    45 
       
    46 #ifdef QTEST_XMLPATTERNS
       
    47 
       
    48 #include "../qxmlquery/TestFundament.h"
       
    49 #include "../network-settings.h"
       
    50 
       
    51 /*!
       
    52  \class tst_XmlPatterns
       
    53  \internal
       
    54  \since 4.4
       
    55  \brief Tests the command line interface, \c xmlpatterns, for the XQuery code.
       
    56 
       
    57  This test is not intended for testing the engine, but all the gluing the
       
    58  command line interface do: error reporting, query output, variable bindings, exit
       
    59  codes, and so on.
       
    60 
       
    61  In other words, if you have an engine bug; don't add it here because it won't be
       
    62  tested properly. Instead add it to the test suite.
       
    63 
       
    64  */
       
    65 class tst_XmlPatterns : public QObject
       
    66                       , private TestFundament
       
    67 {
       
    68     Q_OBJECT
       
    69 
       
    70 public:
       
    71     tst_XmlPatterns();
       
    72 
       
    73 private Q_SLOTS:
       
    74     void initTestCase();
       
    75     void xquerySupport();
       
    76     void xquerySupport_data() const;
       
    77     void xsltSupport();
       
    78     void xsltSupport_data() const;
       
    79     void stdoutFailure() const;
       
    80     void cleanupTestCase() const;
       
    81 
       
    82 private:
       
    83     static void createNonWritable(const QString &name);
       
    84     static void removeNonWritable(QFile &outFile);
       
    85 
       
    86     int             m_generatedTests;
       
    87     /**
       
    88      * Get rid of characters that complicates on various file systems.
       
    89      */
       
    90     const QRegExp   m_normalizeTestName;
       
    91     /**
       
    92      * @note Perforce disallows wildcards in the name.
       
    93      */
       
    94     const QRegExp   m_filenameInStderr;
       
    95     const QString   m_command;
       
    96     bool            m_dontRun;
       
    97 };
       
    98 
       
    99 tst_XmlPatterns::tst_XmlPatterns() : m_generatedTests(0)
       
   100                                    , m_normalizeTestName(QLatin1String("[\\*\\?#\\-\\/:; ()',&]"))
       
   101                                    , m_filenameInStderr(QLatin1String("file:\\/\\/.*(\\.xq|\\.gccxml|\\.xml|\\.xsl|-)(,|:)"))
       
   102                                    , m_command(QLatin1String("xmlpatterns"))
       
   103                                    , m_dontRun(false)
       
   104 {
       
   105     Q_SET_DEFAULT_IAP
       
   106 
       
   107     Q_ASSERT(m_normalizeTestName.isValid());
       
   108     Q_ASSERT(m_filenameInStderr.isValid());
       
   109 }
       
   110 
       
   111 void tst_XmlPatterns::initTestCase()
       
   112 {
       
   113     QProcess process;
       
   114     process.start(m_command);
       
   115 
       
   116     if(!process.waitForFinished())
       
   117     {
       
   118         m_dontRun = true;
       
   119         QEXPECT_FAIL("", "The command line tool is not in the path, most likely because Qt "
       
   120                          "has been partically built, such as only the sub-src rule. No tests will be run.", Abort);
       
   121         QVERIFY(false);
       
   122     }
       
   123 
       
   124 }
       
   125 
       
   126 void tst_XmlPatterns::xquerySupport()
       
   127 {
       
   128     if(m_dontRun)
       
   129         QSKIP("The command line utility is not in the path.", SkipAll);
       
   130 
       
   131 #ifdef Q_OS_WINCE
       
   132     QSKIP("WinCE: This test uses unsupported WinCE functionality", SkipAll);
       
   133 #endif
       
   134 
       
   135     QFETCH(int,         expectedExitCode);
       
   136     QFETCH(QByteArray,  expectedQueryOutput);
       
   137     QFETCH(QStringList, arguments);
       
   138     QFETCH(QString,     cwd);
       
   139     QFETCH(QString,     outputFile);
       
   140 
       
   141     QProcess process;
       
   142 
       
   143     if(!cwd.isEmpty())
       
   144         process.setWorkingDirectory(inputFile(cwd));
       
   145 
       
   146     process.start(m_command, arguments);
       
   147 
       
   148     QCOMPARE(process.exitStatus(), QProcess::NormalExit);
       
   149     QVERIFY(process.waitForFinished());
       
   150 
       
   151     if(process.exitCode() != expectedExitCode)
       
   152         QTextStream(stderr) << "stderr:" << process.readAllStandardError();
       
   153 
       
   154     QCOMPARE(process.exitCode(), expectedExitCode);
       
   155 
       
   156     const QByteArray rawProducedStderr((process.readAllStandardError()));
       
   157     const QString fixedStderr(QString::fromLocal8Bit(rawProducedStderr).remove(m_filenameInStderr));
       
   158 
       
   159     const QString errorFileName(inputFile(QLatin1String(SRCDIR "stderrBaselines/") +
       
   160                                           QString::fromUtf8(QTest::currentDataTag()).remove(m_normalizeTestName) +
       
   161                                           QLatin1String(".txt")));
       
   162 
       
   163     QFile writeErr(errorFileName);
       
   164 
       
   165     if(writeErr.exists())
       
   166     {
       
   167         QVERIFY(writeErr.open(QIODevice::ReadOnly));
       
   168         QString rawExpectedStdErr(QString::fromLocal8Bit(writeErr.readAll()));
       
   169 
       
   170         /* On Windows, at least MinGW, this differs. */
       
   171         if(qstrcmp(QTest::currentDataTag(), "-output with a non-writable file") == 0)
       
   172         {
       
   173             QVERIFY(fixedStderr == rawExpectedStdErr.remove(m_filenameInStderr) ||
       
   174                     fixedStderr.trimmed() == "Failed to open file notWritable.out for writing: Access is denied.");
       
   175         }
       
   176         else if(qstrcmp(QTest::currentDataTag(), "Invoke -version") == 0)
       
   177         {
       
   178             /* There's a wide range of different version strings used. For
       
   179              * instance, "4.4.0-rc1". */
       
   180             const QRegExp removeVersion(QLatin1String(" Qt \\d\\.\\d.*"));
       
   181             QVERIFY(removeVersion.isValid());
       
   182             QCOMPARE(QString(fixedStderr).remove(removeVersion) + QChar('|'), rawExpectedStdErr + QChar('|'));
       
   183         }
       
   184         else
       
   185             QCOMPARE(fixedStderr, rawExpectedStdErr.remove(m_filenameInStderr));
       
   186     }
       
   187     else
       
   188     {
       
   189         QFile writeErr(errorFileName);
       
   190         QVERIFY(writeErr.open(QIODevice::WriteOnly));
       
   191 
       
   192         QCOMPARE(writeErr.write(rawProducedStderr), qint64(rawProducedStderr.count()));
       
   193         QTextStream(stderr) << "creating file " << errorFileName;
       
   194         ++m_generatedTests;
       
   195     }
       
   196 
       
   197     const QByteArray actual(process.readAllStandardOutput());
       
   198 
       
   199     if(outputFile.isEmpty())
       
   200     {
       
   201         QCOMPARE(actual, expectedQueryOutput);
       
   202         return; /* We're done, this test was not creating any output file. */
       
   203     }
       
   204     else
       
   205     {
       
   206         QVERIFY(actual.isEmpty());
       
   207 
       
   208         QFile outFile(outputFile);
       
   209 
       
   210         QVERIFY(outFile.exists());
       
   211         QVERIFY(outFile.open(QIODevice::ReadOnly));
       
   212 
       
   213         QCOMPARE(outFile.readAll(), expectedQueryOutput);
       
   214 
       
   215         removeNonWritable(outFile);
       
   216     }
       
   217 }
       
   218 
       
   219 void tst_XmlPatterns::xquerySupport_data() const
       
   220 {
       
   221 #ifdef Q_OS_WINCE
       
   222     return;
       
   223 #endif
       
   224 
       
   225     /* Check one file for existence, to avoid possible false positives. */
       
   226     QVERIFY(QFile::exists(inputFile(QLatin1String(SRCDIR "queries/onePlusOne.xq"))));
       
   227 
       
   228     QTest::addColumn<int>("expectedExitCode");
       
   229     QTest::addColumn<QByteArray>("expectedQueryOutput");
       
   230     QTest::addColumn<QStringList>("arguments");
       
   231     QTest::addColumn<QString>("cwd");
       
   232     QTest::addColumn<QString>("outputFile");
       
   233 
       
   234     QTest::newRow("A simple math query")
       
   235         << 0
       
   236         << QByteArray("2\n")
       
   237         << QStringList((QLatin1String(SRCDIR "queries/onePlusOne.xq")))
       
   238         << QString()
       
   239         << QString();
       
   240 
       
   241     QTest::newRow("An unbound external variable")
       
   242         << 2
       
   243         << QByteArray()
       
   244         << QStringList(QLatin1String(SRCDIR "queries/externalVariable.xq"))
       
   245         << QString()
       
   246         << QString();
       
   247 
       
   248     QTest::newRow("Bind an external variable")
       
   249         << 0
       
   250         << QByteArray("1 4<e>1</e>true\n")
       
   251         << (QStringList() << QLatin1String(SRCDIR "queries/externalVariable.xq")
       
   252                           << QLatin1String("-param")
       
   253                           << QLatin1String("externalVariable=1"))
       
   254         << QString()
       
   255         << QString();
       
   256 
       
   257     QTest::newRow("Bind an external variable, query appearing last")
       
   258         << 0
       
   259         << QByteArray("1 4<e>1</e>true\n")
       
   260         << (QStringList() << QLatin1String("-param")
       
   261                           << QLatin1String("externalVariable=1")
       
   262                           << QLatin1String(SRCDIR "queries/externalVariable.xq"))
       
   263         << QString()
       
   264         << QString();
       
   265 
       
   266     QTest::newRow("Use fn:doc")
       
   267         << 0
       
   268         << QByteArray("<e xmlns=\"http://example.com\" xmlns:p=\"http://example.com/P\" attr=\"1\" p:attr=\"\">\n    <?target data?>\n    <!-- a comment -->\n    <e/>text <f/>text node</e>\n")
       
   269         << QStringList(QLatin1String(SRCDIR "queries/openDocument.xq"))
       
   270         << QString()
       
   271         << QString();
       
   272 
       
   273     QTest::newRow("Use fn:doc, together with -no-format, last")
       
   274         << 0
       
   275         << QByteArray("<e xmlns=\"http://example.com\" xmlns:p=\"http://example.com/P\" attr=\"1\" p:attr=\"\"><?target data?><!-- a comment --><e/>text <f/>text node</e>")
       
   276         << (QStringList() << QLatin1String(SRCDIR "queries/openDocument.xq")
       
   277                           << QLatin1String("-no-format"))
       
   278         << QString()
       
   279         << QString();
       
   280 
       
   281     QTest::newRow("Use fn:doc, together with -no-format, first")
       
   282         << 0
       
   283         << QByteArray("<e xmlns=\"http://example.com\" xmlns:p=\"http://example.com/P\" attr=\"1\" p:attr=\"\"><?target data?><!-- a comment --><e/>text <f/>text node</e>")
       
   284         << (QStringList() << QLatin1String("-no-format")
       
   285                           << QLatin1String(SRCDIR "queries/openDocument.xq"))
       
   286         << QString()
       
   287         << QString();
       
   288 
       
   289     /* This is true for the command line utility, but not QXmlQuery::setQuery(). */
       
   290     QTest::newRow("Make sure query paths are resolved against CWD, not the location of the executable.")
       
   291         << 0
       
   292         << QByteArray("2\n")
       
   293         << QStringList(QLatin1String(SRCDIR "queries/onePlusOne.xq"))
       
   294         << QString::fromLatin1("queries")
       
   295         << QString();
       
   296 
       
   297     QTest::newRow("Call fn:error()")
       
   298         << 2
       
   299         << QByteArray()
       
   300         << QStringList(QLatin1String(SRCDIR "queries/errorFunction.xq"))
       
   301         << QString()
       
   302         << QString();
       
   303 
       
   304     QTest::newRow("Evaluate a library module")
       
   305         << 2
       
   306         << QByteArray()
       
   307         << QStringList(QLatin1String(SRCDIR "queries/simpleLibraryModule.xq"))
       
   308         << QString()
       
   309         << QString();
       
   310 
       
   311     QTest::newRow("Trigger a static error.")
       
   312         << 2
       
   313         << QByteArray()
       
   314         << QStringList(QLatin1String(SRCDIR "queries/staticError.xq"))
       
   315         << QString()
       
   316         << QString();
       
   317 
       
   318     QTest::newRow("Pass -help")
       
   319         << 0
       
   320         << QByteArray()
       
   321         << QStringList(QLatin1String("-help"))
       
   322         << QString()
       
   323         << QString();
       
   324 
       
   325     QTest::newRow("Open an nonexistent file")
       
   326         << 2
       
   327         << QByteArray()
       
   328         << QStringList(QLatin1String(SRCDIR "queries/ThisFileDoesNotExist.xq"))
       
   329         << QString()
       
   330         << QString();
       
   331 
       
   332     /* The following five tests exists to test the various
       
   333      * markup classes in the message. */
       
   334     QTest::newRow("XQuery-function message markups")
       
   335         << 2
       
   336         << QByteArray()
       
   337         << QStringList(QLatin1String(SRCDIR "queries/wrongArity.xq"))
       
   338         << QString()
       
   339         << QString();
       
   340 
       
   341     QTest::newRow("XQuery-type message markups")
       
   342         << 2
       
   343         << QByteArray()
       
   344         << QStringList(QLatin1String(SRCDIR "queries/typeError.xq"))
       
   345         << QString()
       
   346         << QString();
       
   347 
       
   348     QTest::newRow("XQuery-data & XQuery-keyword message markups")
       
   349         << 2
       
   350         << QByteArray()
       
   351         << QStringList(QLatin1String(SRCDIR "queries/zeroDivision.xq"))
       
   352         << QString()
       
   353         << QString();
       
   354 
       
   355     QTest::newRow("XQuery-uri message markups")
       
   356         << 2
       
   357         << QByteArray()
       
   358         << QStringList(QLatin1String(SRCDIR "queries/unsupportedCollation.xq"))
       
   359         << QString()
       
   360         << QString();
       
   361 
       
   362     QTest::newRow("XQuery-expression message markups")
       
   363         << 2
       
   364         << QByteArray()
       
   365         << QStringList(QLatin1String(SRCDIR "queries/invalidRegexp.xq"))
       
   366         << QString()
       
   367         << QString();
       
   368 
       
   369     QTest::newRow("Print a list of available regexp flags(The available flags are formatted in a complex way.)")
       
   370         << 2
       
   371         << QByteArray()
       
   372         << QStringList(QLatin1String(SRCDIR "queries/invalidRegexpFlag.xq"))
       
   373         << QString()
       
   374         << QString();
       
   375 
       
   376     QTest::newRow("Trigger an assert in QPatternist::ColorOutput. The query naturally contains an error; XPTY0004.")
       
   377         << 2
       
   378         << QByteArray()
       
   379         << QStringList(QLatin1String(SRCDIR "queries/flwor.xq"))
       
   380         << QString()
       
   381         << QString();
       
   382 
       
   383     QTest::newRow("Trigger a second assert in QPatternist::ColorOutput. The query naturally contains XPST0003.")
       
   384         << 2
       
   385         << QByteArray()
       
   386         << QStringList(QLatin1String(SRCDIR "queries/syntaxError.xq"))
       
   387         << QString()
       
   388         << QString();
       
   389 
       
   390     QTest::newRow("-param is missing so multiple queries appear")
       
   391         << 2
       
   392         << QByteArray()
       
   393         << (QStringList() << QLatin1String(SRCDIR "queries/reportGlobals.xq")
       
   394                           << QLatin1String("fileToOpen=globals.gccxml"))
       
   395         << QString()
       
   396         << QString();
       
   397 
       
   398     QTest::newRow("only -no-format")
       
   399         << 1
       
   400         << QByteArray()
       
   401         << (QStringList() << QLatin1String("-no-format"))
       
   402         << QString()
       
   403         << QString();
       
   404 
       
   405     QTest::newRow("Basic use of -output, query first")
       
   406         << 0
       
   407         << QByteArray("2\n")
       
   408         << (QStringList() << QLatin1String(SRCDIR "queries/onePlusOne.xq")
       
   409                           << QLatin1String("-output")
       
   410                           << QLatin1String("basicOutput.out"))
       
   411         << QString()
       
   412         << QString::fromLatin1("basicOutput.out");
       
   413 
       
   414     QTest::newRow("Basic use of -output, query last")
       
   415         << 0
       
   416         << QByteArray("<e/>\n")
       
   417         << (QStringList() << QLatin1String("-output")
       
   418                           << QLatin1String("basicOutput2.out")
       
   419                           << QLatin1String(SRCDIR "queries/oneElement.xq"))
       
   420         << QString()
       
   421         << QString::fromLatin1("basicOutput2.out");
       
   422 
       
   423     QTest::newRow("A single query, that does not exist")
       
   424         << 2
       
   425         << QByteArray()
       
   426         << (QStringList() << QLatin1String(SRCDIR "doesNotExist.xq"))
       
   427         << QString()
       
   428         << QString();
       
   429 
       
   430     QTest::newRow("Specify two identical query names")
       
   431         << 2
       
   432         << QByteArray()
       
   433         << (QStringList() << QLatin1String(SRCDIR "query.xq")
       
   434                           << QLatin1String(SRCDIR "query.xq"))
       
   435         << QString()
       
   436         << QString();
       
   437 
       
   438     QTest::newRow("Specify no arguments at all.")
       
   439         << 1
       
   440         << QByteArray()
       
   441         << QStringList()
       
   442         << QString()
       
   443         << QString();
       
   444 
       
   445     QTest::newRow("Use -output twice")
       
   446         << 1
       
   447         << QByteArray()
       
   448         << (QStringList() << QLatin1String("-output")
       
   449                           << QLatin1String("output1")
       
   450                           << QLatin1String("-output")
       
   451                           << QLatin1String("output2"))
       
   452         << QString()
       
   453         << QString();
       
   454 
       
   455     {
       
   456         const QString filename(QString::fromLatin1("notWritable.out"));
       
   457         createNonWritable(filename);
       
   458 
       
   459         QTest::newRow("-output with a non-writable file")
       
   460             << 1
       
   461             << QByteArray()
       
   462             << (QStringList() << QLatin1String("-output")
       
   463                               << filename
       
   464                               << QLatin1String(SRCDIR "queries/onePlusOne.xq"))
       
   465             << QString()
       
   466             << filename;
       
   467     }
       
   468 
       
   469     {
       
   470         const QString outName(QString::fromLatin1("existingContent.out"));
       
   471         QFile outFile(outName);
       
   472         QVERIFY(outFile.open(QIODevice::WriteOnly));
       
   473         QCOMPARE(outFile.write("Existing content\n"), qint64(17));
       
   474         outFile.close();
       
   475 
       
   476         QTest::newRow("Use -output on a file with existing content, to ensure we truncate, not append the content we produce.")
       
   477             << 0
       
   478             << QByteArray("2\n")
       
   479             << (QStringList() << QLatin1String("-output")
       
   480                               << outName
       
   481                               << QLatin1String(SRCDIR "queries/onePlusOne.xq"))
       
   482             << QString()
       
   483             << outName;
       
   484     }
       
   485 
       
   486     QTest::newRow("one query, and a terminating dash at the end")
       
   487         << 0
       
   488         << QByteArray("2\n")
       
   489         << (QStringList() << QLatin1String(SRCDIR "queries/onePlusOne.xq")
       
   490                           << QLatin1String("-"))
       
   491         << QString()
       
   492         << QString();
       
   493 
       
   494     QTest::newRow("one query, with a preceding dash")
       
   495         << 0
       
   496         << QByteArray("2\n")
       
   497         << (QStringList() << QLatin1String("-")
       
   498                           << QLatin1String(SRCDIR "queries/onePlusOne.xq"))
       
   499         << QString()
       
   500         << QString();
       
   501 
       
   502     QTest::newRow("A single dash, that's invalid")
       
   503         << 1
       
   504         << QByteArray()
       
   505         << (QStringList() << QLatin1String("-"))
       
   506         << QString()
       
   507         << QString();
       
   508 
       
   509     QTest::newRow("Invoke -version")
       
   510         << 0
       
   511         << QByteArray()
       
   512         << (QStringList() << QLatin1String("-version"))
       
   513         << QString()
       
   514         << QString();
       
   515 
       
   516     QTest::newRow("Unknown switch; -unknown-switch")
       
   517         << 1
       
   518         << QByteArray()
       
   519         << (QStringList() << QLatin1String("-unknown-switch"))
       
   520         << QString()
       
   521         << QString();
       
   522 
       
   523     QTest::newRow("Unknown switch; -d")
       
   524         << 1
       
   525         << QByteArray()
       
   526         << (QStringList() << QLatin1String("-d"))
       
   527         << QString()
       
   528         << QString();
       
   529 
       
   530     QTest::newRow("Passing a single dash is insufficient")
       
   531         << 1
       
   532         << QByteArray()
       
   533         << (QStringList() << QLatin1String("-"))
       
   534         << QString()
       
   535         << QString();
       
   536 
       
   537     QTest::newRow("Passing two dashes, the last is interpreted as a file name")
       
   538         << 2
       
   539         << QByteArray()
       
   540         << (QStringList() << QLatin1String("-")
       
   541                           << QLatin1String("-"))
       
   542         << QString()
       
   543         << QString();
       
   544 
       
   545     QTest::newRow("Pass three dashes, the two last gets interpreted as two query arguments")
       
   546         << 2
       
   547         << QByteArray()
       
   548         << (QStringList() << QLatin1String("-")
       
   549                           << QLatin1String("-")
       
   550                           << QLatin1String("-"))
       
   551         << QString()
       
   552         << QString();
       
   553 
       
   554     QTest::newRow("Load query via data: scheme")
       
   555         << 0
       
   556         << QByteArray("<e/>\n")
       
   557         << (QStringList() << QLatin1String("-is-uri") << QLatin1String("data:application/xml,%3Ce%2F%3E"))
       
   558         << QString()
       
   559         << QString();
       
   560 
       
   561     QTest::newRow("Load query via FTP")
       
   562         << 0
       
   563         << QByteArray("This was received via FTP\n")
       
   564         << (QStringList() << QLatin1String("-is-uri") << QString("ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/viaFtp.xq"))
       
   565         << QString()
       
   566         << QString();
       
   567 
       
   568     QTest::newRow("Load query via HTTP")
       
   569         << 0
       
   570         << QByteArray("This was received via HTTP.\n")
       
   571         << (QStringList() << QLatin1String("-is-uri") << QString("http://" + QtNetworkSettings::serverName() + "/qxmlquery/viaHttp.xq"))
       
   572         << QString()
       
   573         << QString();
       
   574 
       
   575     QTest::newRow("We don't support -format any longer")
       
   576         << 1
       
   577         << QByteArray()
       
   578         << (QStringList() << QLatin1String("-format"))
       
   579         << QString()
       
   580         << QString();
       
   581 
       
   582     QTest::newRow("Run a query which evaluates to the empty sequence.")
       
   583         << 0
       
   584         << QByteArray("\n")
       
   585         << (QStringList() << QLatin1String(SRCDIR "queries/emptySequence.xq"))
       
   586         << QString()
       
   587         << QString();
       
   588 
       
   589     QTest::newRow("Run a query which evaluates to a single document node with no children.")
       
   590         << 0
       
   591         << QByteArray("\n")
       
   592         << (QStringList() << QLatin1String(SRCDIR "queries/onlyDocumentNode.xq"))
       
   593         << QString()
       
   594         << QString();
       
   595 
       
   596     QTest::newRow("Invoke with invalid -param value.")
       
   597         << 1
       
   598         << QByteArray()
       
   599         << (QStringList() << QLatin1String(SRCDIR "queries/externalVariable.xq")
       
   600                           << QLatin1String("-param")
       
   601                           << QLatin1String("EqualSignIsMissing"))
       
   602         << QString()
       
   603         << QString();
       
   604 
       
   605     QTest::newRow("Invoke with colon in variable name.")
       
   606         << 1
       
   607         << QByteArray()
       
   608         << (QStringList() << QLatin1String(SRCDIR "queries/externalVariable.xq")
       
   609                           << QLatin1String("-param")
       
   610                           << QLatin1String("xs:name=value"))
       
   611         << QString()
       
   612         << QString();
       
   613 
       
   614     QTest::newRow("Invoke with missing name in -param arg.")
       
   615         << 1
       
   616         << QByteArray()
       
   617         << (QStringList() << QLatin1String(SRCDIR "queries/externalVariable.xq")
       
   618                           << QLatin1String("-param")
       
   619                           << QLatin1String("=value"))
       
   620         << QString()
       
   621         << QString();
       
   622 
       
   623     QTest::newRow("Invoke with -param that has two adjacent equal signs.")
       
   624         << 0
       
   625         << QByteArray("START =text END\n")
       
   626         << (QStringList() << QLatin1String(SRCDIR "queries/externalStringVariable.xq")
       
   627                           << QLatin1String("-param")
       
   628                           << QLatin1String("externalString==text"))
       
   629         << QString()
       
   630         << QString();
       
   631 
       
   632     QTest::newRow("Pass in an external variable, but the query doesn't use it.")
       
   633         << 0
       
   634         << QByteArray("2\n")
       
   635         << (QStringList() << QLatin1String(SRCDIR "queries/onePlusOne.xq")
       
   636                           << QLatin1String("-param")
       
   637                           << QLatin1String("externalString==text"))
       
   638         << QString()
       
   639         << QString();
       
   640 
       
   641     /* This is how an empty string would have been passed in. */
       
   642     QTest::newRow("Invoke with -param that has no value.")
       
   643         << 0
       
   644         << QByteArray("START  END\n")
       
   645         << (QStringList() << QLatin1String(SRCDIR "queries/externalStringVariable.xq")
       
   646                           << QLatin1String("-param")
       
   647                           << QLatin1String("externalString="))
       
   648         << QString()
       
   649         << QString();
       
   650 
       
   651     QTest::newRow("Ensure -is-uri can appear after the query filename")
       
   652         << 0
       
   653         << QByteArray("<e/>\n")
       
   654         << (QStringList() << QLatin1String("data:application/xml,%3Ce%2F%3E") << QLatin1String("-is-uri"))
       
   655         << QString()
       
   656         << QString();
       
   657 
       
   658     QTest::newRow("Use a native path")
       
   659         << 0
       
   660         << QByteArray("2\n")
       
   661         << (QStringList() << QDir::toNativeSeparators(QLatin1String(SRCDIR "queries/onePlusOne.xq")))
       
   662         << QString()
       
   663         << QString();
       
   664 
       
   665     QTest::newRow("Pass in invalid URI")
       
   666         << 2
       
   667         << QByteArray()
       
   668         << (QStringList() << QLatin1String("-is-uri") << QLatin1String("data:application/xml;base64,PGUvg==="))
       
   669         << QString()
       
   670         << QString();
       
   671 
       
   672     /* Not relevant anymore.
       
   673     QTest::newRow("A valid, existing query, followed by a bogus one")
       
   674         << 1
       
   675         << QByteArray()
       
   676         << (QStringList() << QLatin1String(SRCDIR "queries/onePlusOne.xq")
       
   677                           << QLatin1String(SRCDIR "doesNotExist.xq"))
       
   678         << QString()
       
   679         << QString();
       
   680         */
       
   681 
       
   682     /* Not relevant anymore.
       
   683     QTest::newRow("Specify two different query names")
       
   684         << 1
       
   685         << QByteArray()
       
   686         << (QStringList() << QLatin1String(SRCDIR "query1.xq")
       
   687                           << QLatin1String(SRCDIR "query2.xq"))
       
   688         << QString()
       
   689         << QString();
       
   690         */
       
   691 
       
   692     // TODO use focus with xquery
       
   693     // TODO fail to load focus with xquery
       
   694     // TODO focus with URI with xquery
       
   695     // TODO focus via FTP or so with xquery
       
   696 
       
   697 
       
   698     QTest::newRow("Use -param twice")
       
   699         << 0
       
   700         << QByteArray("param1 param2\n")
       
   701         << (QStringList() << QLatin1String(SRCDIR "queries/twoVariables.xq")
       
   702                           << QLatin1String("-param")
       
   703                           << QLatin1String("var1=param1")
       
   704                           << QLatin1String("-param")
       
   705                           << QLatin1String("var2=param2"))
       
   706         << QString()
       
   707         << QString();
       
   708 
       
   709     QTest::newRow("Use -param thrice")
       
   710         << 0
       
   711         << QByteArray("param1 param2 third\n")
       
   712         << (QStringList() << QLatin1String(SRCDIR "queries/threeVariables.xq")
       
   713                           << QLatin1String("-param")
       
   714                           << QLatin1String("var1=param1")
       
   715                           << QLatin1String("-param")
       
   716                           << QLatin1String("var2=param2")
       
   717                           << QLatin1String("-param")
       
   718                           << QLatin1String("var3=third"))
       
   719         << QString()
       
   720         << QString();
       
   721 
       
   722     QTest::newRow("Specify the same parameter twice, different values")
       
   723         << 1
       
   724         << QByteArray()
       
   725         << (QStringList() << QLatin1String(SRCDIR "queries/onePlusOne.xq")
       
   726                           << QLatin1String("-param")
       
   727                           << QLatin1String("duplicated=param1")
       
   728                           << QLatin1String("-param")
       
   729                           << QLatin1String("duplicated=param2"))
       
   730         << QString()
       
   731         << QString();
       
   732 
       
   733     QTest::newRow("Specify the same parameter twice, same values")
       
   734         << 1
       
   735         << QByteArray()
       
   736         << (QStringList() << QLatin1String(SRCDIR "queries/onePlusOne.xq")
       
   737                           << QLatin1String("-param")
       
   738                           << QLatin1String("duplicated=param1")
       
   739                           << QLatin1String("-param")
       
   740                           << QLatin1String("duplicated=param2"))
       
   741         << QString()
       
   742         << QString();
       
   743 
       
   744     QTest::newRow("Open a non-existing collection.")
       
   745         << 2
       
   746         << QByteArray()
       
   747         << (QStringList() << QLatin1String(SRCDIR "queries/nonexistingCollection.xq"))
       
   748         << QString()
       
   749         << QString();
       
   750 
       
   751     // TODO https?
       
   752     // TODO pass external variables that allows space around the equal sign.
       
   753     // TODO run fn:trace()
       
   754     // TODO Trigger warning
       
   755     // TODO what can we do with queries/nodeSequence.xq?
       
   756     // TODO trigger serialization error
       
   757     // TODO "xmlpatterns e.xq x" gives "binding must equal .."
       
   758     //
       
   759     // TODO use stdout where it's connected to a non-writable file.
       
   760     // TODO specify -format twice, or whatever it's called.
       
   761     // TODO query name that starts with "-".
       
   762     //
       
   763     // TODO Consider what we should do with paths on windows. Stuff like path\filename.xml fails.
       
   764     // TODO use invalid URI in query name, xmlpatterns -is-uri 'as1/#(¤/¤)("#'
       
   765 
       
   766     // TODO add xmlpatterns file1 file2 file3
       
   767     // TODO add xmlpatterns -is-uri file1 file2 file3
       
   768 }
       
   769 
       
   770 void tst_XmlPatterns::createNonWritable(const QString &name)
       
   771 {
       
   772     /* Create an existing, empty, non-writable file. */
       
   773     QFile outFile(name);
       
   774     QVERIFY(outFile.open(QIODevice::ReadWrite));
       
   775     outFile.write(QByteArray("1"));
       
   776     QVERIFY(outFile.resize(0));
       
   777     outFile.close();
       
   778     QVERIFY(outFile.setPermissions(QFile::Permissions(QFile::ReadOwner)));
       
   779 }
       
   780 
       
   781 void tst_XmlPatterns::removeNonWritable(QFile &outFile)
       
   782 {
       
   783     /* Kill off temporary files. */
       
   784     if(!outFile.remove())
       
   785     {
       
   786         /* Since one file is used for testing that we can handle non-writable file by
       
   787          * changing the permissions, we need to revert it such that we can remove it. */
       
   788         outFile.setPermissions(QFile::WriteOwner);
       
   789         outFile.remove();
       
   790     }
       
   791 }
       
   792 
       
   793 /*!
       
   794  Check that we gracefully handle writing out to stdout
       
   795  when the latter is not writable.
       
   796  */
       
   797 void tst_XmlPatterns::stdoutFailure() const
       
   798 {
       
   799     return; // TODO It's really hard to write testing code for this.
       
   800 
       
   801     const QString outName(QLatin1String("stdoutFailure.out"));
       
   802     createNonWritable(outName);
       
   803 
       
   804     QProcess process;
       
   805     // If we enable this line, waitForFinished() fails.
       
   806     //process.setStandardOutputFile(outName);
       
   807 
       
   808     process.setWorkingDirectory(QDir::current().absoluteFilePath(QString()));
       
   809     process.start(m_command, QStringList(SRCDIR "queries/onePlusOne.xq"));
       
   810 
       
   811     QCOMPARE(process.exitStatus(), QProcess::NormalExit);
       
   812     QVERIFY(process.waitForFinished());
       
   813 
       
   814     QFile outFile(outName);
       
   815     QVERIFY(outFile.open(QIODevice::ReadOnly));
       
   816     QCOMPARE(outFile.readAll(), QByteArray());
       
   817 
       
   818     QCOMPARE(process.exitCode(), 1);
       
   819 
       
   820     removeNonWritable(outFile);
       
   821 }
       
   822 
       
   823 void tst_XmlPatterns::cleanupTestCase() const
       
   824 {
       
   825     /* Remove temporaries that we create. */
       
   826     QStringList files;
       
   827     files << QLatin1String("existingContent.out")
       
   828           << QLatin1String("notWritable.out")
       
   829           << QLatin1String("output1");
       
   830 
       
   831     for(int i = 0; i < files.count(); ++i)
       
   832     {
       
   833         QFile file(files.at(i));
       
   834         removeNonWritable(file);
       
   835     }
       
   836 
       
   837     QCOMPARE(m_generatedTests, 0);
       
   838 }
       
   839 
       
   840 void tst_XmlPatterns::xsltSupport()
       
   841 {
       
   842     xquerySupport();
       
   843 }
       
   844 
       
   845 void tst_XmlPatterns::xsltSupport_data() const
       
   846 {
       
   847     if(m_dontRun)
       
   848         QSKIP("The command line utility is not in the path.", SkipAll);
       
   849 
       
   850 #ifdef Q_OS_WINCE
       
   851     QSKIP("WinCE: This test uses unsupported WinCE functionality", SkipAll);
       
   852 #endif
       
   853 
       
   854     QTest::addColumn<int>("expectedExitCode");
       
   855     QTest::addColumn<QByteArray>("expectedQueryOutput");
       
   856     QTest::addColumn<QStringList>("arguments");
       
   857     QTest::addColumn<QString>("cwd");
       
   858     QTest::addColumn<QString>("outputFile");
       
   859 
       
   860     QTest::newRow("Evaluate a stylesheet, with no context document")
       
   861         << 1
       
   862         << QByteArray()
       
   863         << (QStringList() << QLatin1String("stylesheets/onlyRootTemplate.xsl"))
       
   864         << QString()
       
   865         << QString();
       
   866 
       
   867     QTest::newRow("Pass in a stylesheet file which contains an XQuery query")
       
   868         << 2
       
   869         << QByteArray()
       
   870         << (QStringList() << QLatin1String(SRCDIR "stylesheets/queryAsStylesheet.xsl")
       
   871                           << QLatin1String(SRCDIR "queries/simpleDocument.xml"))
       
   872         << QString()
       
   873         << QString();
       
   874 
       
   875     QTest::newRow("Pass in a stylesheet file and a focus file which doesn't exist")
       
   876         << 2
       
   877         << QByteArray()
       
   878         << (QStringList() << QLatin1String("stylesheets/onlyRootTemplate.xsl")
       
   879                           << QLatin1String("doesNotExist.Nope.xml"))
       
   880         << QString()
       
   881         << QString();
       
   882 
       
   883     QTest::newRow("-initial-template doesn't work with XQueries.")
       
   884         << 1
       
   885         << QByteArray()
       
   886         << (QStringList() << QLatin1String("-initial-template")
       
   887                           << QLatin1String("name")
       
   888                           << QLatin1String(SRCDIR "queries/onePlusOne.xq"))
       
   889         << QString()
       
   890         << QString();
       
   891 
       
   892     QTest::newRow("-initial-template must be followed by a value")
       
   893         << 1
       
   894         << QByteArray()
       
   895         << (QStringList() << QLatin1String("-initial-template")
       
   896                           << QLatin1String("stylesheets/onlyRootTemplate.xsl"))
       
   897         << QString()
       
   898         << QString();
       
   899 
       
   900     QTest::newRow("-initial-template must be followed by a value(#2)")
       
   901         << 1
       
   902         << QByteArray()
       
   903         << (QStringList() << QLatin1String("stylesheets/onlyRootTemplate.xsl")
       
   904                           << QLatin1String("-initial-template"))
       
   905         << QString()
       
   906         << QString();
       
   907 
       
   908     QTest::newRow("Invalid template name")
       
   909         << 1
       
   910         << QByteArray()
       
   911         << (QStringList() << QLatin1String("-initial-template")
       
   912                           << QLatin1String("abc:def")
       
   913                           << QLatin1String("stylesheets/onlyRootTemplate.xsl"))
       
   914         << QString()
       
   915         << QString();
       
   916 
       
   917     QTest::newRow("Specify a named template, that exists")
       
   918         << 0
       
   919         << QByteArray("named-template")
       
   920         << (QStringList() << QLatin1String("-no-format")
       
   921                           << QLatin1String("-initial-template")
       
   922                           << QLatin1String("main")
       
   923                           << QLatin1String(SRCDIR "stylesheets/namedAndRootTemplate.xsl")
       
   924                           << QLatin1String(SRCDIR "stylesheets/documentElement.xml"))
       
   925         << QString()
       
   926         << QString();
       
   927 
       
   928     QTest::newRow("Specify a named template, that does not exists")
       
   929         << 0
       
   930         << QByteArray("root-template")
       
   931         << (QStringList() << QLatin1String("-no-format")
       
   932                           << QLatin1String("-initial-template")
       
   933                           << QLatin1String("no-template-by-this-name")
       
   934                           << QLatin1String(SRCDIR "stylesheets/namedAndRootTemplate.xsl")
       
   935                           << QLatin1String(SRCDIR "stylesheets/documentElement.xml"))
       
   936         << QString()
       
   937         << QString();
       
   938 
       
   939     QTest::newRow("Call a named template, and use no focus.")
       
   940         << 0
       
   941         << QByteArray("named-template")
       
   942         << (QStringList() << QLatin1String("-no-format")
       
   943                           << QLatin1String("-initial-template")
       
   944                           << QLatin1String("main")
       
   945                           << QLatin1String(SRCDIR "stylesheets/namedAndRootTemplate.xsl"))
       
   946         << QString()
       
   947         << QString();
       
   948 
       
   949     QTest::newRow("Call a named template, and use no focus.")
       
   950         << 0
       
   951         << QByteArray("namespaced-template")
       
   952         << (QStringList() << QLatin1String("-no-format")
       
   953                           << QLatin1String("-initial-template")
       
   954                           << QLatin1String("{http://example.com/NS}main")
       
   955                           << QLatin1String(SRCDIR "stylesheets/namedAndRootTemplate.xsl"))
       
   956         << QString()
       
   957         << QString();
       
   958 
       
   959     QTest::newRow("Invoke a template, and use/pass parameters.")
       
   960         << 0
       
   961         << QByteArray("defParam overridedDefaultedParam implicitlyRequiredValue\n")
       
   962         << (QStringList() << QLatin1String("-initial-template")
       
   963                           << QLatin1String("main")
       
   964                           << QLatin1String(SRCDIR "stylesheets/useParameters.xsl")
       
   965                           << QLatin1String("-param")
       
   966                           << QLatin1String("overridedDefaultedParam=overridedDefaultedParam")
       
   967                           << QLatin1String("-param")
       
   968                           << QLatin1String("implicitlyRequiredValue=implicitlyRequiredValue"))
       
   969         << QString()
       
   970         << QString();
       
   971 
       
   972     QTest::newRow("Use a simplified stylesheet module")
       
   973         << 0
       
   974         << QByteArray("<output>some text</output>\n")
       
   975         << (QStringList() << QLatin1String(SRCDIR "stylesheets/simplifiedStylesheetModule.xsl")
       
   976                           << QLatin1String(SRCDIR "stylesheets/simplifiedStylesheetModule.xml"))
       
   977         << QString()
       
   978         << QString();
       
   979 
       
   980     QTest::newRow("Not well-formed stylesheet, causes crash in coloring code.")
       
   981         << 2
       
   982         << QByteArray()
       
   983         << (QStringList() << QLatin1String(SRCDIR "stylesheets/notWellformed.xsl")
       
   984                           << QLatin1String(SRCDIR "queries/simpleDocument.xml"))
       
   985         << QString()
       
   986         << QString();
       
   987 
       
   988     QTest::newRow("Not well-formed instance document, causes crash in coloring code.")
       
   989         << 2
       
   990         << QByteArray()
       
   991         << (QStringList() << QLatin1String(SRCDIR "stylesheets/bool070.xsl")
       
   992                           << QLatin1String(SRCDIR "stylesheets/bool070.xml"))
       
   993         << QString()
       
   994         << QString();
       
   995 
       
   996     // TODO test -is-uris with context
       
   997     // TODO fail to load focus document when using XSL-T
       
   998     // TODO fail to load focus document when using XQuery
       
   999     // TODO focus via FTP or so with xquery
       
  1000     // TODO use URI in focus
       
  1001     // TODO use invalid URI in focus
       
  1002 
       
  1003     // TODO invoke a template which has required params.
       
  1004 }
       
  1005 
       
  1006 QTEST_MAIN(tst_XmlPatterns)
       
  1007 
       
  1008 #include "tst_xmlpatterns.moc"
       
  1009 #else
       
  1010 QTEST_NOOP_MAIN
       
  1011 #endif
       
  1012 
       
  1013 // vim: et:ts=4:sw=4:sts=4