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