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)
101 void defaultConstructor() const;
102 void copyConstructor() const;
103 void constructorQXmlNamePool() const;
104 void constructorQXmlNamePoolQueryLanguage() const;
105 void constructorQXmlNamePoolWithinQSimpleXmlNodeModel() const;
106 void assignmentOperator() const;
107 void isValid() const;
108 void sequentialExecution() const;
109 void bindVariableQString() const;
110 void bindVariableQStringNoExternalDeclaration() const;
111 void bindVariableQXmlName() const;
112 void bindVariableQXmlNameTriggerWarnings() const;
113 void bindVariableQStringQIODevice() const;
114 void bindVariableQStringQIODeviceWithByteArray() const;
115 void bindVariableQStringQIODeviceWithString() const;
116 void bindVariableQStringQIODeviceWithQFile() const;
117 void bindVariableQXmlNameQIODevice() const;
118 void bindVariableQXmlNameQIODeviceTriggerWarnings() const;
119 void bindVariableXSLTSuccess() const;
120 void bindVariableTemporaryNode() const;
121 void setMessageHandler() const;
122 void messageHandler() const;
123 void evaluateToQAbstractXmlReceiverTriggerWarnings() const;
124 void evaluateToQXmlResultItems() const;
125 void evaluateToQXmlResultItemsTriggerWarnings() const;
126 void evaluateToQXmlResultItemsErrorAtEnd() const;
127 void evaluateToReceiver();
128 void evaluateToReceiver_data() const;
129 void evaluateToReceiverOnInvalidQuery() const;
130 void evaluateToQStringTriggerError() const;
131 void evaluateToQString() const;
132 void evaluateToQString_data() const;
133 void evaluateToQStringSignature() const;
134 void checkGeneratedBaselines() const;
135 void basicXQueryToQtTypeCheck() const;
136 void basicQtToXQueryTypeCheck() const;
137 void bindNode() const;
138 void relativeBaseURI() const;
139 void emptyBaseURI() const;
140 void roundTripDateWithinQXmlItem() const;
141 void bindingMissing() const;
142 void bindDefaultConstructedItem() const;
143 void bindDefaultConstructedItem_data() const;
144 void bindEmptyNullString() const;
145 void bindEmptyString() const;
146 void rebindVariableSameType() const;
147 void rebindVariableDifferentType() const;
148 void rebindVariableWithNullItem() const;
149 void eraseQXmlItemBinding() const;
150 void eraseDeviceBinding() const;
151 void constCorrectness() const;
152 void objectSize() const;
153 void setUriResolver() const;
154 void uriResolver() const;
155 void messageXML() const;
156 void resultItemsDeallocatedQuery() const;
157 void copyCheckMessageHandler() const;
158 void shadowedVariables() const;
159 void setFocusQXmlItem() const;
160 void setFocusQUrl() const;
161 void setFocusQIODevice() const;
162 void setFocusQIODeviceAvoidVariableClash() const;
163 void setFocusQIODeviceFailure() const;
164 void setFocusQIODeviceTriggerWarnings() const;
165 void setFocusQString() const;
166 void setFocusQStringFailure() const;
167 void setFocusQStringSignature() const;
168 void recompilationWithEvaluateToResultFailing() const;
169 void secondEvaluationWithEvaluateToResultFailing() const;
170 void recompilationWithEvaluateToReceiver() const;
171 void fnDocOnQIODeviceTimeout() const;
172 void evaluateToQStringListOnInvalidQuery() const;
173 void evaluateToQStringList() const;
174 void evaluateToQStringListTriggerWarnings() const;
175 void evaluateToQStringList_data() const;
176 void evaluateToQStringListNoConversion() const;
177 void evaluateToQIODevice() const;
178 void evaluateToQIODeviceTriggerWarnings() const;
179 void evaluateToQIODeviceSignature() const;
180 void evaluateToQIODeviceOnInvalidQuery() const;
181 void setQueryQIODeviceQUrl() const;
182 void setQueryQIODeviceQUrlTriggerWarnings() const;
183 void setQueryQString() const;
184 void setQueryQUrlSuccess() const;
185 void setQueryQUrlSuccess_data() const;
186 void setQueryQUrlFailSucceed() const;
187 void setQueryQUrlFailure() const;
188 void setQueryQUrlFailure_data() const;
189 void setQueryQUrlBaseURI() const;
190 void setQueryQUrlBaseURI_data() const;
191 void setQueryWithNonExistentQUrlOnValidQuery() const;
192 void setQueryWithInvalidQueryFromQUrlOnValidQuery() const;
193 void retrieveNameFromQuery() const;
194 void retrieveNameFromQuery_data() const;
195 void cleanupTestCase() const;
196 void declareUnavailableExternal() const;
197 void msvcCacheIssue() const;
198 void unavailableExternalVariable() const;
199 void useUriResolver() const;
200 void queryWithFocusAndVariable() const;
201 void undefinedFocus() const;
202 void basicFocusUsage() const;
204 void queryLanguage() const;
205 void queryLanguageSignature() const;
206 void enumQueryLanguage() const;
208 void setNetworkAccessManager() const;
209 void networkAccessManagerSignature() const;
210 void networkAccessManagerDefaultValue() const;
211 void networkAccessManager() const;
213 void setInitialTemplateNameQXmlName() const;
214 void setInitialTemplateNameQXmlNameSignature() const;
215 void setInitialTemplateNameQString() const;
216 void setInitialTemplateNameQStringSignature() const;
217 void initialTemplateName() const;
218 void initialTemplateNameSignature() const;
220 void fnDocNetworkAccessSuccess() const;
221 void fnDocNetworkAccessSuccess_data() const;
222 void fnDocNetworkAccessFailure() const;
223 void fnDocNetworkAccessFailure_data() const;
224 void multipleDocsAndFocus() const;
225 void multipleEvaluationsWithDifferentFocus() const;
226 void bindVariableQXmlQuery() const;
227 void bindVariableQXmlQuery_data() const;
228 void bindVariableQStringQXmlQuerySignature() const;
229 void bindVariableQXmlNameQXmlQuerySignature() const;
230 void bindVariableQXmlNameQXmlQuery() const;
231 void bindVariableQXmlQueryInvalidate() const;
232 void unknownSourceLocation() const;
234 void identityConstraintSuccess() const;
235 void identityConstraintFailure() const;
236 void identityConstraintFailure_data() const;
238 // 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.
239 // TODO bind stringlists, variant lists, both ways.
240 // TODO trigger serialization error, or any error in evaluateToushCallback().
241 // TODO let items travle between two queries, as seen in the SDK
242 // TODO what happens if the query declares local variable and external ones are provided?
248 * One excluded, since we skip static-base-uri.xq.
250 ExpectedQueryCount = 29
253 static void checkBaseURI(const QUrl &baseURI, const QString &candidate);
254 static QStringList queries();
255 static const char *const queriesDirectory;
257 int m_generatedBaselines;
258 int m_pushTestsCount;
259 const bool m_testNetwork;
262 void tst_QXmlQuery::checkBaseURI(const QUrl &baseURI, const QString &candidate)
264 /* The use of QFileInfo::canonicalFilePath() takes into account that drive letters
265 * on Windows may have different cases. */
266 QVERIFY(QDir(baseURI.toLocalFile()).relativeFilePath(QFileInfo(candidate).canonicalFilePath()).startsWith("../"));
269 const char *const tst_QXmlQuery::queriesDirectory = XMLPATTERNSDIR "/queries/";
271 QStringList tst_QXmlQuery::queries()
274 dir.cd(inputFile(QLatin1String(queriesDirectory)));
276 return dir.entryList(QStringList(QLatin1String("*.xq")));
279 void tst_QXmlQuery::defaultConstructor() const
281 /* Allocate instance in different orders. */
298 void tst_QXmlQuery::copyConstructor() const
300 /* Verify that we can take a const reference, and simply do a copy of a default constructed object. */
302 const QXmlQuery query1;
303 QXmlQuery query2(query1);
308 const QXmlQuery query1;
309 QXmlQuery query2(query1);
310 QXmlQuery query3(query2);
313 /* Verify that copying default values works. */
315 const QXmlQuery query1;
316 const QXmlQuery query2(query1);
317 QCOMPARE(query2.messageHandler(), query1.messageHandler());
318 QCOMPARE(query2.uriResolver(), query1.uriResolver());
319 QCOMPARE(query2.queryLanguage(), query1.queryLanguage());
320 QCOMPARE(query2.initialTemplateName(), query1.initialTemplateName());
321 QCOMPARE(query2.networkAccessManager(), query1.networkAccessManager());
330 * - initial template name
332 * sticks with the copy. */
334 MessageSilencer silencer;
335 TestURIResolver resolver;
336 QNetworkAccessManager networkManager;
337 QXmlQuery query1(QXmlQuery::XSLT20);
338 QXmlNamePool np1(query1.namePool());
340 query1.setMessageHandler(&silencer);
341 query1.setUriResolver(&resolver);
342 query1.setNetworkAccessManager(&networkManager);
344 const QXmlName name(np1, QLatin1String("localName"),
345 QLatin1String("http://example.com/"),
346 QLatin1String("prefix"));
347 query1.setInitialTemplateName(name);
349 const QXmlQuery query2(query1);
350 QCOMPARE(query2.messageHandler(), static_cast<QAbstractMessageHandler *>(&silencer));
351 QCOMPARE(query2.uriResolver(), static_cast<const QAbstractUriResolver *>(&resolver));
352 QCOMPARE(query2.queryLanguage(), QXmlQuery::XSLT20);
353 QCOMPARE(query2.initialTemplateName(), name);
354 QCOMPARE(query2.networkAccessManager(), &networkManager);
356 QXmlNamePool np2(query2.namePool());
358 QCOMPARE(name.namespaceUri(np2), QString::fromLatin1("http://example.com/"));
359 QCOMPARE(name.localName(np2), QString::fromLatin1("localName"));
360 QCOMPARE(name.prefix(np2), QString::fromLatin1("prefix"));
366 original.setFocus(QXmlItem(4));
367 original.setQuery(QLatin1String("."));
368 QVERIFY(original.isValid());
370 const QXmlQuery copy(original);
372 QXmlResultItems result;
373 copy.evaluateTo(&result);
374 QCOMPARE(result.next().toAtomicValue(), QVariant(4));
375 QVERIFY(result.next().isNull());
376 QVERIFY(!result.hasError());
379 /* Copy, set, compare. Check that copies are independent. */
381 // TODO all members except queryLanguage().
385 void tst_QXmlQuery::constructorQXmlNamePool() const
387 /* Check that the namepool we are passed, is actually used. */
391 const QXmlName name(np, QLatin1String("localName"),
392 QLatin1String("http://example.com/"),
393 QLatin1String("prefix"));
395 QXmlNamePool np2(query.namePool());
396 QCOMPARE(name.namespaceUri(np2), QString::fromLatin1("http://example.com/"));
397 QCOMPARE(name.localName(np2), QString::fromLatin1("localName"));
398 QCOMPARE(name.prefix(np2), QString::fromLatin1("prefix"));
402 Ensure that the internal variable loading mechanisms uses the user-supplied
405 If that is not the case, different name pools are used and the code crashes.
409 void tst_QXmlQuery::constructorQXmlNamePoolQueryLanguage() const
412 QXmlName name(np, QLatin1String("arbitraryName"));
414 QXmlQuery query(QXmlQuery::XQuery10, np);
417 input.setData("<yall/>");
419 QVERIFY(input.open(QIODevice::ReadOnly));
420 query.bindVariable(name, &input);
421 query.setQuery("string(doc($arbitraryName))");
424 query.evaluateTo(&result);
427 void tst_QXmlQuery::constructorQXmlNamePoolWithinQSimpleXmlNodeModel() const
429 class TestCTOR : public TestSimpleNodeModel
432 TestCTOR(const QXmlNamePool &np) : TestSimpleNodeModel(np)
436 void checkCTOR() const
438 /* If this fails to compile, the constructor has trouble with taking
439 * a mutable reference.
441 * The reason we use the this pointer explicitly, is to avoid a compiler
442 * warnings with MSVC 2005. */
443 QXmlQuery(this->namePool());
452 void tst_QXmlQuery::assignmentOperator() const
454 class ReturnURI : public QAbstractUriResolver
458 virtual QUrl resolve(const QUrl &relative,
459 const QUrl &baseURI) const
461 return baseURI.resolved(relative);
465 /* Assign this to this. */
472 /* Just call a couple of functions to give valgrind
473 * something to check. */
474 QVERIFY(!query.isValid());
475 query.messageHandler();
478 /* Assign null instances a couple of times. */
486 /* Just call a couple of functions to give valgrind
487 * something to check. */
488 QVERIFY(!query1.isValid());
489 query1.messageHandler();
491 /* Just call a couple of functions to give valgrind
492 * something to check. */
493 QVERIFY(!query2.isValid());
494 query2.messageHandler();
497 /* Create a query, set all the things it stores, and ensure it
498 * travels over to the new instance. */
500 MessageSilencer silencer;
501 const ReturnURI returnURI;
502 QXmlNamePool namePool;
504 QBuffer documentDevice;
505 documentDevice.setData(QByteArray("<e>a</e>"));
506 QVERIFY(documentDevice.open(QIODevice::ReadOnly));
508 QXmlQuery original(namePool);
509 QXmlName testName(namePool, QLatin1String("somethingToCheck"));
511 original.setMessageHandler(&silencer);
512 original.bindVariable(QLatin1String("var"), QXmlItem(1));
513 original.bindVariable(QLatin1String("device"), &documentDevice);
514 original.setUriResolver(&returnURI);
515 original.setFocus(QXmlItem(3));
516 original.setQuery(QLatin1String("$var, 1 + 1, ., string(doc($device))"));
518 /* Do a copy, and check that everything followed on into the copy. No modification
523 /* We use assignment operator, not copy constructor. */
526 QVERIFY(copy.isValid());
527 QCOMPARE(copy.uriResolver(), static_cast<const QAbstractUriResolver *>(&returnURI));
528 QCOMPARE(copy.messageHandler(), static_cast<QAbstractMessageHandler *>(&silencer));
529 QCOMPARE(testName.localName(copy.namePool()), QString::fromLatin1("somethingToCheck"));
531 QXmlResultItems result;
532 copy.evaluateTo(&result);
533 QCOMPARE(result.next().toAtomicValue(), QVariant(1));
534 QCOMPARE(result.next().toAtomicValue(), QVariant(2));
535 QCOMPARE(result.next().toAtomicValue(), QVariant(3));
536 QCOMPARE(result.next().toAtomicValue(), QVariant(QString::fromLatin1("a")));
537 QVERIFY(result.next().isNull());
538 QVERIFY(!result.hasError());
541 /* Copy, and change values. Things should detach. */
543 /* Evaluate the copy. */
545 MessageSilencer secondSilencer;
546 const ReturnURI secondUriResolver;
547 QBuffer documentDeviceCopy;
548 documentDeviceCopy.setData(QByteArray("<e>b</e>"));
549 QVERIFY(documentDeviceCopy.open(QIODevice::ReadOnly));
554 copy.setMessageHandler(&secondSilencer);
555 /* Here we rebind variable values. */
556 copy.bindVariable(QLatin1String("var"), QXmlItem(4));
557 copy.bindVariable(QLatin1String("device"), &documentDeviceCopy);
558 copy.setUriResolver(&secondUriResolver);
559 copy.setFocus(QXmlItem(6));
560 copy.setQuery(QLatin1String("$var, 1 + 1, ., string(doc($device))"));
562 /* Check that the copy picked up the new things. */
563 QVERIFY(copy.isValid());
564 QCOMPARE(copy.uriResolver(), static_cast<const QAbstractUriResolver *>(&secondUriResolver));
565 QCOMPARE(copy.messageHandler(), static_cast<QAbstractMessageHandler *>(&secondSilencer));
567 QXmlResultItems resultCopy;
568 copy.evaluateTo(&resultCopy);
569 QCOMPARE(resultCopy.next().toAtomicValue(), QVariant(4));
570 QCOMPARE(resultCopy.next().toAtomicValue(), QVariant(2));
571 QCOMPARE(resultCopy.next().toAtomicValue(), QVariant(6));
572 const QString stringedDevice(resultCopy.next().toAtomicValue().toString());
573 QCOMPARE(stringedDevice, QString::fromLatin1("b"));
574 QVERIFY(resultCopy.next().isNull());
575 QVERIFY(!resultCopy.hasError());
578 /* Evaluate the original. */
580 /* Check that the original is unchanged. */
581 QVERIFY(original.isValid());
582 QCOMPARE(original.uriResolver(), static_cast<const QAbstractUriResolver *>(&returnURI));
583 QCOMPARE(original.messageHandler(), static_cast<QAbstractMessageHandler *>(&silencer));
585 QXmlResultItems resultOriginal;
586 original.evaluateTo(&resultOriginal);
587 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(1));
588 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(2));
589 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(3));
590 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(QString::fromLatin1("a")));
591 QVERIFY(resultOriginal.next().isNull());
592 QVERIFY(!resultOriginal.hasError());
599 Since QXmlQuery doesn't seek devices to position 0, this code triggers a bug
600 where document caching doesn't work. Since the document caching doesn't work,
601 the device will be read twice, and the second time the device is at the end,
602 hence premature end of document.
604 void tst_QXmlQuery::sequentialExecution() const
607 inBuffer.setData(QByteArray("<input/>"));
608 QVERIFY(inBuffer.open(QIODevice::ReadOnly));
611 query.bindVariable("inputDocument", &inBuffer);
614 QBuffer outBuffer(&outArray);
615 outBuffer.open(QIODevice::WriteOnly);
617 const QString queryString(QLatin1String("doc($inputDocument)"));
618 query.setQuery(queryString);
620 QXmlFormatter formatter(query, &outBuffer);
622 QVERIFY(query.evaluateTo(&formatter));
624 /* If this line is removed, the bug isn't triggered. */
625 query.setQuery(queryString);
627 QVERIFY(query.evaluateTo(&formatter));
630 void tst_QXmlQuery::isValid() const
632 /* Check default value. */
634 QVERIFY(!query.isValid());
637 void tst_QXmlQuery::bindVariableQString() const
641 /* Bind with a null QXmlItem. */
642 query.bindVariable(QLatin1String("name"), QXmlItem());
647 /* Bind with a null QVariant. */
648 query.bindVariable(QLatin1String("name"), QXmlItem(QVariant()));
653 /* Bind with a null QXmlNodeModelIndex. */
654 query.bindVariable(QLatin1String("name"), QXmlItem(QXmlNodeModelIndex()));
658 void tst_QXmlQuery::bindVariableQStringNoExternalDeclaration() const
661 query.bindVariable(QLatin1String("foo"), QXmlItem(QLatin1String("Variable Value")));
662 query.setQuery(QLatin1String("$foo"));
664 QVERIFY(query.isValid());
667 QVERIFY(query.evaluateTo(&result));
669 QCOMPARE(result, QStringList() << QLatin1String("Variable Value"));
672 void tst_QXmlQuery::bindVariableQXmlName() const
677 void tst_QXmlQuery::bindVariableQXmlNameTriggerWarnings() const
681 QTest::ignoreMessage(QtWarningMsg, "The variable name cannot be null.");
682 query.bindVariable(QXmlName(), QVariant());
685 void tst_QXmlQuery::bindVariableQStringQIODeviceWithByteArray() const
689 QByteArray in("<e/>");
691 QVERIFY(device.open(QIODevice::ReadOnly));
693 query.bindVariable("doc", &device);
695 query.setQuery(QLatin1String("declare variable $doc external; $doc"));
697 QVERIFY(query.isValid());
699 /* Check the URI corresponding to the variable. */
701 QXmlResultItems items;
702 query.evaluateTo(&items);
704 QCOMPARE(items.next().toAtomicValue().toString(), QString::fromLatin1("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:doc"));
707 /* Now, actually load the document. We use the same QXmlQuery just to stress recompilation a bit. */
709 query.setQuery(QLatin1String("declare variable $doc external; doc($doc)"));
712 QBuffer outBuffer(&out);
713 QVERIFY(outBuffer.open(QIODevice::WriteOnly));
715 QXmlSerializer serializer(query, &outBuffer);
717 QVERIFY(query.evaluateTo(&serializer));
722 void tst_QXmlQuery::bindVariableQStringQIODeviceWithString() const
726 QString in("<qstring/>");
727 QByteArray inUtf8(in.toUtf8());
728 QBuffer inDevice(&inUtf8);
730 QVERIFY(inDevice.open(QIODevice::ReadOnly));
732 query.bindVariable("doc", &inDevice);
734 query.setQuery(QLatin1String("declare variable $doc external; doc($doc)"));
737 QBuffer outBuffer(&out);
738 QVERIFY(outBuffer.open(QIODevice::WriteOnly));
740 QXmlSerializer serializer(query, &outBuffer);
741 QVERIFY(query.evaluateTo(&serializer));
743 QCOMPARE(out, inUtf8);
746 void tst_QXmlQuery::bindVariableQStringQIODeviceWithQFile() const
749 QFile inDevice(QLatin1String(SRCDIR "input.xml"));
751 QVERIFY(inDevice.open(QIODevice::ReadOnly));
753 query.bindVariable("doc", &inDevice);
755 query.setQuery(QLatin1String("declare variable $doc external; doc($doc)"));
758 QBuffer outBuffer(&out);
759 QVERIFY(outBuffer.open(QIODevice::WriteOnly));
761 QXmlSerializer serializer(query, &outBuffer);
762 QVERIFY(query.evaluateTo(&serializer));
765 QCOMPARE(out, QByteArray("<!-- This is just a file for testing. --><input/>"));
768 void tst_QXmlQuery::bindVariableQStringQIODevice() const
772 /* Rebind the variable. */
774 /* First evaluation. */
776 QByteArray in1("<e1/>");
777 QBuffer inDevice1(&in1);
778 QVERIFY(inDevice1.open(QIODevice::ReadOnly));
780 query.bindVariable("in", &inDevice1);
781 query.setQuery(QLatin1String("doc($in)"));
784 QBuffer outDevice1(&out1);
785 QVERIFY(outDevice1.open(QIODevice::WriteOnly));
787 QXmlSerializer serializer(query, &outDevice1);
788 query.evaluateTo(&serializer);
792 /* Second evaluation, rebind variable. */
794 QByteArray in2("<e2/>");
795 QBuffer inDevice2(&in2);
796 QVERIFY(inDevice2.open(QIODevice::ReadOnly));
798 query.bindVariable(QLatin1String("in"), &inDevice2);
801 QBuffer outDevice2(&out2);
802 QVERIFY(outDevice2.open(QIODevice::WriteOnly));
804 QXmlSerializer serializer(query, &outDevice2);
805 QVERIFY(query.evaluateTo(&serializer));
810 // TODO trigger recompilation when setting qiodevices., and qiodevice overwritten by other type, etc.
813 void tst_QXmlQuery::bindVariableQXmlNameQIODevice() const
818 void tst_QXmlQuery::bindVariableQXmlNameQIODeviceTriggerWarnings() const
824 QTest::ignoreMessage(QtWarningMsg, "A null, or readable QIODevice must be passed.");
825 query.bindVariable(QXmlName(np, QLatin1String("foo")), &buffer);
827 QTest::ignoreMessage(QtWarningMsg, "The variable name cannot be null.");
828 query.bindVariable(QXmlName(), 0);
831 void tst_QXmlQuery::bindVariableXSLTSuccess() const
833 QXmlQuery stylesheet(QXmlQuery::XSLT20);
834 stylesheet.setInitialTemplateName(QLatin1String("main"));
836 stylesheet.bindVariable(QLatin1String("variableNoSelectNoBodyBoundWithBindVariable"),
837 QVariant(QLatin1String("MUST NOT SHOW 1")));
839 stylesheet.bindVariable(QLatin1String("variableSelectBoundWithBindVariable"),
840 QVariant(QLatin1String("MUST NOT SHOW 2")));
842 stylesheet.bindVariable(QLatin1String("variableSelectWithTypeIntBoundWithBindVariable"),
843 QVariant(QLatin1String("MUST NOT SHOW 3")));
845 stylesheet.bindVariable(QLatin1String("paramNoSelectNoBodyBoundWithBindVariable"),
846 QVariant(QLatin1String("param1")));
848 stylesheet.bindVariable(QLatin1String("paramNoSelectNoBodyBoundWithBindVariableRequired"),
849 QVariant(QLatin1String("param1")));
851 stylesheet.bindVariable(QLatin1String("paramSelectBoundWithBindVariable"),
852 QVariant(QLatin1String("param2")));
854 stylesheet.bindVariable(QLatin1String("paramSelectBoundWithBindVariableRequired"),
855 QVariant(QLatin1String("param3")));
857 stylesheet.bindVariable(QLatin1String("paramSelectWithTypeIntBoundWithBindVariable"),
860 stylesheet.bindVariable(QLatin1String("paramSelectWithTypeIntBoundWithBindVariableRequired"),
861 QVariant(QLatin1String("param5")));
863 stylesheet.setQuery(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/parameters.xsl"))));
865 QVERIFY(stylesheet.isValid());
868 QVERIFY(deviceOut.open(QIODevice::ReadWrite));
870 QVERIFY(stylesheet.evaluateTo(&deviceOut));
872 const QString result(QString::fromUtf8(deviceOut.data().constData()));
875 QString::fromLatin1("Variables: variableSelectsDefaultValue variableSelectsDefaultValue2 3 4 "
876 "Parameters: param1 param1 param2 param3 4 param5"));
879 void tst_QXmlQuery::bindVariableTemporaryNode() const
881 /* First we do it with QXmlResultItems staying in scope. */;
884 query1.setQuery("<anElement/>");
886 QXmlResultItems result1;
887 query1.evaluateTo(&result1);
889 QXmlQuery query2(query1);
890 query2.bindVariable("fromQuery1", result1.next());
891 query2.setQuery("$fromQuery1");
894 QVERIFY(query2.evaluateTo(&output));
896 QCOMPARE(output, QString::fromLatin1("<anElement/>\n"));
899 /* And now with it deallocating, so its internal DynamicContext pointer is
900 * released. This doesn't work in Qt 4.5 and is ok. */
903 query1.setQuery("<anElement/>");
908 QXmlResultItems result1;
909 query1.evaluateTo(&result1);
911 query2.bindVariable("fromQuery1", result1.next());
912 query2.setQuery("$fromQuery1");
916 return; // See comment above.
917 QVERIFY(query2.evaluateTo(&output));
919 QCOMPARE(output, QString::fromLatin1("<anElement/>\n"));
923 void tst_QXmlQuery::messageHandler() const
926 /* Check default value. */
928 QCOMPARE(query.messageHandler(), static_cast<QAbstractMessageHandler *>(0));
932 void tst_QXmlQuery::setMessageHandler() const
935 MessageSilencer silencer;
936 query.setMessageHandler(&silencer);
937 QCOMPARE(static_cast<QAbstractMessageHandler *>(&silencer), query.messageHandler());
940 void tst_QXmlQuery::evaluateToReceiver()
942 QFETCH(QString, inputQuery);
944 /* This query prints a URI specific to the local system. */
945 if(inputQuery == QLatin1String("static-base-uri.xq"))
949 const QString queryURI(inputFile(QLatin1String(queriesDirectory) + inputQuery));
950 QFile queryFile(queryURI);
952 QVERIFY(queryFile.exists());
953 QVERIFY(queryFile.open(QIODevice::ReadOnly));
957 MessageSilencer receiver;
958 query.setMessageHandler(&receiver);
959 query.setQuery(&queryFile, QUrl::fromLocalFile(queryURI));
961 /* We read all the queries, and some of them are invalid. However, we
962 * only want those that compile. */
967 QTextStream stream(&produced, QIODevice::WriteOnly);
968 PushBaseliner push(stream, query.namePool());
969 QVERIFY(push.isValid());
970 query.evaluateTo(&push);
972 const QString baselineName(inputFile(QLatin1String(SRCDIR "pushBaselines/") + inputQuery.left(inputQuery.length() - 2) + QString::fromLatin1("ref")));
973 QFile baseline(baselineName);
975 if(baseline.exists())
977 QVERIFY(baseline.open(QIODevice::ReadOnly | QIODevice::Text));
978 const QString stringedBaseline(QString::fromUtf8(baseline.readAll()));
979 QCOMPARE(produced, stringedBaseline);
983 QVERIFY(baseline.open(QIODevice::WriteOnly));
984 /* This is intentionally a warning, don't remove it. Update the baselines instead. */
985 qWarning() << "Generated baseline for:" << baselineName;
986 ++m_generatedBaselines;
988 baseline.write(produced.toUtf8());
992 void tst_QXmlQuery::evaluateToReceiver_data() const
994 QTest::addColumn<QString>("inputQuery");
996 foreach (QString const& query, queries())
998 /* This outputs a URI specific to the environment, so we can't use it for this
999 * particular test. */
1000 if (query != QLatin1String("staticBaseURI.xq"))
1001 QTest::newRow(query.toUtf8().constData()) << query;
1005 void tst_QXmlQuery::evaluateToReceiverOnInvalidQuery() const
1007 /* Invoke on a default constructed object. */
1010 QBuffer buffer(&out);
1011 buffer.open(QIODevice::WriteOnly);
1014 QXmlSerializer serializer(query, &buffer);
1015 QVERIFY(!query.evaluateTo(&serializer));
1018 /* Invoke on an invalid query; compile time error. */
1021 QBuffer buffer(&out);
1022 buffer.open(QIODevice::WriteOnly);
1023 MessageSilencer silencer;
1026 query.setMessageHandler(&silencer);
1027 query.setQuery(QLatin1String("1 + "));
1028 QXmlSerializer serializer(query, &buffer);
1029 QVERIFY(!query.evaluateTo(&serializer));
1032 /* Invoke on an invalid query; runtime error. */
1035 QBuffer buffer(&out);
1036 buffer.open(QIODevice::WriteOnly);
1037 MessageSilencer silencer;
1040 query.setMessageHandler(&silencer);
1041 query.setQuery(QLatin1String("error()"));
1042 QXmlSerializer serializer(query, &buffer);
1043 QVERIFY(!query.evaluateTo(&serializer));
1047 void tst_QXmlQuery::evaluateToQStringTriggerError() const
1049 /* Invoke on a default constructed object. */
1053 QVERIFY(!query.evaluateTo(&out));
1056 /* Invoke on an invalid query; compile time error. */
1059 MessageSilencer silencer;
1060 query.setMessageHandler(&silencer);
1062 query.setQuery(QLatin1String("1 + "));
1065 QVERIFY(!query.evaluateTo(&out));
1068 /* Invoke on an invalid query; runtime error. */
1071 MessageSilencer silencer;
1072 query.setMessageHandler(&silencer);
1074 query.setQuery(QLatin1String("error()"));
1077 QVERIFY(!query.evaluateTo(&out));
1081 void tst_QXmlQuery::evaluateToQString() const
1083 QFETCH(QString, query);
1084 QFETCH(QString, expectedOutput);
1086 QXmlQuery queryInstance;
1087 queryInstance.setQuery(query);
1088 QVERIFY(queryInstance.isValid());
1091 QVERIFY(queryInstance.evaluateTo(&result));
1093 QCOMPARE(result, expectedOutput);
1096 void tst_QXmlQuery::evaluateToQString_data() const
1098 QTest::addColumn<QString>("query");
1099 QTest::addColumn<QString>("expectedOutput");
1101 QTest::newRow("Two atomics")
1102 << QString::fromLatin1("1, 'two'")
1103 << QString::fromLatin1("1 two\n");
1105 QTest::newRow("An element")
1106 << QString::fromLatin1("<e>{1}</e>")
1107 << QString::fromLatin1("<e>1</e>\n");
1110 void tst_QXmlQuery::evaluateToQStringSignature() const
1112 const QXmlQuery query;
1116 /* evaluateTo(QString *) should be a const function. */
1117 query.evaluateTo(&output);
1120 void tst_QXmlQuery::evaluateToQAbstractXmlReceiverTriggerWarnings() const
1124 /* We check the return value as well as warning message here. */
1125 QTest::ignoreMessage(QtWarningMsg, "A non-null callback must be passed.");
1126 QCOMPARE(query.evaluateTo(static_cast<QAbstractXmlReceiver *>(0)),
1130 void tst_QXmlQuery::evaluateToQXmlResultItems() const
1132 /* Invoke on a default constructed object. */
1135 QXmlResultItems result;
1136 query.evaluateTo(&result);
1137 QVERIFY(result.next().isNull());
1141 void tst_QXmlQuery::evaluateToQXmlResultItemsTriggerWarnings() const
1143 QTest::ignoreMessage(QtWarningMsg, "A null pointer cannot be passed.");
1145 query.evaluateTo(static_cast<QXmlResultItems *>(0));
1148 void tst_QXmlQuery::evaluateToQXmlResultItemsErrorAtEnd() const
1151 MessageSilencer silencer;
1152 query.setMessageHandler(&silencer);
1153 query.setQuery(QLatin1String("1 to 100, fn:error()"));
1154 QVERIFY(query.isValid());
1157 query.evaluateTo(&it);
1159 while(!it.next().isNull())
1165 If baselines were generated, we flag it as a failure such that it gets
1166 attention, and that they are adjusted accordingly.
1168 void tst_QXmlQuery::checkGeneratedBaselines() const
1170 QCOMPARE(m_generatedBaselines, 0);
1172 /* If this check fails, the auto test setup is misconfigured, or files have
1173 * been added/removed without this number being updated. */
1174 QCOMPARE(m_pushTestsCount, int(ExpectedQueryCount));
1177 void tst_QXmlQuery::basicXQueryToQtTypeCheck() const
1179 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("allAtomics.xq"));
1180 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1183 query.setQuery(&queryFile);
1184 QVERIFY(query.isValid());
1187 query.evaluateTo(&it);
1189 QVariantList expectedValues;
1190 expectedValues.append(QString::fromLatin1("xs:untypedAtomic"));
1191 expectedValues.append(QDateTime(QDate(2002, 10, 10), QTime(23, 2, 11), Qt::UTC));
1192 expectedValues.append(QDate(2002, 10, 10));
1193 expectedValues.append(QVariant()); /* We currently doesn't support xs:time through the API. */
1195 expectedValues.append(QVariant()); /* xs:duration */
1196 expectedValues.append(QVariant()); /* xs:dayTimeDuration */
1197 expectedValues.append(QVariant()); /* xs:yearMonthDuration */
1199 if(sizeof(qreal) == sizeof(float)) {//ARM casts to Float not to double
1200 expectedValues.append(QVariant(float(3e3))); /* xs:float */
1201 expectedValues.append(QVariant(float(4e4))); /* xs:double */
1202 expectedValues.append(QVariant(float(2))); /* xs:decimal */
1204 expectedValues.append(QVariant(double(3e3))); /* xs:float */
1205 expectedValues.append(QVariant(double(4e4))); /* xs:double */
1206 expectedValues.append(QVariant(double(2))); /* xs:decimal */
1209 /* xs:integer and its sub-types. */
1210 expectedValues.append(QVariant(qlonglong(16)));
1211 expectedValues.append(QVariant(qlonglong(-6)));
1212 expectedValues.append(QVariant(qlonglong(-4)));
1213 expectedValues.append(QVariant(qlonglong(5)));
1214 expectedValues.append(QVariant(qlonglong(6)));
1215 expectedValues.append(QVariant(qlonglong(7)));
1216 expectedValues.append(QVariant(qlonglong(8)));
1217 expectedValues.append(QVariant(qlonglong(9)));
1218 expectedValues.append(QVariant(qulonglong(10)));
1219 expectedValues.append(QVariant(qlonglong(11)));
1220 expectedValues.append(QVariant(qlonglong(12)));
1221 expectedValues.append(QVariant(qlonglong(13)));
1222 expectedValues.append(QVariant(qlonglong(14)));
1224 expectedValues.append(QVariant()); /* xs:gYearMonth("1976-02"), */
1225 expectedValues.append(QVariant()); /* xs:gYear("2005-12:00"), */
1226 expectedValues.append(QVariant()); /* xs:gMonthDay("--12-25-14:00"), */
1227 expectedValues.append(QVariant()); /* xs:gDay("---25-14:00"), */
1228 expectedValues.append(QVariant()); /* xs:gMonth("--12-14:00"), */
1229 expectedValues.append(true); /* xs:boolean("true"), */
1230 expectedValues.append(QVariant(QByteArray::fromBase64(QByteArray("aaaa")))); /* xs:base64Binary("aaaa"), */
1231 expectedValues.append(QVariant(QByteArray::fromHex(QByteArray("FFFF")))); /* xs:hexBinary("FFFF"), */
1232 expectedValues.append(QVariant(QString::fromLatin1("http://example.com/"))); /* xs:anyURI("http://example.com/"), */
1233 QXmlNamePool np(query.namePool());
1234 expectedValues.append(QVariant(qVariantFromValue(QXmlName(np, QLatin1String("localName"),
1235 QLatin1String("http://example.com/2"),
1236 QLatin1String("prefix")))));
1238 expectedValues.append(QVariant(QString::fromLatin1("An xs:string")));
1239 expectedValues.append(QVariant(QString::fromLatin1("normalizedString")));
1240 expectedValues.append(QVariant(QString::fromLatin1("token")));
1241 expectedValues.append(QVariant(QString::fromLatin1("language")));
1242 expectedValues.append(QVariant(QString::fromLatin1("NMTOKEN")));
1243 expectedValues.append(QVariant(QString::fromLatin1("Name")));
1244 expectedValues.append(QVariant(QString::fromLatin1("NCName")));
1245 expectedValues.append(QVariant(QString::fromLatin1("ID")));
1246 expectedValues.append(QVariant(QString::fromLatin1("IDREF")));
1247 expectedValues.append(QVariant(QString::fromLatin1("ENTITY")));
1250 QXmlItem item(it.next());
1252 while(!item.isNull())
1254 QVERIFY(item.isAtomicValue());
1255 const QVariant produced(item.toAtomicValue());
1257 const QVariant &expected = expectedValues.at(i);
1259 /* For the cases where we can't represent a value in the XDM with Qt,
1260 * we return an invalid QVariant. */
1261 QCOMPARE(expected.isValid(), produced.isValid());
1263 QCOMPARE(produced.type(), expected.type());
1265 if(expected.isValid())
1267 /* This is only needed for xs:decimal though, for some reason. Probably
1268 * just artifacts created somewhere. */
1269 if(produced.type() == QVariant::Double)
1270 QVERIFY(qFuzzyCompare(produced.toDouble(), expected.toDouble()));
1271 else if(qVariantCanConvert<QXmlName>(produced))
1273 /* QVariant::operator==() does identity comparison, it doesn't delegate to operator==() of
1274 * the contained type, unless it's hardcoded into QVariant. */
1275 const QXmlName n1 = qVariantValue<QXmlName>(produced);
1276 const QXmlName n2 = qVariantValue<QXmlName>(expected);
1280 QCOMPARE(produced, expected);
1287 QCOMPARE(i, expectedValues.count());
1291 Send values from Qt into XQuery.
1293 void tst_QXmlQuery::basicQtToXQueryTypeCheck() const
1295 QFile queryFile(QLatin1String(queriesDirectory) + QLatin1String("allAtomicsExternally.xq"));
1296 QVERIFY(queryFile.exists());
1297 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1299 QCOMPARE(QVariant(QDate(1999, 9, 10)).type(), QVariant::Date);
1303 QXmlNamePool np(query.namePool());
1305 const QXmlName name(np, QLatin1String("localname"),
1306 QLatin1String("http://example.com"),
1307 QLatin1String("prefix"));
1309 query.bindVariable(QLatin1String("fromQUrl"), QXmlItem(QUrl(QString::fromLatin1("http://example.com/"))));
1310 query.bindVariable(QLatin1String("fromQByteArray"), QXmlItem(QByteArray("AAAA")));
1311 query.bindVariable(QLatin1String("fromBool"), QXmlItem(bool(true)));
1312 query.bindVariable(QLatin1String("fromQDate"), QXmlItem(QDate(2000, 10, 11)));
1313 // TODO Do with different QDateTime time specs
1314 query.bindVariable(QLatin1String("fromQDateTime"), QXmlItem(QDateTime(QDate(2001, 9, 10), QTime(1, 2, 3))));
1315 query.bindVariable(QLatin1String("fromDouble"), QXmlItem(double(3)));
1316 query.bindVariable(QLatin1String("fromFloat"), QXmlItem(float(4)));
1317 query.bindVariable(QLatin1String("integer"), QXmlItem(5));
1318 query.bindVariable(QLatin1String("fromQString"), QXmlItem(QString::fromLatin1("A QString")));
1319 query.bindVariable(QLatin1String("fromQChar"), QXmlItem(QChar::fromLatin1('C')));
1321 query.bindVariable(QLatin1String("fromIntLiteral"), QXmlItem(QVariant(654)));
1324 QVariant ui(uint(5));
1325 QCOMPARE(ui.type(), QVariant::UInt);
1326 query.bindVariable(QLatin1String("fromUInt"), ui);
1330 QVariant ulnglng(qulonglong(6));
1331 QCOMPARE(ulnglng.type(), QVariant::ULongLong);
1332 query.bindVariable(QLatin1String("fromULongLong"), ulnglng);
1336 QVariant qlnglng(qlonglong(7));
1337 QCOMPARE(qlnglng.type(), QVariant::LongLong);
1338 query.bindVariable(QLatin1String("fromLongLong"), qlnglng);
1341 query.setQuery(&queryFile);
1343 // TODO do queries which declares external variables with types. Tons of combos here.
1344 // TODO ensure that binding with QXmlItem() doesn't make a binding available.
1345 // TODO test rebinding a variable.
1347 QVERIFY(query.isValid());
1350 query.evaluateTo(&it);
1351 QXmlItem item(it.next());
1352 QVERIFY(!item.isNull());
1353 QVERIFY(item.isAtomicValue());
1355 if(sizeof(qreal) == sizeof(float)) //ARM casts to Float not to double
1356 QCOMPARE(item.toAtomicValue().toString(),
1357 QLatin1String("4 true 3 654 7 41414141 C 2000-10-11Z 2001-09-10T01:02:03 "
1358 "A QString http://example.com/ 5 6 true false false true true true true true true true "
1361 QCOMPARE(item.toAtomicValue().toString(),
1362 QLatin1String("4 true 3 654 7 41414141 C 2000-10-11Z 2001-09-10T01:02:03 "
1363 "A QString http://example.com/ 5 6 true true true true true true true true true true "
1368 void tst_QXmlQuery::bindNode() const
1371 TestSimpleNodeModel nodeModel(query.namePool());
1373 query.bindVariable(QLatin1String("node"), nodeModel.root());
1376 QVERIFY(buff.open(QIODevice::WriteOnly));
1378 query.setQuery(QLatin1String("declare variable $node external; $node"));
1379 QXmlSerializer serializer(query, &buff);
1381 QVERIFY(query.evaluateTo(&serializer));
1382 QCOMPARE(out, QByteArray("<nodeName/>"));
1386 Pass in a relative URI, and make sure it is resolved against the current application directory.
1388 void tst_QXmlQuery::relativeBaseURI() const
1391 query.setQuery(QLatin1String("fn:static-base-uri()"), QUrl(QLatin1String("a/relative/uri.weirdExtension")));
1392 QVERIFY(query.isValid());
1395 QBuffer buffer(&result);
1396 QVERIFY(buffer.open(QIODevice::ReadWrite));
1398 QXmlSerializer serializer(query, &buffer);
1399 QVERIFY(query.evaluateTo(&serializer));
1401 const QUrl loaded(QUrl::fromEncoded(result));
1402 QUrl appPath(QUrl::fromLocalFile(QCoreApplication::applicationFilePath()));
1404 QVERIFY(loaded.isValid());
1405 QVERIFY(appPath.isValid());
1406 QVERIFY(!loaded.isRelative());
1407 QVERIFY(!appPath.isRelative());
1409 QFileInfo dir(appPath.toLocalFile());
1410 dir.setFile(QString());
1412 /* We can't use QUrl::isParentOf() because it doesn't do what we want it to */
1413 if(!loaded.toLocalFile().startsWith(dir.absoluteFilePath()))
1414 QTextStream(stderr) << "dir.absoluteFilePath():" << dir.absoluteFilePath() << "loaded.toLocalFile():" << loaded.toLocalFile();
1416 checkBaseURI(loaded, dir.absoluteFilePath());
1419 void tst_QXmlQuery::emptyBaseURI() const
1422 query.setQuery(QLatin1String("fn:static-base-uri()"), QUrl());
1423 QVERIFY(query.isValid());
1426 QBuffer buffer(&result);
1427 QVERIFY(buffer.open(QIODevice::ReadWrite));
1429 QXmlSerializer serializer(query, &buffer);
1430 QVERIFY(query.evaluateTo(&serializer));
1432 const QUrl loaded(QUrl::fromEncoded(result));
1433 QUrl appPath(QUrl::fromLocalFile(QCoreApplication::applicationFilePath()));
1435 QVERIFY(loaded.isValid());
1436 QVERIFY(appPath.isValid());
1437 QVERIFY(!loaded.isRelative());
1438 QVERIFY(!appPath.isRelative());
1440 QFileInfo dir(appPath.toLocalFile());
1441 dir.setFile(QString());
1443 QCOMPARE(loaded, appPath);
1447 Ensure that QDate comes out as QDateTime.
1449 void tst_QXmlQuery::roundTripDateWithinQXmlItem() const
1451 const QDate date(1999, 9, 10);
1452 QVERIFY(date.isValid());
1454 const QVariant variant(date);
1455 QVERIFY(variant.isValid());
1456 QCOMPARE(variant.type(), QVariant::Date);
1458 const QXmlItem item(variant);
1459 QVERIFY(!item.isNull());
1460 QVERIFY(item.isAtomicValue());
1462 const QVariant out(item.toAtomicValue());
1463 QVERIFY(out.isValid());
1464 QCOMPARE(out.type(), QVariant::Date);
1465 QCOMPARE(out.toDate(), date);
1469 Check whether a query is valid, which uses an unbound variable.
1471 void tst_QXmlQuery::bindingMissing() const
1474 MessageSilencer messageHandler;
1475 query.setMessageHandler(&messageHandler);
1477 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
1478 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1479 query.setQuery(&queryFile);
1481 QVERIFY(!query.isValid());
1484 void tst_QXmlQuery::bindDefaultConstructedItem() const
1486 QFETCH(QXmlItem, item);
1489 MessageSilencer messageHandler;
1490 query.setMessageHandler(&messageHandler);
1492 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
1493 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1494 query.setQuery(&queryFile);
1495 query.bindVariable(QLatin1String("externalVariable"), item);
1497 QVERIFY(!query.isValid());
1500 void tst_QXmlQuery::bindDefaultConstructedItem_data() const
1502 QTest::addColumn<QXmlItem>("item");
1504 QTest::newRow("QXmlItem()") << QXmlItem();
1505 QTest::newRow("QXmlItem(QVariant())") << QXmlItem(QVariant());
1506 QTest::newRow("QXmlItem(QXmlNodeModelIndex())") << QXmlItem(QXmlNodeModelIndex());
1510 Remove a binding by binding QXmlItem() with the same name.
1512 void tst_QXmlQuery::eraseQXmlItemBinding() const
1515 MessageSilencer messageHandler;
1516 query.setMessageHandler(&messageHandler);
1518 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
1519 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1520 query.bindVariable(QLatin1String("externalVariable"), QXmlItem(3));
1521 query.setQuery(&queryFile);
1522 QVERIFY(query.isValid());
1525 QBuffer buffer(&result);
1526 QVERIFY(buffer.open(QIODevice::ReadWrite));
1528 QXmlSerializer serializer(query, &buffer);
1529 QVERIFY(query.evaluateTo(&serializer));
1531 QCOMPARE(result, QByteArray("3 6<e>3</e>false"));
1533 query.bindVariable(QLatin1String("externalVariable"), QXmlItem());
1534 QVERIFY(!query.isValid());
1538 Erase a variable binding
1540 void tst_QXmlQuery::eraseDeviceBinding() const
1542 /* Erase an existing QIODevice binding with another QIODevice binding. */
1546 QByteArray doc("<e/>");
1547 QBuffer buffer(&doc);
1548 QVERIFY(buffer.open(QIODevice::ReadOnly));
1550 query.bindVariable(QLatin1String("in"), &buffer);
1551 query.setQuery(QLatin1String("$in"));
1552 QVERIFY(query.isValid());
1554 query.bindVariable(QLatin1String("in"), 0);
1555 QVERIFY(!query.isValid());
1558 /* Erase an existing QXmlItem binding with another QIODevice binding. */
1562 query.bindVariable(QLatin1String("in"), QXmlItem(5));
1563 query.setQuery(QLatin1String("$in"));
1564 QVERIFY(query.isValid());
1566 query.bindVariable(QLatin1String("in"), 0);
1567 QVERIFY(!query.isValid());
1572 Bind a variable, evaluate, bind with a different value but same type, and evaluate again.
1574 void tst_QXmlQuery::rebindVariableSameType() const
1577 MessageSilencer messageHandler;
1578 query.setMessageHandler(&messageHandler);
1580 query.bindVariable(QLatin1String("externalVariable"), QXmlItem(3));
1583 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
1584 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1585 query.setQuery(&queryFile);
1588 QVERIFY(query.isValid());
1592 QBuffer buffer(&result);
1593 QVERIFY(buffer.open(QIODevice::ReadWrite));
1595 QXmlSerializer serializer(query, &buffer);
1596 QVERIFY(query.evaluateTo(&serializer));
1598 QCOMPARE(result, QByteArray("3 6<e>3</e>false"));
1602 query.bindVariable(QLatin1String("externalVariable"), QXmlItem(5));
1604 QBuffer buffer(&result);
1605 QVERIFY(buffer.open(QIODevice::ReadWrite));
1607 QXmlSerializer serializer(query, &buffer);
1608 QVERIFY(query.evaluateTo(&serializer));
1610 QCOMPARE(result, QByteArray("5 8<e>5</e>false"));
1615 void tst_QXmlQuery::rebindVariableDifferentType() const
1617 /* Rebind QXmlItem variable with QXmlItem variable. */
1620 query.bindVariable(QLatin1String("in"), QXmlItem(3));
1621 query.setQuery(QLatin1String("$in"));
1622 QVERIFY(query.isValid());
1624 query.bindVariable(QLatin1String("in"), QXmlItem("A string"));
1625 QVERIFY(!query.isValid());
1628 /* Rebind QIODevice variable with QXmlItem variable. */
1632 buffer.setData(QByteArray("<e/>"));
1633 QVERIFY(buffer.open(QIODevice::ReadOnly));
1635 query.bindVariable(QLatin1String("in"), &buffer);
1636 query.setQuery(QLatin1String("$in"));
1637 QVERIFY(query.isValid());
1639 query.bindVariable(QLatin1String("in"), QXmlItem("A string"));
1640 QVERIFY(!query.isValid());
1643 /* Rebind QXmlItem variable with QIODevice variable. The type of the
1644 * variable changes, so a recompile is necessary. */
1648 query.bindVariable(QLatin1String("in"), QXmlItem(QLatin1String("A string")));
1649 query.setQuery(QLatin1String("$in"));
1650 QVERIFY(query.isValid());
1653 buffer.setData(QByteArray("<e/>"));
1654 QVERIFY(buffer.open(QIODevice::ReadOnly));
1655 query.bindVariable(QLatin1String("in"), &buffer);
1656 QVERIFY(!query.isValid());
1660 void tst_QXmlQuery::rebindVariableWithNullItem() const
1664 query.bindVariable(QLatin1String("name"), QXmlItem(5));
1665 query.bindVariable(QLatin1String("name"), QXmlItem());
1668 void tst_QXmlQuery::constCorrectness() const
1670 QXmlResultItems result;
1672 tmp.setQuery(QLatin1String("1")); /* Just so we have a valid query. */
1673 const QXmlQuery query(tmp);
1675 /* These functions should be const. */
1677 query.evaluateTo(&result);
1679 query.uriResolver();
1680 query.messageHandler();
1683 QString dummyString;
1684 QTextStream dummyStream(&dummyString);
1685 PushBaseliner dummy(dummyStream, query.namePool());
1686 QVERIFY(dummy.isValid());
1687 query.evaluateTo(&dummy);
1691 void tst_QXmlQuery::objectSize() const
1693 /* We have a d pointer. */
1694 QCOMPARE(sizeof(QXmlQuery), sizeof(void *));
1697 void tst_QXmlQuery::setUriResolver() const
1699 /* Set a null resolver, and make sure it can take a const pointer. */
1702 query.setUriResolver(static_cast<const QAbstractUriResolver *>(0));
1703 QCOMPARE(query.uriResolver(), static_cast<const QAbstractUriResolver *>(0));
1707 TestURIResolver resolver;
1709 query.setUriResolver(&resolver);
1710 QCOMPARE(query.uriResolver(), static_cast<const QAbstractUriResolver *>(&resolver));
1714 void tst_QXmlQuery::uriResolver() const
1716 /* Check default value. */
1719 QCOMPARE(query.uriResolver(), static_cast<const QAbstractUriResolver *>(0));
1723 void tst_QXmlQuery::messageXML() const
1727 MessageValidator messageValidator;
1728 query.setMessageHandler(&messageValidator);
1730 query.setQuery(QLatin1String("1basicSyntaxError"));
1732 const QRegExp removeFilename(QLatin1String("Location: file:.*\\#"));
1733 QVERIFY(removeFilename.isValid());
1735 QVERIFY(messageValidator.success());
1736 QCOMPARE(messageValidator.received().remove(removeFilename),
1737 QString::fromLatin1("Type:3\n"
1738 "Description: <html xmlns='http://www.w3.org/1999/xhtml/'><body><p>syntax error, unexpected unknown keyword</p></body></html>\n"
1739 "Identifier: http://www.w3.org/2005/xqt-errors#XPST0003\n"
1744 1. Allocate QXmlResultItems
1745 2. Allocate QXmlQuery
1746 3. evaluate to the QXmlResultItems instance
1747 4. Dellocate the QXmlQuery instance
1748 5. Ensure QXmlResultItems works
1750 void tst_QXmlQuery::resultItemsDeallocatedQuery() const
1752 QXmlResultItems result;
1756 query.setQuery(QLatin1String("1, 2, xs:integer(<e>3</e>)"));
1757 query.evaluateTo(&result);
1760 QCOMPARE(result.next().toAtomicValue(), QVariant(1));
1761 QCOMPARE(result.next().toAtomicValue(), QVariant(2));
1762 QCOMPARE(result.next().toAtomicValue(), QVariant(3));
1763 QVERIFY(result.next().isNull());
1764 QVERIFY(!result.hasError());
1768 1. Bind variable with bindVariable()
1769 2. setQuery that has 'declare variable' with same name.
1770 3. Ensure the value inside the query is used. We don't guarantee this behavior
1771 but that's what we lock.
1773 void tst_QXmlQuery::shadowedVariables() const
1776 query.bindVariable("varName", QXmlItem(3));
1777 query.setQuery(QLatin1String("declare variable $varName := 5; $varName"));
1779 QXmlResultItems result;
1780 query.evaluateTo(&result);
1782 QCOMPARE(result.next().toAtomicValue(), QVariant(5));
1785 void tst_QXmlQuery::setFocusQXmlItem() const
1787 /* Make sure we can take a const reference. */
1790 const QXmlItem item;
1791 query.setFocus(item);
1794 // TODO evaluate with atomic value, check type
1795 // TODO evaluate with node, check type
1796 // TODO ensure that setFocus() triggers query recompilation, as appropriate.
1797 // TODO let the focus be undefined, call isvalid, call evaluate anyway
1798 // TODO let the focus be undefined, call evaluate directly
1801 void tst_QXmlQuery::setFocusQUrl() const
1803 /* Load a focus which isn't well-formed. */
1806 MessageSilencer silencer;
1808 query.setMessageHandler(&silencer);
1810 QVERIFY(!query.setFocus(QUrl(QLatin1String("data/notWellformed.xml"))));
1813 /* Ensure the same URI resolver is used. */
1815 QXmlQuery query(QXmlQuery::XSLT20);
1817 const TestURIResolver resolver(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/documentElement.xml"))));
1818 query.setUriResolver(&resolver);
1820 QVERIFY(query.setFocus(QUrl(QLatin1String("arbitraryURI"))));
1821 query.setQuery(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/copyWholeDocument.xsl"))));
1822 QVERIFY(query.isValid());
1825 QVERIFY(result.open(QIODevice::ReadWrite));
1826 QXmlSerializer serializer(query, &result);
1827 query.evaluateTo(&serializer);
1829 QCOMPARE(result.data(), QByteArray("<doc/>"));
1832 // TODO ensure that the focus type doesn't change from XSLT20 on the main instance.
1836 This code poses a challenge wrt. to internal caching.
1838 void tst_QXmlQuery::setFocusQIODevice() const
1844 focus.setData(QByteArray("<e>abc</e>"));
1845 QVERIFY(focus.open(QIODevice::ReadOnly));
1846 query.setFocus(&focus);
1847 query.setQuery(QLatin1String("string()"));
1848 QVERIFY(query.isValid());
1851 query.evaluateTo(&output);
1853 QCOMPARE(output, QString::fromLatin1("abc\n"));
1856 /* Set a new focus, make sure it changes & works. */
1859 focus2.setData(QByteArray("<e>abc2</e>"));
1860 QVERIFY(focus2.open(QIODevice::ReadOnly));
1861 query.setFocus(&focus2);
1862 QVERIFY(query.isValid());
1865 query.evaluateTo(&output);
1867 QCOMPARE(output, QString::fromLatin1("abc2\n"));
1872 Since we internally use variable bindings for implementing the focus, we need
1873 to make sure we don't clash in this area.
1875 void tst_QXmlQuery::setFocusQIODeviceAvoidVariableClash() const
1878 buffer.setData("<e>focus</e>");
1879 QVERIFY(buffer.open(QIODevice::ReadOnly));
1881 /* First we bind the variable name, then the focus. */
1884 query.bindVariable(QString(QLatin1Char('u')), QVariant(1));
1885 query.setFocus(&buffer);
1886 query.setQuery(QLatin1String("string()"));
1889 query.evaluateTo(&out);
1891 QCOMPARE(out, QString::fromLatin1("focus\n"));
1894 /* First we bind the focus, then the variable name. */
1897 QVERIFY(buffer.open(QIODevice::ReadOnly));
1898 query.setFocus(&buffer);
1899 query.bindVariable(QString(QLatin1Char('u')), QVariant(1));
1900 query.setQuery(QLatin1String("string()"));
1903 query.evaluateTo(&out);
1905 QCOMPARE(out, QString::fromLatin1("focus\n"));
1909 void tst_QXmlQuery::setFocusQIODeviceFailure() const
1911 /* A not well-formed input document. */
1915 MessageSilencer silencer;
1916 query.setMessageHandler(&silencer);
1919 input.setData("<e");
1920 QVERIFY(input.open(QIODevice::ReadOnly));
1922 QCOMPARE(query.setFocus(&input), false);
1926 void tst_QXmlQuery::setFocusQString() const
1930 /* Basic use of focus. */
1932 QVERIFY(query.setFocus(QLatin1String("<e>textNode</e>")));
1933 query.setQuery(QLatin1String("string()"));
1934 QVERIFY(query.isValid());
1936 query.evaluateTo(&out);
1937 QCOMPARE(out, QString::fromLatin1("textNode\n"));
1940 /* Set to a new focus, make sure it changes and works. */
1942 QVERIFY(query.setFocus(QLatin1String("<e>newFocus</e>")));
1944 query.evaluateTo(&out);
1945 QCOMPARE(out, QString::fromLatin1("newFocus\n"));
1949 void tst_QXmlQuery::setFocusQStringFailure() const
1952 MessageSilencer silencer;
1954 query.setMessageHandler(&silencer);
1955 QVERIFY(!query.setFocus(QLatin1String("<notWellformed")));
1957 /* Let's try the slight special case of a null string. */
1958 QVERIFY(!query.setFocus(QString()));
1961 void tst_QXmlQuery::setFocusQStringSignature() const
1964 MessageSilencer silencer;
1965 query.setMessageHandler(&silencer);
1967 const QString argument;
1968 /* We should take a const ref. */
1969 query.setFocus(argument);
1971 /* We should return a bool. */
1972 static_cast<bool>(query.setFocus(QString()));
1975 void tst_QXmlQuery::setFocusQIODeviceTriggerWarnings() const
1977 /* A null pointer. */
1981 QTest::ignoreMessage(QtWarningMsg, "A null QIODevice pointer cannot be passed.");
1982 QCOMPARE(query.setFocus(static_cast<QIODevice *>(0)), false);
1985 /* A non opened-device. */
1989 QBuffer notReadable;
1990 QVERIFY(!notReadable.isReadable());
1992 QTest::ignoreMessage(QtWarningMsg, "The device must be readable.");
1993 QCOMPARE(query.setFocus(¬Readable), false);
1997 void tst_QXmlQuery::fnDocNetworkAccessSuccess() const
1999 #if defined(Q_OS_WINCE) && !defined(_X86_)
2000 QStringList testsToSkip;
2001 testsToSkip << "http scheme" << "ftp scheme";
2002 if (testsToSkip.contains(QTest::currentDataTag()))
2003 QSKIP("Network tests are currently unsupported on Windows CE.", SkipSingle);
2006 QFETCH(QUrl, uriToOpen);
2007 QFETCH(QByteArray, expectedOutput);
2009 if(!uriToOpen.isValid())
2010 qDebug() << "uriToOpen:" << uriToOpen;
2012 QVERIFY(uriToOpen.isValid());
2015 query.bindVariable(QLatin1String("uri"), QVariant(uriToOpen));
2016 query.setQuery(QLatin1String("declare variable $uri external;\ndoc($uri)"));
2017 QVERIFY(query.isValid());
2020 QBuffer buffer(&result);
2021 QVERIFY(buffer.open(QIODevice::WriteOnly));
2023 QXmlSerializer serializer(query, &buffer);
2024 QVERIFY(query.evaluateTo(&serializer));
2026 QCOMPARE(result, expectedOutput);
2029 void tst_QXmlQuery::fnDocNetworkAccessSuccess_data() const
2031 QTest::addColumn<QUrl>("uriToOpen");
2032 QTest::addColumn<QByteArray>("expectedOutput");
2034 QTest::newRow("file scheme")
2035 << inputFileAsURI(QLatin1String(SRCDIR "input.xml"))
2036 << QByteArray("<!-- This is just a file for testing. --><input/>");
2038 QTest::newRow("data scheme with ASCII")
2039 /* QUrl::toPercentEncoding(QLatin1String("<e/>")) yields "%3Ce%2F%3E". */
2040 << QUrl::fromEncoded("data:application/xml,%3Ce%2F%3E")
2041 << QByteArray("<e/>");
2043 QTest::newRow("data scheme with ASCII no MIME type")
2044 << QUrl::fromEncoded("data:,%3Ce%2F%3E")
2045 << QByteArray("<e/>");
2047 QTest::newRow("data scheme with base 64")
2048 << QUrl::fromEncoded("data:application/xml;base64,PGUvPg==")
2049 << QByteArray("<e/>");
2051 QTest::newRow("qrc scheme")
2052 << QUrl::fromEncoded("qrc:/QXmlQueryTestData/data/oneElement.xml")
2053 << QByteArray("<oneElement/>");
2058 QTest::newRow("http scheme")
2059 << QUrl(QString("http://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/wellFormed.xml"))
2060 << QByteArray("<!-- a comment --><e from=\"http\">Some Text</e>");
2062 QTest::newRow("ftp scheme")
2063 << QUrl(QString("ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/wellFormed.xml"))
2064 << QByteArray("<!-- a comment --><e from=\"ftp\">Some Text</e>");
2068 void tst_QXmlQuery::fnDocNetworkAccessFailure() const
2070 QFETCH(QUrl, uriToOpen);
2072 QVERIFY(uriToOpen.isValid());
2075 MessageSilencer silencer;
2076 query.setMessageHandler(&silencer);
2077 query.bindVariable(QLatin1String("uri"), QVariant(uriToOpen));
2078 query.setQuery(QLatin1String("declare variable $uri external;\ndoc($uri)"));
2079 QVERIFY(query.isValid());
2081 QXmlResultItems result;
2082 query.evaluateTo(&result);
2084 while(!result.next().isNull())
2086 /* Just loop until the end. */
2089 // TODO do something that triggers a /timeout/.
2090 QVERIFY(result.hasError());
2093 void tst_QXmlQuery::fnDocNetworkAccessFailure_data() const
2095 QTest::addColumn<QUrl>("uriToOpen");
2097 QTest::newRow("data scheme, not-well-formed")
2098 << QUrl(QLatin1String("data:application/xml;base64,PGUvg==="));
2100 QTest::newRow("file scheme, non-existant file")
2101 << QUrl(QLatin1String("file:///example.com/does/notExist.xml"));
2103 QTest::newRow("http scheme, file not found")
2104 << QUrl(QLatin1String("http://www.example.com/does/not/exist.xml"));
2106 QTest::newRow("http scheme, nonexistent host")
2107 << QUrl(QLatin1String("http://this.host.does.not.exist.I.SWear"));
2109 QTest::newRow("qrc scheme, not well-formed")
2110 << QUrl(QLatin1String("qrc:/QXmlQueryTestData/notWellformed.xml"));
2112 QTest::newRow("'qrc:/', non-existing file")
2113 << QUrl(QLatin1String(":/QXmlQueryTestData/data/thisFileDoesNotExist.xml"));
2115 QTest::newRow("':/', this scheme is not supported")
2116 << QUrl(QLatin1String(":/QXmlQueryTestData/data/notWellformed.xml"));
2121 QTest::newRow("http scheme, not well-formed")
2122 << QUrl(QString("http://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/notWellformed.xml"));
2124 QTest::newRow("https scheme, not well-formed")
2125 << QUrl(QString("https://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/notWellformedViaHttps.xml"));
2127 QTest::newRow("https scheme, nonexistent host")
2128 << QUrl(QLatin1String("https://this.host.does.not.exist.I.SWear"));
2130 QTest::newRow("ftp scheme, nonexistent host")
2131 << QUrl(QLatin1String("ftp://this.host.does.not.exist.I.SWear"));
2133 QTest::newRow("ftp scheme, not well-formed")
2134 << QUrl(QString("ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/notWellFormed.xml"));
2138 Create a network timeout from a QIODevice binding such
2139 that we ensure we don't hang infinitely.
2141 void tst_QXmlQuery::fnDocOnQIODeviceTimeout() const
2147 server.listen(QHostAddress::LocalHost, 1088);
2150 client.connectToHost("localhost", 1088);
2151 QVERIFY(client.isReadable());
2155 MessageSilencer silencer;
2156 query.setMessageHandler(&silencer);
2158 query.bindVariable(QLatin1String("inDevice"), &client);
2159 query.setQuery(QLatin1String("declare variable $inDevice external;\ndoc($inDevice)"));
2160 QVERIFY(query.isValid());
2162 QXmlResultItems result;
2163 query.evaluateTo(&result);
2164 QXmlItem next(result.next());
2166 while(!next.isNull())
2168 next = result.next();
2171 QVERIFY(result.hasError());
2175 When changing query, the static context must change too, such that
2176 the source locations are updated.
2178 void tst_QXmlQuery::recompilationWithEvaluateToResultFailing() const
2181 MessageSilencer silencer;
2182 query.setMessageHandler(&silencer);
2184 query.setQuery(QLatin1String("1 + 1")); /* An arbitrary valid query. */
2185 QVERIFY(query.isValid()); /* Trigger query compilation. */
2187 query.setQuery(QLatin1String("fn:doc('doesNotExist.example.com.xml')")); /* An arbitrary invalid query that make use of a source location. */
2188 QVERIFY(query.isValid()); /* Trigger second compilation. */
2190 QXmlResultItems items;
2191 query.evaluateTo(&items);
2193 QVERIFY(items.hasError());
2196 void tst_QXmlQuery::secondEvaluationWithEvaluateToResultFailing() const
2199 MessageSilencer silencer;
2200 query.setMessageHandler(&silencer);
2202 query.setQuery(QLatin1String("1 + 1")); /* An arbitrary valid query. */
2203 QVERIFY(query.isValid()); /* Trigger query compilation. */
2205 query.setQuery(QLatin1String("fn:doc('doesNotExist.example.com.xml')")); /* An arbitrary invalid query that make use of a source location. */
2206 /* We don't call isValid(). */
2207 QXmlResultItems items;
2208 query.evaluateTo(&items);
2210 QVERIFY(items.hasError());
2214 Compilation is triggered in the evaluation function due to no call to QXmlQuery::isValid().
2216 void tst_QXmlQuery::recompilationWithEvaluateToReceiver() const
2219 MessageSilencer silencer;
2220 query.setMessageHandler(&silencer);
2222 query.setQuery(QLatin1String("1 + 1")); /* An arbitrary valid query. */
2223 QVERIFY(query.isValid()); /* Trigger query compilation. */
2225 query.setQuery(QLatin1String("fn:doc('doesNotExist.example.com.xml')")); /* An arbitrary invalid query that make use of a source location. */
2226 /* We don't call isValid(). */
2229 QBuffer buffer(&dummy);
2230 buffer.open(QIODevice::WriteOnly);
2232 QXmlSerializer serializer(query, &buffer);
2234 QVERIFY(!query.evaluateTo(&serializer));
2237 void tst_QXmlQuery::evaluateToQStringListOnInvalidQuery() const
2239 MessageSilencer silencer;
2241 /* Invoke on a default constructed object. */
2245 QVERIFY(!query.evaluateTo(&out));
2248 /* Invoke on a syntactically invalid query. */
2252 MessageSilencer silencer;
2254 query.setMessageHandler(&silencer);
2255 query.setQuery(QLatin1String("1 + "));
2257 QVERIFY(!query.evaluateTo(&out));
2260 /* Invoke on a query with the wrong type, one atomic. */
2265 query.setQuery(QLatin1String("1"));
2266 query.setMessageHandler(&silencer);
2267 QVERIFY(!query.evaluateTo(&out));
2270 /* Invoke on a query with the wrong type, one element. */
2275 query.setQuery(QLatin1String("<e/>"));
2276 QVERIFY(!query.evaluateTo(&out));
2279 /* Invoke on a query with the wrong type, mixed nodes & atomics. */
2284 query.setQuery(QLatin1String("<e/>, 1, 'a string'"));
2285 query.setMessageHandler(&silencer);
2286 QVERIFY(!query.evaluateTo(&out));
2289 /* Evaluate the empty sequence. */
2294 query.setQuery(QLatin1String("()"));
2295 QVERIFY(!query.evaluateTo(&out));
2296 QVERIFY(out.isEmpty());
2300 void tst_QXmlQuery::evaluateToQStringList() const
2302 QFETCH(QString, queryString);
2303 QFETCH(QStringList, expectedOutput);
2306 query.setQuery(queryString);
2308 QVERIFY(query.isValid());
2310 QVERIFY(query.evaluateTo(&out));
2312 QCOMPARE(out, expectedOutput);
2315 void tst_QXmlQuery::evaluateToQStringListTriggerWarnings() const
2319 QTest::ignoreMessage(QtWarningMsg, "A non-null callback must be passed.");
2320 QCOMPARE(query.evaluateTo(static_cast<QStringList *>(0)),
2324 void tst_QXmlQuery::evaluateToQStringList_data() const
2326 QTest::addColumn<QString>("queryString");
2327 QTest::addColumn<QStringList>("expectedOutput");
2329 QTest::newRow("One atomic")
2330 << QString::fromLatin1("(1 + 1) cast as xs:string")
2331 << QStringList(QString::fromLatin1("2"));
2334 QStringList expected;
2335 expected << QLatin1String("2");
2336 expected << QLatin1String("a string");
2338 QTest::newRow("Two atomics")
2339 << QString::fromLatin1("(1 + 1) cast as xs:string, 'a string'")
2343 QTest::newRow("A query which evaluates to sub-types of xs:string.")
2344 << QString::fromLatin1("xs:NCName('NCName'), xs:normalizedString(' a b c ')")
2345 << (QStringList() << QString::fromLatin1("NCName")
2346 << QString::fromLatin1(" a b c "));
2348 QTest::newRow("A query which evaluates to two elements.")
2349 << QString::fromLatin1("string(<e>theString1</e>), string(<e>theString2</e>)")
2350 << (QStringList() << QString::fromLatin1("theString1")
2351 << QString::fromLatin1("theString2"));
2355 Ensure that we don't automatically convert non-xs:string values.
2357 void tst_QXmlQuery::evaluateToQStringListNoConversion() const
2360 query.setQuery(QString::fromLatin1("<e/>"));
2361 QVERIFY(query.isValid());
2363 QVERIFY(!query.evaluateTo(&result));
2366 void tst_QXmlQuery::evaluateToQIODevice() const
2368 /* an XQuery, check that no indentation is performed. */
2371 QVERIFY(out.open(QIODevice::ReadWrite));
2374 query.setQuery(QLatin1String("<a><b/></a>"));
2375 QVERIFY(query.isValid());
2376 QVERIFY(query.evaluateTo(&out));
2377 QCOMPARE(out.data(), QByteArray("<a><b/></a>"));
2381 void tst_QXmlQuery::evaluateToQIODeviceTriggerWarnings() const
2385 QTest::ignoreMessage(QtWarningMsg, "The pointer to the device cannot be null.");
2386 QCOMPARE(query.evaluateTo(static_cast<QIODevice *>(0)),
2391 QTest::ignoreMessage(QtWarningMsg, "The device must be writable.");
2392 QCOMPARE(query.evaluateTo(&buffer),
2396 void tst_QXmlQuery::evaluateToQIODeviceSignature() const
2398 /* The function should be const. */
2401 QVERIFY(out.open(QIODevice::ReadWrite));
2403 const QXmlQuery query;
2405 query.evaluateTo(&out);
2409 void tst_QXmlQuery::evaluateToQIODeviceOnInvalidQuery() const
2412 QVERIFY(out.open(QIODevice::WriteOnly));
2414 /* On syntactically invalid query. */
2417 MessageSilencer silencer;
2418 query.setMessageHandler(&silencer);
2419 query.setQuery(QLatin1String("1 +"));
2420 QVERIFY(!query.isValid());
2421 QVERIFY(!query.evaluateTo(&out));
2424 /* On null QXmlQuery instance. */
2427 QVERIFY(!query.evaluateTo(&out));
2432 void tst_QXmlQuery::setQueryQIODeviceQUrl() const
2437 buffer.setData("1, 2, 2 + 1");
2438 QVERIFY(buffer.open(QIODevice::ReadOnly));
2441 query.setQuery(&buffer);
2442 QVERIFY(query.isValid());
2444 QXmlResultItems result;
2445 query.evaluateTo(&result);
2446 QCOMPARE(result.next().toAtomicValue(), QVariant(1));
2447 QCOMPARE(result.next().toAtomicValue(), QVariant(2));
2448 QCOMPARE(result.next().toAtomicValue(), QVariant(3));
2449 QVERIFY(result.next().isNull());
2450 QVERIFY(!result.hasError());
2453 /* Set query that is invalid. */
2456 buffer.setData("1, ");
2457 QVERIFY(buffer.open(QIODevice::ReadOnly));
2460 MessageSilencer silencer;
2461 query.setMessageHandler(&silencer);
2462 query.setQuery(&buffer);
2463 QVERIFY(!query.isValid());
2466 /* Check that the base URI passes through. */
2469 buffer.setData("string(static-base-uri())");
2470 QVERIFY(buffer.open(QIODevice::ReadOnly));
2473 query.setQuery(&buffer, QUrl::fromEncoded("http://www.example.com/QIODeviceQUrl"));
2474 QVERIFY(query.isValid());
2477 query.evaluateTo(&result);
2478 QCOMPARE(result, QStringList(QLatin1String("http://www.example.com/QIODeviceQUrl")));
2482 void tst_QXmlQuery::setQueryQIODeviceQUrlTriggerWarnings() const
2485 QTest::ignoreMessage(QtWarningMsg, "A null QIODevice pointer cannot be passed.");
2489 QTest::ignoreMessage(QtWarningMsg, "The device must be readable.");
2490 query.setQuery(&buffer);
2493 void tst_QXmlQuery::setQueryQString() const
2498 query.setQuery(QLatin1String("1, 2, 2 + 1"));
2499 QVERIFY(query.isValid());
2501 QXmlResultItems result;
2502 query.evaluateTo(&result);
2503 QCOMPARE(result.next().toAtomicValue(), QVariant(1));
2504 QCOMPARE(result.next().toAtomicValue(), QVariant(2));
2505 QCOMPARE(result.next().toAtomicValue(), QVariant(3));
2506 QVERIFY(result.next().isNull());
2507 QVERIFY(!result.hasError());
2510 /* Set query that is invalid. */
2512 MessageSilencer silencer;
2514 query.setMessageHandler(&silencer);
2515 query.setQuery(QLatin1String("1, "));
2516 QVERIFY(!query.isValid());
2519 /* Check that the base URI passes through. */
2522 query.setQuery(QLatin1String("string(static-base-uri())"), QUrl::fromEncoded("http://www.example.com/QIODeviceQUrl"));
2523 QVERIFY(query.isValid());
2526 query.evaluateTo(&result);
2527 QCOMPARE(result, QStringList(QLatin1String("http://www.example.com/QIODeviceQUrl")));
2531 void tst_QXmlQuery::setQueryQUrlSuccess() const
2533 #if defined(Q_OS_WINCE) && !defined(_X86_)
2534 QStringList testsToSkip;
2535 testsToSkip << "A valid query via the ftp scheme" << "A valid query via the http scheme";
2536 if (testsToSkip.contains(QTest::currentDataTag()))
2537 QSKIP("Network tests are currently unsupported on Windows CE.", SkipSingle);
2540 QFETCH(QUrl, queryURI);
2541 QFETCH(QByteArray, expectedOutput);
2543 QVERIFY(queryURI.isValid());
2547 MessageSilencer silencer;
2548 query.setMessageHandler(&silencer);
2550 query.setQuery(queryURI);
2551 QVERIFY(query.isValid());
2554 QBuffer buffer(&out);
2555 QVERIFY(buffer.open(QIODevice::WriteOnly));
2556 QXmlSerializer serializer(query, &buffer);
2558 query.evaluateTo(&serializer);
2559 QCOMPARE(out, expectedOutput);
2562 void tst_QXmlQuery::setQueryQUrlSuccess_data() const
2564 QTest::addColumn<QUrl>("queryURI");
2565 QTest::addColumn<QByteArray>("expectedOutput");
2567 QTest::newRow("A valid query via the data scheme")
2568 << QUrl::fromEncoded("data:application/xml,1%20%2B%201") /* "1 + 1" */
2571 QTest::newRow("A valid query via the file scheme")
2572 << QUrl::fromLocalFile(inputFile(QLatin1String(queriesDirectory) + QLatin1String("onePlusOne.xq")))
2578 QTest::newRow("A valid query via the ftp scheme")
2579 << QUrl::fromEncoded(QString("ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/viaFtp.xq").toLatin1())
2580 << QByteArray("This was received via FTP");
2582 QTest::newRow("A valid query via the http scheme")
2583 << QUrl::fromEncoded(QString("http://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/viaHttp.xq").toLatin1())
2584 << QByteArray("This was received via HTTP.");
2587 void tst_QXmlQuery::setQueryQUrlFailSucceed() const
2590 MessageSilencer silencer;
2592 query.setMessageHandler(&silencer);
2594 query.setQuery(QLatin1String("1 + 1"));
2595 QVERIFY(query.isValid());
2597 query.setQuery(QUrl::fromEncoded("file://example.com/does/not/exist"));
2598 QVERIFY(!query.isValid());
2601 void tst_QXmlQuery::setQueryQUrlFailure() const
2603 QFETCH(QUrl, queryURI);
2605 MessageSilencer silencer;
2608 query.setMessageHandler(&silencer);
2609 query.setQuery(queryURI);
2610 QVERIFY(!query.isValid());
2613 void tst_QXmlQuery::setQueryQUrlFailure_data() const
2615 QTest::addColumn<QUrl>("queryURI");
2617 QTest::newRow("Query via file:// that does not exist.")
2618 << QUrl::fromEncoded("file://example.com/does/not/exist");
2620 QTest::newRow("A query via file:// that is completely empty, but readable.")
2621 << QUrl::fromLocalFile(QCoreApplication::applicationFilePath()).resolved(QUrl("../xmlpatterns/queries/completelyEmptyQuery.xq"));
2624 const QString name(QLatin1String("nonReadableFile.xq"));
2625 QFile outFile(name);
2626 QVERIFY(outFile.open(QIODevice::WriteOnly));
2627 outFile.write(QByteArray("1"));
2629 /* On some windows versions, this fails, so we don't check that this works with QVERIFY. */
2630 outFile.setPermissions(QFile::Permissions(QFile::Permissions()));
2632 QTest::newRow("Query via file:/ that does not have read permissions.")
2633 << QUrl::fromLocalFile(QCoreApplication::applicationFilePath()).resolved(QUrl("nonReadableFile.xq"));
2639 QTest::newRow("Query via HTTP that does not exist.")
2640 << QUrl::fromEncoded("http://example.com/NoQuery/ISWear");
2643 QTest::newRow("Query via FTP that does not exist.")
2644 << QUrl::fromEncoded("ftp://example.com/NoQuery/ISWear");
2647 QTest::newRow("A query via http:// that is completely empty, but readable.")
2648 << QUrl::fromEncoded(QString(
2649 "http://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/completelyEmptyQuery.xq").toLatin1());
2651 QTest::newRow("A query via ftp:// that is completely empty, but readable.")
2652 << QUrl::fromEncoded(QString(
2653 "ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/completelyEmptyQuery.xq").toLatin1());
2657 void tst_QXmlQuery::setQueryQUrlBaseURI() const
2659 QFETCH(QUrl, inputBaseURI);
2660 QFETCH(QUrl, expectedBaseURI);
2664 query.setQuery(QUrl(QLatin1String("qrc:/QXmlQueryTestData/queries/staticBaseURI.xq")), inputBaseURI);
2665 QVERIFY(query.isValid());
2668 QVERIFY(query.evaluateTo(&result));
2669 QCOMPARE(result.count(), 1);
2671 if(qstrcmp(QTest::currentDataTag(), "Relative base URI") == 0)
2672 checkBaseURI(QUrl(result.first()), QCoreApplication::applicationFilePath());
2674 QCOMPARE(result.first(), expectedBaseURI.toString());
2677 void tst_QXmlQuery::setQueryQUrlBaseURI_data() const
2679 QTest::addColumn<QUrl>("inputBaseURI");
2680 QTest::addColumn<QUrl>("expectedBaseURI");
2682 QTest::newRow("absolute HTTP")
2683 << QUrl(QLatin1String("http://www.example.com/"))
2684 << QUrl(QLatin1String("http://www.example.com/"));
2686 QTest::newRow("None, so the query URI is used")
2688 << QUrl(QLatin1String("qrc:/QXmlQueryTestData/queries/staticBaseURI.xq"));
2690 QTest::newRow("Relative base URI")
2691 << QUrl(QLatin1String("../data/relative.uri"))
2696 1. Create a valid query.
2697 2. Call setQuery(QUrl), with a query file that doesn't exist.
2698 3. Verify that the query has changed state into invalid.
2700 void tst_QXmlQuery::setQueryWithNonExistentQUrlOnValidQuery() const
2704 MessageSilencer messageSilencer;
2705 query.setMessageHandler(&messageSilencer);
2707 query.setQuery(QLatin1String("1 + 1"));
2708 QVERIFY(query.isValid());
2710 query.setQuery(QUrl::fromEncoded("qrc:/QXmlQueryTestData/DOESNOTEXIST.xq"));
2711 QVERIFY(!query.isValid());
2715 1. Create a valid query.
2716 2. Call setQuery(QUrl), with a query file that is invalid.
2717 3. Verify that the query has changed state into invalid.
2719 void tst_QXmlQuery::setQueryWithInvalidQueryFromQUrlOnValidQuery() const
2723 MessageSilencer messageSilencer;
2724 query.setMessageHandler(&messageSilencer);
2726 query.setQuery(QLatin1String("1 + 1"));
2727 QVERIFY(query.isValid());
2729 query.setQuery(QUrl::fromEncoded("qrc:/QXmlQueryTestData/queries/syntaxError.xq"));
2730 QVERIFY(!query.isValid());
2734 This triggered two bugs:
2736 - First, the DynamicContext wasn't assigned to QXmlResultItems, meaning it went out of
2737 scope and therefore deallocated the document pool, and calls
2738 to QXmlResultItems::next() would use dangling pointers.
2740 - Conversion between QPatternist::Item and QXmlItem was incorrectly done, leading to nodes
2741 being treated as atomic values, and subsequent crashes.
2744 void tst_QXmlQuery::retrieveNameFromQuery() const
2746 QFETCH(QString, queryString);
2747 QFETCH(QString, expectedName);
2750 query.setQuery(queryString);
2751 QVERIFY(query.isValid());
2752 QXmlResultItems result;
2753 query.evaluateTo(&result);
2755 QVERIFY(!result.hasError());
2757 const QXmlItem item(result.next());
2758 QVERIFY(!result.hasError());
2759 QVERIFY(!item.isNull());
2760 QVERIFY(item.isNode());
2762 const QXmlNodeModelIndex node(item.toNodeModelIndex());
2763 QVERIFY(!node.isNull());
2765 QCOMPARE(node.model()->name(node).localName(query.namePool()), expectedName);
2768 void tst_QXmlQuery::retrieveNameFromQuery_data() const
2770 QTest::addColumn<QString>("queryString");
2771 QTest::addColumn<QString>("expectedName");
2773 QTest::newRow("Document-node")
2774 << QString::fromLatin1("document{<elementName/>}")
2777 QTest::newRow("Element")
2778 << QString::fromLatin1("document{<elementName/>}/*")
2779 << QString::fromLatin1("elementName");
2783 Binding a null QString leads to no variable binding, but an
2784 empty non-null QString is possible.
2786 void tst_QXmlQuery::bindEmptyNullString() const
2788 MessageSilencer messageHandler;
2790 query.setMessageHandler(&messageHandler);
2791 query.setQuery(QLatin1String("declare variable $v external; $v"));
2792 /* Here, we effectively pass an invalid QVariant. */
2793 query.bindVariable(QLatin1String("v"), QVariant(QString()));
2794 QVERIFY(!query.isValid());
2797 QVERIFY(!query.evaluateTo(&result));
2800 void tst_QXmlQuery::bindEmptyString() const
2803 query.bindVariable(QLatin1String("v"), QVariant(QString(QLatin1String(""))));
2804 query.setQuery(QLatin1String("declare variable $v external; $v"));
2805 QVERIFY(query.isValid());
2808 QVERIFY(query.evaluateTo(&result));
2809 QStringList expected((QString()));
2810 QCOMPARE(result, expected);
2813 void tst_QXmlQuery::cleanupTestCase() const
2815 /* Remove a weird file we created. */
2816 const QString name(QLatin1String("nonReadableFile.xq"));
2818 if(QFile::exists(name))
2821 QVERIFY(file.setPermissions(QFile::WriteOwner));
2822 QVERIFY(file.remove());
2826 void tst_QXmlQuery::declareUnavailableExternal() const
2829 MessageSilencer silencer;
2830 query.setMessageHandler(&silencer);
2831 query.setQuery(QLatin1String("declare variable $var external;"
2833 /* We do not bind $var with QXmlQuery::bindVariable(). */
2834 QVERIFY(!query.isValid());
2838 This test triggers an assert in one of the cache iterator
2839 with MSVC 2005 when compiled in debug mode.
2841 void tst_QXmlQuery::msvcCacheIssue() const
2844 query.bindVariable(QLatin1String("externalVariable"), QXmlItem("Variable Value"));
2845 query.setQuery(QUrl::fromLocalFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariableUsedTwice.xq")));
2847 QVERIFY(query.evaluateTo(&result));
2850 QStringList() << QString::fromLatin1("Variable Value") << QString::fromLatin1("Variable Value"));
2853 void tst_QXmlQuery::unavailableExternalVariable() const
2857 MessageSilencer silencer;
2858 query.setMessageHandler(&silencer);
2860 query.setQuery(QLatin1String("declare variable $foo external; 1"));
2862 QVERIFY(!query.isValid());
2866 Ensure that setUriResolver() affects \c fn:doc() and \c fn:doc-available().
2868 void tst_QXmlQuery::useUriResolver() const
2870 class TestUriResolver : public QAbstractUriResolver
2871 , private TestFundament
2874 TestUriResolver() {}
2875 virtual QUrl resolve(const QUrl &relative,
2876 const QUrl &baseURI) const
2879 return baseURI.resolved(inputFile(QLatin1String(queriesDirectory) + QLatin1String("simpleDocument.xml")));
2883 const TestUriResolver uriResolver;
2886 query.setUriResolver(&uriResolver);
2887 query.setQuery(QLatin1String("let $i := 'http://www.example.com/DoesNotExist'"
2888 "return (string(doc($i)), doc-available($i))"));
2891 QXmlResultItems result;
2892 query.evaluateTo(&result);
2894 QVERIFY(!result.hasError());
2895 QCOMPARE(result.next().toAtomicValue().toString(), QString::fromLatin1("text text node"));
2896 QCOMPARE(result.next().toAtomicValue().toBool(), true);
2897 QVERIFY(result.next().isNull());
2898 QVERIFY(!result.hasError());
2901 void tst_QXmlQuery::queryWithFocusAndVariable() const
2904 query.setFocus(QXmlItem(5));
2905 query.bindVariable(QLatin1String("var"), QXmlItem(2));
2907 query.setQuery(QLatin1String("string(. * $var)"));
2911 QVERIFY(query.evaluateTo(&result));
2913 QCOMPARE(result, QStringList(QLatin1String("10")));
2916 void tst_QXmlQuery::undefinedFocus() const
2920 MessageSilencer silencer;
2921 query.setMessageHandler(&silencer);
2923 query.setQuery(QLatin1String("."));
2924 QVERIFY(!query.isValid());
2927 void tst_QXmlQuery::basicFocusUsage() const
2931 MessageSilencer silencer;
2932 query.setMessageHandler(&silencer);
2934 query.setFocus(QXmlItem(5));
2935 query.setQuery(QLatin1String("string(. * .)"));
2936 QVERIFY(query.isValid());
2939 QVERIFY(query.evaluateTo(&result));
2941 QCOMPARE(result, QStringList(QLatin1String("25")));
2945 Triggers an ownership related crash.
2947 void tst_QXmlQuery::copyCheckMessageHandler() const
2950 QCOMPARE(query.messageHandler(), static_cast<QAbstractMessageHandler *>(0));
2952 query.setQuery(QLatin1String("doc('qrc:/QXmlQueryTestData/data/oneElement.xml')"));
2953 /* By now, we should have set the builtin message handler. */
2954 const QAbstractMessageHandler *const messageHandler = query.messageHandler();
2955 QVERIFY(messageHandler);
2958 /* This copies QXmlQueryPrivate::m_ownerObject, and its destructor
2959 * will delete it, and hence the builtin message handler attached to it. */
2960 QXmlQuery copy(query);
2963 QXmlResultItems result;
2964 query.evaluateTo(&result);
2966 while(!result.next().isNull())
2969 QVERIFY(!result.hasError());
2972 void tst_QXmlQuery::queryLanguage() const
2974 /* Check default value. */
2976 const QXmlQuery query;
2977 QCOMPARE(query.queryLanguage(), QXmlQuery::XQuery10);
2980 /* Check default value of copies default instance. */
2982 const QXmlQuery query1;
2983 const QXmlQuery query2(query1);
2985 QCOMPARE(query1.queryLanguage(), QXmlQuery::XQuery10);
2986 QCOMPARE(query2.queryLanguage(), QXmlQuery::XQuery10);
2990 void tst_QXmlQuery::queryLanguageSignature() const
2992 /* This getter should be const. */
2994 query.queryLanguage();
2997 void tst_QXmlQuery::enumQueryLanguage() const
2999 /* These enum values should be possible to OR for future plans. */
3000 QCOMPARE(int(QXmlQuery::XQuery10), 1);
3001 QCOMPARE(int(QXmlQuery::XSLT20), 2);
3002 QCOMPARE(int(QXmlQuery::XmlSchema11IdentityConstraintSelector), 1024);
3003 QCOMPARE(int(QXmlQuery::XmlSchema11IdentityConstraintField), 2048);
3004 QCOMPARE(int(QXmlQuery::XPath20), 4096);
3007 void tst_QXmlQuery::setInitialTemplateNameQXmlName() const
3009 QXmlQuery query(QXmlQuery::XSLT20);
3010 QXmlNamePool np(query.namePool());
3011 const QXmlName name(np, QLatin1String("main"));
3013 query.setInitialTemplateName(name);
3015 QCOMPARE(query.initialTemplateName(), name);
3017 query.setQuery(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/namedTemplate.xsl"))));
3018 QVERIFY(query.isValid());
3021 QVERIFY(result.open(QIODevice::ReadWrite));
3022 QXmlSerializer serializer(query, &result);
3023 query.evaluateTo(&serializer);
3025 QCOMPARE(result.data(), QByteArray("1 2 3 4 5"));
3027 // TODO invoke a template which has required params.
3030 void tst_QXmlQuery::setInitialTemplateNameQXmlNameSignature() const
3033 QXmlNamePool np(query.namePool());
3034 const QXmlName name(np, QLatin1String("foo"));
3036 /* The signature should take a const reference. */
3037 query.setInitialTemplateName(name);
3040 void tst_QXmlQuery::setInitialTemplateNameQString() const
3043 QXmlNamePool np(query.namePool());
3044 query.setInitialTemplateName(QLatin1String("foo"));
3046 QCOMPARE(query.initialTemplateName(), QXmlName(np, QLatin1String("foo")));
3049 void tst_QXmlQuery::setInitialTemplateNameQStringSignature() const
3051 const QString name(QLatin1String("name"));
3054 /* We should take a const reference. */
3055 query.setInitialTemplateName(name);
3058 void tst_QXmlQuery::initialTemplateName() const
3060 /* Check our default value. */
3062 QCOMPARE(query.initialTemplateName(), QXmlName());
3063 QVERIFY(query.initialTemplateName().isNull());
3066 void tst_QXmlQuery::initialTemplateNameSignature() const
3068 const QXmlQuery query;
3069 /* This should be a const member. */
3070 query.initialTemplateName();
3073 void tst_QXmlQuery::setNetworkAccessManager() const
3076 /* Ensure fn:doc() picks up the right QNetworkAccessManager. */
3078 NetworkOverrider networkOverrider(QUrl(QLatin1String("tag:example.com:DOESNOTEXIST")),
3079 QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/queries/simpleDocument.xml"))));
3080 QVERIFY(networkOverrider.isValid());
3083 query.setNetworkAccessManager(&networkOverrider);
3084 query.setQuery(QLatin1String("string(doc('tag:example.com:DOESNOTEXIST'))"));
3085 QVERIFY(query.isValid());
3088 QVERIFY(query.evaluateTo(&result));
3090 QCOMPARE(result, QStringList(QLatin1String("text text node")));
3093 /* Ensure setQuery() is using the right network manager. */
3095 NetworkOverrider networkOverrider(QUrl(QLatin1String("tag:example.com:DOESNOTEXIST")),
3096 QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/queries/concat.xq"))));
3097 QVERIFY(networkOverrider.isValid());
3100 query.setNetworkAccessManager(&networkOverrider);
3101 query.setQuery(QUrl("tag:example.com:DOESNOTEXIST"));
3102 QVERIFY(query.isValid());
3105 QVERIFY(query.evaluateTo(&result));
3107 QCOMPARE(result, QStringList(QLatin1String("abcdef")));
3110 void tst_QXmlQuery::networkAccessManagerSignature() const
3113 const QXmlQuery query;
3115 /* The function should be const. */
3116 query.networkAccessManager();
3119 void tst_QXmlQuery::networkAccessManagerDefaultValue() const
3121 const QXmlQuery query;
3123 QCOMPARE(query.networkAccessManager(), static_cast<QNetworkAccessManager *>(0));
3126 void tst_QXmlQuery::networkAccessManager() const
3128 /* Test that we return the network manager that was set. */
3130 QNetworkAccessManager manager;
3132 query.setNetworkAccessManager(&manager);
3133 QCOMPARE(query.networkAccessManager(), &manager);
3141 1. Load a document into QXmlQuery's document cache, by executing a query which does it.
3143 3. Change query, to one which uses the focus
3148 void tst_QXmlQuery::multipleDocsAndFocus() const
3152 /* We use string concatenation, since variable bindings might disturb what
3154 query.setQuery(QLatin1String("string(doc('") +
3155 inputFile(QLatin1String(XMLPATTERNSDIR "/queries/simpleDocument.xml")) +
3156 QLatin1String("'))"));
3157 query.setFocus(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/documentElement.xml"))));
3158 query.setQuery(QLatin1String("string(.)"));
3161 QVERIFY(query.evaluateTo(&result));
3176 void tst_QXmlQuery::multipleEvaluationsWithDifferentFocus() const
3181 query.setFocus(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/documentElement.xml"))));
3182 query.setQuery(QLatin1String("string(.)"));
3183 QVERIFY(query.evaluateTo(&result));
3185 query.setFocus(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/documentElement.xml"))));
3186 QVERIFY(query.evaluateTo(&result));
3189 void tst_QXmlQuery::bindVariableQXmlQuery() const
3191 QFETCH(QString, query1);
3192 QFETCH(QString, query2);
3193 QFETCH(QString, expectedOutput);
3194 QFETCH(bool, expectedSuccess);
3196 MessageSilencer silencer;
3197 QXmlQuery xmlQuery1;
3198 xmlQuery1.setMessageHandler(&silencer);
3199 xmlQuery1.setQuery(query1);
3201 QXmlQuery xmlQuery2(xmlQuery1);
3202 xmlQuery2.bindVariable("query1", xmlQuery1);
3203 xmlQuery2.setQuery(query2);
3206 const bool querySuccess = xmlQuery2.evaluateTo(&output);
3208 QCOMPARE(querySuccess, expectedSuccess);
3211 QCOMPARE(output, expectedOutput);
3214 void tst_QXmlQuery::bindVariableQXmlQuery_data() const
3216 QTest::addColumn<QString>("query1");
3217 QTest::addColumn<QString>("query2");
3218 QTest::addColumn<QString>("expectedOutput");
3219 QTest::addColumn<bool>("expectedSuccess");
3221 QTest::newRow("First query has one atomic value.")
3227 QTest::newRow("First query has two atomic values.")
3233 QTest::newRow("First query is a node.")
3239 /* This is a good test, because it triggers the exception in the
3240 * bindVariable() call, as supposed to when the actual evaluation is done.
3242 QTest::newRow("First query has a dynamic error.")
3245 << QString() /* We don't care. */
3249 void tst_QXmlQuery::bindVariableQStringQXmlQuerySignature() const
3252 query1.setQuery("'dummy'");
3255 const QString name(QLatin1String("name"));
3257 /* We should be able to take a const QXmlQuery reference. Evaluation never mutate
3258 * QXmlQuery, and evaluation is what we do here. */
3259 query2.bindVariable(name, const_cast<const QXmlQuery &>(query1));
3262 void tst_QXmlQuery::bindVariableQXmlNameQXmlQuerySignature() const
3265 QXmlQuery query1(np);
3266 query1.setQuery("'dummy'");
3269 const QXmlName name(np, QLatin1String("name"));
3271 /* We should be able to take a const QXmlQuery reference. Evaluation never mutate
3272 * QXmlQuery, and evaluation is what we do here. */
3273 query2.bindVariable(name, const_cast<const QXmlQuery &>(query1));
3277 Check that the QXmlName is handled correctly.
3279 void tst_QXmlQuery::bindVariableQXmlNameQXmlQuery() const
3283 query1.setQuery(QLatin1String("1"));
3285 QXmlQuery query2(np);
3286 query2.bindVariable(QXmlName(np, QLatin1String("theName")), query1);
3287 query2.setQuery("$theName");
3290 query2.evaluateTo(&result);
3292 QCOMPARE(result, QString::fromLatin1("1\n"));
3295 void tst_QXmlQuery::bindVariableQXmlQueryInvalidate() const
3298 query.bindVariable(QLatin1String("name"), QVariant(1));
3299 query.setQuery("$name");
3300 QVERIFY(query.isValid());
3303 query2.setQuery("'query2'");
3305 query.bindVariable(QLatin1String("name"), query);
3306 QVERIFY(!query.isValid());
3309 void tst_QXmlQuery::unknownSourceLocation() const
3312 b.setData("<a><b/><b/></a>");
3313 b.open(QIODevice::ReadOnly);
3315 MessageSilencer silencer;
3317 query.bindVariable(QLatin1String("inputDocument"), &b);
3318 query.setMessageHandler(&silencer);
3320 query.setQuery(QLatin1String("doc($inputDocument)/a/(let $v := b/string() return if ($v) then $v else ())"));
3323 query.evaluateTo(&output);
3326 void tst_QXmlQuery::identityConstraintSuccess() const
3328 QXmlQuery::QueryLanguage queryLanguage = QXmlQuery::XmlSchema11IdentityConstraintSelector;
3330 /* We run this code for Selector and Field. */
3331 for(int i = 0; i < 3; ++i)
3333 QXmlNamePool namePool;
3334 QXmlResultItems result;
3338 QXmlQuery nodeSource(namePool);
3339 nodeSource.setQuery(QLatin1String("<e/>"));
3341 nodeSource.evaluateTo(&result);
3342 node = result.next();
3346 * 1. The focus is undefined, but it's still valid.
3347 * 2. We never evaluate. */
3349 QXmlQuery query(queryLanguage);
3350 query.setQuery(QLatin1String("a"));
3351 QVERIFY(query.isValid());
3355 * 1. The focus is undefined, but it's still valid.
3356 * 2. We afterwards set the focus. */
3358 QXmlQuery query(queryLanguage, namePool);
3359 query.setQuery(QLatin1String("a"));
3360 query.setFocus(node);
3361 QVERIFY(query.isValid());
3365 * 1. The focus is undefined, but it's still valid.
3366 * 2. We afterwards set the focus.
3367 * 3. We evaluate. */
3369 QXmlQuery query(queryLanguage, namePool);
3370 query.setQuery(QString(QLatin1Char('.')));
3371 query.setFocus(node);
3372 QVERIFY(query.isValid());
3375 QVERIFY(query.evaluateTo(&result));
3376 QCOMPARE(result, QString::fromLatin1("<e/>\n"));
3379 /* A slightly more complex Field. */
3381 QXmlQuery query(queryLanguage);
3382 query.setQuery(QLatin1String("* | .//xml:*/."));
3383 QVERIFY(query.isValid());
3386 /* @ is only allowed in Field. */
3387 if(queryLanguage == QXmlQuery::XmlSchema11IdentityConstraintField)
3389 QXmlQuery query(QXmlQuery::XmlSchema11IdentityConstraintField);
3390 query.setQuery(QLatin1String("@abc"));
3391 QVERIFY(query.isValid());
3394 /* Field allows attribute:: and child:: .*/
3395 if(queryLanguage == QXmlQuery::XmlSchema11IdentityConstraintField)
3397 QXmlQuery query(QXmlQuery::XmlSchema11IdentityConstraintField);
3398 query.setQuery(QLatin1String("attribute::name | child::name"));
3399 QVERIFY(query.isValid());
3402 /* Selector allows only child:: .*/
3404 QXmlQuery query(QXmlQuery::XmlSchema11IdentityConstraintSelector);
3405 query.setQuery(QLatin1String("child::name"));
3406 QVERIFY(query.isValid());
3410 queryLanguage = QXmlQuery::XmlSchema11IdentityConstraintField;
3412 queryLanguage = QXmlQuery::XPath20;
3416 Q_DECLARE_METATYPE(QXmlQuery::QueryLanguage);
3419 We just do some basic tests for boot strapping and sanity checking. The actual regression
3420 testing is in the Schema suite.
3422 void tst_QXmlQuery::identityConstraintFailure() const
3424 QFETCH(QXmlQuery::QueryLanguage, queryLanguage);
3425 QFETCH(QString, inputQuery);
3427 QXmlQuery query(queryLanguage);
3428 MessageSilencer silencer;
3429 query.setMessageHandler(&silencer);
3431 query.setQuery(inputQuery);
3432 QVERIFY(!query.isValid());
3435 void tst_QXmlQuery::identityConstraintFailure_data() const
3437 QTest::addColumn<QXmlQuery::QueryLanguage>("queryLanguage");
3438 QTest::addColumn<QString>("inputQuery");
3440 QTest::newRow("We don't have element constructors in identity constraint pattern, "
3441 "it's an XQuery feature(Selector).")
3442 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3443 << QString::fromLatin1("<e/>");
3445 QTest::newRow("We don't have functions in identity constraint pattern, "
3446 "it's an XPath feature(Selector).")
3447 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3448 << QString::fromLatin1("current-time()");
3450 QTest::newRow("We don't have element constructors in identity constraint pattern, "
3451 "it's an XQuery feature(Field).")
3452 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3453 << QString::fromLatin1("<e/>");
3455 QTest::newRow("We don't have functions in identity constraint pattern, "
3456 "it's an XPath feature(Field).")
3457 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3458 << QString::fromLatin1("current-time()");
3460 QTest::newRow("@attributeName is disallowed for the selector.")
3461 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3462 << QString::fromLatin1("@abc");
3464 QTest::newRow("attribute:: is disallowed for the selector.")
3465 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3466 << QString::fromLatin1("attribute::name");
3468 QTest::newRow("ancestor::name is disallowed for the selector.")
3469 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3470 << QString::fromLatin1("ancestor::name");
3472 QTest::newRow("ancestor::name is disallowed for the field.")
3473 << QXmlQuery::XmlSchema11IdentityConstraintField
3474 << QString::fromLatin1("ancestor::name");
3477 QTEST_MAIN(tst_QXmlQuery)
3479 #include "tst_qxmlquery.moc"
3480 #else //QTEST_XMLPATTERNS