Update licenseheader text in source files for qtxmlpatterns Qt module
[profile/ivi/qtxmlpatterns.git] / tests / auto / xmlpatterns / tst_xmlpatterns.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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
112 void tst_XmlPatterns::initTestCase()
113 {
114     QVERIFY(m_normalizeTestName.isValid());
115     QVERIFY(m_filenameInStderr.isValid());
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 partially 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