1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
43 #include <QtTest/QtTest>
45 #ifdef QTEST_XMLPATTERNS
47 #include <QAbstractMessageHandler>
49 #include <QNetworkReply>
50 #include <QtNetwork/QTcpServer>
51 #include <QtNetwork/QTcpSocket>
52 #include <QXmlFormatter>
56 #include <QXmlResultItems>
57 #include <QXmlSerializer>
59 #include "MessageSilencer.h"
60 #include "MessageValidator.h"
61 #include "NetworkOverrider.h"
62 #include "PushBaseliner.h"
63 #include "../qabstracturiresolver/TestURIResolver.h"
64 #include "../qsimplexmlnodemodel/TestSimpleNodeModel.h"
65 #include "TestFundament.h"
66 #include "../network-settings.h"
68 #if defined(Q_OS_SYMBIAN)
70 #define XMLPATTERNSDIR "xmlpatterns"
72 #define XMLPATTERNSDIR SRCDIR "../xmlpatterns"
79 \brief Tests class QXmlQuery.
81 This test is not intended for testing the engine, but the functionality specific
82 to the QXmlQuery class.
84 In other words, if you have an engine bug; don't add it here because it won't be
85 tested properly. Instead add it to the test suite.
88 class tst_QXmlQuery : public QObject
89 , private TestFundament
94 inline tst_QXmlQuery() : m_generatedBaselines(0)
102 void defaultConstructor() const;
103 void copyConstructor() const;
104 void constructorQXmlNamePool() const;
105 void constructorQXmlNamePoolQueryLanguage() const;
106 void constructorQXmlNamePoolWithinQSimpleXmlNodeModel() const;
107 void assignmentOperator() const;
108 void isValid() const;
109 void sequentialExecution() const;
110 void bindVariableQString() const;
111 void bindVariableQStringNoExternalDeclaration() const;
112 void bindVariableQXmlName() const;
113 void bindVariableQXmlNameTriggerWarnings() const;
114 void bindVariableQStringQIODevice() const;
115 void bindVariableQStringQIODeviceWithByteArray() const;
116 void bindVariableQStringQIODeviceWithString() const;
117 void bindVariableQStringQIODeviceWithQFile() const;
118 void bindVariableQXmlNameQIODevice() const;
119 void bindVariableQXmlNameQIODeviceTriggerWarnings() const;
120 void bindVariableXSLTSuccess() const;
121 void bindVariableTemporaryNode() const;
122 void setMessageHandler() const;
123 void messageHandler() const;
124 void evaluateToQAbstractXmlReceiverTriggerWarnings() const;
125 void evaluateToQXmlResultItems() const;
126 void evaluateToQXmlResultItemsTriggerWarnings() const;
127 void evaluateToQXmlResultItemsErrorAtEnd() const;
128 void evaluateToReceiver();
129 void evaluateToReceiver_data() const;
130 void evaluateToReceiverOnInvalidQuery() const;
131 void evaluateToQStringTriggerError() const;
132 void evaluateToQString() const;
133 void evaluateToQString_data() const;
134 void evaluateToQStringSignature() const;
135 void checkGeneratedBaselines() const;
136 void basicXQueryToQtTypeCheck() const;
137 void basicQtToXQueryTypeCheck() const;
138 void bindNode() const;
139 void relativeBaseURI() const;
140 void emptyBaseURI() const;
141 void roundTripDateWithinQXmlItem() const;
142 void bindingMissing() const;
143 void bindDefaultConstructedItem() const;
144 void bindDefaultConstructedItem_data() const;
145 void bindEmptyNullString() const;
146 void bindEmptyString() const;
147 void rebindVariableSameType() const;
148 void rebindVariableDifferentType() const;
149 void rebindVariableWithNullItem() const;
150 void eraseQXmlItemBinding() const;
151 void eraseDeviceBinding() const;
152 void constCorrectness() const;
153 void objectSize() const;
154 void setUriResolver() const;
155 void uriResolver() const;
156 void messageXML() const;
157 void resultItemsDeallocatedQuery() const;
158 void copyCheckMessageHandler() const;
159 void shadowedVariables() const;
160 void setFocusQXmlItem() const;
161 void setFocusQUrl() const;
162 void setFocusQIODevice() const;
163 void setFocusQIODeviceAvoidVariableClash() const;
164 void setFocusQIODeviceFailure() const;
165 void setFocusQIODeviceTriggerWarnings() const;
166 void setFocusQString() const;
167 void setFocusQStringFailure() const;
168 void setFocusQStringSignature() const;
169 void recompilationWithEvaluateToResultFailing() const;
170 void secondEvaluationWithEvaluateToResultFailing() const;
171 void recompilationWithEvaluateToReceiver() const;
172 void fnDocOnQIODeviceTimeout() const;
173 void evaluateToQStringListOnInvalidQuery() const;
174 void evaluateToQStringList() const;
175 void evaluateToQStringListTriggerWarnings() const;
176 void evaluateToQStringList_data() const;
177 void evaluateToQStringListNoConversion() const;
178 void evaluateToQIODevice() const;
179 void evaluateToQIODeviceTriggerWarnings() const;
180 void evaluateToQIODeviceSignature() const;
181 void evaluateToQIODeviceOnInvalidQuery() const;
182 void setQueryQIODeviceQUrl() const;
183 void setQueryQIODeviceQUrlTriggerWarnings() const;
184 void setQueryQString() const;
185 void setQueryQUrlSuccess() const;
186 void setQueryQUrlSuccess_data() const;
187 void setQueryQUrlFailSucceed() const;
188 void setQueryQUrlFailure() const;
189 void setQueryQUrlFailure_data() const;
190 void setQueryQUrlBaseURI() const;
191 void setQueryQUrlBaseURI_data() const;
192 void setQueryWithNonExistentQUrlOnValidQuery() const;
193 void setQueryWithInvalidQueryFromQUrlOnValidQuery() const;
194 void retrieveNameFromQuery() const;
195 void retrieveNameFromQuery_data() const;
196 void cleanupTestCase() const;
197 void declareUnavailableExternal() const;
198 void msvcCacheIssue() const;
199 void unavailableExternalVariable() const;
200 void useUriResolver() const;
201 void queryWithFocusAndVariable() const;
202 void undefinedFocus() const;
203 void basicFocusUsage() const;
205 void queryLanguage() const;
206 void queryLanguageSignature() const;
207 void enumQueryLanguage() const;
209 void setNetworkAccessManager() const;
210 void networkAccessManagerSignature() const;
211 void networkAccessManagerDefaultValue() const;
212 void networkAccessManager() const;
214 void setInitialTemplateNameQXmlName() const;
215 void setInitialTemplateNameQXmlNameSignature() const;
216 void setInitialTemplateNameQString() const;
217 void setInitialTemplateNameQStringSignature() const;
218 void initialTemplateName() const;
219 void initialTemplateNameSignature() const;
221 void fnDocNetworkAccessSuccess() const;
222 void fnDocNetworkAccessSuccess_data() const;
223 void fnDocNetworkAccessFailure() const;
224 void fnDocNetworkAccessFailure_data() const;
225 void multipleDocsAndFocus() const;
226 void multipleEvaluationsWithDifferentFocus() const;
227 void bindVariableQXmlQuery() const;
228 void bindVariableQXmlQuery_data() const;
229 void bindVariableQStringQXmlQuerySignature() const;
230 void bindVariableQXmlNameQXmlQuerySignature() const;
231 void bindVariableQXmlNameQXmlQuery() const;
232 void bindVariableQXmlQueryInvalidate() const;
233 void unknownSourceLocation() const;
235 void identityConstraintSuccess() const;
236 void identityConstraintFailure() const;
237 void identityConstraintFailure_data() const;
239 // TODO call all URI resolving functions where 1) the URI resolver return a null QUrl(); 2) resolves into valid, existing URI, 3) invalid, non-existing URI.
240 // TODO bind stringlists, variant lists, both ways.
241 // TODO trigger serialization error, or any error in evaluateToushCallback().
242 // TODO let items travle between two queries, as seen in the SDK
243 // TODO what happens if the query declares local variable and external ones are provided?
249 * One excluded, since we skip static-base-uri.xq.
251 ExpectedQueryCount = 29
254 static void checkBaseURI(const QUrl &baseURI, const QString &candidate);
255 static QStringList queries();
256 static const char *const queriesDirectory;
258 int m_generatedBaselines;
259 int m_pushTestsCount;
260 const bool m_testNetwork;
263 void tst_QXmlQuery::checkBaseURI(const QUrl &baseURI, const QString &candidate)
265 /* The use of QFileInfo::canonicalFilePath() takes into account that drive letters
266 * on Windows may have different cases. */
267 QVERIFY(QDir(baseURI.toLocalFile()).relativeFilePath(QFileInfo(candidate).canonicalFilePath()).startsWith("../"));
270 const char *const tst_QXmlQuery::queriesDirectory = XMLPATTERNSDIR "/queries/";
272 QStringList tst_QXmlQuery::queries()
275 dir.cd(inputFile(QLatin1String(queriesDirectory)));
277 return dir.entryList(QStringList(QLatin1String("*.xq")));
280 void tst_QXmlQuery::defaultConstructor() const
282 /* Allocate instance in different orders. */
299 void tst_QXmlQuery::copyConstructor() const
301 /* Verify that we can take a const reference, and simply do a copy of a default constructed object. */
303 const QXmlQuery query1;
304 QXmlQuery query2(query1);
309 const QXmlQuery query1;
310 QXmlQuery query2(query1);
311 QXmlQuery query3(query2);
314 /* Verify that copying default values works. */
316 const QXmlQuery query1;
317 const QXmlQuery query2(query1);
318 QCOMPARE(query2.messageHandler(), query1.messageHandler());
319 QCOMPARE(query2.uriResolver(), query1.uriResolver());
320 QCOMPARE(query2.queryLanguage(), query1.queryLanguage());
321 QCOMPARE(query2.initialTemplateName(), query1.initialTemplateName());
322 QCOMPARE(query2.networkAccessManager(), query1.networkAccessManager());
331 * - initial template name
333 * sticks with the copy. */
335 MessageSilencer silencer;
336 TestURIResolver resolver;
337 QNetworkAccessManager networkManager;
338 QXmlQuery query1(QXmlQuery::XSLT20);
339 QXmlNamePool np1(query1.namePool());
341 query1.setMessageHandler(&silencer);
342 query1.setUriResolver(&resolver);
343 query1.setNetworkAccessManager(&networkManager);
345 const QXmlName name(np1, QLatin1String("localName"),
346 QLatin1String("http://example.com/"),
347 QLatin1String("prefix"));
348 query1.setInitialTemplateName(name);
350 const QXmlQuery query2(query1);
351 QCOMPARE(query2.messageHandler(), static_cast<QAbstractMessageHandler *>(&silencer));
352 QCOMPARE(query2.uriResolver(), static_cast<const QAbstractUriResolver *>(&resolver));
353 QCOMPARE(query2.queryLanguage(), QXmlQuery::XSLT20);
354 QCOMPARE(query2.initialTemplateName(), name);
355 QCOMPARE(query2.networkAccessManager(), &networkManager);
357 QXmlNamePool np2(query2.namePool());
359 QCOMPARE(name.namespaceUri(np2), QString::fromLatin1("http://example.com/"));
360 QCOMPARE(name.localName(np2), QString::fromLatin1("localName"));
361 QCOMPARE(name.prefix(np2), QString::fromLatin1("prefix"));
367 original.setFocus(QXmlItem(4));
368 original.setQuery(QLatin1String("."));
369 QVERIFY(original.isValid());
371 const QXmlQuery copy(original);
373 QXmlResultItems result;
374 copy.evaluateTo(&result);
375 QCOMPARE(result.next().toAtomicValue(), QVariant(4));
376 QVERIFY(result.next().isNull());
377 QVERIFY(!result.hasError());
380 /* Copy, set, compare. Check that copies are independent. */
382 // TODO all members except queryLanguage().
386 void tst_QXmlQuery::constructorQXmlNamePool() const
388 /* Check that the namepool we are passed, is actually used. */
392 const QXmlName name(np, QLatin1String("localName"),
393 QLatin1String("http://example.com/"),
394 QLatin1String("prefix"));
396 QXmlNamePool np2(query.namePool());
397 QCOMPARE(name.namespaceUri(np2), QString::fromLatin1("http://example.com/"));
398 QCOMPARE(name.localName(np2), QString::fromLatin1("localName"));
399 QCOMPARE(name.prefix(np2), QString::fromLatin1("prefix"));
403 Ensure that the internal variable loading mechanisms uses the user-supplied
406 If that is not the case, different name pools are used and the code crashes.
410 void tst_QXmlQuery::constructorQXmlNamePoolQueryLanguage() const
413 QXmlName name(np, QLatin1String("arbitraryName"));
415 QXmlQuery query(QXmlQuery::XQuery10, np);
418 input.setData("<yall/>");
420 QVERIFY(input.open(QIODevice::ReadOnly));
421 query.bindVariable(name, &input);
422 query.setQuery("string(doc($arbitraryName))");
425 query.evaluateTo(&result);
428 void tst_QXmlQuery::constructorQXmlNamePoolWithinQSimpleXmlNodeModel() const
430 class TestCTOR : public TestSimpleNodeModel
433 TestCTOR(const QXmlNamePool &np) : TestSimpleNodeModel(np)
437 void checkCTOR() const
439 /* If this fails to compile, the constructor has trouble with taking
440 * a mutable reference.
442 * The reason we use the this pointer explicitly, is to avoid a compiler
443 * warnings with MSVC 2005. */
444 QXmlQuery(this->namePool());
453 void tst_QXmlQuery::assignmentOperator() const
455 class ReturnURI : public QAbstractUriResolver
459 virtual QUrl resolve(const QUrl &relative,
460 const QUrl &baseURI) const
462 return baseURI.resolved(relative);
466 /* Assign this to this. */
473 /* Just call a couple of functions to give valgrind
474 * something to check. */
475 QVERIFY(!query.isValid());
476 query.messageHandler();
479 /* Assign null instances a couple of times. */
487 /* Just call a couple of functions to give valgrind
488 * something to check. */
489 QVERIFY(!query1.isValid());
490 query1.messageHandler();
492 /* Just call a couple of functions to give valgrind
493 * something to check. */
494 QVERIFY(!query2.isValid());
495 query2.messageHandler();
498 /* Create a query, set all the things it stores, and ensure it
499 * travels over to the new instance. */
501 MessageSilencer silencer;
502 const ReturnURI returnURI;
503 QXmlNamePool namePool;
505 QBuffer documentDevice;
506 documentDevice.setData(QByteArray("<e>a</e>"));
507 QVERIFY(documentDevice.open(QIODevice::ReadOnly));
509 QXmlQuery original(namePool);
510 QXmlName testName(namePool, QLatin1String("somethingToCheck"));
512 original.setMessageHandler(&silencer);
513 original.bindVariable(QLatin1String("var"), QXmlItem(1));
514 original.bindVariable(QLatin1String("device"), &documentDevice);
515 original.setUriResolver(&returnURI);
516 original.setFocus(QXmlItem(3));
517 original.setQuery(QLatin1String("$var, 1 + 1, ., string(doc($device))"));
519 /* Do a copy, and check that everything followed on into the copy. No modification
524 /* We use assignment operator, not copy constructor. */
527 QVERIFY(copy.isValid());
528 QCOMPARE(copy.uriResolver(), static_cast<const QAbstractUriResolver *>(&returnURI));
529 QCOMPARE(copy.messageHandler(), static_cast<QAbstractMessageHandler *>(&silencer));
530 QCOMPARE(testName.localName(copy.namePool()), QString::fromLatin1("somethingToCheck"));
532 QXmlResultItems result;
533 copy.evaluateTo(&result);
534 QCOMPARE(result.next().toAtomicValue(), QVariant(1));
535 QCOMPARE(result.next().toAtomicValue(), QVariant(2));
536 QCOMPARE(result.next().toAtomicValue(), QVariant(3));
537 QCOMPARE(result.next().toAtomicValue(), QVariant(QString::fromLatin1("a")));
538 QVERIFY(result.next().isNull());
539 QVERIFY(!result.hasError());
542 /* Copy, and change values. Things should detach. */
544 /* Evaluate the copy. */
546 MessageSilencer secondSilencer;
547 const ReturnURI secondUriResolver;
548 QBuffer documentDeviceCopy;
549 documentDeviceCopy.setData(QByteArray("<e>b</e>"));
550 QVERIFY(documentDeviceCopy.open(QIODevice::ReadOnly));
555 copy.setMessageHandler(&secondSilencer);
556 /* Here we rebind variable values. */
557 copy.bindVariable(QLatin1String("var"), QXmlItem(4));
558 copy.bindVariable(QLatin1String("device"), &documentDeviceCopy);
559 copy.setUriResolver(&secondUriResolver);
560 copy.setFocus(QXmlItem(6));
561 copy.setQuery(QLatin1String("$var, 1 + 1, ., string(doc($device))"));
563 /* Check that the copy picked up the new things. */
564 QVERIFY(copy.isValid());
565 QCOMPARE(copy.uriResolver(), static_cast<const QAbstractUriResolver *>(&secondUriResolver));
566 QCOMPARE(copy.messageHandler(), static_cast<QAbstractMessageHandler *>(&secondSilencer));
568 QXmlResultItems resultCopy;
569 copy.evaluateTo(&resultCopy);
570 QCOMPARE(resultCopy.next().toAtomicValue(), QVariant(4));
571 QCOMPARE(resultCopy.next().toAtomicValue(), QVariant(2));
572 QCOMPARE(resultCopy.next().toAtomicValue(), QVariant(6));
573 const QString stringedDevice(resultCopy.next().toAtomicValue().toString());
574 QCOMPARE(stringedDevice, QString::fromLatin1("b"));
575 QVERIFY(resultCopy.next().isNull());
576 QVERIFY(!resultCopy.hasError());
579 /* Evaluate the original. */
581 /* Check that the original is unchanged. */
582 QVERIFY(original.isValid());
583 QCOMPARE(original.uriResolver(), static_cast<const QAbstractUriResolver *>(&returnURI));
584 QCOMPARE(original.messageHandler(), static_cast<QAbstractMessageHandler *>(&silencer));
586 QXmlResultItems resultOriginal;
587 original.evaluateTo(&resultOriginal);
588 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(1));
589 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(2));
590 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(3));
591 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(QString::fromLatin1("a")));
592 QVERIFY(resultOriginal.next().isNull());
593 QVERIFY(!resultOriginal.hasError());
600 Since QXmlQuery doesn't seek devices to position 0, this code triggers a bug
601 where document caching doesn't work. Since the document caching doesn't work,
602 the device will be read twice, and the second time the device is at the end,
603 hence premature end of document.
605 void tst_QXmlQuery::sequentialExecution() const
608 inBuffer.setData(QByteArray("<input/>"));
609 QVERIFY(inBuffer.open(QIODevice::ReadOnly));
612 query.bindVariable("inputDocument", &inBuffer);
615 QBuffer outBuffer(&outArray);
616 outBuffer.open(QIODevice::WriteOnly);
618 const QString queryString(QLatin1String("doc($inputDocument)"));
619 query.setQuery(queryString);
621 QXmlFormatter formatter(query, &outBuffer);
623 QVERIFY(query.evaluateTo(&formatter));
625 /* If this line is removed, the bug isn't triggered. */
626 query.setQuery(queryString);
628 QVERIFY(query.evaluateTo(&formatter));
631 void tst_QXmlQuery::isValid() const
633 /* Check default value. */
635 QVERIFY(!query.isValid());
638 void tst_QXmlQuery::bindVariableQString() const
642 /* Bind with a null QXmlItem. */
643 query.bindVariable(QLatin1String("name"), QXmlItem());
648 /* Bind with a null QVariant. */
649 query.bindVariable(QLatin1String("name"), QXmlItem(QVariant()));
654 /* Bind with a null QXmlNodeModelIndex. */
655 query.bindVariable(QLatin1String("name"), QXmlItem(QXmlNodeModelIndex()));
659 void tst_QXmlQuery::bindVariableQStringNoExternalDeclaration() const
662 query.bindVariable(QLatin1String("foo"), QXmlItem(QLatin1String("Variable Value")));
663 query.setQuery(QLatin1String("$foo"));
665 QVERIFY(query.isValid());
668 QVERIFY(query.evaluateTo(&result));
670 QCOMPARE(result, QStringList() << QLatin1String("Variable Value"));
673 void tst_QXmlQuery::bindVariableQXmlName() const
678 void tst_QXmlQuery::bindVariableQXmlNameTriggerWarnings() const
682 QTest::ignoreMessage(QtWarningMsg, "The variable name cannot be null.");
683 query.bindVariable(QXmlName(), QVariant());
686 void tst_QXmlQuery::bindVariableQStringQIODeviceWithByteArray() const
690 QByteArray in("<e/>");
692 QVERIFY(device.open(QIODevice::ReadOnly));
694 query.bindVariable("doc", &device);
696 query.setQuery(QLatin1String("declare variable $doc external; $doc"));
698 QVERIFY(query.isValid());
700 /* Check the URI corresponding to the variable. */
702 QXmlResultItems items;
703 query.evaluateTo(&items);
705 QCOMPARE(items.next().toAtomicValue().toString(), QString::fromLatin1("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:doc"));
708 /* Now, actually load the document. We use the same QXmlQuery just to stress recompilation a bit. */
710 query.setQuery(QLatin1String("declare variable $doc external; doc($doc)"));
713 QBuffer outBuffer(&out);
714 QVERIFY(outBuffer.open(QIODevice::WriteOnly));
716 QXmlSerializer serializer(query, &outBuffer);
718 QVERIFY(query.evaluateTo(&serializer));
723 void tst_QXmlQuery::bindVariableQStringQIODeviceWithString() const
727 QString in("<qstring/>");
728 QByteArray inUtf8(in.toUtf8());
729 QBuffer inDevice(&inUtf8);
731 QVERIFY(inDevice.open(QIODevice::ReadOnly));
733 query.bindVariable("doc", &inDevice);
735 query.setQuery(QLatin1String("declare variable $doc external; doc($doc)"));
738 QBuffer outBuffer(&out);
739 QVERIFY(outBuffer.open(QIODevice::WriteOnly));
741 QXmlSerializer serializer(query, &outBuffer);
742 QVERIFY(query.evaluateTo(&serializer));
744 QCOMPARE(out, inUtf8);
747 void tst_QXmlQuery::bindVariableQStringQIODeviceWithQFile() const
750 QFile inDevice(QLatin1String(SRCDIR "input.xml"));
752 QVERIFY(inDevice.open(QIODevice::ReadOnly));
754 query.bindVariable("doc", &inDevice);
756 query.setQuery(QLatin1String("declare variable $doc external; doc($doc)"));
759 QBuffer outBuffer(&out);
760 QVERIFY(outBuffer.open(QIODevice::WriteOnly));
762 QXmlSerializer serializer(query, &outBuffer);
763 QVERIFY(query.evaluateTo(&serializer));
766 QCOMPARE(out, QByteArray("<!-- This is just a file for testing. --><input/>"));
769 void tst_QXmlQuery::bindVariableQStringQIODevice() const
773 /* Rebind the variable. */
775 /* First evaluation. */
777 QByteArray in1("<e1/>");
778 QBuffer inDevice1(&in1);
779 QVERIFY(inDevice1.open(QIODevice::ReadOnly));
781 query.bindVariable("in", &inDevice1);
782 query.setQuery(QLatin1String("doc($in)"));
785 QBuffer outDevice1(&out1);
786 QVERIFY(outDevice1.open(QIODevice::WriteOnly));
788 QXmlSerializer serializer(query, &outDevice1);
789 query.evaluateTo(&serializer);
793 /* Second evaluation, rebind variable. */
795 QByteArray in2("<e2/>");
796 QBuffer inDevice2(&in2);
797 QVERIFY(inDevice2.open(QIODevice::ReadOnly));
799 query.bindVariable(QLatin1String("in"), &inDevice2);
802 QBuffer outDevice2(&out2);
803 QVERIFY(outDevice2.open(QIODevice::WriteOnly));
805 QXmlSerializer serializer(query, &outDevice2);
806 QVERIFY(query.evaluateTo(&serializer));
811 // TODO trigger recompilation when setting qiodevices., and qiodevice overwritten by other type, etc.
814 void tst_QXmlQuery::bindVariableQXmlNameQIODevice() const
819 void tst_QXmlQuery::bindVariableQXmlNameQIODeviceTriggerWarnings() const
825 QTest::ignoreMessage(QtWarningMsg, "A null, or readable QIODevice must be passed.");
826 query.bindVariable(QXmlName(np, QLatin1String("foo")), &buffer);
828 QTest::ignoreMessage(QtWarningMsg, "The variable name cannot be null.");
829 query.bindVariable(QXmlName(), 0);
832 void tst_QXmlQuery::bindVariableXSLTSuccess() const
834 QXmlQuery stylesheet(QXmlQuery::XSLT20);
835 stylesheet.setInitialTemplateName(QLatin1String("main"));
837 stylesheet.bindVariable(QLatin1String("variableNoSelectNoBodyBoundWithBindVariable"),
838 QVariant(QLatin1String("MUST NOT SHOW 1")));
840 stylesheet.bindVariable(QLatin1String("variableSelectBoundWithBindVariable"),
841 QVariant(QLatin1String("MUST NOT SHOW 2")));
843 stylesheet.bindVariable(QLatin1String("variableSelectWithTypeIntBoundWithBindVariable"),
844 QVariant(QLatin1String("MUST NOT SHOW 3")));
846 stylesheet.bindVariable(QLatin1String("paramNoSelectNoBodyBoundWithBindVariable"),
847 QVariant(QLatin1String("param1")));
849 stylesheet.bindVariable(QLatin1String("paramNoSelectNoBodyBoundWithBindVariableRequired"),
850 QVariant(QLatin1String("param1")));
852 stylesheet.bindVariable(QLatin1String("paramSelectBoundWithBindVariable"),
853 QVariant(QLatin1String("param2")));
855 stylesheet.bindVariable(QLatin1String("paramSelectBoundWithBindVariableRequired"),
856 QVariant(QLatin1String("param3")));
858 stylesheet.bindVariable(QLatin1String("paramSelectWithTypeIntBoundWithBindVariable"),
861 stylesheet.bindVariable(QLatin1String("paramSelectWithTypeIntBoundWithBindVariableRequired"),
862 QVariant(QLatin1String("param5")));
864 stylesheet.setQuery(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/parameters.xsl"))));
866 QVERIFY(stylesheet.isValid());
869 QVERIFY(deviceOut.open(QIODevice::ReadWrite));
871 QVERIFY(stylesheet.evaluateTo(&deviceOut));
873 const QString result(QString::fromUtf8(deviceOut.data().constData()));
876 QString::fromLatin1("Variables: variableSelectsDefaultValue variableSelectsDefaultValue2 3 4 "
877 "Parameters: param1 param1 param2 param3 4 param5"));
880 void tst_QXmlQuery::bindVariableTemporaryNode() const
882 /* First we do it with QXmlResultItems staying in scope. */;
885 query1.setQuery("<anElement/>");
887 QXmlResultItems result1;
888 query1.evaluateTo(&result1);
890 QXmlQuery query2(query1);
891 query2.bindVariable("fromQuery1", result1.next());
892 query2.setQuery("$fromQuery1");
895 QVERIFY(query2.evaluateTo(&output));
897 QCOMPARE(output, QString::fromLatin1("<anElement/>\n"));
900 /* And now with it deallocating, so its internal DynamicContext pointer is
901 * released. This doesn't work in Qt 4.5 and is ok. */
904 query1.setQuery("<anElement/>");
909 QXmlResultItems result1;
910 query1.evaluateTo(&result1);
912 query2.bindVariable("fromQuery1", result1.next());
913 query2.setQuery("$fromQuery1");
917 return; // See comment above.
918 QVERIFY(query2.evaluateTo(&output));
920 QCOMPARE(output, QString::fromLatin1("<anElement/>\n"));
924 void tst_QXmlQuery::messageHandler() const
927 /* Check default value. */
929 QCOMPARE(query.messageHandler(), static_cast<QAbstractMessageHandler *>(0));
933 void tst_QXmlQuery::setMessageHandler() const
936 MessageSilencer silencer;
937 query.setMessageHandler(&silencer);
938 QCOMPARE(static_cast<QAbstractMessageHandler *>(&silencer), query.messageHandler());
941 void tst_QXmlQuery::evaluateToReceiver()
943 QFETCH(QString, inputQuery);
945 /* This query prints a URI specific to the local system. */
946 if(inputQuery == QLatin1String("static-base-uri.xq"))
950 const QString queryURI(inputFile(QLatin1String(queriesDirectory) + inputQuery));
951 QFile queryFile(queryURI);
953 QVERIFY(queryFile.exists());
954 QVERIFY(queryFile.open(QIODevice::ReadOnly));
958 MessageSilencer receiver;
959 query.setMessageHandler(&receiver);
960 query.setQuery(&queryFile, QUrl::fromLocalFile(queryURI));
962 /* We read all the queries, and some of them are invalid. However, we
963 * only want those that compile. */
968 QTextStream stream(&produced, QIODevice::WriteOnly);
969 PushBaseliner push(stream, query.namePool());
970 QVERIFY(push.isValid());
971 query.evaluateTo(&push);
973 const QString baselineName(inputFile(QLatin1String(SRCDIR "pushBaselines/") + inputQuery.left(inputQuery.length() - 2) + QString::fromLatin1("ref")));
974 QFile baseline(baselineName);
976 if(baseline.exists())
978 QVERIFY(baseline.open(QIODevice::ReadOnly | QIODevice::Text));
979 const QString stringedBaseline(QString::fromUtf8(baseline.readAll()));
980 QCOMPARE(produced, stringedBaseline);
984 QVERIFY(baseline.open(QIODevice::WriteOnly));
985 /* This is intentionally a warning, don't remove it. Update the baselines instead. */
986 qWarning() << "Generated baseline for:" << baselineName;
987 ++m_generatedBaselines;
989 baseline.write(produced.toUtf8());
993 void tst_QXmlQuery::evaluateToReceiver_data() const
995 QTest::addColumn<QString>("inputQuery");
997 foreach (QString const& query, queries())
999 /* This outputs a URI specific to the environment, so we can't use it for this
1000 * particular test. */
1001 if (query != QLatin1String("staticBaseURI.xq"))
1002 QTest::newRow(query.toUtf8().constData()) << query;
1006 void tst_QXmlQuery::evaluateToReceiverOnInvalidQuery() const
1008 /* Invoke on a default constructed object. */
1011 QBuffer buffer(&out);
1012 buffer.open(QIODevice::WriteOnly);
1015 QXmlSerializer serializer(query, &buffer);
1016 QVERIFY(!query.evaluateTo(&serializer));
1019 /* Invoke on an invalid query; compile time error. */
1022 QBuffer buffer(&out);
1023 buffer.open(QIODevice::WriteOnly);
1024 MessageSilencer silencer;
1027 query.setMessageHandler(&silencer);
1028 query.setQuery(QLatin1String("1 + "));
1029 QXmlSerializer serializer(query, &buffer);
1030 QVERIFY(!query.evaluateTo(&serializer));
1033 /* Invoke on an invalid query; runtime error. */
1036 QBuffer buffer(&out);
1037 buffer.open(QIODevice::WriteOnly);
1038 MessageSilencer silencer;
1041 query.setMessageHandler(&silencer);
1042 query.setQuery(QLatin1String("error()"));
1043 QXmlSerializer serializer(query, &buffer);
1044 QVERIFY(!query.evaluateTo(&serializer));
1048 void tst_QXmlQuery::evaluateToQStringTriggerError() const
1050 /* Invoke on a default constructed object. */
1054 QVERIFY(!query.evaluateTo(&out));
1057 /* Invoke on an invalid query; compile time error. */
1060 MessageSilencer silencer;
1061 query.setMessageHandler(&silencer);
1063 query.setQuery(QLatin1String("1 + "));
1066 QVERIFY(!query.evaluateTo(&out));
1069 /* Invoke on an invalid query; runtime error. */
1072 MessageSilencer silencer;
1073 query.setMessageHandler(&silencer);
1075 query.setQuery(QLatin1String("error()"));
1078 QVERIFY(!query.evaluateTo(&out));
1082 void tst_QXmlQuery::evaluateToQString() const
1084 QFETCH(QString, query);
1085 QFETCH(QString, expectedOutput);
1087 QXmlQuery queryInstance;
1088 queryInstance.setQuery(query);
1089 QVERIFY(queryInstance.isValid());
1092 QVERIFY(queryInstance.evaluateTo(&result));
1094 QCOMPARE(result, expectedOutput);
1097 void tst_QXmlQuery::evaluateToQString_data() const
1099 QTest::addColumn<QString>("query");
1100 QTest::addColumn<QString>("expectedOutput");
1102 QTest::newRow("Two atomics")
1103 << QString::fromLatin1("1, 'two'")
1104 << QString::fromLatin1("1 two\n");
1106 QTest::newRow("An element")
1107 << QString::fromLatin1("<e>{1}</e>")
1108 << QString::fromLatin1("<e>1</e>\n");
1111 void tst_QXmlQuery::evaluateToQStringSignature() const
1113 const QXmlQuery query;
1117 /* evaluateTo(QString *) should be a const function. */
1118 query.evaluateTo(&output);
1121 void tst_QXmlQuery::evaluateToQAbstractXmlReceiverTriggerWarnings() const
1125 /* We check the return value as well as warning message here. */
1126 QTest::ignoreMessage(QtWarningMsg, "A non-null callback must be passed.");
1127 QCOMPARE(query.evaluateTo(static_cast<QAbstractXmlReceiver *>(0)),
1131 void tst_QXmlQuery::evaluateToQXmlResultItems() const
1133 /* Invoke on a default constructed object. */
1136 QXmlResultItems result;
1137 query.evaluateTo(&result);
1138 QVERIFY(result.next().isNull());
1142 void tst_QXmlQuery::evaluateToQXmlResultItemsTriggerWarnings() const
1144 QTest::ignoreMessage(QtWarningMsg, "A null pointer cannot be passed.");
1146 query.evaluateTo(static_cast<QXmlResultItems *>(0));
1149 void tst_QXmlQuery::evaluateToQXmlResultItemsErrorAtEnd() const
1152 MessageSilencer silencer;
1153 query.setMessageHandler(&silencer);
1154 query.setQuery(QLatin1String("1 to 100, fn:error()"));
1155 QVERIFY(query.isValid());
1158 query.evaluateTo(&it);
1160 while(!it.next().isNull())
1166 If baselines were generated, we flag it as a failure such that it gets
1167 attention, and that they are adjusted accordingly.
1169 void tst_QXmlQuery::checkGeneratedBaselines() const
1171 QCOMPARE(m_generatedBaselines, 0);
1173 /* If this check fails, the auto test setup is misconfigured, or files have
1174 * been added/removed without this number being updated. */
1175 QCOMPARE(m_pushTestsCount, int(ExpectedQueryCount));
1178 void tst_QXmlQuery::basicXQueryToQtTypeCheck() const
1180 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("allAtomics.xq"));
1181 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1184 query.setQuery(&queryFile);
1185 QVERIFY(query.isValid());
1188 query.evaluateTo(&it);
1190 QVariantList expectedValues;
1191 expectedValues.append(QString::fromLatin1("xs:untypedAtomic"));
1192 expectedValues.append(QDateTime(QDate(2002, 10, 10), QTime(23, 2, 11), Qt::UTC));
1193 expectedValues.append(QDate(2002, 10, 10));
1194 expectedValues.append(QVariant()); /* We currently doesn't support xs:time through the API. */
1196 expectedValues.append(QVariant()); /* xs:duration */
1197 expectedValues.append(QVariant()); /* xs:dayTimeDuration */
1198 expectedValues.append(QVariant()); /* xs:yearMonthDuration */
1200 if(sizeof(qreal) == sizeof(float)) {//ARM casts to Float not to double
1201 expectedValues.append(QVariant(float(3e3))); /* xs:float */
1202 expectedValues.append(QVariant(float(4e4))); /* xs:double */
1203 expectedValues.append(QVariant(float(2))); /* xs:decimal */
1205 expectedValues.append(QVariant(double(3e3))); /* xs:float */
1206 expectedValues.append(QVariant(double(4e4))); /* xs:double */
1207 expectedValues.append(QVariant(double(2))); /* xs:decimal */
1210 /* xs:integer and its sub-types. */
1211 expectedValues.append(QVariant(qlonglong(16)));
1212 expectedValues.append(QVariant(qlonglong(-6)));
1213 expectedValues.append(QVariant(qlonglong(-4)));
1214 expectedValues.append(QVariant(qlonglong(5)));
1215 expectedValues.append(QVariant(qlonglong(6)));
1216 expectedValues.append(QVariant(qlonglong(7)));
1217 expectedValues.append(QVariant(qlonglong(8)));
1218 expectedValues.append(QVariant(qlonglong(9)));
1219 expectedValues.append(QVariant(qulonglong(10)));
1220 expectedValues.append(QVariant(qlonglong(11)));
1221 expectedValues.append(QVariant(qlonglong(12)));
1222 expectedValues.append(QVariant(qlonglong(13)));
1223 expectedValues.append(QVariant(qlonglong(14)));
1225 expectedValues.append(QVariant()); /* xs:gYearMonth("1976-02"), */
1226 expectedValues.append(QVariant()); /* xs:gYear("2005-12:00"), */
1227 expectedValues.append(QVariant()); /* xs:gMonthDay("--12-25-14:00"), */
1228 expectedValues.append(QVariant()); /* xs:gDay("---25-14:00"), */
1229 expectedValues.append(QVariant()); /* xs:gMonth("--12-14:00"), */
1230 expectedValues.append(true); /* xs:boolean("true"), */
1231 expectedValues.append(QVariant(QByteArray::fromBase64(QByteArray("aaaa")))); /* xs:base64Binary("aaaa"), */
1232 expectedValues.append(QVariant(QByteArray::fromHex(QByteArray("FFFF")))); /* xs:hexBinary("FFFF"), */
1233 expectedValues.append(QVariant(QString::fromLatin1("http://example.com/"))); /* xs:anyURI("http://example.com/"), */
1234 QXmlNamePool np(query.namePool());
1235 expectedValues.append(QVariant(qVariantFromValue(QXmlName(np, QLatin1String("localName"),
1236 QLatin1String("http://example.com/2"),
1237 QLatin1String("prefix")))));
1239 expectedValues.append(QVariant(QString::fromLatin1("An xs:string")));
1240 expectedValues.append(QVariant(QString::fromLatin1("normalizedString")));
1241 expectedValues.append(QVariant(QString::fromLatin1("token")));
1242 expectedValues.append(QVariant(QString::fromLatin1("language")));
1243 expectedValues.append(QVariant(QString::fromLatin1("NMTOKEN")));
1244 expectedValues.append(QVariant(QString::fromLatin1("Name")));
1245 expectedValues.append(QVariant(QString::fromLatin1("NCName")));
1246 expectedValues.append(QVariant(QString::fromLatin1("ID")));
1247 expectedValues.append(QVariant(QString::fromLatin1("IDREF")));
1248 expectedValues.append(QVariant(QString::fromLatin1("ENTITY")));
1251 QXmlItem item(it.next());
1253 while(!item.isNull())
1255 QVERIFY(item.isAtomicValue());
1256 const QVariant produced(item.toAtomicValue());
1258 const QVariant &expected = expectedValues.at(i);
1260 /* For the cases where we can't represent a value in the XDM with Qt,
1261 * we return an invalid QVariant. */
1262 QCOMPARE(expected.isValid(), produced.isValid());
1264 QCOMPARE(produced.type(), expected.type());
1266 if(expected.isValid())
1268 /* This is only needed for xs:decimal though, for some reason. Probably
1269 * just artifacts created somewhere. */
1270 if(produced.type() == QVariant::Double)
1271 QVERIFY(qFuzzyCompare(produced.toDouble(), expected.toDouble()));
1272 else if(qVariantCanConvert<QXmlName>(produced))
1274 /* QVariant::operator==() does identity comparison, it doesn't delegate to operator==() of
1275 * the contained type, unless it's hardcoded into QVariant. */
1276 const QXmlName n1 = qVariantValue<QXmlName>(produced);
1277 const QXmlName n2 = qVariantValue<QXmlName>(expected);
1281 QCOMPARE(produced, expected);
1288 QCOMPARE(i, expectedValues.count());
1292 Send values from Qt into XQuery.
1294 void tst_QXmlQuery::basicQtToXQueryTypeCheck() const
1296 QFile queryFile(QLatin1String(queriesDirectory) + QLatin1String("allAtomicsExternally.xq"));
1297 QVERIFY(queryFile.exists());
1298 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1300 QCOMPARE(QVariant(QDate(1999, 9, 10)).type(), QVariant::Date);
1304 QXmlNamePool np(query.namePool());
1306 const QXmlName name(np, QLatin1String("localname"),
1307 QLatin1String("http://example.com"),
1308 QLatin1String("prefix"));
1310 query.bindVariable(QLatin1String("fromQUrl"), QXmlItem(QUrl(QString::fromLatin1("http://example.com/"))));
1311 query.bindVariable(QLatin1String("fromQByteArray"), QXmlItem(QByteArray("AAAA")));
1312 query.bindVariable(QLatin1String("fromBool"), QXmlItem(bool(true)));
1313 query.bindVariable(QLatin1String("fromQDate"), QXmlItem(QDate(2000, 10, 11)));
1314 // TODO Do with different QDateTime time specs
1315 query.bindVariable(QLatin1String("fromQDateTime"), QXmlItem(QDateTime(QDate(2001, 9, 10), QTime(1, 2, 3))));
1316 query.bindVariable(QLatin1String("fromDouble"), QXmlItem(double(3)));
1317 query.bindVariable(QLatin1String("fromFloat"), QXmlItem(float(4)));
1318 query.bindVariable(QLatin1String("integer"), QXmlItem(5));
1319 query.bindVariable(QLatin1String("fromQString"), QXmlItem(QString::fromLatin1("A QString")));
1320 query.bindVariable(QLatin1String("fromQChar"), QXmlItem(QChar::fromLatin1('C')));
1322 query.bindVariable(QLatin1String("fromIntLiteral"), QXmlItem(QVariant(654)));
1325 QVariant ui(uint(5));
1326 QCOMPARE(ui.type(), QVariant::UInt);
1327 query.bindVariable(QLatin1String("fromUInt"), ui);
1331 QVariant ulnglng(qulonglong(6));
1332 QCOMPARE(ulnglng.type(), QVariant::ULongLong);
1333 query.bindVariable(QLatin1String("fromULongLong"), ulnglng);
1337 QVariant qlnglng(qlonglong(7));
1338 QCOMPARE(qlnglng.type(), QVariant::LongLong);
1339 query.bindVariable(QLatin1String("fromLongLong"), qlnglng);
1342 query.setQuery(&queryFile);
1344 // TODO do queries which declares external variables with types. Tons of combos here.
1345 // TODO ensure that binding with QXmlItem() doesn't make a binding available.
1346 // TODO test rebinding a variable.
1348 QVERIFY(query.isValid());
1351 query.evaluateTo(&it);
1352 QXmlItem item(it.next());
1353 QVERIFY(!item.isNull());
1354 QVERIFY(item.isAtomicValue());
1356 if(sizeof(qreal) == sizeof(float)) //ARM casts to Float not to double
1357 QCOMPARE(item.toAtomicValue().toString(),
1358 QLatin1String("4 true 3 654 7 41414141 C 2000-10-11Z 2001-09-10T01:02:03 "
1359 "A QString http://example.com/ 5 6 true false false true true true true true true true "
1362 QCOMPARE(item.toAtomicValue().toString(),
1363 QLatin1String("4 true 3 654 7 41414141 C 2000-10-11Z 2001-09-10T01:02:03 "
1364 "A QString http://example.com/ 5 6 true true true true true true true true true true "
1369 void tst_QXmlQuery::bindNode() const
1372 TestSimpleNodeModel nodeModel(query.namePool());
1374 query.bindVariable(QLatin1String("node"), nodeModel.root());
1377 QVERIFY(buff.open(QIODevice::WriteOnly));
1379 query.setQuery(QLatin1String("declare variable $node external; $node"));
1380 QXmlSerializer serializer(query, &buff);
1382 QVERIFY(query.evaluateTo(&serializer));
1383 QCOMPARE(out, QByteArray("<nodeName/>"));
1387 Pass in a relative URI, and make sure it is resolved against the current application directory.
1389 void tst_QXmlQuery::relativeBaseURI() const
1392 query.setQuery(QLatin1String("fn:static-base-uri()"), QUrl(QLatin1String("a/relative/uri.weirdExtension")));
1393 QVERIFY(query.isValid());
1396 QBuffer buffer(&result);
1397 QVERIFY(buffer.open(QIODevice::ReadWrite));
1399 QXmlSerializer serializer(query, &buffer);
1400 QVERIFY(query.evaluateTo(&serializer));
1402 const QUrl loaded(QUrl::fromEncoded(result));
1403 QUrl appPath(QUrl::fromLocalFile(QCoreApplication::applicationFilePath()));
1405 QVERIFY(loaded.isValid());
1406 QVERIFY(appPath.isValid());
1407 QVERIFY(!loaded.isRelative());
1408 QVERIFY(!appPath.isRelative());
1410 QFileInfo dir(appPath.toLocalFile());
1411 dir.setFile(QString());
1413 /* We can't use QUrl::isParentOf() because it doesn't do what we want it to */
1414 if(!loaded.toLocalFile().startsWith(dir.absoluteFilePath()))
1415 QTextStream(stderr) << "dir.absoluteFilePath():" << dir.absoluteFilePath() << "loaded.toLocalFile():" << loaded.toLocalFile();
1417 checkBaseURI(loaded, dir.absoluteFilePath());
1420 void tst_QXmlQuery::emptyBaseURI() const
1423 query.setQuery(QLatin1String("fn:static-base-uri()"), QUrl());
1424 QVERIFY(query.isValid());
1427 QBuffer buffer(&result);
1428 QVERIFY(buffer.open(QIODevice::ReadWrite));
1430 QXmlSerializer serializer(query, &buffer);
1431 QVERIFY(query.evaluateTo(&serializer));
1433 const QUrl loaded(QUrl::fromEncoded(result));
1434 QUrl appPath(QUrl::fromLocalFile(QCoreApplication::applicationFilePath()));
1436 QVERIFY(loaded.isValid());
1437 QVERIFY(appPath.isValid());
1438 QVERIFY(!loaded.isRelative());
1439 QVERIFY(!appPath.isRelative());
1441 QFileInfo dir(appPath.toLocalFile());
1442 dir.setFile(QString());
1444 QCOMPARE(loaded, appPath);
1448 Ensure that QDate comes out as QDateTime.
1450 void tst_QXmlQuery::roundTripDateWithinQXmlItem() const
1452 const QDate date(1999, 9, 10);
1453 QVERIFY(date.isValid());
1455 const QVariant variant(date);
1456 QVERIFY(variant.isValid());
1457 QCOMPARE(variant.type(), QVariant::Date);
1459 const QXmlItem item(variant);
1460 QVERIFY(!item.isNull());
1461 QVERIFY(item.isAtomicValue());
1463 const QVariant out(item.toAtomicValue());
1464 QVERIFY(out.isValid());
1465 QCOMPARE(out.type(), QVariant::Date);
1466 QCOMPARE(out.toDate(), date);
1470 Check whether a query is valid, which uses an unbound variable.
1472 void tst_QXmlQuery::bindingMissing() const
1475 MessageSilencer messageHandler;
1476 query.setMessageHandler(&messageHandler);
1478 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
1479 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1480 query.setQuery(&queryFile);
1482 QVERIFY(!query.isValid());
1485 void tst_QXmlQuery::bindDefaultConstructedItem() const
1487 QFETCH(QXmlItem, item);
1490 MessageSilencer messageHandler;
1491 query.setMessageHandler(&messageHandler);
1493 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
1494 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1495 query.setQuery(&queryFile);
1496 query.bindVariable(QLatin1String("externalVariable"), item);
1498 QVERIFY(!query.isValid());
1501 void tst_QXmlQuery::bindDefaultConstructedItem_data() const
1503 QTest::addColumn<QXmlItem>("item");
1505 QTest::newRow("QXmlItem()") << QXmlItem();
1506 QTest::newRow("QXmlItem(QVariant())") << QXmlItem(QVariant());
1507 QTest::newRow("QXmlItem(QXmlNodeModelIndex())") << QXmlItem(QXmlNodeModelIndex());
1511 Remove a binding by binding QXmlItem() with the same name.
1513 void tst_QXmlQuery::eraseQXmlItemBinding() const
1516 MessageSilencer messageHandler;
1517 query.setMessageHandler(&messageHandler);
1519 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
1520 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1521 query.bindVariable(QLatin1String("externalVariable"), QXmlItem(3));
1522 query.setQuery(&queryFile);
1523 QVERIFY(query.isValid());
1526 QBuffer buffer(&result);
1527 QVERIFY(buffer.open(QIODevice::ReadWrite));
1529 QXmlSerializer serializer(query, &buffer);
1530 QVERIFY(query.evaluateTo(&serializer));
1532 QCOMPARE(result, QByteArray("3 6<e>3</e>false"));
1534 query.bindVariable(QLatin1String("externalVariable"), QXmlItem());
1535 QVERIFY(!query.isValid());
1539 Erase a variable binding
1541 void tst_QXmlQuery::eraseDeviceBinding() const
1543 /* Erase an existing QIODevice binding with another QIODevice binding. */
1547 QByteArray doc("<e/>");
1548 QBuffer buffer(&doc);
1549 QVERIFY(buffer.open(QIODevice::ReadOnly));
1551 query.bindVariable(QLatin1String("in"), &buffer);
1552 query.setQuery(QLatin1String("$in"));
1553 QVERIFY(query.isValid());
1555 query.bindVariable(QLatin1String("in"), 0);
1556 QVERIFY(!query.isValid());
1559 /* Erase an existing QXmlItem binding with another QIODevice binding. */
1563 query.bindVariable(QLatin1String("in"), QXmlItem(5));
1564 query.setQuery(QLatin1String("$in"));
1565 QVERIFY(query.isValid());
1567 query.bindVariable(QLatin1String("in"), 0);
1568 QVERIFY(!query.isValid());
1573 Bind a variable, evaluate, bind with a different value but same type, and evaluate again.
1575 void tst_QXmlQuery::rebindVariableSameType() const
1578 MessageSilencer messageHandler;
1579 query.setMessageHandler(&messageHandler);
1581 query.bindVariable(QLatin1String("externalVariable"), QXmlItem(3));
1584 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
1585 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1586 query.setQuery(&queryFile);
1589 QVERIFY(query.isValid());
1593 QBuffer buffer(&result);
1594 QVERIFY(buffer.open(QIODevice::ReadWrite));
1596 QXmlSerializer serializer(query, &buffer);
1597 QVERIFY(query.evaluateTo(&serializer));
1599 QCOMPARE(result, QByteArray("3 6<e>3</e>false"));
1603 query.bindVariable(QLatin1String("externalVariable"), QXmlItem(5));
1605 QBuffer buffer(&result);
1606 QVERIFY(buffer.open(QIODevice::ReadWrite));
1608 QXmlSerializer serializer(query, &buffer);
1609 QVERIFY(query.evaluateTo(&serializer));
1611 QCOMPARE(result, QByteArray("5 8<e>5</e>false"));
1616 void tst_QXmlQuery::rebindVariableDifferentType() const
1618 /* Rebind QXmlItem variable with QXmlItem variable. */
1621 query.bindVariable(QLatin1String("in"), QXmlItem(3));
1622 query.setQuery(QLatin1String("$in"));
1623 QVERIFY(query.isValid());
1625 query.bindVariable(QLatin1String("in"), QXmlItem("A string"));
1626 QVERIFY(!query.isValid());
1629 /* Rebind QIODevice variable with QXmlItem variable. */
1633 buffer.setData(QByteArray("<e/>"));
1634 QVERIFY(buffer.open(QIODevice::ReadOnly));
1636 query.bindVariable(QLatin1String("in"), &buffer);
1637 query.setQuery(QLatin1String("$in"));
1638 QVERIFY(query.isValid());
1640 query.bindVariable(QLatin1String("in"), QXmlItem("A string"));
1641 QVERIFY(!query.isValid());
1644 /* Rebind QXmlItem variable with QIODevice variable. The type of the
1645 * variable changes, so a recompile is necessary. */
1649 query.bindVariable(QLatin1String("in"), QXmlItem(QLatin1String("A string")));
1650 query.setQuery(QLatin1String("$in"));
1651 QVERIFY(query.isValid());
1654 buffer.setData(QByteArray("<e/>"));
1655 QVERIFY(buffer.open(QIODevice::ReadOnly));
1656 query.bindVariable(QLatin1String("in"), &buffer);
1657 QVERIFY(!query.isValid());
1661 void tst_QXmlQuery::rebindVariableWithNullItem() const
1665 query.bindVariable(QLatin1String("name"), QXmlItem(5));
1666 query.bindVariable(QLatin1String("name"), QXmlItem());
1669 void tst_QXmlQuery::constCorrectness() const
1671 QXmlResultItems result;
1673 tmp.setQuery(QLatin1String("1")); /* Just so we have a valid query. */
1674 const QXmlQuery query(tmp);
1676 /* These functions should be const. */
1678 query.evaluateTo(&result);
1680 query.uriResolver();
1681 query.messageHandler();
1684 QString dummyString;
1685 QTextStream dummyStream(&dummyString);
1686 PushBaseliner dummy(dummyStream, query.namePool());
1687 QVERIFY(dummy.isValid());
1688 query.evaluateTo(&dummy);
1692 void tst_QXmlQuery::objectSize() const
1694 /* We have a d pointer. */
1695 QCOMPARE(sizeof(QXmlQuery), sizeof(void *));
1698 void tst_QXmlQuery::setUriResolver() const
1700 /* Set a null resolver, and make sure it can take a const pointer. */
1703 query.setUriResolver(static_cast<const QAbstractUriResolver *>(0));
1704 QCOMPARE(query.uriResolver(), static_cast<const QAbstractUriResolver *>(0));
1708 TestURIResolver resolver;
1710 query.setUriResolver(&resolver);
1711 QCOMPARE(query.uriResolver(), static_cast<const QAbstractUriResolver *>(&resolver));
1715 void tst_QXmlQuery::uriResolver() const
1717 /* Check default value. */
1720 QCOMPARE(query.uriResolver(), static_cast<const QAbstractUriResolver *>(0));
1724 void tst_QXmlQuery::messageXML() const
1728 MessageValidator messageValidator;
1729 query.setMessageHandler(&messageValidator);
1731 query.setQuery(QLatin1String("1basicSyntaxError"));
1733 const QRegExp removeFilename(QLatin1String("Location: file:.*\\#"));
1734 QVERIFY(removeFilename.isValid());
1736 QVERIFY(messageValidator.success());
1737 QCOMPARE(messageValidator.received().remove(removeFilename),
1738 QString::fromLatin1("Type:3\n"
1739 "Description: <html xmlns='http://www.w3.org/1999/xhtml/'><body><p>syntax error, unexpected unknown keyword</p></body></html>\n"
1740 "Identifier: http://www.w3.org/2005/xqt-errors#XPST0003\n"
1745 1. Allocate QXmlResultItems
1746 2. Allocate QXmlQuery
1747 3. evaluate to the QXmlResultItems instance
1748 4. Dellocate the QXmlQuery instance
1749 5. Ensure QXmlResultItems works
1751 void tst_QXmlQuery::resultItemsDeallocatedQuery() const
1753 QXmlResultItems result;
1757 query.setQuery(QLatin1String("1, 2, xs:integer(<e>3</e>)"));
1758 query.evaluateTo(&result);
1761 QCOMPARE(result.next().toAtomicValue(), QVariant(1));
1762 QCOMPARE(result.next().toAtomicValue(), QVariant(2));
1763 QCOMPARE(result.next().toAtomicValue(), QVariant(3));
1764 QVERIFY(result.next().isNull());
1765 QVERIFY(!result.hasError());
1769 1. Bind variable with bindVariable()
1770 2. setQuery that has 'declare variable' with same name.
1771 3. Ensure the value inside the query is used. We don't guarantee this behavior
1772 but that's what we lock.
1774 void tst_QXmlQuery::shadowedVariables() const
1777 query.bindVariable("varName", QXmlItem(3));
1778 query.setQuery(QLatin1String("declare variable $varName := 5; $varName"));
1780 QXmlResultItems result;
1781 query.evaluateTo(&result);
1783 QCOMPARE(result.next().toAtomicValue(), QVariant(5));
1786 void tst_QXmlQuery::setFocusQXmlItem() const
1788 /* Make sure we can take a const reference. */
1791 const QXmlItem item;
1792 query.setFocus(item);
1795 // TODO evaluate with atomic value, check type
1796 // TODO evaluate with node, check type
1797 // TODO ensure that setFocus() triggers query recompilation, as appropriate.
1798 // TODO let the focus be undefined, call isvalid, call evaluate anyway
1799 // TODO let the focus be undefined, call evaluate directly
1802 void tst_QXmlQuery::setFocusQUrl() const
1804 /* Load a focus which isn't well-formed. */
1807 MessageSilencer silencer;
1809 query.setMessageHandler(&silencer);
1811 QVERIFY(!query.setFocus(QUrl(QLatin1String("data/notWellformed.xml"))));
1814 /* Ensure the same URI resolver is used. */
1816 QXmlQuery query(QXmlQuery::XSLT20);
1818 const TestURIResolver resolver(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/documentElement.xml"))));
1819 query.setUriResolver(&resolver);
1821 QVERIFY(query.setFocus(QUrl(QLatin1String("arbitraryURI"))));
1822 query.setQuery(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/copyWholeDocument.xsl"))));
1823 QVERIFY(query.isValid());
1826 QVERIFY(result.open(QIODevice::ReadWrite));
1827 QXmlSerializer serializer(query, &result);
1828 query.evaluateTo(&serializer);
1830 QCOMPARE(result.data(), QByteArray("<doc/>"));
1833 // TODO ensure that the focus type doesn't change from XSLT20 on the main instance.
1837 This code poses a challenge wrt. to internal caching.
1839 void tst_QXmlQuery::setFocusQIODevice() const
1845 focus.setData(QByteArray("<e>abc</e>"));
1846 QVERIFY(focus.open(QIODevice::ReadOnly));
1847 query.setFocus(&focus);
1848 query.setQuery(QLatin1String("string()"));
1849 QVERIFY(query.isValid());
1852 query.evaluateTo(&output);
1854 QCOMPARE(output, QString::fromLatin1("abc\n"));
1857 /* Set a new focus, make sure it changes & works. */
1860 focus2.setData(QByteArray("<e>abc2</e>"));
1861 QVERIFY(focus2.open(QIODevice::ReadOnly));
1862 query.setFocus(&focus2);
1863 QVERIFY(query.isValid());
1866 query.evaluateTo(&output);
1868 QCOMPARE(output, QString::fromLatin1("abc2\n"));
1873 Since we internally use variable bindings for implementing the focus, we need
1874 to make sure we don't clash in this area.
1876 void tst_QXmlQuery::setFocusQIODeviceAvoidVariableClash() const
1879 buffer.setData("<e>focus</e>");
1880 QVERIFY(buffer.open(QIODevice::ReadOnly));
1882 /* First we bind the variable name, then the focus. */
1885 query.bindVariable(QString(QLatin1Char('u')), QVariant(1));
1886 query.setFocus(&buffer);
1887 query.setQuery(QLatin1String("string()"));
1890 query.evaluateTo(&out);
1892 QCOMPARE(out, QString::fromLatin1("focus\n"));
1895 /* First we bind the focus, then the variable name. */
1898 QVERIFY(buffer.open(QIODevice::ReadOnly));
1899 query.setFocus(&buffer);
1900 query.bindVariable(QString(QLatin1Char('u')), QVariant(1));
1901 query.setQuery(QLatin1String("string()"));
1904 query.evaluateTo(&out);
1906 QCOMPARE(out, QString::fromLatin1("focus\n"));
1910 void tst_QXmlQuery::setFocusQIODeviceFailure() const
1912 /* A not well-formed input document. */
1916 MessageSilencer silencer;
1917 query.setMessageHandler(&silencer);
1920 input.setData("<e");
1921 QVERIFY(input.open(QIODevice::ReadOnly));
1923 QCOMPARE(query.setFocus(&input), false);
1927 void tst_QXmlQuery::setFocusQString() const
1931 /* Basic use of focus. */
1933 QVERIFY(query.setFocus(QLatin1String("<e>textNode</e>")));
1934 query.setQuery(QLatin1String("string()"));
1935 QVERIFY(query.isValid());
1937 query.evaluateTo(&out);
1938 QCOMPARE(out, QString::fromLatin1("textNode\n"));
1941 /* Set to a new focus, make sure it changes and works. */
1943 QVERIFY(query.setFocus(QLatin1String("<e>newFocus</e>")));
1945 query.evaluateTo(&out);
1946 QCOMPARE(out, QString::fromLatin1("newFocus\n"));
1950 void tst_QXmlQuery::setFocusQStringFailure() const
1953 MessageSilencer silencer;
1955 query.setMessageHandler(&silencer);
1956 QVERIFY(!query.setFocus(QLatin1String("<notWellformed")));
1958 /* Let's try the slight special case of a null string. */
1959 QVERIFY(!query.setFocus(QString()));
1962 void tst_QXmlQuery::setFocusQStringSignature() const
1965 MessageSilencer silencer;
1966 query.setMessageHandler(&silencer);
1968 const QString argument;
1969 /* We should take a const ref. */
1970 query.setFocus(argument);
1972 /* We should return a bool. */
1973 static_cast<bool>(query.setFocus(QString()));
1976 void tst_QXmlQuery::setFocusQIODeviceTriggerWarnings() const
1978 /* A null pointer. */
1982 QTest::ignoreMessage(QtWarningMsg, "A null QIODevice pointer cannot be passed.");
1983 QCOMPARE(query.setFocus(static_cast<QIODevice *>(0)), false);
1986 /* A non opened-device. */
1990 QBuffer notReadable;
1991 QVERIFY(!notReadable.isReadable());
1993 QTest::ignoreMessage(QtWarningMsg, "The device must be readable.");
1994 QCOMPARE(query.setFocus(¬Readable), false);
1998 void tst_QXmlQuery::fnDocNetworkAccessSuccess() const
2000 #if defined(Q_OS_WINCE) && !defined(_X86_)
2001 QStringList testsToSkip;
2002 testsToSkip << "http scheme" << "ftp scheme";
2003 if (testsToSkip.contains(QTest::currentDataTag()))
2004 QSKIP("Network tests are currently unsupported on Windows CE.", SkipSingle);
2007 QFETCH(QUrl, uriToOpen);
2008 QFETCH(QByteArray, expectedOutput);
2010 if(!uriToOpen.isValid())
2011 qDebug() << "uriToOpen:" << uriToOpen;
2013 QVERIFY(uriToOpen.isValid());
2016 query.bindVariable(QLatin1String("uri"), QVariant(uriToOpen));
2017 query.setQuery(QLatin1String("declare variable $uri external;\ndoc($uri)"));
2018 QVERIFY(query.isValid());
2021 QBuffer buffer(&result);
2022 QVERIFY(buffer.open(QIODevice::WriteOnly));
2024 QXmlSerializer serializer(query, &buffer);
2025 QVERIFY(query.evaluateTo(&serializer));
2027 QCOMPARE(result, expectedOutput);
2030 void tst_QXmlQuery::fnDocNetworkAccessSuccess_data() const
2032 QTest::addColumn<QUrl>("uriToOpen");
2033 QTest::addColumn<QByteArray>("expectedOutput");
2035 QTest::newRow("file scheme")
2036 << inputFileAsURI(QLatin1String(SRCDIR "input.xml"))
2037 << QByteArray("<!-- This is just a file for testing. --><input/>");
2039 QTest::newRow("data scheme with ASCII")
2040 /* QUrl::toPercentEncoding(QLatin1String("<e/>")) yields "%3Ce%2F%3E". */
2041 << QUrl::fromEncoded("data:application/xml,%3Ce%2F%3E")
2042 << QByteArray("<e/>");
2044 QTest::newRow("data scheme with ASCII no MIME type")
2045 << QUrl::fromEncoded("data:,%3Ce%2F%3E")
2046 << QByteArray("<e/>");
2048 QTest::newRow("data scheme with base 64")
2049 << QUrl::fromEncoded("data:application/xml;base64,PGUvPg==")
2050 << QByteArray("<e/>");
2052 QTest::newRow("qrc scheme")
2053 << QUrl::fromEncoded("qrc:/QXmlQueryTestData/data/oneElement.xml")
2054 << QByteArray("<oneElement/>");
2059 QTest::newRow("http scheme")
2060 << QUrl(QString("http://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/wellFormed.xml"))
2061 << QByteArray("<!-- a comment --><e from=\"http\">Some Text</e>");
2063 QTest::newRow("ftp scheme")
2064 << QUrl(QString("ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/wellFormed.xml"))
2065 << QByteArray("<!-- a comment --><e from=\"ftp\">Some Text</e>");
2069 void tst_QXmlQuery::fnDocNetworkAccessFailure() const
2071 QFETCH(QUrl, uriToOpen);
2073 QVERIFY(uriToOpen.isValid());
2076 MessageSilencer silencer;
2077 query.setMessageHandler(&silencer);
2078 query.bindVariable(QLatin1String("uri"), QVariant(uriToOpen));
2079 query.setQuery(QLatin1String("declare variable $uri external;\ndoc($uri)"));
2080 QVERIFY(query.isValid());
2082 QXmlResultItems result;
2083 query.evaluateTo(&result);
2085 while(!result.next().isNull())
2087 /* Just loop until the end. */
2090 // TODO do something that triggers a /timeout/.
2091 QVERIFY(result.hasError());
2094 void tst_QXmlQuery::fnDocNetworkAccessFailure_data() const
2096 QTest::addColumn<QUrl>("uriToOpen");
2098 QTest::newRow("data scheme, not-well-formed")
2099 << QUrl(QLatin1String("data:application/xml;base64,PGUvg==="));
2101 QTest::newRow("file scheme, non-existant file")
2102 << QUrl(QLatin1String("file:///example.com/does/notExist.xml"));
2104 QTest::newRow("http scheme, file not found")
2105 << QUrl(QLatin1String("http://www.example.com/does/not/exist.xml"));
2107 QTest::newRow("http scheme, nonexistent host")
2108 << QUrl(QLatin1String("http://this.host.does.not.exist.I.SWear"));
2110 QTest::newRow("qrc scheme, not well-formed")
2111 << QUrl(QLatin1String("qrc:/QXmlQueryTestData/notWellformed.xml"));
2113 QTest::newRow("'qrc:/', non-existing file")
2114 << QUrl(QLatin1String(":/QXmlQueryTestData/data/thisFileDoesNotExist.xml"));
2116 QTest::newRow("':/', this scheme is not supported")
2117 << QUrl(QLatin1String(":/QXmlQueryTestData/data/notWellformed.xml"));
2122 QTest::newRow("http scheme, not well-formed")
2123 << QUrl(QString("http://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/notWellformed.xml"));
2125 QTest::newRow("https scheme, not well-formed")
2126 << QUrl(QString("https://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/notWellformedViaHttps.xml"));
2128 QTest::newRow("https scheme, nonexistent host")
2129 << QUrl(QLatin1String("https://this.host.does.not.exist.I.SWear"));
2131 QTest::newRow("ftp scheme, nonexistent host")
2132 << QUrl(QLatin1String("ftp://this.host.does.not.exist.I.SWear"));
2134 QTest::newRow("ftp scheme, not well-formed")
2135 << QUrl(QString("ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/notWellFormed.xml"));
2139 Create a network timeout from a QIODevice binding such
2140 that we ensure we don't hang infinitely.
2142 void tst_QXmlQuery::fnDocOnQIODeviceTimeout() const
2148 server.listen(QHostAddress::LocalHost, 1088);
2151 client.connectToHost("localhost", 1088);
2152 QVERIFY(client.isReadable());
2156 MessageSilencer silencer;
2157 query.setMessageHandler(&silencer);
2159 query.bindVariable(QLatin1String("inDevice"), &client);
2160 query.setQuery(QLatin1String("declare variable $inDevice external;\ndoc($inDevice)"));
2161 QVERIFY(query.isValid());
2163 QXmlResultItems result;
2164 query.evaluateTo(&result);
2165 QXmlItem next(result.next());
2167 while(!next.isNull())
2169 next = result.next();
2172 QVERIFY(result.hasError());
2176 When changing query, the static context must change too, such that
2177 the source locations are updated.
2179 void tst_QXmlQuery::recompilationWithEvaluateToResultFailing() const
2182 MessageSilencer silencer;
2183 query.setMessageHandler(&silencer);
2185 query.setQuery(QLatin1String("1 + 1")); /* An arbitrary valid query. */
2186 QVERIFY(query.isValid()); /* Trigger query compilation. */
2188 query.setQuery(QLatin1String("fn:doc('doesNotExist.example.com.xml')")); /* An arbitrary invalid query that make use of a source location. */
2189 QVERIFY(query.isValid()); /* Trigger second compilation. */
2191 QXmlResultItems items;
2192 query.evaluateTo(&items);
2194 QVERIFY(items.hasError());
2197 void tst_QXmlQuery::secondEvaluationWithEvaluateToResultFailing() const
2200 MessageSilencer silencer;
2201 query.setMessageHandler(&silencer);
2203 query.setQuery(QLatin1String("1 + 1")); /* An arbitrary valid query. */
2204 QVERIFY(query.isValid()); /* Trigger query compilation. */
2206 query.setQuery(QLatin1String("fn:doc('doesNotExist.example.com.xml')")); /* An arbitrary invalid query that make use of a source location. */
2207 /* We don't call isValid(). */
2208 QXmlResultItems items;
2209 query.evaluateTo(&items);
2211 QVERIFY(items.hasError());
2215 Compilation is triggered in the evaluation function due to no call to QXmlQuery::isValid().
2217 void tst_QXmlQuery::recompilationWithEvaluateToReceiver() const
2220 MessageSilencer silencer;
2221 query.setMessageHandler(&silencer);
2223 query.setQuery(QLatin1String("1 + 1")); /* An arbitrary valid query. */
2224 QVERIFY(query.isValid()); /* Trigger query compilation. */
2226 query.setQuery(QLatin1String("fn:doc('doesNotExist.example.com.xml')")); /* An arbitrary invalid query that make use of a source location. */
2227 /* We don't call isValid(). */
2230 QBuffer buffer(&dummy);
2231 buffer.open(QIODevice::WriteOnly);
2233 QXmlSerializer serializer(query, &buffer);
2235 QVERIFY(!query.evaluateTo(&serializer));
2238 void tst_QXmlQuery::evaluateToQStringListOnInvalidQuery() const
2240 MessageSilencer silencer;
2242 /* Invoke on a default constructed object. */
2246 QVERIFY(!query.evaluateTo(&out));
2249 /* Invoke on a syntactically invalid query. */
2253 MessageSilencer silencer;
2255 query.setMessageHandler(&silencer);
2256 query.setQuery(QLatin1String("1 + "));
2258 QVERIFY(!query.evaluateTo(&out));
2261 /* Invoke on a query with the wrong type, one atomic. */
2266 query.setQuery(QLatin1String("1"));
2267 query.setMessageHandler(&silencer);
2268 QVERIFY(!query.evaluateTo(&out));
2271 /* Invoke on a query with the wrong type, one element. */
2276 query.setQuery(QLatin1String("<e/>"));
2277 QVERIFY(!query.evaluateTo(&out));
2280 /* Invoke on a query with the wrong type, mixed nodes & atomics. */
2285 query.setQuery(QLatin1String("<e/>, 1, 'a string'"));
2286 query.setMessageHandler(&silencer);
2287 QVERIFY(!query.evaluateTo(&out));
2290 /* Evaluate the empty sequence. */
2295 query.setQuery(QLatin1String("()"));
2296 QVERIFY(!query.evaluateTo(&out));
2297 QVERIFY(out.isEmpty());
2301 void tst_QXmlQuery::evaluateToQStringList() const
2303 QFETCH(QString, queryString);
2304 QFETCH(QStringList, expectedOutput);
2307 query.setQuery(queryString);
2309 QVERIFY(query.isValid());
2311 QVERIFY(query.evaluateTo(&out));
2313 QCOMPARE(out, expectedOutput);
2316 void tst_QXmlQuery::evaluateToQStringListTriggerWarnings() const
2320 QTest::ignoreMessage(QtWarningMsg, "A non-null callback must be passed.");
2321 QCOMPARE(query.evaluateTo(static_cast<QStringList *>(0)),
2325 void tst_QXmlQuery::evaluateToQStringList_data() const
2327 QTest::addColumn<QString>("queryString");
2328 QTest::addColumn<QStringList>("expectedOutput");
2330 QTest::newRow("One atomic")
2331 << QString::fromLatin1("(1 + 1) cast as xs:string")
2332 << QStringList(QString::fromLatin1("2"));
2335 QStringList expected;
2336 expected << QLatin1String("2");
2337 expected << QLatin1String("a string");
2339 QTest::newRow("Two atomics")
2340 << QString::fromLatin1("(1 + 1) cast as xs:string, 'a string'")
2344 QTest::newRow("A query which evaluates to sub-types of xs:string.")
2345 << QString::fromLatin1("xs:NCName('NCName'), xs:normalizedString(' a b c ')")
2346 << (QStringList() << QString::fromLatin1("NCName")
2347 << QString::fromLatin1(" a b c "));
2349 QTest::newRow("A query which evaluates to two elements.")
2350 << QString::fromLatin1("string(<e>theString1</e>), string(<e>theString2</e>)")
2351 << (QStringList() << QString::fromLatin1("theString1")
2352 << QString::fromLatin1("theString2"));
2356 Ensure that we don't automatically convert non-xs:string values.
2358 void tst_QXmlQuery::evaluateToQStringListNoConversion() const
2361 query.setQuery(QString::fromLatin1("<e/>"));
2362 QVERIFY(query.isValid());
2364 QVERIFY(!query.evaluateTo(&result));
2367 void tst_QXmlQuery::evaluateToQIODevice() const
2369 /* an XQuery, check that no indentation is performed. */
2372 QVERIFY(out.open(QIODevice::ReadWrite));
2375 query.setQuery(QLatin1String("<a><b/></a>"));
2376 QVERIFY(query.isValid());
2377 QVERIFY(query.evaluateTo(&out));
2378 QCOMPARE(out.data(), QByteArray("<a><b/></a>"));
2382 void tst_QXmlQuery::evaluateToQIODeviceTriggerWarnings() const
2386 QTest::ignoreMessage(QtWarningMsg, "The pointer to the device cannot be null.");
2387 QCOMPARE(query.evaluateTo(static_cast<QIODevice *>(0)),
2392 QTest::ignoreMessage(QtWarningMsg, "The device must be writable.");
2393 QCOMPARE(query.evaluateTo(&buffer),
2397 void tst_QXmlQuery::evaluateToQIODeviceSignature() const
2399 /* The function should be const. */
2402 QVERIFY(out.open(QIODevice::ReadWrite));
2404 const QXmlQuery query;
2406 query.evaluateTo(&out);
2410 void tst_QXmlQuery::evaluateToQIODeviceOnInvalidQuery() const
2413 QVERIFY(out.open(QIODevice::WriteOnly));
2415 /* On syntactically invalid query. */
2418 MessageSilencer silencer;
2419 query.setMessageHandler(&silencer);
2420 query.setQuery(QLatin1String("1 +"));
2421 QVERIFY(!query.isValid());
2422 QVERIFY(!query.evaluateTo(&out));
2425 /* On null QXmlQuery instance. */
2428 QVERIFY(!query.evaluateTo(&out));
2433 void tst_QXmlQuery::setQueryQIODeviceQUrl() const
2438 buffer.setData("1, 2, 2 + 1");
2439 QVERIFY(buffer.open(QIODevice::ReadOnly));
2442 query.setQuery(&buffer);
2443 QVERIFY(query.isValid());
2445 QXmlResultItems result;
2446 query.evaluateTo(&result);
2447 QCOMPARE(result.next().toAtomicValue(), QVariant(1));
2448 QCOMPARE(result.next().toAtomicValue(), QVariant(2));
2449 QCOMPARE(result.next().toAtomicValue(), QVariant(3));
2450 QVERIFY(result.next().isNull());
2451 QVERIFY(!result.hasError());
2454 /* Set query that is invalid. */
2457 buffer.setData("1, ");
2458 QVERIFY(buffer.open(QIODevice::ReadOnly));
2461 MessageSilencer silencer;
2462 query.setMessageHandler(&silencer);
2463 query.setQuery(&buffer);
2464 QVERIFY(!query.isValid());
2467 /* Check that the base URI passes through. */
2470 buffer.setData("string(static-base-uri())");
2471 QVERIFY(buffer.open(QIODevice::ReadOnly));
2474 query.setQuery(&buffer, QUrl::fromEncoded("http://www.example.com/QIODeviceQUrl"));
2475 QVERIFY(query.isValid());
2478 query.evaluateTo(&result);
2479 QCOMPARE(result, QStringList(QLatin1String("http://www.example.com/QIODeviceQUrl")));
2483 void tst_QXmlQuery::setQueryQIODeviceQUrlTriggerWarnings() const
2486 QTest::ignoreMessage(QtWarningMsg, "A null QIODevice pointer cannot be passed.");
2490 QTest::ignoreMessage(QtWarningMsg, "The device must be readable.");
2491 query.setQuery(&buffer);
2494 void tst_QXmlQuery::setQueryQString() const
2499 query.setQuery(QLatin1String("1, 2, 2 + 1"));
2500 QVERIFY(query.isValid());
2502 QXmlResultItems result;
2503 query.evaluateTo(&result);
2504 QCOMPARE(result.next().toAtomicValue(), QVariant(1));
2505 QCOMPARE(result.next().toAtomicValue(), QVariant(2));
2506 QCOMPARE(result.next().toAtomicValue(), QVariant(3));
2507 QVERIFY(result.next().isNull());
2508 QVERIFY(!result.hasError());
2511 /* Set query that is invalid. */
2513 MessageSilencer silencer;
2515 query.setMessageHandler(&silencer);
2516 query.setQuery(QLatin1String("1, "));
2517 QVERIFY(!query.isValid());
2520 /* Check that the base URI passes through. */
2523 query.setQuery(QLatin1String("string(static-base-uri())"), QUrl::fromEncoded("http://www.example.com/QIODeviceQUrl"));
2524 QVERIFY(query.isValid());
2527 query.evaluateTo(&result);
2528 QCOMPARE(result, QStringList(QLatin1String("http://www.example.com/QIODeviceQUrl")));
2532 void tst_QXmlQuery::setQueryQUrlSuccess() const
2534 #if defined(Q_OS_WINCE) && !defined(_X86_)
2535 QStringList testsToSkip;
2536 testsToSkip << "A valid query via the ftp scheme" << "A valid query via the http scheme";
2537 if (testsToSkip.contains(QTest::currentDataTag()))
2538 QSKIP("Network tests are currently unsupported on Windows CE.", SkipSingle);
2541 QFETCH(QUrl, queryURI);
2542 QFETCH(QByteArray, expectedOutput);
2544 QVERIFY(queryURI.isValid());
2548 MessageSilencer silencer;
2549 query.setMessageHandler(&silencer);
2551 query.setQuery(queryURI);
2552 QVERIFY(query.isValid());
2555 QBuffer buffer(&out);
2556 QVERIFY(buffer.open(QIODevice::WriteOnly));
2557 QXmlSerializer serializer(query, &buffer);
2559 query.evaluateTo(&serializer);
2560 QCOMPARE(out, expectedOutput);
2563 void tst_QXmlQuery::setQueryQUrlSuccess_data() const
2565 QTest::addColumn<QUrl>("queryURI");
2566 QTest::addColumn<QByteArray>("expectedOutput");
2568 QTest::newRow("A valid query via the data scheme")
2569 << QUrl::fromEncoded("data:application/xml,1%20%2B%201") /* "1 + 1" */
2572 QTest::newRow("A valid query via the file scheme")
2573 << QUrl::fromLocalFile(inputFile(QLatin1String(queriesDirectory) + QLatin1String("onePlusOne.xq")))
2579 QTest::newRow("A valid query via the ftp scheme")
2580 << QUrl::fromEncoded(QString("ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/viaFtp.xq").toLatin1())
2581 << QByteArray("This was received via FTP");
2583 QTest::newRow("A valid query via the http scheme")
2584 << QUrl::fromEncoded(QString("http://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/viaHttp.xq").toLatin1())
2585 << QByteArray("This was received via HTTP.");
2588 void tst_QXmlQuery::setQueryQUrlFailSucceed() const
2591 MessageSilencer silencer;
2593 query.setMessageHandler(&silencer);
2595 query.setQuery(QLatin1String("1 + 1"));
2596 QVERIFY(query.isValid());
2598 query.setQuery(QUrl::fromEncoded("file://example.com/does/not/exist"));
2599 QVERIFY(!query.isValid());
2602 void tst_QXmlQuery::setQueryQUrlFailure() const
2604 QFETCH(QUrl, queryURI);
2606 MessageSilencer silencer;
2609 query.setMessageHandler(&silencer);
2610 query.setQuery(queryURI);
2611 QVERIFY(!query.isValid());
2614 void tst_QXmlQuery::setQueryQUrlFailure_data() const
2616 QTest::addColumn<QUrl>("queryURI");
2618 QTest::newRow("Query via file:// that does not exist.")
2619 << QUrl::fromEncoded("file://example.com/does/not/exist");
2621 QTest::newRow("A query via file:// that is completely empty, but readable.")
2622 << QUrl::fromLocalFile(QCoreApplication::applicationFilePath()).resolved(QUrl("../xmlpatterns/queries/completelyEmptyQuery.xq"));
2625 const QString name(QLatin1String("nonReadableFile.xq"));
2626 QFile outFile(name);
2627 QVERIFY(outFile.open(QIODevice::WriteOnly));
2628 outFile.write(QByteArray("1"));
2630 /* On some windows versions, this fails, so we don't check that this works with QVERIFY. */
2631 outFile.setPermissions(QFile::Permissions(QFile::Permissions()));
2633 QTest::newRow("Query via file:/ that does not have read permissions.")
2634 << QUrl::fromLocalFile(QCoreApplication::applicationFilePath()).resolved(QUrl("nonReadableFile.xq"));
2640 QTest::newRow("Query via HTTP that does not exist.")
2641 << QUrl::fromEncoded("http://example.com/NoQuery/ISWear");
2644 QTest::newRow("Query via FTP that does not exist.")
2645 << QUrl::fromEncoded("ftp://example.com/NoQuery/ISWear");
2648 QTest::newRow("A query via http:// that is completely empty, but readable.")
2649 << QUrl::fromEncoded(QString(
2650 "http://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/completelyEmptyQuery.xq").toLatin1());
2652 QTest::newRow("A query via ftp:// that is completely empty, but readable.")
2653 << QUrl::fromEncoded(QString(
2654 "ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/completelyEmptyQuery.xq").toLatin1());
2658 void tst_QXmlQuery::setQueryQUrlBaseURI() const
2660 QFETCH(QUrl, inputBaseURI);
2661 QFETCH(QUrl, expectedBaseURI);
2665 query.setQuery(QUrl(QLatin1String("qrc:/QXmlQueryTestData/queries/staticBaseURI.xq")), inputBaseURI);
2666 QVERIFY(query.isValid());
2669 QVERIFY(query.evaluateTo(&result));
2670 QCOMPARE(result.count(), 1);
2672 if(qstrcmp(QTest::currentDataTag(), "Relative base URI") == 0)
2673 checkBaseURI(QUrl(result.first()), QCoreApplication::applicationFilePath());
2675 QCOMPARE(result.first(), expectedBaseURI.toString());
2678 void tst_QXmlQuery::setQueryQUrlBaseURI_data() const
2680 QTest::addColumn<QUrl>("inputBaseURI");
2681 QTest::addColumn<QUrl>("expectedBaseURI");
2683 QTest::newRow("absolute HTTP")
2684 << QUrl(QLatin1String("http://www.example.com/"))
2685 << QUrl(QLatin1String("http://www.example.com/"));
2687 QTest::newRow("None, so the query URI is used")
2689 << QUrl(QLatin1String("qrc:/QXmlQueryTestData/queries/staticBaseURI.xq"));
2691 QTest::newRow("Relative base URI")
2692 << QUrl(QLatin1String("../data/relative.uri"))
2697 1. Create a valid query.
2698 2. Call setQuery(QUrl), with a query file that doesn't exist.
2699 3. Verify that the query has changed state into invalid.
2701 void tst_QXmlQuery::setQueryWithNonExistentQUrlOnValidQuery() const
2705 MessageSilencer messageSilencer;
2706 query.setMessageHandler(&messageSilencer);
2708 query.setQuery(QLatin1String("1 + 1"));
2709 QVERIFY(query.isValid());
2711 query.setQuery(QUrl::fromEncoded("qrc:/QXmlQueryTestData/DOESNOTEXIST.xq"));
2712 QVERIFY(!query.isValid());
2716 1. Create a valid query.
2717 2. Call setQuery(QUrl), with a query file that is invalid.
2718 3. Verify that the query has changed state into invalid.
2720 void tst_QXmlQuery::setQueryWithInvalidQueryFromQUrlOnValidQuery() const
2724 MessageSilencer messageSilencer;
2725 query.setMessageHandler(&messageSilencer);
2727 query.setQuery(QLatin1String("1 + 1"));
2728 QVERIFY(query.isValid());
2730 query.setQuery(QUrl::fromEncoded("qrc:/QXmlQueryTestData/queries/syntaxError.xq"));
2731 QVERIFY(!query.isValid());
2735 This triggered two bugs:
2737 - First, the DynamicContext wasn't assigned to QXmlResultItems, meaning it went out of
2738 scope and therefore deallocated the document pool, and calls
2739 to QXmlResultItems::next() would use dangling pointers.
2741 - Conversion between QPatternist::Item and QXmlItem was incorrectly done, leading to nodes
2742 being treated as atomic values, and subsequent crashes.
2745 void tst_QXmlQuery::retrieveNameFromQuery() const
2747 QFETCH(QString, queryString);
2748 QFETCH(QString, expectedName);
2751 query.setQuery(queryString);
2752 QVERIFY(query.isValid());
2753 QXmlResultItems result;
2754 query.evaluateTo(&result);
2756 QVERIFY(!result.hasError());
2758 const QXmlItem item(result.next());
2759 QVERIFY(!result.hasError());
2760 QVERIFY(!item.isNull());
2761 QVERIFY(item.isNode());
2763 const QXmlNodeModelIndex node(item.toNodeModelIndex());
2764 QVERIFY(!node.isNull());
2766 QCOMPARE(node.model()->name(node).localName(query.namePool()), expectedName);
2769 void tst_QXmlQuery::retrieveNameFromQuery_data() const
2771 QTest::addColumn<QString>("queryString");
2772 QTest::addColumn<QString>("expectedName");
2774 QTest::newRow("Document-node")
2775 << QString::fromLatin1("document{<elementName/>}")
2778 QTest::newRow("Element")
2779 << QString::fromLatin1("document{<elementName/>}/*")
2780 << QString::fromLatin1("elementName");
2784 Binding a null QString leads to no variable binding, but an
2785 empty non-null QString is possible.
2787 void tst_QXmlQuery::bindEmptyNullString() const
2789 MessageSilencer messageHandler;
2791 query.setMessageHandler(&messageHandler);
2792 query.setQuery(QLatin1String("declare variable $v external; $v"));
2793 /* Here, we effectively pass an invalid QVariant. */
2794 query.bindVariable(QLatin1String("v"), QVariant(QString()));
2795 QVERIFY(!query.isValid());
2798 QVERIFY(!query.evaluateTo(&result));
2801 void tst_QXmlQuery::bindEmptyString() const
2804 query.bindVariable(QLatin1String("v"), QVariant(QString(QLatin1String(""))));
2805 query.setQuery(QLatin1String("declare variable $v external; $v"));
2806 QVERIFY(query.isValid());
2809 QVERIFY(query.evaluateTo(&result));
2810 QStringList expected((QString()));
2811 QCOMPARE(result, expected);
2814 void tst_QXmlQuery::cleanupTestCase() const
2816 /* Remove a weird file we created. */
2817 const QString name(QLatin1String("nonReadableFile.xq"));
2819 if(QFile::exists(name))
2822 QVERIFY(file.setPermissions(QFile::WriteOwner));
2823 QVERIFY(file.remove());
2827 void tst_QXmlQuery::declareUnavailableExternal() const
2830 MessageSilencer silencer;
2831 query.setMessageHandler(&silencer);
2832 query.setQuery(QLatin1String("declare variable $var external;"
2834 /* We do not bind $var with QXmlQuery::bindVariable(). */
2835 QVERIFY(!query.isValid());
2839 This test triggers an assert in one of the cache iterator
2840 with MSVC 2005 when compiled in debug mode.
2842 void tst_QXmlQuery::msvcCacheIssue() const
2845 query.bindVariable(QLatin1String("externalVariable"), QXmlItem("Variable Value"));
2846 query.setQuery(QUrl::fromLocalFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariableUsedTwice.xq")));
2848 QVERIFY(query.evaluateTo(&result));
2851 QStringList() << QString::fromLatin1("Variable Value") << QString::fromLatin1("Variable Value"));
2854 void tst_QXmlQuery::unavailableExternalVariable() const
2858 MessageSilencer silencer;
2859 query.setMessageHandler(&silencer);
2861 query.setQuery(QLatin1String("declare variable $foo external; 1"));
2863 QVERIFY(!query.isValid());
2867 Ensure that setUriResolver() affects \c fn:doc() and \c fn:doc-available().
2869 void tst_QXmlQuery::useUriResolver() const
2871 class TestUriResolver : public QAbstractUriResolver
2872 , private TestFundament
2875 TestUriResolver() {}
2876 virtual QUrl resolve(const QUrl &relative,
2877 const QUrl &baseURI) const
2880 return baseURI.resolved(inputFile(QLatin1String(queriesDirectory) + QLatin1String("simpleDocument.xml")));
2884 const TestUriResolver uriResolver;
2887 query.setUriResolver(&uriResolver);
2888 query.setQuery(QLatin1String("let $i := 'http://www.example.com/DoesNotExist'"
2889 "return (string(doc($i)), doc-available($i))"));
2892 QXmlResultItems result;
2893 query.evaluateTo(&result);
2895 QVERIFY(!result.hasError());
2896 QCOMPARE(result.next().toAtomicValue().toString(), QString::fromLatin1("text text node"));
2897 QCOMPARE(result.next().toAtomicValue().toBool(), true);
2898 QVERIFY(result.next().isNull());
2899 QVERIFY(!result.hasError());
2902 void tst_QXmlQuery::queryWithFocusAndVariable() const
2905 query.setFocus(QXmlItem(5));
2906 query.bindVariable(QLatin1String("var"), QXmlItem(2));
2908 query.setQuery(QLatin1String("string(. * $var)"));
2912 QVERIFY(query.evaluateTo(&result));
2914 QCOMPARE(result, QStringList(QLatin1String("10")));
2917 void tst_QXmlQuery::undefinedFocus() const
2921 MessageSilencer silencer;
2922 query.setMessageHandler(&silencer);
2924 query.setQuery(QLatin1String("."));
2925 QVERIFY(!query.isValid());
2928 void tst_QXmlQuery::basicFocusUsage() const
2932 MessageSilencer silencer;
2933 query.setMessageHandler(&silencer);
2935 query.setFocus(QXmlItem(5));
2936 query.setQuery(QLatin1String("string(. * .)"));
2937 QVERIFY(query.isValid());
2940 QVERIFY(query.evaluateTo(&result));
2942 QCOMPARE(result, QStringList(QLatin1String("25")));
2946 Triggers an ownership related crash.
2948 void tst_QXmlQuery::copyCheckMessageHandler() const
2951 QCOMPARE(query.messageHandler(), static_cast<QAbstractMessageHandler *>(0));
2953 query.setQuery(QLatin1String("doc('qrc:/QXmlQueryTestData/data/oneElement.xml')"));
2954 /* By now, we should have set the builtin message handler. */
2955 const QAbstractMessageHandler *const messageHandler = query.messageHandler();
2956 QVERIFY(messageHandler);
2959 /* This copies QXmlQueryPrivate::m_ownerObject, and its destructor
2960 * will delete it, and hence the builtin message handler attached to it. */
2961 QXmlQuery copy(query);
2964 QXmlResultItems result;
2965 query.evaluateTo(&result);
2967 while(!result.next().isNull())
2970 QVERIFY(!result.hasError());
2973 void tst_QXmlQuery::queryLanguage() const
2975 /* Check default value. */
2977 const QXmlQuery query;
2978 QCOMPARE(query.queryLanguage(), QXmlQuery::XQuery10);
2981 /* Check default value of copies default instance. */
2983 const QXmlQuery query1;
2984 const QXmlQuery query2(query1);
2986 QCOMPARE(query1.queryLanguage(), QXmlQuery::XQuery10);
2987 QCOMPARE(query2.queryLanguage(), QXmlQuery::XQuery10);
2991 void tst_QXmlQuery::queryLanguageSignature() const
2993 /* This getter should be const. */
2995 query.queryLanguage();
2998 void tst_QXmlQuery::enumQueryLanguage() const
3000 /* These enum values should be possible to OR for future plans. */
3001 QCOMPARE(int(QXmlQuery::XQuery10), 1);
3002 QCOMPARE(int(QXmlQuery::XSLT20), 2);
3003 QCOMPARE(int(QXmlQuery::XmlSchema11IdentityConstraintSelector), 1024);
3004 QCOMPARE(int(QXmlQuery::XmlSchema11IdentityConstraintField), 2048);
3005 QCOMPARE(int(QXmlQuery::XPath20), 4096);
3008 void tst_QXmlQuery::setInitialTemplateNameQXmlName() const
3010 QXmlQuery query(QXmlQuery::XSLT20);
3011 QXmlNamePool np(query.namePool());
3012 const QXmlName name(np, QLatin1String("main"));
3014 query.setInitialTemplateName(name);
3016 QCOMPARE(query.initialTemplateName(), name);
3018 query.setQuery(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/namedTemplate.xsl"))));
3019 QVERIFY(query.isValid());
3022 QVERIFY(result.open(QIODevice::ReadWrite));
3023 QXmlSerializer serializer(query, &result);
3024 query.evaluateTo(&serializer);
3026 QCOMPARE(result.data(), QByteArray("1 2 3 4 5"));
3028 // TODO invoke a template which has required params.
3031 void tst_QXmlQuery::setInitialTemplateNameQXmlNameSignature() const
3034 QXmlNamePool np(query.namePool());
3035 const QXmlName name(np, QLatin1String("foo"));
3037 /* The signature should take a const reference. */
3038 query.setInitialTemplateName(name);
3041 void tst_QXmlQuery::setInitialTemplateNameQString() const
3044 QXmlNamePool np(query.namePool());
3045 query.setInitialTemplateName(QLatin1String("foo"));
3047 QCOMPARE(query.initialTemplateName(), QXmlName(np, QLatin1String("foo")));
3050 void tst_QXmlQuery::setInitialTemplateNameQStringSignature() const
3052 const QString name(QLatin1String("name"));
3055 /* We should take a const reference. */
3056 query.setInitialTemplateName(name);
3059 void tst_QXmlQuery::initialTemplateName() const
3061 /* Check our default value. */
3063 QCOMPARE(query.initialTemplateName(), QXmlName());
3064 QVERIFY(query.initialTemplateName().isNull());
3067 void tst_QXmlQuery::initialTemplateNameSignature() const
3069 const QXmlQuery query;
3070 /* This should be a const member. */
3071 query.initialTemplateName();
3074 void tst_QXmlQuery::setNetworkAccessManager() const
3077 /* Ensure fn:doc() picks up the right QNetworkAccessManager. */
3079 NetworkOverrider networkOverrider(QUrl(QLatin1String("tag:example.com:DOESNOTEXIST")),
3080 QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/queries/simpleDocument.xml"))));
3081 QVERIFY(networkOverrider.isValid());
3084 query.setNetworkAccessManager(&networkOverrider);
3085 query.setQuery(QLatin1String("string(doc('tag:example.com:DOESNOTEXIST'))"));
3086 QVERIFY(query.isValid());
3089 QVERIFY(query.evaluateTo(&result));
3091 QCOMPARE(result, QStringList(QLatin1String("text text node")));
3094 /* Ensure setQuery() is using the right network manager. */
3096 NetworkOverrider networkOverrider(QUrl(QLatin1String("tag:example.com:DOESNOTEXIST")),
3097 QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/queries/concat.xq"))));
3098 QVERIFY(networkOverrider.isValid());
3101 query.setNetworkAccessManager(&networkOverrider);
3102 query.setQuery(QUrl("tag:example.com:DOESNOTEXIST"));
3103 QVERIFY(query.isValid());
3106 QVERIFY(query.evaluateTo(&result));
3108 QCOMPARE(result, QStringList(QLatin1String("abcdef")));
3111 void tst_QXmlQuery::networkAccessManagerSignature() const
3114 const QXmlQuery query;
3116 /* The function should be const. */
3117 query.networkAccessManager();
3120 void tst_QXmlQuery::networkAccessManagerDefaultValue() const
3122 const QXmlQuery query;
3124 QCOMPARE(query.networkAccessManager(), static_cast<QNetworkAccessManager *>(0));
3127 void tst_QXmlQuery::networkAccessManager() const
3129 /* Test that we return the network manager that was set. */
3131 QNetworkAccessManager manager;
3133 query.setNetworkAccessManager(&manager);
3134 QCOMPARE(query.networkAccessManager(), &manager);
3142 1. Load a document into QXmlQuery's document cache, by executing a query which does it.
3144 3. Change query, to one which uses the focus
3149 void tst_QXmlQuery::multipleDocsAndFocus() const
3153 /* We use string concatenation, since variable bindings might disturb what
3155 query.setQuery(QLatin1String("string(doc('") +
3156 inputFile(QLatin1String(XMLPATTERNSDIR "/queries/simpleDocument.xml")) +
3157 QLatin1String("'))"));
3158 query.setFocus(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/documentElement.xml"))));
3159 query.setQuery(QLatin1String("string(.)"));
3162 QVERIFY(query.evaluateTo(&result));
3177 void tst_QXmlQuery::multipleEvaluationsWithDifferentFocus() const
3182 query.setFocus(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/documentElement.xml"))));
3183 query.setQuery(QLatin1String("string(.)"));
3184 QVERIFY(query.evaluateTo(&result));
3186 query.setFocus(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/documentElement.xml"))));
3187 QVERIFY(query.evaluateTo(&result));
3190 void tst_QXmlQuery::bindVariableQXmlQuery() const
3192 QFETCH(QString, query1);
3193 QFETCH(QString, query2);
3194 QFETCH(QString, expectedOutput);
3195 QFETCH(bool, expectedSuccess);
3197 MessageSilencer silencer;
3198 QXmlQuery xmlQuery1;
3199 xmlQuery1.setMessageHandler(&silencer);
3200 xmlQuery1.setQuery(query1);
3202 QXmlQuery xmlQuery2(xmlQuery1);
3203 xmlQuery2.bindVariable("query1", xmlQuery1);
3204 xmlQuery2.setQuery(query2);
3207 const bool querySuccess = xmlQuery2.evaluateTo(&output);
3209 QCOMPARE(querySuccess, expectedSuccess);
3212 QCOMPARE(output, expectedOutput);
3215 void tst_QXmlQuery::bindVariableQXmlQuery_data() const
3217 QTest::addColumn<QString>("query1");
3218 QTest::addColumn<QString>("query2");
3219 QTest::addColumn<QString>("expectedOutput");
3220 QTest::addColumn<bool>("expectedSuccess");
3222 QTest::newRow("First query has one atomic value.")
3228 QTest::newRow("First query has two atomic values.")
3234 QTest::newRow("First query is a node.")
3240 /* This is a good test, because it triggers the exception in the
3241 * bindVariable() call, as supposed to when the actual evaluation is done.
3243 QTest::newRow("First query has a dynamic error.")
3246 << QString() /* We don't care. */
3250 void tst_QXmlQuery::bindVariableQStringQXmlQuerySignature() const
3253 query1.setQuery("'dummy'");
3256 const QString name(QLatin1String("name"));
3258 /* We should be able to take a const QXmlQuery reference. Evaluation never mutate
3259 * QXmlQuery, and evaluation is what we do here. */
3260 query2.bindVariable(name, const_cast<const QXmlQuery &>(query1));
3263 void tst_QXmlQuery::bindVariableQXmlNameQXmlQuerySignature() const
3266 QXmlQuery query1(np);
3267 query1.setQuery("'dummy'");
3270 const QXmlName name(np, QLatin1String("name"));
3272 /* We should be able to take a const QXmlQuery reference. Evaluation never mutate
3273 * QXmlQuery, and evaluation is what we do here. */
3274 query2.bindVariable(name, const_cast<const QXmlQuery &>(query1));
3278 Check that the QXmlName is handled correctly.
3280 void tst_QXmlQuery::bindVariableQXmlNameQXmlQuery() const
3284 query1.setQuery(QLatin1String("1"));
3286 QXmlQuery query2(np);
3287 query2.bindVariable(QXmlName(np, QLatin1String("theName")), query1);
3288 query2.setQuery("$theName");
3291 query2.evaluateTo(&result);
3293 QCOMPARE(result, QString::fromLatin1("1\n"));
3296 void tst_QXmlQuery::bindVariableQXmlQueryInvalidate() const
3299 query.bindVariable(QLatin1String("name"), QVariant(1));
3300 query.setQuery("$name");
3301 QVERIFY(query.isValid());
3304 query2.setQuery("'query2'");
3306 query.bindVariable(QLatin1String("name"), query);
3307 QVERIFY(!query.isValid());
3310 void tst_QXmlQuery::unknownSourceLocation() const
3313 b.setData("<a><b/><b/></a>");
3314 b.open(QIODevice::ReadOnly);
3316 MessageSilencer silencer;
3318 query.bindVariable(QLatin1String("inputDocument"), &b);
3319 query.setMessageHandler(&silencer);
3321 query.setQuery(QLatin1String("doc($inputDocument)/a/(let $v := b/string() return if ($v) then $v else ())"));
3324 query.evaluateTo(&output);
3327 void tst_QXmlQuery::identityConstraintSuccess() const
3329 QXmlQuery::QueryLanguage queryLanguage = QXmlQuery::XmlSchema11IdentityConstraintSelector;
3331 /* We run this code for Selector and Field. */
3332 for(int i = 0; i < 3; ++i)
3334 QXmlNamePool namePool;
3335 QXmlResultItems result;
3339 QXmlQuery nodeSource(namePool);
3340 nodeSource.setQuery(QLatin1String("<e/>"));
3342 nodeSource.evaluateTo(&result);
3343 node = result.next();
3347 * 1. The focus is undefined, but it's still valid.
3348 * 2. We never evaluate. */
3350 QXmlQuery query(queryLanguage);
3351 query.setQuery(QLatin1String("a"));
3352 QVERIFY(query.isValid());
3356 * 1. The focus is undefined, but it's still valid.
3357 * 2. We afterwards set the focus. */
3359 QXmlQuery query(queryLanguage, namePool);
3360 query.setQuery(QLatin1String("a"));
3361 query.setFocus(node);
3362 QVERIFY(query.isValid());
3366 * 1. The focus is undefined, but it's still valid.
3367 * 2. We afterwards set the focus.
3368 * 3. We evaluate. */
3370 QXmlQuery query(queryLanguage, namePool);
3371 query.setQuery(QString(QLatin1Char('.')));
3372 query.setFocus(node);
3373 QVERIFY(query.isValid());
3376 QVERIFY(query.evaluateTo(&result));
3377 QCOMPARE(result, QString::fromLatin1("<e/>\n"));
3380 /* A slightly more complex Field. */
3382 QXmlQuery query(queryLanguage);
3383 query.setQuery(QLatin1String("* | .//xml:*/."));
3384 QVERIFY(query.isValid());
3387 /* @ is only allowed in Field. */
3388 if(queryLanguage == QXmlQuery::XmlSchema11IdentityConstraintField)
3390 QXmlQuery query(QXmlQuery::XmlSchema11IdentityConstraintField);
3391 query.setQuery(QLatin1String("@abc"));
3392 QVERIFY(query.isValid());
3395 /* Field allows attribute:: and child:: .*/
3396 if(queryLanguage == QXmlQuery::XmlSchema11IdentityConstraintField)
3398 QXmlQuery query(QXmlQuery::XmlSchema11IdentityConstraintField);
3399 query.setQuery(QLatin1String("attribute::name | child::name"));
3400 QVERIFY(query.isValid());
3403 /* Selector allows only child:: .*/
3405 QXmlQuery query(QXmlQuery::XmlSchema11IdentityConstraintSelector);
3406 query.setQuery(QLatin1String("child::name"));
3407 QVERIFY(query.isValid());
3411 queryLanguage = QXmlQuery::XmlSchema11IdentityConstraintField;
3413 queryLanguage = QXmlQuery::XPath20;
3417 Q_DECLARE_METATYPE(QXmlQuery::QueryLanguage);
3420 We just do some basic tests for boot strapping and sanity checking. The actual regression
3421 testing is in the Schema suite.
3423 void tst_QXmlQuery::identityConstraintFailure() const
3425 QFETCH(QXmlQuery::QueryLanguage, queryLanguage);
3426 QFETCH(QString, inputQuery);
3428 QXmlQuery query(queryLanguage);
3429 MessageSilencer silencer;
3430 query.setMessageHandler(&silencer);
3432 query.setQuery(inputQuery);
3433 QVERIFY(!query.isValid());
3436 void tst_QXmlQuery::identityConstraintFailure_data() const
3438 QTest::addColumn<QXmlQuery::QueryLanguage>("queryLanguage");
3439 QTest::addColumn<QString>("inputQuery");
3441 QTest::newRow("We don't have element constructors in identity constraint pattern, "
3442 "it's an XQuery feature(Selector).")
3443 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3444 << QString::fromLatin1("<e/>");
3446 QTest::newRow("We don't have functions in identity constraint pattern, "
3447 "it's an XPath feature(Selector).")
3448 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3449 << QString::fromLatin1("current-time()");
3451 QTest::newRow("We don't have element constructors in identity constraint pattern, "
3452 "it's an XQuery feature(Field).")
3453 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3454 << QString::fromLatin1("<e/>");
3456 QTest::newRow("We don't have functions in identity constraint pattern, "
3457 "it's an XPath feature(Field).")
3458 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3459 << QString::fromLatin1("current-time()");
3461 QTest::newRow("@attributeName is disallowed for the selector.")
3462 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3463 << QString::fromLatin1("@abc");
3465 QTest::newRow("attribute:: is disallowed for the selector.")
3466 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3467 << QString::fromLatin1("attribute::name");
3469 QTest::newRow("ancestor::name is disallowed for the selector.")
3470 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3471 << QString::fromLatin1("ancestor::name");
3473 QTest::newRow("ancestor::name is disallowed for the field.")
3474 << QXmlQuery::XmlSchema11IdentityConstraintField
3475 << QString::fromLatin1("ancestor::name");
3478 QTEST_MAIN(tst_QXmlQuery)
3480 #include "tst_qxmlquery.moc"
3481 #else //QTEST_XMLPATTERNS