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 #include <QAbstractMessageHandler>
47 #include <QNetworkReply>
48 #include <QtNetwork/QTcpServer>
49 #include <QtNetwork/QTcpSocket>
50 #include <QXmlFormatter>
54 #include <QXmlResultItems>
55 #include <QXmlSerializer>
57 #include "MessageSilencer.h"
58 #include "MessageValidator.h"
59 #include "NetworkOverrider.h"
60 #include "PushBaseliner.h"
61 #include "../qabstracturiresolver/TestURIResolver.h"
62 #include "../qsimplexmlnodemodel/TestSimpleNodeModel.h"
63 #include "TestFundament.h"
64 #include "../network-settings.h"
66 #if defined(Q_OS_SYMBIAN)
68 #define XMLPATTERNSDIR "xmlpatterns"
70 #define XMLPATTERNSDIR SRCDIR "../xmlpatterns"
77 \brief Tests class QXmlQuery.
79 This test is not intended for testing the engine, but the functionality specific
80 to the QXmlQuery class.
82 In other words, if you have an engine bug; don't add it here because it won't be
83 tested properly. Instead add it to the test suite.
86 class tst_QXmlQuery : public QObject
87 , private TestFundament
92 inline tst_QXmlQuery() : m_generatedBaselines(0)
99 void defaultConstructor() const;
100 void copyConstructor() const;
101 void constructorQXmlNamePool() const;
102 void constructorQXmlNamePoolQueryLanguage() const;
103 void constructorQXmlNamePoolWithinQSimpleXmlNodeModel() const;
104 void assignmentOperator() const;
105 void isValid() const;
106 void sequentialExecution() const;
107 void bindVariableQString() const;
108 void bindVariableQStringNoExternalDeclaration() const;
109 void bindVariableQXmlName() const;
110 void bindVariableQXmlNameTriggerWarnings() const;
111 void bindVariableQStringQIODevice() const;
112 void bindVariableQStringQIODeviceWithByteArray() const;
113 void bindVariableQStringQIODeviceWithString() const;
114 void bindVariableQStringQIODeviceWithQFile() const;
115 void bindVariableQXmlNameQIODevice() const;
116 void bindVariableQXmlNameQIODeviceTriggerWarnings() const;
117 void bindVariableXSLTSuccess() const;
118 void bindVariableTemporaryNode() const;
119 void setMessageHandler() const;
120 void messageHandler() const;
121 void evaluateToQAbstractXmlReceiverTriggerWarnings() const;
122 void evaluateToQXmlResultItems() const;
123 void evaluateToQXmlResultItemsTriggerWarnings() const;
124 void evaluateToQXmlResultItemsErrorAtEnd() const;
125 void evaluateToReceiver();
126 void evaluateToReceiver_data() const;
127 void evaluateToReceiverOnInvalidQuery() const;
128 void evaluateToQStringTriggerError() const;
129 void evaluateToQString() const;
130 void evaluateToQString_data() const;
131 void evaluateToQStringSignature() const;
132 void checkGeneratedBaselines() const;
133 void basicXQueryToQtTypeCheck() const;
134 void basicQtToXQueryTypeCheck() const;
135 void bindNode() const;
136 void relativeBaseURI() const;
137 void emptyBaseURI() const;
138 void roundTripDateWithinQXmlItem() const;
139 void bindingMissing() const;
140 void bindDefaultConstructedItem() const;
141 void bindDefaultConstructedItem_data() const;
142 void bindEmptyNullString() const;
143 void bindEmptyString() const;
144 void rebindVariableSameType() const;
145 void rebindVariableDifferentType() const;
146 void rebindVariableWithNullItem() const;
147 void eraseQXmlItemBinding() const;
148 void eraseDeviceBinding() const;
149 void constCorrectness() const;
150 void objectSize() const;
151 void setUriResolver() const;
152 void uriResolver() const;
153 void messageXML() const;
154 void resultItemsDeallocatedQuery() const;
155 void copyCheckMessageHandler() const;
156 void shadowedVariables() const;
157 void setFocusQXmlItem() const;
158 void setFocusQUrl() const;
159 void setFocusQIODevice() const;
160 void setFocusQIODeviceAvoidVariableClash() const;
161 void setFocusQIODeviceFailure() const;
162 void setFocusQIODeviceTriggerWarnings() const;
163 void setFocusQString() const;
164 void setFocusQStringFailure() const;
165 void setFocusQStringSignature() const;
166 void recompilationWithEvaluateToResultFailing() const;
167 void secondEvaluationWithEvaluateToResultFailing() const;
168 void recompilationWithEvaluateToReceiver() const;
169 void fnDocOnQIODeviceTimeout() const;
170 void evaluateToQStringListOnInvalidQuery() const;
171 void evaluateToQStringList() const;
172 void evaluateToQStringListTriggerWarnings() const;
173 void evaluateToQStringList_data() const;
174 void evaluateToQStringListNoConversion() const;
175 void evaluateToQIODevice() const;
176 void evaluateToQIODeviceTriggerWarnings() const;
177 void evaluateToQIODeviceSignature() const;
178 void evaluateToQIODeviceOnInvalidQuery() const;
179 void setQueryQIODeviceQUrl() const;
180 void setQueryQIODeviceQUrlTriggerWarnings() const;
181 void setQueryQString() const;
182 void setQueryQUrlSuccess() const;
183 void setQueryQUrlSuccess_data() const;
184 void setQueryQUrlFailSucceed() const;
185 void setQueryQUrlFailure() const;
186 void setQueryQUrlFailure_data() const;
187 void setQueryQUrlBaseURI() const;
188 void setQueryQUrlBaseURI_data() const;
189 void setQueryWithNonExistentQUrlOnValidQuery() const;
190 void setQueryWithInvalidQueryFromQUrlOnValidQuery() const;
191 void retrieveNameFromQuery() const;
192 void retrieveNameFromQuery_data() const;
193 void cleanupTestCase() const;
194 void declareUnavailableExternal() const;
195 void msvcCacheIssue() const;
196 void unavailableExternalVariable() const;
197 void useUriResolver() const;
198 void queryWithFocusAndVariable() const;
199 void undefinedFocus() const;
200 void basicFocusUsage() const;
202 void queryLanguage() const;
203 void queryLanguageSignature() const;
204 void enumQueryLanguage() const;
206 void setNetworkAccessManager() const;
207 void networkAccessManagerSignature() const;
208 void networkAccessManagerDefaultValue() const;
209 void networkAccessManager() const;
211 void setInitialTemplateNameQXmlName() const;
212 void setInitialTemplateNameQXmlNameSignature() const;
213 void setInitialTemplateNameQString() const;
214 void setInitialTemplateNameQStringSignature() const;
215 void initialTemplateName() const;
216 void initialTemplateNameSignature() const;
218 void fnDocNetworkAccessSuccess() const;
219 void fnDocNetworkAccessSuccess_data() const;
220 void fnDocNetworkAccessFailure() const;
221 void fnDocNetworkAccessFailure_data() const;
222 void multipleDocsAndFocus() const;
223 void multipleEvaluationsWithDifferentFocus() const;
224 void bindVariableQXmlQuery() const;
225 void bindVariableQXmlQuery_data() const;
226 void bindVariableQStringQXmlQuerySignature() const;
227 void bindVariableQXmlNameQXmlQuerySignature() const;
228 void bindVariableQXmlNameQXmlQuery() const;
229 void bindVariableQXmlQueryInvalidate() const;
230 void unknownSourceLocation() const;
232 void identityConstraintSuccess() const;
233 void identityConstraintFailure() const;
234 void identityConstraintFailure_data() const;
236 // 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.
237 // TODO bind stringlists, variant lists, both ways.
238 // TODO trigger serialization error, or any error in evaluateToushCallback().
239 // TODO let items travle between two queries, as seen in the SDK
240 // TODO what happens if the query declares local variable and external ones are provided?
246 * One excluded, since we skip static-base-uri.xq.
248 ExpectedQueryCount = 29
251 static void checkBaseURI(const QUrl &baseURI, const QString &candidate);
252 static QStringList queries();
253 static const char *const queriesDirectory;
255 int m_generatedBaselines;
256 int m_pushTestsCount;
257 const bool m_testNetwork;
260 void tst_QXmlQuery::checkBaseURI(const QUrl &baseURI, const QString &candidate)
262 /* The use of QFileInfo::canonicalFilePath() takes into account that drive letters
263 * on Windows may have different cases. */
264 QVERIFY(QDir(baseURI.toLocalFile()).relativeFilePath(QFileInfo(candidate).canonicalFilePath()).startsWith("../"));
267 const char *const tst_QXmlQuery::queriesDirectory = XMLPATTERNSDIR "/queries/";
269 QStringList tst_QXmlQuery::queries()
272 dir.cd(inputFile(QLatin1String(queriesDirectory)));
274 return dir.entryList(QStringList(QLatin1String("*.xq")));
277 void tst_QXmlQuery::defaultConstructor() const
279 /* Allocate instance in different orders. */
296 void tst_QXmlQuery::copyConstructor() const
298 /* Verify that we can take a const reference, and simply do a copy of a default constructed object. */
300 const QXmlQuery query1;
301 QXmlQuery query2(query1);
306 const QXmlQuery query1;
307 QXmlQuery query2(query1);
308 QXmlQuery query3(query2);
311 /* Verify that copying default values works. */
313 const QXmlQuery query1;
314 const QXmlQuery query2(query1);
315 QCOMPARE(query2.messageHandler(), query1.messageHandler());
316 QCOMPARE(query2.uriResolver(), query1.uriResolver());
317 QCOMPARE(query2.queryLanguage(), query1.queryLanguage());
318 QCOMPARE(query2.initialTemplateName(), query1.initialTemplateName());
319 QCOMPARE(query2.networkAccessManager(), query1.networkAccessManager());
328 * - initial template name
330 * sticks with the copy. */
332 MessageSilencer silencer;
333 TestURIResolver resolver;
334 QNetworkAccessManager networkManager;
335 QXmlQuery query1(QXmlQuery::XSLT20);
336 QXmlNamePool np1(query1.namePool());
338 query1.setMessageHandler(&silencer);
339 query1.setUriResolver(&resolver);
340 query1.setNetworkAccessManager(&networkManager);
342 const QXmlName name(np1, QLatin1String("localName"),
343 QLatin1String("http://example.com/"),
344 QLatin1String("prefix"));
345 query1.setInitialTemplateName(name);
347 const QXmlQuery query2(query1);
348 QCOMPARE(query2.messageHandler(), static_cast<QAbstractMessageHandler *>(&silencer));
349 QCOMPARE(query2.uriResolver(), static_cast<const QAbstractUriResolver *>(&resolver));
350 QCOMPARE(query2.queryLanguage(), QXmlQuery::XSLT20);
351 QCOMPARE(query2.initialTemplateName(), name);
352 QCOMPARE(query2.networkAccessManager(), &networkManager);
354 QXmlNamePool np2(query2.namePool());
356 QCOMPARE(name.namespaceUri(np2), QString::fromLatin1("http://example.com/"));
357 QCOMPARE(name.localName(np2), QString::fromLatin1("localName"));
358 QCOMPARE(name.prefix(np2), QString::fromLatin1("prefix"));
364 original.setFocus(QXmlItem(4));
365 original.setQuery(QLatin1String("."));
366 QVERIFY(original.isValid());
368 const QXmlQuery copy(original);
370 QXmlResultItems result;
371 copy.evaluateTo(&result);
372 QCOMPARE(result.next().toAtomicValue(), QVariant(4));
373 QVERIFY(result.next().isNull());
374 QVERIFY(!result.hasError());
377 /* Copy, set, compare. Check that copies are independent. */
379 // TODO all members except queryLanguage().
383 void tst_QXmlQuery::constructorQXmlNamePool() const
385 /* Check that the namepool we are passed, is actually used. */
389 const QXmlName name(np, QLatin1String("localName"),
390 QLatin1String("http://example.com/"),
391 QLatin1String("prefix"));
393 QXmlNamePool np2(query.namePool());
394 QCOMPARE(name.namespaceUri(np2), QString::fromLatin1("http://example.com/"));
395 QCOMPARE(name.localName(np2), QString::fromLatin1("localName"));
396 QCOMPARE(name.prefix(np2), QString::fromLatin1("prefix"));
400 Ensure that the internal variable loading mechanisms uses the user-supplied
403 If that is not the case, different name pools are used and the code crashes.
407 void tst_QXmlQuery::constructorQXmlNamePoolQueryLanguage() const
410 QXmlName name(np, QLatin1String("arbitraryName"));
412 QXmlQuery query(QXmlQuery::XQuery10, np);
415 input.setData("<yall/>");
417 QVERIFY(input.open(QIODevice::ReadOnly));
418 query.bindVariable(name, &input);
419 query.setQuery("string(doc($arbitraryName))");
422 query.evaluateTo(&result);
425 void tst_QXmlQuery::constructorQXmlNamePoolWithinQSimpleXmlNodeModel() const
427 class TestCTOR : public TestSimpleNodeModel
430 TestCTOR(const QXmlNamePool &np) : TestSimpleNodeModel(np)
434 void checkCTOR() const
436 /* If this fails to compile, the constructor has trouble with taking
437 * a mutable reference.
439 * The reason we use the this pointer explicitly, is to avoid a compiler
440 * warnings with MSVC 2005. */
441 QXmlQuery(this->namePool());
450 void tst_QXmlQuery::assignmentOperator() const
452 class ReturnURI : public QAbstractUriResolver
456 virtual QUrl resolve(const QUrl &relative,
457 const QUrl &baseURI) const
459 return baseURI.resolved(relative);
463 /* Assign this to this. */
470 /* Just call a couple of functions to give valgrind
471 * something to check. */
472 QVERIFY(!query.isValid());
473 query.messageHandler();
476 /* Assign null instances a couple of times. */
484 /* Just call a couple of functions to give valgrind
485 * something to check. */
486 QVERIFY(!query1.isValid());
487 query1.messageHandler();
489 /* Just call a couple of functions to give valgrind
490 * something to check. */
491 QVERIFY(!query2.isValid());
492 query2.messageHandler();
495 /* Create a query, set all the things it stores, and ensure it
496 * travels over to the new instance. */
498 MessageSilencer silencer;
499 const ReturnURI returnURI;
500 QXmlNamePool namePool;
502 QBuffer documentDevice;
503 documentDevice.setData(QByteArray("<e>a</e>"));
504 QVERIFY(documentDevice.open(QIODevice::ReadOnly));
506 QXmlQuery original(namePool);
507 QXmlName testName(namePool, QLatin1String("somethingToCheck"));
509 original.setMessageHandler(&silencer);
510 original.bindVariable(QLatin1String("var"), QXmlItem(1));
511 original.bindVariable(QLatin1String("device"), &documentDevice);
512 original.setUriResolver(&returnURI);
513 original.setFocus(QXmlItem(3));
514 original.setQuery(QLatin1String("$var, 1 + 1, ., string(doc($device))"));
516 /* Do a copy, and check that everything followed on into the copy. No modification
521 /* We use assignment operator, not copy constructor. */
524 QVERIFY(copy.isValid());
525 QCOMPARE(copy.uriResolver(), static_cast<const QAbstractUriResolver *>(&returnURI));
526 QCOMPARE(copy.messageHandler(), static_cast<QAbstractMessageHandler *>(&silencer));
527 QCOMPARE(testName.localName(copy.namePool()), QString::fromLatin1("somethingToCheck"));
529 QXmlResultItems result;
530 copy.evaluateTo(&result);
531 QCOMPARE(result.next().toAtomicValue(), QVariant(1));
532 QCOMPARE(result.next().toAtomicValue(), QVariant(2));
533 QCOMPARE(result.next().toAtomicValue(), QVariant(3));
534 QCOMPARE(result.next().toAtomicValue(), QVariant(QString::fromLatin1("a")));
535 QVERIFY(result.next().isNull());
536 QVERIFY(!result.hasError());
539 /* Copy, and change values. Things should detach. */
541 /* Evaluate the copy. */
543 MessageSilencer secondSilencer;
544 const ReturnURI secondUriResolver;
545 QBuffer documentDeviceCopy;
546 documentDeviceCopy.setData(QByteArray("<e>b</e>"));
547 QVERIFY(documentDeviceCopy.open(QIODevice::ReadOnly));
552 copy.setMessageHandler(&secondSilencer);
553 /* Here we rebind variable values. */
554 copy.bindVariable(QLatin1String("var"), QXmlItem(4));
555 copy.bindVariable(QLatin1String("device"), &documentDeviceCopy);
556 copy.setUriResolver(&secondUriResolver);
557 copy.setFocus(QXmlItem(6));
558 copy.setQuery(QLatin1String("$var, 1 + 1, ., string(doc($device))"));
560 /* Check that the copy picked up the new things. */
561 QVERIFY(copy.isValid());
562 QCOMPARE(copy.uriResolver(), static_cast<const QAbstractUriResolver *>(&secondUriResolver));
563 QCOMPARE(copy.messageHandler(), static_cast<QAbstractMessageHandler *>(&secondSilencer));
565 QXmlResultItems resultCopy;
566 copy.evaluateTo(&resultCopy);
567 QCOMPARE(resultCopy.next().toAtomicValue(), QVariant(4));
568 QCOMPARE(resultCopy.next().toAtomicValue(), QVariant(2));
569 QCOMPARE(resultCopy.next().toAtomicValue(), QVariant(6));
570 const QString stringedDevice(resultCopy.next().toAtomicValue().toString());
571 QCOMPARE(stringedDevice, QString::fromLatin1("b"));
572 QVERIFY(resultCopy.next().isNull());
573 QVERIFY(!resultCopy.hasError());
576 /* Evaluate the original. */
578 /* Check that the original is unchanged. */
579 QVERIFY(original.isValid());
580 QCOMPARE(original.uriResolver(), static_cast<const QAbstractUriResolver *>(&returnURI));
581 QCOMPARE(original.messageHandler(), static_cast<QAbstractMessageHandler *>(&silencer));
583 QXmlResultItems resultOriginal;
584 original.evaluateTo(&resultOriginal);
585 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(1));
586 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(2));
587 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(3));
588 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(QString::fromLatin1("a")));
589 QVERIFY(resultOriginal.next().isNull());
590 QVERIFY(!resultOriginal.hasError());
597 Since QXmlQuery doesn't seek devices to position 0, this code triggers a bug
598 where document caching doesn't work. Since the document caching doesn't work,
599 the device will be read twice, and the second time the device is at the end,
600 hence premature end of document.
602 void tst_QXmlQuery::sequentialExecution() const
605 inBuffer.setData(QByteArray("<input/>"));
606 QVERIFY(inBuffer.open(QIODevice::ReadOnly));
609 query.bindVariable("inputDocument", &inBuffer);
612 QBuffer outBuffer(&outArray);
613 outBuffer.open(QIODevice::WriteOnly);
615 const QString queryString(QLatin1String("doc($inputDocument)"));
616 query.setQuery(queryString);
618 QXmlFormatter formatter(query, &outBuffer);
620 QVERIFY(query.evaluateTo(&formatter));
622 /* If this line is removed, the bug isn't triggered. */
623 query.setQuery(queryString);
625 QVERIFY(query.evaluateTo(&formatter));
628 void tst_QXmlQuery::isValid() const
630 /* Check default value. */
632 QVERIFY(!query.isValid());
635 void tst_QXmlQuery::bindVariableQString() const
639 /* Bind with a null QXmlItem. */
640 query.bindVariable(QLatin1String("name"), QXmlItem());
645 /* Bind with a null QVariant. */
646 query.bindVariable(QLatin1String("name"), QXmlItem(QVariant()));
651 /* Bind with a null QXmlNodeModelIndex. */
652 query.bindVariable(QLatin1String("name"), QXmlItem(QXmlNodeModelIndex()));
656 void tst_QXmlQuery::bindVariableQStringNoExternalDeclaration() const
659 query.bindVariable(QLatin1String("foo"), QXmlItem(QLatin1String("Variable Value")));
660 query.setQuery(QLatin1String("$foo"));
662 QVERIFY(query.isValid());
665 QVERIFY(query.evaluateTo(&result));
667 QCOMPARE(result, QStringList() << QLatin1String("Variable Value"));
670 void tst_QXmlQuery::bindVariableQXmlName() const
675 void tst_QXmlQuery::bindVariableQXmlNameTriggerWarnings() const
679 QTest::ignoreMessage(QtWarningMsg, "The variable name cannot be null.");
680 query.bindVariable(QXmlName(), QVariant());
683 void tst_QXmlQuery::bindVariableQStringQIODeviceWithByteArray() const
687 QByteArray in("<e/>");
689 QVERIFY(device.open(QIODevice::ReadOnly));
691 query.bindVariable("doc", &device);
693 query.setQuery(QLatin1String("declare variable $doc external; $doc"));
695 QVERIFY(query.isValid());
697 /* Check the URI corresponding to the variable. */
699 QXmlResultItems items;
700 query.evaluateTo(&items);
702 QCOMPARE(items.next().toAtomicValue().toString(), QString::fromLatin1("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:doc"));
705 /* Now, actually load the document. We use the same QXmlQuery just to stress recompilation a bit. */
707 query.setQuery(QLatin1String("declare variable $doc external; doc($doc)"));
710 QBuffer outBuffer(&out);
711 QVERIFY(outBuffer.open(QIODevice::WriteOnly));
713 QXmlSerializer serializer(query, &outBuffer);
715 QVERIFY(query.evaluateTo(&serializer));
720 void tst_QXmlQuery::bindVariableQStringQIODeviceWithString() const
724 QString in("<qstring/>");
725 QByteArray inUtf8(in.toUtf8());
726 QBuffer inDevice(&inUtf8);
728 QVERIFY(inDevice.open(QIODevice::ReadOnly));
730 query.bindVariable("doc", &inDevice);
732 query.setQuery(QLatin1String("declare variable $doc external; doc($doc)"));
735 QBuffer outBuffer(&out);
736 QVERIFY(outBuffer.open(QIODevice::WriteOnly));
738 QXmlSerializer serializer(query, &outBuffer);
739 QVERIFY(query.evaluateTo(&serializer));
741 QCOMPARE(out, inUtf8);
744 void tst_QXmlQuery::bindVariableQStringQIODeviceWithQFile() const
747 QFile inDevice(QLatin1String(SRCDIR "input.xml"));
749 QVERIFY(inDevice.open(QIODevice::ReadOnly));
751 query.bindVariable("doc", &inDevice);
753 query.setQuery(QLatin1String("declare variable $doc external; doc($doc)"));
756 QBuffer outBuffer(&out);
757 QVERIFY(outBuffer.open(QIODevice::WriteOnly));
759 QXmlSerializer serializer(query, &outBuffer);
760 QVERIFY(query.evaluateTo(&serializer));
763 QCOMPARE(out, QByteArray("<!-- This is just a file for testing. --><input/>"));
766 void tst_QXmlQuery::bindVariableQStringQIODevice() const
770 /* Rebind the variable. */
772 /* First evaluation. */
774 QByteArray in1("<e1/>");
775 QBuffer inDevice1(&in1);
776 QVERIFY(inDevice1.open(QIODevice::ReadOnly));
778 query.bindVariable("in", &inDevice1);
779 query.setQuery(QLatin1String("doc($in)"));
782 QBuffer outDevice1(&out1);
783 QVERIFY(outDevice1.open(QIODevice::WriteOnly));
785 QXmlSerializer serializer(query, &outDevice1);
786 query.evaluateTo(&serializer);
790 /* Second evaluation, rebind variable. */
792 QByteArray in2("<e2/>");
793 QBuffer inDevice2(&in2);
794 QVERIFY(inDevice2.open(QIODevice::ReadOnly));
796 query.bindVariable(QLatin1String("in"), &inDevice2);
799 QBuffer outDevice2(&out2);
800 QVERIFY(outDevice2.open(QIODevice::WriteOnly));
802 QXmlSerializer serializer(query, &outDevice2);
803 QVERIFY(query.evaluateTo(&serializer));
808 // TODO trigger recompilation when setting qiodevices., and qiodevice overwritten by other type, etc.
811 void tst_QXmlQuery::bindVariableQXmlNameQIODevice() const
816 void tst_QXmlQuery::bindVariableQXmlNameQIODeviceTriggerWarnings() const
822 QTest::ignoreMessage(QtWarningMsg, "A null, or readable QIODevice must be passed.");
823 query.bindVariable(QXmlName(np, QLatin1String("foo")), &buffer);
825 QTest::ignoreMessage(QtWarningMsg, "The variable name cannot be null.");
826 query.bindVariable(QXmlName(), 0);
829 void tst_QXmlQuery::bindVariableXSLTSuccess() const
831 QXmlQuery stylesheet(QXmlQuery::XSLT20);
832 stylesheet.setInitialTemplateName(QLatin1String("main"));
834 stylesheet.bindVariable(QLatin1String("variableNoSelectNoBodyBoundWithBindVariable"),
835 QVariant(QLatin1String("MUST NOT SHOW 1")));
837 stylesheet.bindVariable(QLatin1String("variableSelectBoundWithBindVariable"),
838 QVariant(QLatin1String("MUST NOT SHOW 2")));
840 stylesheet.bindVariable(QLatin1String("variableSelectWithTypeIntBoundWithBindVariable"),
841 QVariant(QLatin1String("MUST NOT SHOW 3")));
843 stylesheet.bindVariable(QLatin1String("paramNoSelectNoBodyBoundWithBindVariable"),
844 QVariant(QLatin1String("param1")));
846 stylesheet.bindVariable(QLatin1String("paramNoSelectNoBodyBoundWithBindVariableRequired"),
847 QVariant(QLatin1String("param1")));
849 stylesheet.bindVariable(QLatin1String("paramSelectBoundWithBindVariable"),
850 QVariant(QLatin1String("param2")));
852 stylesheet.bindVariable(QLatin1String("paramSelectBoundWithBindVariableRequired"),
853 QVariant(QLatin1String("param3")));
855 stylesheet.bindVariable(QLatin1String("paramSelectWithTypeIntBoundWithBindVariable"),
858 stylesheet.bindVariable(QLatin1String("paramSelectWithTypeIntBoundWithBindVariableRequired"),
859 QVariant(QLatin1String("param5")));
861 stylesheet.setQuery(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/parameters.xsl"))));
863 QVERIFY(stylesheet.isValid());
866 QVERIFY(deviceOut.open(QIODevice::ReadWrite));
868 QVERIFY(stylesheet.evaluateTo(&deviceOut));
870 const QString result(QString::fromUtf8(deviceOut.data().constData()));
873 QString::fromLatin1("Variables: variableSelectsDefaultValue variableSelectsDefaultValue2 3 4 "
874 "Parameters: param1 param1 param2 param3 4 param5"));
877 void tst_QXmlQuery::bindVariableTemporaryNode() const
879 /* First we do it with QXmlResultItems staying in scope. */;
882 query1.setQuery("<anElement/>");
884 QXmlResultItems result1;
885 query1.evaluateTo(&result1);
887 QXmlQuery query2(query1);
888 query2.bindVariable("fromQuery1", result1.next());
889 query2.setQuery("$fromQuery1");
892 QVERIFY(query2.evaluateTo(&output));
894 QCOMPARE(output, QString::fromLatin1("<anElement/>\n"));
897 /* And now with it deallocating, so its internal DynamicContext pointer is
898 * released. This doesn't work in Qt 4.5 and is ok. */
901 query1.setQuery("<anElement/>");
906 QXmlResultItems result1;
907 query1.evaluateTo(&result1);
909 query2.bindVariable("fromQuery1", result1.next());
910 query2.setQuery("$fromQuery1");
914 return; // See comment above.
915 QVERIFY(query2.evaluateTo(&output));
917 QCOMPARE(output, QString::fromLatin1("<anElement/>\n"));
921 void tst_QXmlQuery::messageHandler() const
924 /* Check default value. */
926 QCOMPARE(query.messageHandler(), static_cast<QAbstractMessageHandler *>(0));
930 void tst_QXmlQuery::setMessageHandler() const
933 MessageSilencer silencer;
934 query.setMessageHandler(&silencer);
935 QCOMPARE(static_cast<QAbstractMessageHandler *>(&silencer), query.messageHandler());
938 void tst_QXmlQuery::evaluateToReceiver()
940 QFETCH(QString, inputQuery);
942 /* This query prints a URI specific to the local system. */
943 if(inputQuery == QLatin1String("static-base-uri.xq"))
947 const QString queryURI(inputFile(QLatin1String(queriesDirectory) + inputQuery));
948 QFile queryFile(queryURI);
950 QVERIFY(queryFile.exists());
951 QVERIFY(queryFile.open(QIODevice::ReadOnly));
955 MessageSilencer receiver;
956 query.setMessageHandler(&receiver);
957 query.setQuery(&queryFile, QUrl::fromLocalFile(queryURI));
959 /* We read all the queries, and some of them are invalid. However, we
960 * only want those that compile. */
965 QTextStream stream(&produced, QIODevice::WriteOnly);
966 PushBaseliner push(stream, query.namePool());
967 QVERIFY(push.isValid());
968 query.evaluateTo(&push);
970 const QString baselineName(inputFile(QLatin1String(SRCDIR "pushBaselines/") + inputQuery.left(inputQuery.length() - 2) + QString::fromLatin1("ref")));
971 QFile baseline(baselineName);
973 if(baseline.exists())
975 QVERIFY(baseline.open(QIODevice::ReadOnly | QIODevice::Text));
976 const QString stringedBaseline(QString::fromUtf8(baseline.readAll()));
977 QCOMPARE(produced, stringedBaseline);
981 QVERIFY(baseline.open(QIODevice::WriteOnly));
982 /* This is intentionally a warning, don't remove it. Update the baselines instead. */
983 qWarning() << "Generated baseline for:" << baselineName;
984 ++m_generatedBaselines;
986 baseline.write(produced.toUtf8());
990 void tst_QXmlQuery::evaluateToReceiver_data() const
992 QTest::addColumn<QString>("inputQuery");
994 foreach (QString const& query, queries())
996 /* This outputs a URI specific to the environment, so we can't use it for this
997 * particular test. */
998 if (query != QLatin1String("staticBaseURI.xq"))
999 QTest::newRow(query.toUtf8().constData()) << query;
1003 void tst_QXmlQuery::evaluateToReceiverOnInvalidQuery() const
1005 /* Invoke on a default constructed object. */
1008 QBuffer buffer(&out);
1009 buffer.open(QIODevice::WriteOnly);
1012 QXmlSerializer serializer(query, &buffer);
1013 QVERIFY(!query.evaluateTo(&serializer));
1016 /* Invoke on an invalid query; compile time error. */
1019 QBuffer buffer(&out);
1020 buffer.open(QIODevice::WriteOnly);
1021 MessageSilencer silencer;
1024 query.setMessageHandler(&silencer);
1025 query.setQuery(QLatin1String("1 + "));
1026 QXmlSerializer serializer(query, &buffer);
1027 QVERIFY(!query.evaluateTo(&serializer));
1030 /* Invoke on an invalid query; runtime error. */
1033 QBuffer buffer(&out);
1034 buffer.open(QIODevice::WriteOnly);
1035 MessageSilencer silencer;
1038 query.setMessageHandler(&silencer);
1039 query.setQuery(QLatin1String("error()"));
1040 QXmlSerializer serializer(query, &buffer);
1041 QVERIFY(!query.evaluateTo(&serializer));
1045 void tst_QXmlQuery::evaluateToQStringTriggerError() const
1047 /* Invoke on a default constructed object. */
1051 QVERIFY(!query.evaluateTo(&out));
1054 /* Invoke on an invalid query; compile time error. */
1057 MessageSilencer silencer;
1058 query.setMessageHandler(&silencer);
1060 query.setQuery(QLatin1String("1 + "));
1063 QVERIFY(!query.evaluateTo(&out));
1066 /* Invoke on an invalid query; runtime error. */
1069 MessageSilencer silencer;
1070 query.setMessageHandler(&silencer);
1072 query.setQuery(QLatin1String("error()"));
1075 QVERIFY(!query.evaluateTo(&out));
1079 void tst_QXmlQuery::evaluateToQString() const
1081 QFETCH(QString, query);
1082 QFETCH(QString, expectedOutput);
1084 QXmlQuery queryInstance;
1085 queryInstance.setQuery(query);
1086 QVERIFY(queryInstance.isValid());
1089 QVERIFY(queryInstance.evaluateTo(&result));
1091 QCOMPARE(result, expectedOutput);
1094 void tst_QXmlQuery::evaluateToQString_data() const
1096 QTest::addColumn<QString>("query");
1097 QTest::addColumn<QString>("expectedOutput");
1099 QTest::newRow("Two atomics")
1100 << QString::fromLatin1("1, 'two'")
1101 << QString::fromLatin1("1 two\n");
1103 QTest::newRow("An element")
1104 << QString::fromLatin1("<e>{1}</e>")
1105 << QString::fromLatin1("<e>1</e>\n");
1108 void tst_QXmlQuery::evaluateToQStringSignature() const
1110 const QXmlQuery query;
1114 /* evaluateTo(QString *) should be a const function. */
1115 query.evaluateTo(&output);
1118 void tst_QXmlQuery::evaluateToQAbstractXmlReceiverTriggerWarnings() const
1122 /* We check the return value as well as warning message here. */
1123 QTest::ignoreMessage(QtWarningMsg, "A non-null callback must be passed.");
1124 QCOMPARE(query.evaluateTo(static_cast<QAbstractXmlReceiver *>(0)),
1128 void tst_QXmlQuery::evaluateToQXmlResultItems() const
1130 /* Invoke on a default constructed object. */
1133 QXmlResultItems result;
1134 query.evaluateTo(&result);
1135 QVERIFY(result.next().isNull());
1139 void tst_QXmlQuery::evaluateToQXmlResultItemsTriggerWarnings() const
1141 QTest::ignoreMessage(QtWarningMsg, "A null pointer cannot be passed.");
1143 query.evaluateTo(static_cast<QXmlResultItems *>(0));
1146 void tst_QXmlQuery::evaluateToQXmlResultItemsErrorAtEnd() const
1149 MessageSilencer silencer;
1150 query.setMessageHandler(&silencer);
1151 query.setQuery(QLatin1String("1 to 100, fn:error()"));
1152 QVERIFY(query.isValid());
1155 query.evaluateTo(&it);
1157 while(!it.next().isNull())
1163 If baselines were generated, we flag it as a failure such that it gets
1164 attention, and that they are adjusted accordingly.
1166 void tst_QXmlQuery::checkGeneratedBaselines() const
1168 QCOMPARE(m_generatedBaselines, 0);
1170 /* If this check fails, the auto test setup is misconfigured, or files have
1171 * been added/removed without this number being updated. */
1172 QCOMPARE(m_pushTestsCount, int(ExpectedQueryCount));
1175 void tst_QXmlQuery::basicXQueryToQtTypeCheck() const
1177 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("allAtomics.xq"));
1178 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1181 query.setQuery(&queryFile);
1182 QVERIFY(query.isValid());
1185 query.evaluateTo(&it);
1187 QVariantList expectedValues;
1188 expectedValues.append(QString::fromLatin1("xs:untypedAtomic"));
1189 expectedValues.append(QDateTime(QDate(2002, 10, 10), QTime(23, 2, 11), Qt::UTC));
1190 expectedValues.append(QDate(2002, 10, 10));
1191 expectedValues.append(QVariant()); /* We currently doesn't support xs:time through the API. */
1193 expectedValues.append(QVariant()); /* xs:duration */
1194 expectedValues.append(QVariant()); /* xs:dayTimeDuration */
1195 expectedValues.append(QVariant()); /* xs:yearMonthDuration */
1197 if(sizeof(qreal) == sizeof(float)) {//ARM casts to Float not to double
1198 expectedValues.append(QVariant(float(3e3))); /* xs:float */
1199 expectedValues.append(QVariant(float(4e4))); /* xs:double */
1200 expectedValues.append(QVariant(float(2))); /* xs:decimal */
1202 expectedValues.append(QVariant(double(3e3))); /* xs:float */
1203 expectedValues.append(QVariant(double(4e4))); /* xs:double */
1204 expectedValues.append(QVariant(double(2))); /* xs:decimal */
1207 /* xs:integer and its sub-types. */
1208 expectedValues.append(QVariant(qlonglong(16)));
1209 expectedValues.append(QVariant(qlonglong(-6)));
1210 expectedValues.append(QVariant(qlonglong(-4)));
1211 expectedValues.append(QVariant(qlonglong(5)));
1212 expectedValues.append(QVariant(qlonglong(6)));
1213 expectedValues.append(QVariant(qlonglong(7)));
1214 expectedValues.append(QVariant(qlonglong(8)));
1215 expectedValues.append(QVariant(qlonglong(9)));
1216 expectedValues.append(QVariant(qulonglong(10)));
1217 expectedValues.append(QVariant(qlonglong(11)));
1218 expectedValues.append(QVariant(qlonglong(12)));
1219 expectedValues.append(QVariant(qlonglong(13)));
1220 expectedValues.append(QVariant(qlonglong(14)));
1222 expectedValues.append(QVariant()); /* xs:gYearMonth("1976-02"), */
1223 expectedValues.append(QVariant()); /* xs:gYear("2005-12:00"), */
1224 expectedValues.append(QVariant()); /* xs:gMonthDay("--12-25-14:00"), */
1225 expectedValues.append(QVariant()); /* xs:gDay("---25-14:00"), */
1226 expectedValues.append(QVariant()); /* xs:gMonth("--12-14:00"), */
1227 expectedValues.append(true); /* xs:boolean("true"), */
1228 expectedValues.append(QVariant(QByteArray::fromBase64(QByteArray("aaaa")))); /* xs:base64Binary("aaaa"), */
1229 expectedValues.append(QVariant(QByteArray::fromHex(QByteArray("FFFF")))); /* xs:hexBinary("FFFF"), */
1230 expectedValues.append(QVariant(QString::fromLatin1("http://example.com/"))); /* xs:anyURI("http://example.com/"), */
1231 QXmlNamePool np(query.namePool());
1232 expectedValues.append(QVariant(qVariantFromValue(QXmlName(np, QLatin1String("localName"),
1233 QLatin1String("http://example.com/2"),
1234 QLatin1String("prefix")))));
1236 expectedValues.append(QVariant(QString::fromLatin1("An xs:string")));
1237 expectedValues.append(QVariant(QString::fromLatin1("normalizedString")));
1238 expectedValues.append(QVariant(QString::fromLatin1("token")));
1239 expectedValues.append(QVariant(QString::fromLatin1("language")));
1240 expectedValues.append(QVariant(QString::fromLatin1("NMTOKEN")));
1241 expectedValues.append(QVariant(QString::fromLatin1("Name")));
1242 expectedValues.append(QVariant(QString::fromLatin1("NCName")));
1243 expectedValues.append(QVariant(QString::fromLatin1("ID")));
1244 expectedValues.append(QVariant(QString::fromLatin1("IDREF")));
1245 expectedValues.append(QVariant(QString::fromLatin1("ENTITY")));
1248 QXmlItem item(it.next());
1250 while(!item.isNull())
1252 QVERIFY(item.isAtomicValue());
1253 const QVariant produced(item.toAtomicValue());
1255 const QVariant &expected = expectedValues.at(i);
1257 /* For the cases where we can't represent a value in the XDM with Qt,
1258 * we return an invalid QVariant. */
1259 QCOMPARE(expected.isValid(), produced.isValid());
1261 QCOMPARE(produced.type(), expected.type());
1263 if(expected.isValid())
1265 /* This is only needed for xs:decimal though, for some reason. Probably
1266 * just artifacts created somewhere. */
1267 if(produced.type() == QVariant::Double)
1268 QVERIFY(qFuzzyCompare(produced.toDouble(), expected.toDouble()));
1269 else if(qVariantCanConvert<QXmlName>(produced))
1271 /* QVariant::operator==() does identity comparison, it doesn't delegate to operator==() of
1272 * the contained type, unless it's hardcoded into QVariant. */
1273 const QXmlName n1 = qVariantValue<QXmlName>(produced);
1274 const QXmlName n2 = qVariantValue<QXmlName>(expected);
1278 QCOMPARE(produced, expected);
1285 QCOMPARE(i, expectedValues.count());
1289 Send values from Qt into XQuery.
1291 void tst_QXmlQuery::basicQtToXQueryTypeCheck() const
1293 QFile queryFile(QLatin1String(queriesDirectory) + QLatin1String("allAtomicsExternally.xq"));
1294 QVERIFY(queryFile.exists());
1295 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1297 QCOMPARE(QVariant(QDate(1999, 9, 10)).type(), QVariant::Date);
1301 QXmlNamePool np(query.namePool());
1303 const QXmlName name(np, QLatin1String("localname"),
1304 QLatin1String("http://example.com"),
1305 QLatin1String("prefix"));
1307 query.bindVariable(QLatin1String("fromQUrl"), QXmlItem(QUrl(QString::fromLatin1("http://example.com/"))));
1308 query.bindVariable(QLatin1String("fromQByteArray"), QXmlItem(QByteArray("AAAA")));
1309 query.bindVariable(QLatin1String("fromBool"), QXmlItem(bool(true)));
1310 query.bindVariable(QLatin1String("fromQDate"), QXmlItem(QDate(2000, 10, 11)));
1311 // TODO Do with different QDateTime time specs
1312 query.bindVariable(QLatin1String("fromQDateTime"), QXmlItem(QDateTime(QDate(2001, 9, 10), QTime(1, 2, 3))));
1313 query.bindVariable(QLatin1String("fromDouble"), QXmlItem(double(3)));
1314 query.bindVariable(QLatin1String("fromFloat"), QXmlItem(float(4)));
1315 query.bindVariable(QLatin1String("integer"), QXmlItem(5));
1316 query.bindVariable(QLatin1String("fromQString"), QXmlItem(QString::fromLatin1("A QString")));
1317 query.bindVariable(QLatin1String("fromQChar"), QXmlItem(QChar::fromLatin1('C')));
1319 query.bindVariable(QLatin1String("fromIntLiteral"), QXmlItem(QVariant(654)));
1322 QVariant ui(uint(5));
1323 QCOMPARE(ui.type(), QVariant::UInt);
1324 query.bindVariable(QLatin1String("fromUInt"), ui);
1328 QVariant ulnglng(qulonglong(6));
1329 QCOMPARE(ulnglng.type(), QVariant::ULongLong);
1330 query.bindVariable(QLatin1String("fromULongLong"), ulnglng);
1334 QVariant qlnglng(qlonglong(7));
1335 QCOMPARE(qlnglng.type(), QVariant::LongLong);
1336 query.bindVariable(QLatin1String("fromLongLong"), qlnglng);
1339 query.setQuery(&queryFile);
1341 // TODO do queries which declares external variables with types. Tons of combos here.
1342 // TODO ensure that binding with QXmlItem() doesn't make a binding available.
1343 // TODO test rebinding a variable.
1345 QVERIFY(query.isValid());
1348 query.evaluateTo(&it);
1349 QXmlItem item(it.next());
1350 QVERIFY(!item.isNull());
1351 QVERIFY(item.isAtomicValue());
1353 if(sizeof(qreal) == sizeof(float)) //ARM casts to Float not to double
1354 QCOMPARE(item.toAtomicValue().toString(),
1355 QLatin1String("4 true 3 654 7 41414141 C 2000-10-11Z 2001-09-10T01:02:03 "
1356 "A QString http://example.com/ 5 6 true false false true true true true true true true "
1359 QCOMPARE(item.toAtomicValue().toString(),
1360 QLatin1String("4 true 3 654 7 41414141 C 2000-10-11Z 2001-09-10T01:02:03 "
1361 "A QString http://example.com/ 5 6 true true true true true true true true true true "
1366 void tst_QXmlQuery::bindNode() const
1369 TestSimpleNodeModel nodeModel(query.namePool());
1371 query.bindVariable(QLatin1String("node"), nodeModel.root());
1374 QVERIFY(buff.open(QIODevice::WriteOnly));
1376 query.setQuery(QLatin1String("declare variable $node external; $node"));
1377 QXmlSerializer serializer(query, &buff);
1379 QVERIFY(query.evaluateTo(&serializer));
1380 QCOMPARE(out, QByteArray("<nodeName/>"));
1384 Pass in a relative URI, and make sure it is resolved against the current application directory.
1386 void tst_QXmlQuery::relativeBaseURI() const
1389 query.setQuery(QLatin1String("fn:static-base-uri()"), QUrl(QLatin1String("a/relative/uri.weirdExtension")));
1390 QVERIFY(query.isValid());
1393 QBuffer buffer(&result);
1394 QVERIFY(buffer.open(QIODevice::ReadWrite));
1396 QXmlSerializer serializer(query, &buffer);
1397 QVERIFY(query.evaluateTo(&serializer));
1399 const QUrl loaded(QUrl::fromEncoded(result));
1400 QUrl appPath(QUrl::fromLocalFile(QCoreApplication::applicationFilePath()));
1402 QVERIFY(loaded.isValid());
1403 QVERIFY(appPath.isValid());
1404 QVERIFY(!loaded.isRelative());
1405 QVERIFY(!appPath.isRelative());
1407 QFileInfo dir(appPath.toLocalFile());
1408 dir.setFile(QString());
1410 /* We can't use QUrl::isParentOf() because it doesn't do what we want it to */
1411 if(!loaded.toLocalFile().startsWith(dir.absoluteFilePath()))
1412 QTextStream(stderr) << "dir.absoluteFilePath():" << dir.absoluteFilePath() << "loaded.toLocalFile():" << loaded.toLocalFile();
1414 checkBaseURI(loaded, dir.absoluteFilePath());
1417 void tst_QXmlQuery::emptyBaseURI() const
1420 query.setQuery(QLatin1String("fn:static-base-uri()"), QUrl());
1421 QVERIFY(query.isValid());
1424 QBuffer buffer(&result);
1425 QVERIFY(buffer.open(QIODevice::ReadWrite));
1427 QXmlSerializer serializer(query, &buffer);
1428 QVERIFY(query.evaluateTo(&serializer));
1430 const QUrl loaded(QUrl::fromEncoded(result));
1431 QUrl appPath(QUrl::fromLocalFile(QCoreApplication::applicationFilePath()));
1433 QVERIFY(loaded.isValid());
1434 QVERIFY(appPath.isValid());
1435 QVERIFY(!loaded.isRelative());
1436 QVERIFY(!appPath.isRelative());
1438 QFileInfo dir(appPath.toLocalFile());
1439 dir.setFile(QString());
1441 QCOMPARE(loaded, appPath);
1445 Ensure that QDate comes out as QDateTime.
1447 void tst_QXmlQuery::roundTripDateWithinQXmlItem() const
1449 const QDate date(1999, 9, 10);
1450 QVERIFY(date.isValid());
1452 const QVariant variant(date);
1453 QVERIFY(variant.isValid());
1454 QCOMPARE(variant.type(), QVariant::Date);
1456 const QXmlItem item(variant);
1457 QVERIFY(!item.isNull());
1458 QVERIFY(item.isAtomicValue());
1460 const QVariant out(item.toAtomicValue());
1461 QVERIFY(out.isValid());
1462 QCOMPARE(out.type(), QVariant::Date);
1463 QCOMPARE(out.toDate(), date);
1467 Check whether a query is valid, which uses an unbound variable.
1469 void tst_QXmlQuery::bindingMissing() const
1472 MessageSilencer messageHandler;
1473 query.setMessageHandler(&messageHandler);
1475 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
1476 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1477 query.setQuery(&queryFile);
1479 QVERIFY(!query.isValid());
1482 void tst_QXmlQuery::bindDefaultConstructedItem() const
1484 QFETCH(QXmlItem, item);
1487 MessageSilencer messageHandler;
1488 query.setMessageHandler(&messageHandler);
1490 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
1491 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1492 query.setQuery(&queryFile);
1493 query.bindVariable(QLatin1String("externalVariable"), item);
1495 QVERIFY(!query.isValid());
1498 void tst_QXmlQuery::bindDefaultConstructedItem_data() const
1500 QTest::addColumn<QXmlItem>("item");
1502 QTest::newRow("QXmlItem()") << QXmlItem();
1503 QTest::newRow("QXmlItem(QVariant())") << QXmlItem(QVariant());
1504 QTest::newRow("QXmlItem(QXmlNodeModelIndex())") << QXmlItem(QXmlNodeModelIndex());
1508 Remove a binding by binding QXmlItem() with the same name.
1510 void tst_QXmlQuery::eraseQXmlItemBinding() const
1513 MessageSilencer messageHandler;
1514 query.setMessageHandler(&messageHandler);
1516 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
1517 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1518 query.bindVariable(QLatin1String("externalVariable"), QXmlItem(3));
1519 query.setQuery(&queryFile);
1520 QVERIFY(query.isValid());
1523 QBuffer buffer(&result);
1524 QVERIFY(buffer.open(QIODevice::ReadWrite));
1526 QXmlSerializer serializer(query, &buffer);
1527 QVERIFY(query.evaluateTo(&serializer));
1529 QCOMPARE(result, QByteArray("3 6<e>3</e>false"));
1531 query.bindVariable(QLatin1String("externalVariable"), QXmlItem());
1532 QVERIFY(!query.isValid());
1536 Erase a variable binding
1538 void tst_QXmlQuery::eraseDeviceBinding() const
1540 /* Erase an existing QIODevice binding with another QIODevice binding. */
1544 QByteArray doc("<e/>");
1545 QBuffer buffer(&doc);
1546 QVERIFY(buffer.open(QIODevice::ReadOnly));
1548 query.bindVariable(QLatin1String("in"), &buffer);
1549 query.setQuery(QLatin1String("$in"));
1550 QVERIFY(query.isValid());
1552 query.bindVariable(QLatin1String("in"), 0);
1553 QVERIFY(!query.isValid());
1556 /* Erase an existing QXmlItem binding with another QIODevice binding. */
1560 query.bindVariable(QLatin1String("in"), QXmlItem(5));
1561 query.setQuery(QLatin1String("$in"));
1562 QVERIFY(query.isValid());
1564 query.bindVariable(QLatin1String("in"), 0);
1565 QVERIFY(!query.isValid());
1570 Bind a variable, evaluate, bind with a different value but same type, and evaluate again.
1572 void tst_QXmlQuery::rebindVariableSameType() const
1575 MessageSilencer messageHandler;
1576 query.setMessageHandler(&messageHandler);
1578 query.bindVariable(QLatin1String("externalVariable"), QXmlItem(3));
1581 QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
1582 QVERIFY(queryFile.open(QIODevice::ReadOnly));
1583 query.setQuery(&queryFile);
1586 QVERIFY(query.isValid());
1590 QBuffer buffer(&result);
1591 QVERIFY(buffer.open(QIODevice::ReadWrite));
1593 QXmlSerializer serializer(query, &buffer);
1594 QVERIFY(query.evaluateTo(&serializer));
1596 QCOMPARE(result, QByteArray("3 6<e>3</e>false"));
1600 query.bindVariable(QLatin1String("externalVariable"), QXmlItem(5));
1602 QBuffer buffer(&result);
1603 QVERIFY(buffer.open(QIODevice::ReadWrite));
1605 QXmlSerializer serializer(query, &buffer);
1606 QVERIFY(query.evaluateTo(&serializer));
1608 QCOMPARE(result, QByteArray("5 8<e>5</e>false"));
1613 void tst_QXmlQuery::rebindVariableDifferentType() const
1615 /* Rebind QXmlItem variable with QXmlItem variable. */
1618 query.bindVariable(QLatin1String("in"), QXmlItem(3));
1619 query.setQuery(QLatin1String("$in"));
1620 QVERIFY(query.isValid());
1622 query.bindVariable(QLatin1String("in"), QXmlItem("A string"));
1623 QVERIFY(!query.isValid());
1626 /* Rebind QIODevice variable with QXmlItem variable. */
1630 buffer.setData(QByteArray("<e/>"));
1631 QVERIFY(buffer.open(QIODevice::ReadOnly));
1633 query.bindVariable(QLatin1String("in"), &buffer);
1634 query.setQuery(QLatin1String("$in"));
1635 QVERIFY(query.isValid());
1637 query.bindVariable(QLatin1String("in"), QXmlItem("A string"));
1638 QVERIFY(!query.isValid());
1641 /* Rebind QXmlItem variable with QIODevice variable. The type of the
1642 * variable changes, so a recompile is necessary. */
1646 query.bindVariable(QLatin1String("in"), QXmlItem(QLatin1String("A string")));
1647 query.setQuery(QLatin1String("$in"));
1648 QVERIFY(query.isValid());
1651 buffer.setData(QByteArray("<e/>"));
1652 QVERIFY(buffer.open(QIODevice::ReadOnly));
1653 query.bindVariable(QLatin1String("in"), &buffer);
1654 QVERIFY(!query.isValid());
1658 void tst_QXmlQuery::rebindVariableWithNullItem() const
1662 query.bindVariable(QLatin1String("name"), QXmlItem(5));
1663 query.bindVariable(QLatin1String("name"), QXmlItem());
1666 void tst_QXmlQuery::constCorrectness() const
1668 QXmlResultItems result;
1670 tmp.setQuery(QLatin1String("1")); /* Just so we have a valid query. */
1671 const QXmlQuery query(tmp);
1673 /* These functions should be const. */
1675 query.evaluateTo(&result);
1677 query.uriResolver();
1678 query.messageHandler();
1681 QString dummyString;
1682 QTextStream dummyStream(&dummyString);
1683 PushBaseliner dummy(dummyStream, query.namePool());
1684 QVERIFY(dummy.isValid());
1685 query.evaluateTo(&dummy);
1689 void tst_QXmlQuery::objectSize() const
1691 /* We have a d pointer. */
1692 QCOMPARE(sizeof(QXmlQuery), sizeof(void *));
1695 void tst_QXmlQuery::setUriResolver() const
1697 /* Set a null resolver, and make sure it can take a const pointer. */
1700 query.setUriResolver(static_cast<const QAbstractUriResolver *>(0));
1701 QCOMPARE(query.uriResolver(), static_cast<const QAbstractUriResolver *>(0));
1705 TestURIResolver resolver;
1707 query.setUriResolver(&resolver);
1708 QCOMPARE(query.uriResolver(), static_cast<const QAbstractUriResolver *>(&resolver));
1712 void tst_QXmlQuery::uriResolver() const
1714 /* Check default value. */
1717 QCOMPARE(query.uriResolver(), static_cast<const QAbstractUriResolver *>(0));
1721 void tst_QXmlQuery::messageXML() const
1725 MessageValidator messageValidator;
1726 query.setMessageHandler(&messageValidator);
1728 query.setQuery(QLatin1String("1basicSyntaxError"));
1730 const QRegExp removeFilename(QLatin1String("Location: file:.*\\#"));
1731 QVERIFY(removeFilename.isValid());
1733 QVERIFY(messageValidator.success());
1734 QCOMPARE(messageValidator.received().remove(removeFilename),
1735 QString::fromLatin1("Type:3\n"
1736 "Description: <html xmlns='http://www.w3.org/1999/xhtml/'><body><p>syntax error, unexpected unknown keyword</p></body></html>\n"
1737 "Identifier: http://www.w3.org/2005/xqt-errors#XPST0003\n"
1742 1. Allocate QXmlResultItems
1743 2. Allocate QXmlQuery
1744 3. evaluate to the QXmlResultItems instance
1745 4. Dellocate the QXmlQuery instance
1746 5. Ensure QXmlResultItems works
1748 void tst_QXmlQuery::resultItemsDeallocatedQuery() const
1750 QXmlResultItems result;
1754 query.setQuery(QLatin1String("1, 2, xs:integer(<e>3</e>)"));
1755 query.evaluateTo(&result);
1758 QCOMPARE(result.next().toAtomicValue(), QVariant(1));
1759 QCOMPARE(result.next().toAtomicValue(), QVariant(2));
1760 QCOMPARE(result.next().toAtomicValue(), QVariant(3));
1761 QVERIFY(result.next().isNull());
1762 QVERIFY(!result.hasError());
1766 1. Bind variable with bindVariable()
1767 2. setQuery that has 'declare variable' with same name.
1768 3. Ensure the value inside the query is used. We don't guarantee this behavior
1769 but that's what we lock.
1771 void tst_QXmlQuery::shadowedVariables() const
1774 query.bindVariable("varName", QXmlItem(3));
1775 query.setQuery(QLatin1String("declare variable $varName := 5; $varName"));
1777 QXmlResultItems result;
1778 query.evaluateTo(&result);
1780 QCOMPARE(result.next().toAtomicValue(), QVariant(5));
1783 void tst_QXmlQuery::setFocusQXmlItem() const
1785 /* Make sure we can take a const reference. */
1788 const QXmlItem item;
1789 query.setFocus(item);
1792 // TODO evaluate with atomic value, check type
1793 // TODO evaluate with node, check type
1794 // TODO ensure that setFocus() triggers query recompilation, as appropriate.
1795 // TODO let the focus be undefined, call isvalid, call evaluate anyway
1796 // TODO let the focus be undefined, call evaluate directly
1799 void tst_QXmlQuery::setFocusQUrl() const
1801 /* Load a focus which isn't well-formed. */
1804 MessageSilencer silencer;
1806 query.setMessageHandler(&silencer);
1808 QVERIFY(!query.setFocus(QUrl(QLatin1String("data/notWellformed.xml"))));
1811 /* Ensure the same URI resolver is used. */
1813 QXmlQuery query(QXmlQuery::XSLT20);
1815 const TestURIResolver resolver(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/documentElement.xml"))));
1816 query.setUriResolver(&resolver);
1818 QVERIFY(query.setFocus(QUrl(QLatin1String("arbitraryURI"))));
1819 query.setQuery(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/copyWholeDocument.xsl"))));
1820 QVERIFY(query.isValid());
1823 QVERIFY(result.open(QIODevice::ReadWrite));
1824 QXmlSerializer serializer(query, &result);
1825 query.evaluateTo(&serializer);
1827 QCOMPARE(result.data(), QByteArray("<doc/>"));
1830 // TODO ensure that the focus type doesn't change from XSLT20 on the main instance.
1834 This code poses a challenge wrt. to internal caching.
1836 void tst_QXmlQuery::setFocusQIODevice() const
1842 focus.setData(QByteArray("<e>abc</e>"));
1843 QVERIFY(focus.open(QIODevice::ReadOnly));
1844 query.setFocus(&focus);
1845 query.setQuery(QLatin1String("string()"));
1846 QVERIFY(query.isValid());
1849 query.evaluateTo(&output);
1851 QCOMPARE(output, QString::fromLatin1("abc\n"));
1854 /* Set a new focus, make sure it changes & works. */
1857 focus2.setData(QByteArray("<e>abc2</e>"));
1858 QVERIFY(focus2.open(QIODevice::ReadOnly));
1859 query.setFocus(&focus2);
1860 QVERIFY(query.isValid());
1863 query.evaluateTo(&output);
1865 QCOMPARE(output, QString::fromLatin1("abc2\n"));
1870 Since we internally use variable bindings for implementing the focus, we need
1871 to make sure we don't clash in this area.
1873 void tst_QXmlQuery::setFocusQIODeviceAvoidVariableClash() const
1876 buffer.setData("<e>focus</e>");
1877 QVERIFY(buffer.open(QIODevice::ReadOnly));
1879 /* First we bind the variable name, then the focus. */
1882 query.bindVariable(QString(QLatin1Char('u')), QVariant(1));
1883 query.setFocus(&buffer);
1884 query.setQuery(QLatin1String("string()"));
1887 query.evaluateTo(&out);
1889 QCOMPARE(out, QString::fromLatin1("focus\n"));
1892 /* First we bind the focus, then the variable name. */
1895 QVERIFY(buffer.open(QIODevice::ReadOnly));
1896 query.setFocus(&buffer);
1897 query.bindVariable(QString(QLatin1Char('u')), QVariant(1));
1898 query.setQuery(QLatin1String("string()"));
1901 query.evaluateTo(&out);
1903 QCOMPARE(out, QString::fromLatin1("focus\n"));
1907 void tst_QXmlQuery::setFocusQIODeviceFailure() const
1909 /* A not well-formed input document. */
1913 MessageSilencer silencer;
1914 query.setMessageHandler(&silencer);
1917 input.setData("<e");
1918 QVERIFY(input.open(QIODevice::ReadOnly));
1920 QCOMPARE(query.setFocus(&input), false);
1924 void tst_QXmlQuery::setFocusQString() const
1928 /* Basic use of focus. */
1930 QVERIFY(query.setFocus(QLatin1String("<e>textNode</e>")));
1931 query.setQuery(QLatin1String("string()"));
1932 QVERIFY(query.isValid());
1934 query.evaluateTo(&out);
1935 QCOMPARE(out, QString::fromLatin1("textNode\n"));
1938 /* Set to a new focus, make sure it changes and works. */
1940 QVERIFY(query.setFocus(QLatin1String("<e>newFocus</e>")));
1942 query.evaluateTo(&out);
1943 QCOMPARE(out, QString::fromLatin1("newFocus\n"));
1947 void tst_QXmlQuery::setFocusQStringFailure() const
1950 MessageSilencer silencer;
1952 query.setMessageHandler(&silencer);
1953 QVERIFY(!query.setFocus(QLatin1String("<notWellformed")));
1955 /* Let's try the slight special case of a null string. */
1956 QVERIFY(!query.setFocus(QString()));
1959 void tst_QXmlQuery::setFocusQStringSignature() const
1962 MessageSilencer silencer;
1963 query.setMessageHandler(&silencer);
1965 const QString argument;
1966 /* We should take a const ref. */
1967 query.setFocus(argument);
1969 /* We should return a bool. */
1970 static_cast<bool>(query.setFocus(QString()));
1973 void tst_QXmlQuery::setFocusQIODeviceTriggerWarnings() const
1975 /* A null pointer. */
1979 QTest::ignoreMessage(QtWarningMsg, "A null QIODevice pointer cannot be passed.");
1980 QCOMPARE(query.setFocus(static_cast<QIODevice *>(0)), false);
1983 /* A non opened-device. */
1987 QBuffer notReadable;
1988 QVERIFY(!notReadable.isReadable());
1990 QTest::ignoreMessage(QtWarningMsg, "The device must be readable.");
1991 QCOMPARE(query.setFocus(¬Readable), false);
1995 void tst_QXmlQuery::fnDocNetworkAccessSuccess() const
1997 #if defined(Q_OS_WINCE) && !defined(_X86_)
1998 QStringList testsToSkip;
1999 testsToSkip << "http scheme" << "ftp scheme";
2000 if (testsToSkip.contains(QTest::currentDataTag()))
2001 QSKIP("Network tests are currently unsupported on Windows CE.", SkipSingle);
2004 QFETCH(QUrl, uriToOpen);
2005 QFETCH(QByteArray, expectedOutput);
2007 if(!uriToOpen.isValid())
2008 qDebug() << "uriToOpen:" << uriToOpen;
2010 QVERIFY(uriToOpen.isValid());
2013 query.bindVariable(QLatin1String("uri"), QVariant(uriToOpen));
2014 query.setQuery(QLatin1String("declare variable $uri external;\ndoc($uri)"));
2015 QVERIFY(query.isValid());
2018 QBuffer buffer(&result);
2019 QVERIFY(buffer.open(QIODevice::WriteOnly));
2021 QXmlSerializer serializer(query, &buffer);
2022 QVERIFY(query.evaluateTo(&serializer));
2024 QCOMPARE(result, expectedOutput);
2027 void tst_QXmlQuery::fnDocNetworkAccessSuccess_data() const
2029 QTest::addColumn<QUrl>("uriToOpen");
2030 QTest::addColumn<QByteArray>("expectedOutput");
2032 QTest::newRow("file scheme")
2033 << inputFileAsURI(QLatin1String(SRCDIR "input.xml"))
2034 << QByteArray("<!-- This is just a file for testing. --><input/>");
2036 QTest::newRow("data scheme with ASCII")
2037 /* QUrl::toPercentEncoding(QLatin1String("<e/>")) yields "%3Ce%2F%3E". */
2038 << QUrl::fromEncoded("data:application/xml,%3Ce%2F%3E")
2039 << QByteArray("<e/>");
2041 QTest::newRow("data scheme with ASCII no MIME type")
2042 << QUrl::fromEncoded("data:,%3Ce%2F%3E")
2043 << QByteArray("<e/>");
2045 QTest::newRow("data scheme with base 64")
2046 << QUrl::fromEncoded("data:application/xml;base64,PGUvPg==")
2047 << QByteArray("<e/>");
2049 QTest::newRow("qrc scheme")
2050 << QUrl::fromEncoded("qrc:/QXmlQueryTestData/data/oneElement.xml")
2051 << QByteArray("<oneElement/>");
2056 QTest::newRow("http scheme")
2057 << QUrl(QString("http://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/wellFormed.xml"))
2058 << QByteArray("<!-- a comment --><e from=\"http\">Some Text</e>");
2060 QTest::newRow("ftp scheme")
2061 << QUrl(QString("ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/wellFormed.xml"))
2062 << QByteArray("<!-- a comment --><e from=\"ftp\">Some Text</e>");
2066 void tst_QXmlQuery::fnDocNetworkAccessFailure() const
2068 QFETCH(QUrl, uriToOpen);
2070 QVERIFY(uriToOpen.isValid());
2073 MessageSilencer silencer;
2074 query.setMessageHandler(&silencer);
2075 query.bindVariable(QLatin1String("uri"), QVariant(uriToOpen));
2076 query.setQuery(QLatin1String("declare variable $uri external;\ndoc($uri)"));
2077 QVERIFY(query.isValid());
2079 QXmlResultItems result;
2080 query.evaluateTo(&result);
2082 while(!result.next().isNull())
2084 /* Just loop until the end. */
2087 // TODO do something that triggers a /timeout/.
2088 QVERIFY(result.hasError());
2091 void tst_QXmlQuery::fnDocNetworkAccessFailure_data() const
2093 QTest::addColumn<QUrl>("uriToOpen");
2095 QTest::newRow("data scheme, not-well-formed")
2096 << QUrl(QLatin1String("data:application/xml;base64,PGUvg==="));
2098 QTest::newRow("file scheme, non-existant file")
2099 << QUrl(QLatin1String("file:///example.com/does/notExist.xml"));
2101 QTest::newRow("http scheme, file not found")
2102 << QUrl(QLatin1String("http://www.example.com/does/not/exist.xml"));
2104 QTest::newRow("http scheme, nonexistent host")
2105 << QUrl(QLatin1String("http://this.host.does.not.exist.I.SWear"));
2107 QTest::newRow("qrc scheme, not well-formed")
2108 << QUrl(QLatin1String("qrc:/QXmlQueryTestData/notWellformed.xml"));
2110 QTest::newRow("'qrc:/', non-existing file")
2111 << QUrl(QLatin1String(":/QXmlQueryTestData/data/thisFileDoesNotExist.xml"));
2113 QTest::newRow("':/', this scheme is not supported")
2114 << QUrl(QLatin1String(":/QXmlQueryTestData/data/notWellformed.xml"));
2119 QTest::newRow("http scheme, not well-formed")
2120 << QUrl(QString("http://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/notWellformed.xml"));
2122 QTest::newRow("https scheme, not well-formed")
2123 << QUrl(QString("https://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/notWellformedViaHttps.xml"));
2125 QTest::newRow("https scheme, nonexistent host")
2126 << QUrl(QLatin1String("https://this.host.does.not.exist.I.SWear"));
2128 QTest::newRow("ftp scheme, nonexistent host")
2129 << QUrl(QLatin1String("ftp://this.host.does.not.exist.I.SWear"));
2131 QTest::newRow("ftp scheme, not well-formed")
2132 << QUrl(QString("ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/notWellFormed.xml"));
2136 Create a network timeout from a QIODevice binding such
2137 that we ensure we don't hang infinitely.
2139 void tst_QXmlQuery::fnDocOnQIODeviceTimeout() const
2145 server.listen(QHostAddress::LocalHost, 1088);
2148 client.connectToHost("localhost", 1088);
2149 QVERIFY(client.isReadable());
2153 MessageSilencer silencer;
2154 query.setMessageHandler(&silencer);
2156 query.bindVariable(QLatin1String("inDevice"), &client);
2157 query.setQuery(QLatin1String("declare variable $inDevice external;\ndoc($inDevice)"));
2158 QVERIFY(query.isValid());
2160 QXmlResultItems result;
2161 query.evaluateTo(&result);
2162 QXmlItem next(result.next());
2164 while(!next.isNull())
2166 next = result.next();
2169 QVERIFY(result.hasError());
2173 When changing query, the static context must change too, such that
2174 the source locations are updated.
2176 void tst_QXmlQuery::recompilationWithEvaluateToResultFailing() const
2179 MessageSilencer silencer;
2180 query.setMessageHandler(&silencer);
2182 query.setQuery(QLatin1String("1 + 1")); /* An arbitrary valid query. */
2183 QVERIFY(query.isValid()); /* Trigger query compilation. */
2185 query.setQuery(QLatin1String("fn:doc('doesNotExist.example.com.xml')")); /* An arbitrary invalid query that make use of a source location. */
2186 QVERIFY(query.isValid()); /* Trigger second compilation. */
2188 QXmlResultItems items;
2189 query.evaluateTo(&items);
2191 QVERIFY(items.hasError());
2194 void tst_QXmlQuery::secondEvaluationWithEvaluateToResultFailing() const
2197 MessageSilencer silencer;
2198 query.setMessageHandler(&silencer);
2200 query.setQuery(QLatin1String("1 + 1")); /* An arbitrary valid query. */
2201 QVERIFY(query.isValid()); /* Trigger query compilation. */
2203 query.setQuery(QLatin1String("fn:doc('doesNotExist.example.com.xml')")); /* An arbitrary invalid query that make use of a source location. */
2204 /* We don't call isValid(). */
2205 QXmlResultItems items;
2206 query.evaluateTo(&items);
2208 QVERIFY(items.hasError());
2212 Compilation is triggered in the evaluation function due to no call to QXmlQuery::isValid().
2214 void tst_QXmlQuery::recompilationWithEvaluateToReceiver() const
2217 MessageSilencer silencer;
2218 query.setMessageHandler(&silencer);
2220 query.setQuery(QLatin1String("1 + 1")); /* An arbitrary valid query. */
2221 QVERIFY(query.isValid()); /* Trigger query compilation. */
2223 query.setQuery(QLatin1String("fn:doc('doesNotExist.example.com.xml')")); /* An arbitrary invalid query that make use of a source location. */
2224 /* We don't call isValid(). */
2227 QBuffer buffer(&dummy);
2228 buffer.open(QIODevice::WriteOnly);
2230 QXmlSerializer serializer(query, &buffer);
2232 QVERIFY(!query.evaluateTo(&serializer));
2235 void tst_QXmlQuery::evaluateToQStringListOnInvalidQuery() const
2237 MessageSilencer silencer;
2239 /* Invoke on a default constructed object. */
2243 QVERIFY(!query.evaluateTo(&out));
2246 /* Invoke on a syntactically invalid query. */
2250 MessageSilencer silencer;
2252 query.setMessageHandler(&silencer);
2253 query.setQuery(QLatin1String("1 + "));
2255 QVERIFY(!query.evaluateTo(&out));
2258 /* Invoke on a query with the wrong type, one atomic. */
2263 query.setQuery(QLatin1String("1"));
2264 query.setMessageHandler(&silencer);
2265 QVERIFY(!query.evaluateTo(&out));
2268 /* Invoke on a query with the wrong type, one element. */
2273 query.setQuery(QLatin1String("<e/>"));
2274 QVERIFY(!query.evaluateTo(&out));
2277 /* Invoke on a query with the wrong type, mixed nodes & atomics. */
2282 query.setQuery(QLatin1String("<e/>, 1, 'a string'"));
2283 query.setMessageHandler(&silencer);
2284 QVERIFY(!query.evaluateTo(&out));
2287 /* Evaluate the empty sequence. */
2292 query.setQuery(QLatin1String("()"));
2293 QVERIFY(!query.evaluateTo(&out));
2294 QVERIFY(out.isEmpty());
2298 void tst_QXmlQuery::evaluateToQStringList() const
2300 QFETCH(QString, queryString);
2301 QFETCH(QStringList, expectedOutput);
2304 query.setQuery(queryString);
2306 QVERIFY(query.isValid());
2308 QVERIFY(query.evaluateTo(&out));
2310 QCOMPARE(out, expectedOutput);
2313 void tst_QXmlQuery::evaluateToQStringListTriggerWarnings() const
2317 QTest::ignoreMessage(QtWarningMsg, "A non-null callback must be passed.");
2318 QCOMPARE(query.evaluateTo(static_cast<QStringList *>(0)),
2322 void tst_QXmlQuery::evaluateToQStringList_data() const
2324 QTest::addColumn<QString>("queryString");
2325 QTest::addColumn<QStringList>("expectedOutput");
2327 QTest::newRow("One atomic")
2328 << QString::fromLatin1("(1 + 1) cast as xs:string")
2329 << QStringList(QString::fromLatin1("2"));
2332 QStringList expected;
2333 expected << QLatin1String("2");
2334 expected << QLatin1String("a string");
2336 QTest::newRow("Two atomics")
2337 << QString::fromLatin1("(1 + 1) cast as xs:string, 'a string'")
2341 QTest::newRow("A query which evaluates to sub-types of xs:string.")
2342 << QString::fromLatin1("xs:NCName('NCName'), xs:normalizedString(' a b c ')")
2343 << (QStringList() << QString::fromLatin1("NCName")
2344 << QString::fromLatin1(" a b c "));
2346 QTest::newRow("A query which evaluates to two elements.")
2347 << QString::fromLatin1("string(<e>theString1</e>), string(<e>theString2</e>)")
2348 << (QStringList() << QString::fromLatin1("theString1")
2349 << QString::fromLatin1("theString2"));
2353 Ensure that we don't automatically convert non-xs:string values.
2355 void tst_QXmlQuery::evaluateToQStringListNoConversion() const
2358 query.setQuery(QString::fromLatin1("<e/>"));
2359 QVERIFY(query.isValid());
2361 QVERIFY(!query.evaluateTo(&result));
2364 void tst_QXmlQuery::evaluateToQIODevice() const
2366 /* an XQuery, check that no indentation is performed. */
2369 QVERIFY(out.open(QIODevice::ReadWrite));
2372 query.setQuery(QLatin1String("<a><b/></a>"));
2373 QVERIFY(query.isValid());
2374 QVERIFY(query.evaluateTo(&out));
2375 QCOMPARE(out.data(), QByteArray("<a><b/></a>"));
2379 void tst_QXmlQuery::evaluateToQIODeviceTriggerWarnings() const
2383 QTest::ignoreMessage(QtWarningMsg, "The pointer to the device cannot be null.");
2384 QCOMPARE(query.evaluateTo(static_cast<QIODevice *>(0)),
2389 QTest::ignoreMessage(QtWarningMsg, "The device must be writable.");
2390 QCOMPARE(query.evaluateTo(&buffer),
2394 void tst_QXmlQuery::evaluateToQIODeviceSignature() const
2396 /* The function should be const. */
2399 QVERIFY(out.open(QIODevice::ReadWrite));
2401 const QXmlQuery query;
2403 query.evaluateTo(&out);
2407 void tst_QXmlQuery::evaluateToQIODeviceOnInvalidQuery() const
2410 QVERIFY(out.open(QIODevice::WriteOnly));
2412 /* On syntactically invalid query. */
2415 MessageSilencer silencer;
2416 query.setMessageHandler(&silencer);
2417 query.setQuery(QLatin1String("1 +"));
2418 QVERIFY(!query.isValid());
2419 QVERIFY(!query.evaluateTo(&out));
2422 /* On null QXmlQuery instance. */
2425 QVERIFY(!query.evaluateTo(&out));
2430 void tst_QXmlQuery::setQueryQIODeviceQUrl() const
2435 buffer.setData("1, 2, 2 + 1");
2436 QVERIFY(buffer.open(QIODevice::ReadOnly));
2439 query.setQuery(&buffer);
2440 QVERIFY(query.isValid());
2442 QXmlResultItems result;
2443 query.evaluateTo(&result);
2444 QCOMPARE(result.next().toAtomicValue(), QVariant(1));
2445 QCOMPARE(result.next().toAtomicValue(), QVariant(2));
2446 QCOMPARE(result.next().toAtomicValue(), QVariant(3));
2447 QVERIFY(result.next().isNull());
2448 QVERIFY(!result.hasError());
2451 /* Set query that is invalid. */
2454 buffer.setData("1, ");
2455 QVERIFY(buffer.open(QIODevice::ReadOnly));
2458 MessageSilencer silencer;
2459 query.setMessageHandler(&silencer);
2460 query.setQuery(&buffer);
2461 QVERIFY(!query.isValid());
2464 /* Check that the base URI passes through. */
2467 buffer.setData("string(static-base-uri())");
2468 QVERIFY(buffer.open(QIODevice::ReadOnly));
2471 query.setQuery(&buffer, QUrl::fromEncoded("http://www.example.com/QIODeviceQUrl"));
2472 QVERIFY(query.isValid());
2475 query.evaluateTo(&result);
2476 QCOMPARE(result, QStringList(QLatin1String("http://www.example.com/QIODeviceQUrl")));
2480 void tst_QXmlQuery::setQueryQIODeviceQUrlTriggerWarnings() const
2483 QTest::ignoreMessage(QtWarningMsg, "A null QIODevice pointer cannot be passed.");
2487 QTest::ignoreMessage(QtWarningMsg, "The device must be readable.");
2488 query.setQuery(&buffer);
2491 void tst_QXmlQuery::setQueryQString() const
2496 query.setQuery(QLatin1String("1, 2, 2 + 1"));
2497 QVERIFY(query.isValid());
2499 QXmlResultItems result;
2500 query.evaluateTo(&result);
2501 QCOMPARE(result.next().toAtomicValue(), QVariant(1));
2502 QCOMPARE(result.next().toAtomicValue(), QVariant(2));
2503 QCOMPARE(result.next().toAtomicValue(), QVariant(3));
2504 QVERIFY(result.next().isNull());
2505 QVERIFY(!result.hasError());
2508 /* Set query that is invalid. */
2510 MessageSilencer silencer;
2512 query.setMessageHandler(&silencer);
2513 query.setQuery(QLatin1String("1, "));
2514 QVERIFY(!query.isValid());
2517 /* Check that the base URI passes through. */
2520 query.setQuery(QLatin1String("string(static-base-uri())"), QUrl::fromEncoded("http://www.example.com/QIODeviceQUrl"));
2521 QVERIFY(query.isValid());
2524 query.evaluateTo(&result);
2525 QCOMPARE(result, QStringList(QLatin1String("http://www.example.com/QIODeviceQUrl")));
2529 void tst_QXmlQuery::setQueryQUrlSuccess() const
2531 #if defined(Q_OS_WINCE) && !defined(_X86_)
2532 QStringList testsToSkip;
2533 testsToSkip << "A valid query via the ftp scheme" << "A valid query via the http scheme";
2534 if (testsToSkip.contains(QTest::currentDataTag()))
2535 QSKIP("Network tests are currently unsupported on Windows CE.", SkipSingle);
2538 QFETCH(QUrl, queryURI);
2539 QFETCH(QByteArray, expectedOutput);
2541 QVERIFY(queryURI.isValid());
2545 MessageSilencer silencer;
2546 query.setMessageHandler(&silencer);
2548 query.setQuery(queryURI);
2549 QVERIFY(query.isValid());
2552 QBuffer buffer(&out);
2553 QVERIFY(buffer.open(QIODevice::WriteOnly));
2554 QXmlSerializer serializer(query, &buffer);
2556 query.evaluateTo(&serializer);
2557 QCOMPARE(out, expectedOutput);
2560 void tst_QXmlQuery::setQueryQUrlSuccess_data() const
2562 QTest::addColumn<QUrl>("queryURI");
2563 QTest::addColumn<QByteArray>("expectedOutput");
2565 QTest::newRow("A valid query via the data scheme")
2566 << QUrl::fromEncoded("data:application/xml,1%20%2B%201") /* "1 + 1" */
2569 QTest::newRow("A valid query via the file scheme")
2570 << QUrl::fromLocalFile(inputFile(QLatin1String(queriesDirectory) + QLatin1String("onePlusOne.xq")))
2576 QTest::newRow("A valid query via the ftp scheme")
2577 << QUrl::fromEncoded(QString("ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/viaFtp.xq").toLatin1())
2578 << QByteArray("This was received via FTP");
2580 QTest::newRow("A valid query via the http scheme")
2581 << QUrl::fromEncoded(QString("http://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/viaHttp.xq").toLatin1())
2582 << QByteArray("This was received via HTTP.");
2585 void tst_QXmlQuery::setQueryQUrlFailSucceed() const
2588 MessageSilencer silencer;
2590 query.setMessageHandler(&silencer);
2592 query.setQuery(QLatin1String("1 + 1"));
2593 QVERIFY(query.isValid());
2595 query.setQuery(QUrl::fromEncoded("file://example.com/does/not/exist"));
2596 QVERIFY(!query.isValid());
2599 void tst_QXmlQuery::setQueryQUrlFailure() const
2601 QFETCH(QUrl, queryURI);
2603 MessageSilencer silencer;
2606 query.setMessageHandler(&silencer);
2607 query.setQuery(queryURI);
2608 QVERIFY(!query.isValid());
2611 void tst_QXmlQuery::setQueryQUrlFailure_data() const
2613 QTest::addColumn<QUrl>("queryURI");
2615 QTest::newRow("Query via file:// that does not exist.")
2616 << QUrl::fromEncoded("file://example.com/does/not/exist");
2618 QTest::newRow("A query via file:// that is completely empty, but readable.")
2619 << QUrl::fromLocalFile(QCoreApplication::applicationFilePath()).resolved(QUrl("../xmlpatterns/queries/completelyEmptyQuery.xq"));
2622 const QString name(QLatin1String("nonReadableFile.xq"));
2623 QFile outFile(name);
2624 QVERIFY(outFile.open(QIODevice::WriteOnly));
2625 outFile.write(QByteArray("1"));
2627 /* On some windows versions, this fails, so we don't check that this works with QVERIFY. */
2628 outFile.setPermissions(QFile::Permissions(QFile::Permissions()));
2630 QTest::newRow("Query via file:/ that does not have read permissions.")
2631 << QUrl::fromLocalFile(QCoreApplication::applicationFilePath()).resolved(QUrl("nonReadableFile.xq"));
2637 QTest::newRow("Query via HTTP that does not exist.")
2638 << QUrl::fromEncoded("http://example.com/NoQuery/ISWear");
2641 QTest::newRow("Query via FTP that does not exist.")
2642 << QUrl::fromEncoded("ftp://example.com/NoQuery/ISWear");
2645 QTest::newRow("A query via http:// that is completely empty, but readable.")
2646 << QUrl::fromEncoded(QString(
2647 "http://" + QtNetworkSettings::serverName() + "/qtest/qxmlquery/completelyEmptyQuery.xq").toLatin1());
2649 QTest::newRow("A query via ftp:// that is completely empty, but readable.")
2650 << QUrl::fromEncoded(QString(
2651 "ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/completelyEmptyQuery.xq").toLatin1());
2655 void tst_QXmlQuery::setQueryQUrlBaseURI() const
2657 QFETCH(QUrl, inputBaseURI);
2658 QFETCH(QUrl, expectedBaseURI);
2662 query.setQuery(QUrl(QLatin1String("qrc:/QXmlQueryTestData/queries/staticBaseURI.xq")), inputBaseURI);
2663 QVERIFY(query.isValid());
2666 QVERIFY(query.evaluateTo(&result));
2667 QCOMPARE(result.count(), 1);
2669 if(qstrcmp(QTest::currentDataTag(), "Relative base URI") == 0)
2670 checkBaseURI(QUrl(result.first()), QCoreApplication::applicationFilePath());
2672 QCOMPARE(result.first(), expectedBaseURI.toString());
2675 void tst_QXmlQuery::setQueryQUrlBaseURI_data() const
2677 QTest::addColumn<QUrl>("inputBaseURI");
2678 QTest::addColumn<QUrl>("expectedBaseURI");
2680 QTest::newRow("absolute HTTP")
2681 << QUrl(QLatin1String("http://www.example.com/"))
2682 << QUrl(QLatin1String("http://www.example.com/"));
2684 QTest::newRow("None, so the query URI is used")
2686 << QUrl(QLatin1String("qrc:/QXmlQueryTestData/queries/staticBaseURI.xq"));
2688 QTest::newRow("Relative base URI")
2689 << QUrl(QLatin1String("../data/relative.uri"))
2694 1. Create a valid query.
2695 2. Call setQuery(QUrl), with a query file that doesn't exist.
2696 3. Verify that the query has changed state into invalid.
2698 void tst_QXmlQuery::setQueryWithNonExistentQUrlOnValidQuery() const
2702 MessageSilencer messageSilencer;
2703 query.setMessageHandler(&messageSilencer);
2705 query.setQuery(QLatin1String("1 + 1"));
2706 QVERIFY(query.isValid());
2708 query.setQuery(QUrl::fromEncoded("qrc:/QXmlQueryTestData/DOESNOTEXIST.xq"));
2709 QVERIFY(!query.isValid());
2713 1. Create a valid query.
2714 2. Call setQuery(QUrl), with a query file that is invalid.
2715 3. Verify that the query has changed state into invalid.
2717 void tst_QXmlQuery::setQueryWithInvalidQueryFromQUrlOnValidQuery() const
2721 MessageSilencer messageSilencer;
2722 query.setMessageHandler(&messageSilencer);
2724 query.setQuery(QLatin1String("1 + 1"));
2725 QVERIFY(query.isValid());
2727 query.setQuery(QUrl::fromEncoded("qrc:/QXmlQueryTestData/queries/syntaxError.xq"));
2728 QVERIFY(!query.isValid());
2732 This triggered two bugs:
2734 - First, the DynamicContext wasn't assigned to QXmlResultItems, meaning it went out of
2735 scope and therefore deallocated the document pool, and calls
2736 to QXmlResultItems::next() would use dangling pointers.
2738 - Conversion between QPatternist::Item and QXmlItem was incorrectly done, leading to nodes
2739 being treated as atomic values, and subsequent crashes.
2742 void tst_QXmlQuery::retrieveNameFromQuery() const
2744 QFETCH(QString, queryString);
2745 QFETCH(QString, expectedName);
2748 query.setQuery(queryString);
2749 QVERIFY(query.isValid());
2750 QXmlResultItems result;
2751 query.evaluateTo(&result);
2753 QVERIFY(!result.hasError());
2755 const QXmlItem item(result.next());
2756 QVERIFY(!result.hasError());
2757 QVERIFY(!item.isNull());
2758 QVERIFY(item.isNode());
2760 const QXmlNodeModelIndex node(item.toNodeModelIndex());
2761 QVERIFY(!node.isNull());
2763 QCOMPARE(node.model()->name(node).localName(query.namePool()), expectedName);
2766 void tst_QXmlQuery::retrieveNameFromQuery_data() const
2768 QTest::addColumn<QString>("queryString");
2769 QTest::addColumn<QString>("expectedName");
2771 QTest::newRow("Document-node")
2772 << QString::fromLatin1("document{<elementName/>}")
2775 QTest::newRow("Element")
2776 << QString::fromLatin1("document{<elementName/>}/*")
2777 << QString::fromLatin1("elementName");
2781 Binding a null QString leads to no variable binding, but an
2782 empty non-null QString is possible.
2784 void tst_QXmlQuery::bindEmptyNullString() const
2786 MessageSilencer messageHandler;
2788 query.setMessageHandler(&messageHandler);
2789 query.setQuery(QLatin1String("declare variable $v external; $v"));
2790 /* Here, we effectively pass an invalid QVariant. */
2791 query.bindVariable(QLatin1String("v"), QVariant(QString()));
2792 QVERIFY(!query.isValid());
2795 QVERIFY(!query.evaluateTo(&result));
2798 void tst_QXmlQuery::bindEmptyString() const
2801 query.bindVariable(QLatin1String("v"), QVariant(QString(QLatin1String(""))));
2802 query.setQuery(QLatin1String("declare variable $v external; $v"));
2803 QVERIFY(query.isValid());
2806 QVERIFY(query.evaluateTo(&result));
2807 QStringList expected((QString()));
2808 QCOMPARE(result, expected);
2811 void tst_QXmlQuery::cleanupTestCase() const
2813 /* Remove a weird file we created. */
2814 const QString name(QLatin1String("nonReadableFile.xq"));
2816 if(QFile::exists(name))
2819 QVERIFY(file.setPermissions(QFile::WriteOwner));
2820 QVERIFY(file.remove());
2824 void tst_QXmlQuery::declareUnavailableExternal() const
2827 MessageSilencer silencer;
2828 query.setMessageHandler(&silencer);
2829 query.setQuery(QLatin1String("declare variable $var external;"
2831 /* We do not bind $var with QXmlQuery::bindVariable(). */
2832 QVERIFY(!query.isValid());
2836 This test triggers an assert in one of the cache iterator
2837 with MSVC 2005 when compiled in debug mode.
2839 void tst_QXmlQuery::msvcCacheIssue() const
2842 query.bindVariable(QLatin1String("externalVariable"), QXmlItem("Variable Value"));
2843 query.setQuery(QUrl::fromLocalFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariableUsedTwice.xq")));
2845 QVERIFY(query.evaluateTo(&result));
2848 QStringList() << QString::fromLatin1("Variable Value") << QString::fromLatin1("Variable Value"));
2851 void tst_QXmlQuery::unavailableExternalVariable() const
2855 MessageSilencer silencer;
2856 query.setMessageHandler(&silencer);
2858 query.setQuery(QLatin1String("declare variable $foo external; 1"));
2860 QVERIFY(!query.isValid());
2864 Ensure that setUriResolver() affects \c fn:doc() and \c fn:doc-available().
2866 void tst_QXmlQuery::useUriResolver() const
2868 class TestUriResolver : public QAbstractUriResolver
2869 , private TestFundament
2872 TestUriResolver() {}
2873 virtual QUrl resolve(const QUrl &relative,
2874 const QUrl &baseURI) const
2877 return baseURI.resolved(inputFile(QLatin1String(queriesDirectory) + QLatin1String("simpleDocument.xml")));
2881 const TestUriResolver uriResolver;
2884 query.setUriResolver(&uriResolver);
2885 query.setQuery(QLatin1String("let $i := 'http://www.example.com/DoesNotExist'"
2886 "return (string(doc($i)), doc-available($i))"));
2889 QXmlResultItems result;
2890 query.evaluateTo(&result);
2892 QVERIFY(!result.hasError());
2893 QCOMPARE(result.next().toAtomicValue().toString(), QString::fromLatin1("text text node"));
2894 QCOMPARE(result.next().toAtomicValue().toBool(), true);
2895 QVERIFY(result.next().isNull());
2896 QVERIFY(!result.hasError());
2899 void tst_QXmlQuery::queryWithFocusAndVariable() const
2902 query.setFocus(QXmlItem(5));
2903 query.bindVariable(QLatin1String("var"), QXmlItem(2));
2905 query.setQuery(QLatin1String("string(. * $var)"));
2909 QVERIFY(query.evaluateTo(&result));
2911 QCOMPARE(result, QStringList(QLatin1String("10")));
2914 void tst_QXmlQuery::undefinedFocus() const
2918 MessageSilencer silencer;
2919 query.setMessageHandler(&silencer);
2921 query.setQuery(QLatin1String("."));
2922 QVERIFY(!query.isValid());
2925 void tst_QXmlQuery::basicFocusUsage() const
2929 MessageSilencer silencer;
2930 query.setMessageHandler(&silencer);
2932 query.setFocus(QXmlItem(5));
2933 query.setQuery(QLatin1String("string(. * .)"));
2934 QVERIFY(query.isValid());
2937 QVERIFY(query.evaluateTo(&result));
2939 QCOMPARE(result, QStringList(QLatin1String("25")));
2943 Triggers an ownership related crash.
2945 void tst_QXmlQuery::copyCheckMessageHandler() const
2948 QCOMPARE(query.messageHandler(), static_cast<QAbstractMessageHandler *>(0));
2950 query.setQuery(QLatin1String("doc('qrc:/QXmlQueryTestData/data/oneElement.xml')"));
2951 /* By now, we should have set the builtin message handler. */
2952 const QAbstractMessageHandler *const messageHandler = query.messageHandler();
2953 QVERIFY(messageHandler);
2956 /* This copies QXmlQueryPrivate::m_ownerObject, and its destructor
2957 * will delete it, and hence the builtin message handler attached to it. */
2958 QXmlQuery copy(query);
2961 QXmlResultItems result;
2962 query.evaluateTo(&result);
2964 while(!result.next().isNull())
2967 QVERIFY(!result.hasError());
2970 void tst_QXmlQuery::queryLanguage() const
2972 /* Check default value. */
2974 const QXmlQuery query;
2975 QCOMPARE(query.queryLanguage(), QXmlQuery::XQuery10);
2978 /* Check default value of copies default instance. */
2980 const QXmlQuery query1;
2981 const QXmlQuery query2(query1);
2983 QCOMPARE(query1.queryLanguage(), QXmlQuery::XQuery10);
2984 QCOMPARE(query2.queryLanguage(), QXmlQuery::XQuery10);
2988 void tst_QXmlQuery::queryLanguageSignature() const
2990 /* This getter should be const. */
2992 query.queryLanguage();
2995 void tst_QXmlQuery::enumQueryLanguage() const
2997 /* These enum values should be possible to OR for future plans. */
2998 QCOMPARE(int(QXmlQuery::XQuery10), 1);
2999 QCOMPARE(int(QXmlQuery::XSLT20), 2);
3000 QCOMPARE(int(QXmlQuery::XmlSchema11IdentityConstraintSelector), 1024);
3001 QCOMPARE(int(QXmlQuery::XmlSchema11IdentityConstraintField), 2048);
3002 QCOMPARE(int(QXmlQuery::XPath20), 4096);
3005 void tst_QXmlQuery::setInitialTemplateNameQXmlName() const
3007 QXmlQuery query(QXmlQuery::XSLT20);
3008 QXmlNamePool np(query.namePool());
3009 const QXmlName name(np, QLatin1String("main"));
3011 query.setInitialTemplateName(name);
3013 QCOMPARE(query.initialTemplateName(), name);
3015 query.setQuery(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/namedTemplate.xsl"))));
3016 QVERIFY(query.isValid());
3019 QVERIFY(result.open(QIODevice::ReadWrite));
3020 QXmlSerializer serializer(query, &result);
3021 query.evaluateTo(&serializer);
3023 QCOMPARE(result.data(), QByteArray("1 2 3 4 5"));
3025 // TODO invoke a template which has required params.
3028 void tst_QXmlQuery::setInitialTemplateNameQXmlNameSignature() const
3031 QXmlNamePool np(query.namePool());
3032 const QXmlName name(np, QLatin1String("foo"));
3034 /* The signature should take a const reference. */
3035 query.setInitialTemplateName(name);
3038 void tst_QXmlQuery::setInitialTemplateNameQString() const
3041 QXmlNamePool np(query.namePool());
3042 query.setInitialTemplateName(QLatin1String("foo"));
3044 QCOMPARE(query.initialTemplateName(), QXmlName(np, QLatin1String("foo")));
3047 void tst_QXmlQuery::setInitialTemplateNameQStringSignature() const
3049 const QString name(QLatin1String("name"));
3052 /* We should take a const reference. */
3053 query.setInitialTemplateName(name);
3056 void tst_QXmlQuery::initialTemplateName() const
3058 /* Check our default value. */
3060 QCOMPARE(query.initialTemplateName(), QXmlName());
3061 QVERIFY(query.initialTemplateName().isNull());
3064 void tst_QXmlQuery::initialTemplateNameSignature() const
3066 const QXmlQuery query;
3067 /* This should be a const member. */
3068 query.initialTemplateName();
3071 void tst_QXmlQuery::setNetworkAccessManager() const
3074 /* Ensure fn:doc() picks up the right QNetworkAccessManager. */
3076 NetworkOverrider networkOverrider(QUrl(QLatin1String("tag:example.com:DOESNOTEXIST")),
3077 QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/queries/simpleDocument.xml"))));
3078 QVERIFY(networkOverrider.isValid());
3081 query.setNetworkAccessManager(&networkOverrider);
3082 query.setQuery(QLatin1String("string(doc('tag:example.com:DOESNOTEXIST'))"));
3083 QVERIFY(query.isValid());
3086 QVERIFY(query.evaluateTo(&result));
3088 QCOMPARE(result, QStringList(QLatin1String("text text node")));
3091 /* Ensure setQuery() is using the right network manager. */
3093 NetworkOverrider networkOverrider(QUrl(QLatin1String("tag:example.com:DOESNOTEXIST")),
3094 QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/queries/concat.xq"))));
3095 QVERIFY(networkOverrider.isValid());
3098 query.setNetworkAccessManager(&networkOverrider);
3099 query.setQuery(QUrl("tag:example.com:DOESNOTEXIST"));
3100 QVERIFY(query.isValid());
3103 QVERIFY(query.evaluateTo(&result));
3105 QCOMPARE(result, QStringList(QLatin1String("abcdef")));
3108 void tst_QXmlQuery::networkAccessManagerSignature() const
3111 const QXmlQuery query;
3113 /* The function should be const. */
3114 query.networkAccessManager();
3117 void tst_QXmlQuery::networkAccessManagerDefaultValue() const
3119 const QXmlQuery query;
3121 QCOMPARE(query.networkAccessManager(), static_cast<QNetworkAccessManager *>(0));
3124 void tst_QXmlQuery::networkAccessManager() const
3126 /* Test that we return the network manager that was set. */
3128 QNetworkAccessManager manager;
3130 query.setNetworkAccessManager(&manager);
3131 QCOMPARE(query.networkAccessManager(), &manager);
3139 1. Load a document into QXmlQuery's document cache, by executing a query which does it.
3141 3. Change query, to one which uses the focus
3146 void tst_QXmlQuery::multipleDocsAndFocus() const
3150 /* We use string concatenation, since variable bindings might disturb what
3152 query.setQuery(QLatin1String("string(doc('") +
3153 inputFile(QLatin1String(XMLPATTERNSDIR "/queries/simpleDocument.xml")) +
3154 QLatin1String("'))"));
3155 query.setFocus(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/documentElement.xml"))));
3156 query.setQuery(QLatin1String("string(.)"));
3159 QVERIFY(query.evaluateTo(&result));
3174 void tst_QXmlQuery::multipleEvaluationsWithDifferentFocus() const
3179 query.setFocus(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/documentElement.xml"))));
3180 query.setQuery(QLatin1String("string(.)"));
3181 QVERIFY(query.evaluateTo(&result));
3183 query.setFocus(QUrl(inputFileAsURI(QLatin1String(XMLPATTERNSDIR "/stylesheets/documentElement.xml"))));
3184 QVERIFY(query.evaluateTo(&result));
3187 void tst_QXmlQuery::bindVariableQXmlQuery() const
3189 QFETCH(QString, query1);
3190 QFETCH(QString, query2);
3191 QFETCH(QString, expectedOutput);
3192 QFETCH(bool, expectedSuccess);
3194 MessageSilencer silencer;
3195 QXmlQuery xmlQuery1;
3196 xmlQuery1.setMessageHandler(&silencer);
3197 xmlQuery1.setQuery(query1);
3199 QXmlQuery xmlQuery2(xmlQuery1);
3200 xmlQuery2.bindVariable("query1", xmlQuery1);
3201 xmlQuery2.setQuery(query2);
3204 const bool querySuccess = xmlQuery2.evaluateTo(&output);
3206 QCOMPARE(querySuccess, expectedSuccess);
3209 QCOMPARE(output, expectedOutput);
3212 void tst_QXmlQuery::bindVariableQXmlQuery_data() const
3214 QTest::addColumn<QString>("query1");
3215 QTest::addColumn<QString>("query2");
3216 QTest::addColumn<QString>("expectedOutput");
3217 QTest::addColumn<bool>("expectedSuccess");
3219 QTest::newRow("First query has one atomic value.")
3225 QTest::newRow("First query has two atomic values.")
3231 QTest::newRow("First query is a node.")
3237 /* This is a good test, because it triggers the exception in the
3238 * bindVariable() call, as supposed to when the actual evaluation is done.
3240 QTest::newRow("First query has a dynamic error.")
3243 << QString() /* We don't care. */
3247 void tst_QXmlQuery::bindVariableQStringQXmlQuerySignature() const
3250 query1.setQuery("'dummy'");
3253 const QString name(QLatin1String("name"));
3255 /* We should be able to take a const QXmlQuery reference. Evaluation never mutate
3256 * QXmlQuery, and evaluation is what we do here. */
3257 query2.bindVariable(name, const_cast<const QXmlQuery &>(query1));
3260 void tst_QXmlQuery::bindVariableQXmlNameQXmlQuerySignature() const
3263 QXmlQuery query1(np);
3264 query1.setQuery("'dummy'");
3267 const QXmlName name(np, QLatin1String("name"));
3269 /* We should be able to take a const QXmlQuery reference. Evaluation never mutate
3270 * QXmlQuery, and evaluation is what we do here. */
3271 query2.bindVariable(name, const_cast<const QXmlQuery &>(query1));
3275 Check that the QXmlName is handled correctly.
3277 void tst_QXmlQuery::bindVariableQXmlNameQXmlQuery() const
3281 query1.setQuery(QLatin1String("1"));
3283 QXmlQuery query2(np);
3284 query2.bindVariable(QXmlName(np, QLatin1String("theName")), query1);
3285 query2.setQuery("$theName");
3288 query2.evaluateTo(&result);
3290 QCOMPARE(result, QString::fromLatin1("1\n"));
3293 void tst_QXmlQuery::bindVariableQXmlQueryInvalidate() const
3296 query.bindVariable(QLatin1String("name"), QVariant(1));
3297 query.setQuery("$name");
3298 QVERIFY(query.isValid());
3301 query2.setQuery("'query2'");
3303 query.bindVariable(QLatin1String("name"), query);
3304 QVERIFY(!query.isValid());
3307 void tst_QXmlQuery::unknownSourceLocation() const
3310 b.setData("<a><b/><b/></a>");
3311 b.open(QIODevice::ReadOnly);
3313 MessageSilencer silencer;
3315 query.bindVariable(QLatin1String("inputDocument"), &b);
3316 query.setMessageHandler(&silencer);
3318 query.setQuery(QLatin1String("doc($inputDocument)/a/(let $v := b/string() return if ($v) then $v else ())"));
3321 query.evaluateTo(&output);
3324 void tst_QXmlQuery::identityConstraintSuccess() const
3326 QXmlQuery::QueryLanguage queryLanguage = QXmlQuery::XmlSchema11IdentityConstraintSelector;
3328 /* We run this code for Selector and Field. */
3329 for(int i = 0; i < 3; ++i)
3331 QXmlNamePool namePool;
3332 QXmlResultItems result;
3336 QXmlQuery nodeSource(namePool);
3337 nodeSource.setQuery(QLatin1String("<e/>"));
3339 nodeSource.evaluateTo(&result);
3340 node = result.next();
3344 * 1. The focus is undefined, but it's still valid.
3345 * 2. We never evaluate. */
3347 QXmlQuery query(queryLanguage);
3348 query.setQuery(QLatin1String("a"));
3349 QVERIFY(query.isValid());
3353 * 1. The focus is undefined, but it's still valid.
3354 * 2. We afterwards set the focus. */
3356 QXmlQuery query(queryLanguage, namePool);
3357 query.setQuery(QLatin1String("a"));
3358 query.setFocus(node);
3359 QVERIFY(query.isValid());
3363 * 1. The focus is undefined, but it's still valid.
3364 * 2. We afterwards set the focus.
3365 * 3. We evaluate. */
3367 QXmlQuery query(queryLanguage, namePool);
3368 query.setQuery(QString(QLatin1Char('.')));
3369 query.setFocus(node);
3370 QVERIFY(query.isValid());
3373 QVERIFY(query.evaluateTo(&result));
3374 QCOMPARE(result, QString::fromLatin1("<e/>\n"));
3377 /* A slightly more complex Field. */
3379 QXmlQuery query(queryLanguage);
3380 query.setQuery(QLatin1String("* | .//xml:*/."));
3381 QVERIFY(query.isValid());
3384 /* @ is only allowed in Field. */
3385 if(queryLanguage == QXmlQuery::XmlSchema11IdentityConstraintField)
3387 QXmlQuery query(QXmlQuery::XmlSchema11IdentityConstraintField);
3388 query.setQuery(QLatin1String("@abc"));
3389 QVERIFY(query.isValid());
3392 /* Field allows attribute:: and child:: .*/
3393 if(queryLanguage == QXmlQuery::XmlSchema11IdentityConstraintField)
3395 QXmlQuery query(QXmlQuery::XmlSchema11IdentityConstraintField);
3396 query.setQuery(QLatin1String("attribute::name | child::name"));
3397 QVERIFY(query.isValid());
3400 /* Selector allows only child:: .*/
3402 QXmlQuery query(QXmlQuery::XmlSchema11IdentityConstraintSelector);
3403 query.setQuery(QLatin1String("child::name"));
3404 QVERIFY(query.isValid());
3408 queryLanguage = QXmlQuery::XmlSchema11IdentityConstraintField;
3410 queryLanguage = QXmlQuery::XPath20;
3414 Q_DECLARE_METATYPE(QXmlQuery::QueryLanguage);
3417 We just do some basic tests for boot strapping and sanity checking. The actual regression
3418 testing is in the Schema suite.
3420 void tst_QXmlQuery::identityConstraintFailure() const
3422 QFETCH(QXmlQuery::QueryLanguage, queryLanguage);
3423 QFETCH(QString, inputQuery);
3425 QXmlQuery query(queryLanguage);
3426 MessageSilencer silencer;
3427 query.setMessageHandler(&silencer);
3429 query.setQuery(inputQuery);
3430 QVERIFY(!query.isValid());
3433 void tst_QXmlQuery::identityConstraintFailure_data() const
3435 QTest::addColumn<QXmlQuery::QueryLanguage>("queryLanguage");
3436 QTest::addColumn<QString>("inputQuery");
3438 QTest::newRow("We don't have element constructors in identity constraint pattern, "
3439 "it's an XQuery feature(Selector).")
3440 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3441 << QString::fromLatin1("<e/>");
3443 QTest::newRow("We don't have functions in identity constraint pattern, "
3444 "it's an XPath feature(Selector).")
3445 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3446 << QString::fromLatin1("current-time()");
3448 QTest::newRow("We don't have element constructors in identity constraint pattern, "
3449 "it's an XQuery feature(Field).")
3450 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3451 << QString::fromLatin1("<e/>");
3453 QTest::newRow("We don't have functions in identity constraint pattern, "
3454 "it's an XPath feature(Field).")
3455 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3456 << QString::fromLatin1("current-time()");
3458 QTest::newRow("@attributeName is disallowed for the selector.")
3459 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3460 << QString::fromLatin1("@abc");
3462 QTest::newRow("attribute:: is disallowed for the selector.")
3463 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3464 << QString::fromLatin1("attribute::name");
3466 QTest::newRow("ancestor::name is disallowed for the selector.")
3467 << QXmlQuery::XmlSchema11IdentityConstraintSelector
3468 << QString::fromLatin1("ancestor::name");
3470 QTest::newRow("ancestor::name is disallowed for the field.")
3471 << QXmlQuery::XmlSchema11IdentityConstraintField
3472 << QString::fromLatin1("ancestor::name");
3475 QTEST_MAIN(tst_QXmlQuery)
3477 #include "tst_qxmlquery.moc"