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