tests/auto/qxmlquery/tst_qxmlquery.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 #include <QtTest/QtTest>
       
    44 
       
    45 #ifdef QTEST_XMLPATTERNS
       
    46 
       
    47 #include <QAbstractMessageHandler>
       
    48 #include <QFileInfo>
       
    49 #include <QNetworkReply>
       
    50 #include <QtNetwork/QTcpServer>
       
    51 #include <QtNetwork/QTcpSocket>
       
    52 #include <QXmlFormatter>
       
    53 #include <QXmlItem>
       
    54 #include <QXmlName>
       
    55 #include <QXmlQuery>
       
    56 #include <QXmlResultItems>
       
    57 #include <QXmlSerializer>
       
    58 
       
    59 #include "MessageSilencer.h"
       
    60 #include "MessageValidator.h"
       
    61 #include "NetworkOverrider.h"
       
    62 #include "PushBaseliner.h"
       
    63 #include "../qabstracturiresolver/TestURIResolver.h"
       
    64 #include "../qsimplexmlnodemodel/TestSimpleNodeModel.h"
       
    65 #include "TestFundament.h"
       
    66 #include "../network-settings.h"
       
    67 
       
    68 #if defined(Q_OS_SYMBIAN)
       
    69 #define SRCDIR ""
       
    70 #endif
       
    71 
       
    72 /*!
       
    73  \class tst_QXmlQuery
       
    74  \internal
       
    75  \since 4.4
       
    76  \brief Tests class QXmlQuery.
       
    77 
       
    78  This test is not intended for testing the engine, but the functionality specific
       
    79  to the QXmlQuery class.
       
    80 
       
    81  In other words, if you have an engine bug; don't add it here because it won't be
       
    82  tested properly. Instead add it to the test suite.
       
    83 
       
    84  */
       
    85 class tst_QXmlQuery : public QObject
       
    86                     , private TestFundament
       
    87 {
       
    88     Q_OBJECT
       
    89 
       
    90 public:
       
    91     inline tst_QXmlQuery() : m_generatedBaselines(0)
       
    92                            , m_pushTestsCount(0)
       
    93                            , m_testNetwork(true)
       
    94     {
       
    95         Q_SET_DEFAULT_IAP
       
    96     }
       
    97 
       
    98 private Q_SLOTS:
       
    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;
       
   201 
       
   202     void queryLanguage() const;
       
   203     void queryLanguageSignature() const;
       
   204     void enumQueryLanguage() const;
       
   205 
       
   206     void setNetworkAccessManager() const;
       
   207     void networkAccessManagerSignature() const;
       
   208     void networkAccessManagerDefaultValue() const;
       
   209     void networkAccessManager() const;
       
   210 
       
   211     void setInitialTemplateNameQXmlName() const;
       
   212     void setInitialTemplateNameQXmlNameSignature() const;
       
   213     void setInitialTemplateNameQString() const;
       
   214     void setInitialTemplateNameQStringSignature() const;
       
   215     void initialTemplateName() const;
       
   216     void initialTemplateNameSignature() const;
       
   217 
       
   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;
       
   231 
       
   232     void identityConstraintSuccess() const;
       
   233     void identityConstraintFailure() const;
       
   234     void identityConstraintFailure_data() const;
       
   235 
       
   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?
       
   241 
       
   242 private:
       
   243     enum
       
   244     {
       
   245         /**
       
   246          * One excluded, since we skip static-base-uri.xq.
       
   247          */
       
   248         ExpectedQueryCount = 29
       
   249     };
       
   250 
       
   251     static void checkBaseURI(const QUrl &baseURI, const QString &candidate);
       
   252     static QStringList queries();
       
   253     static const char *const queriesDirectory;
       
   254 
       
   255     int m_generatedBaselines;
       
   256     int m_pushTestsCount;
       
   257     const bool m_testNetwork;
       
   258 };
       
   259 
       
   260 void tst_QXmlQuery::checkBaseURI(const QUrl &baseURI, const QString &candidate)
       
   261 {
       
   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("../"));
       
   265 }
       
   266 
       
   267 const char *const tst_QXmlQuery::queriesDirectory = SRCDIR "../xmlpatterns/queries/";
       
   268 
       
   269 QStringList tst_QXmlQuery::queries()
       
   270 {
       
   271     QDir dir;
       
   272     dir.cd(inputFile(QLatin1String(queriesDirectory)));
       
   273 
       
   274     return dir.entryList(QStringList(QLatin1String("*.xq")));
       
   275 }
       
   276 
       
   277 void tst_QXmlQuery::defaultConstructor() const
       
   278 {
       
   279     /* Allocate instance in different orders. */
       
   280     {
       
   281         QXmlQuery query;
       
   282     }
       
   283 
       
   284     {
       
   285         QXmlQuery query1;
       
   286         QXmlQuery query2;
       
   287     }
       
   288 
       
   289     {
       
   290         QXmlQuery query1;
       
   291         QXmlQuery query2;
       
   292         QXmlQuery query3;
       
   293     }
       
   294 }
       
   295 
       
   296 void tst_QXmlQuery::copyConstructor() const
       
   297 {
       
   298     /* Verify that we can take a const reference, and simply do a copy of a default constructed object. */
       
   299     {
       
   300         const QXmlQuery query1;
       
   301         QXmlQuery query2(query1);
       
   302     }
       
   303 
       
   304     /* Copy twice. */
       
   305     {
       
   306         const QXmlQuery query1;
       
   307         QXmlQuery query2(query1);
       
   308         QXmlQuery query3(query2);
       
   309     }
       
   310 
       
   311     /* Verify that copying default values works. */
       
   312     {
       
   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());
       
   320     }
       
   321 
       
   322     /* Check that the
       
   323      *
       
   324      * - name pool
       
   325      * - URI resolver
       
   326      * - message handler
       
   327      * - query language
       
   328      * - initial template name
       
   329      *
       
   330      *   sticks with the copy. */
       
   331     {
       
   332         MessageSilencer silencer;
       
   333         TestURIResolver resolver;
       
   334         QNetworkAccessManager networkManager;
       
   335         QXmlQuery query1(QXmlQuery::XSLT20);
       
   336         QXmlNamePool np1(query1.namePool());
       
   337 
       
   338         query1.setMessageHandler(&silencer);
       
   339         query1.setUriResolver(&resolver);
       
   340         query1.setNetworkAccessManager(&networkManager);
       
   341 
       
   342         const QXmlName name(np1, QLatin1String("localName"),
       
   343                                  QLatin1String("http://example.com/"),
       
   344                                  QLatin1String("prefix"));
       
   345         query1.setInitialTemplateName(name);
       
   346 
       
   347         const QXmlQuery query2(query1);
       
   348         QCOMPARE(query2.messageHandler(), &silencer);
       
   349         QCOMPARE(query2.uriResolver(), &resolver);
       
   350         QCOMPARE(query2.queryLanguage(), QXmlQuery::XSLT20);
       
   351         QCOMPARE(query2.initialTemplateName(), name);
       
   352         QCOMPARE(query2.networkAccessManager(), &networkManager);
       
   353 
       
   354         QXmlNamePool np2(query2.namePool());
       
   355 
       
   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"));
       
   359     }
       
   360 
       
   361     {
       
   362         QXmlQuery original;
       
   363 
       
   364         original.setFocus(QXmlItem(4));
       
   365         original.setQuery(QLatin1String("."));
       
   366         QVERIFY(original.isValid());
       
   367 
       
   368         const QXmlQuery copy(original);
       
   369 
       
   370         QXmlResultItems result;
       
   371         copy.evaluateTo(&result);
       
   372         QCOMPARE(result.next().toAtomicValue(), QVariant(4));
       
   373         QVERIFY(result.next().isNull());
       
   374         QVERIFY(!result.hasError());
       
   375     }
       
   376 
       
   377     /* Copy, set, compare. Check that copies are independent. */
       
   378     {
       
   379         // TODO all members except queryLanguage().
       
   380     }
       
   381 }
       
   382 
       
   383 void tst_QXmlQuery::constructorQXmlNamePool() const
       
   384 {
       
   385     /* Check that the namepool we are passed, is actually used. */
       
   386     QXmlNamePool np;
       
   387 
       
   388     QXmlQuery query(np);
       
   389     const QXmlName name(np, QLatin1String("localName"),
       
   390                             QLatin1String("http://example.com/"),
       
   391                             QLatin1String("prefix"));
       
   392 
       
   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"));
       
   397 }
       
   398 
       
   399 /*!
       
   400   Ensure that the internal variable loading mechanisms uses the user-supplied
       
   401   name pool.
       
   402 
       
   403   If that is not the case, different name pools are used and the code crashes.
       
   404 
       
   405   \since 4.5
       
   406  */
       
   407 void tst_QXmlQuery::constructorQXmlNamePoolQueryLanguage() const
       
   408 {
       
   409     QXmlNamePool np;
       
   410     QXmlName name(np, QLatin1String("arbitraryName"));
       
   411 
       
   412     QXmlQuery query(QXmlQuery::XQuery10, np);
       
   413 
       
   414     QBuffer input;
       
   415     input.setData("<yall/>");
       
   416 
       
   417     QVERIFY(input.open(QIODevice::ReadOnly));
       
   418     query.bindVariable(name, &input);
       
   419     query.setQuery("string(doc($arbitraryName))");
       
   420 
       
   421     QStringList result;
       
   422     query.evaluateTo(&result);
       
   423 }
       
   424 
       
   425 void tst_QXmlQuery::constructorQXmlNamePoolWithinQSimpleXmlNodeModel() const
       
   426 {
       
   427     class TestCTOR : public TestSimpleNodeModel
       
   428     {
       
   429     public:
       
   430         TestCTOR(const QXmlNamePool &np) : TestSimpleNodeModel(np)
       
   431         {
       
   432         }
       
   433 
       
   434         void checkCTOR() const
       
   435         {
       
   436             /* If this fails to compile, the constructor has trouble with taking
       
   437              * a mutable reference.
       
   438              *
       
   439              * The reason we use the this pointer explicitly, is to avoid a compiler
       
   440              * warnings with MSVC 2005. */
       
   441             QXmlQuery(this->namePool());
       
   442         }
       
   443     };
       
   444 
       
   445     QXmlNamePool np;
       
   446     TestCTOR ctor(np);
       
   447     ctor.checkCTOR();
       
   448 }
       
   449 
       
   450 void tst_QXmlQuery::assignmentOperator() const
       
   451 {
       
   452     class ReturnURI : public QAbstractUriResolver
       
   453     {
       
   454     public:
       
   455         virtual QUrl resolve(const QUrl &relative,
       
   456                              const QUrl &baseURI) const
       
   457         {
       
   458             return baseURI.resolved(relative);
       
   459         }
       
   460     };
       
   461 
       
   462     /* Assign this to this. */
       
   463     {
       
   464         QXmlQuery query;
       
   465         query = query;
       
   466         query = query;
       
   467         query = query;
       
   468 
       
   469         /* Just call a couple of functions to give valgrind
       
   470          * something to check. */
       
   471         QVERIFY(!query.isValid());
       
   472         query.messageHandler();
       
   473     }
       
   474 
       
   475     /* Assign null instances a couple of times. */
       
   476     {
       
   477         QXmlQuery query1;
       
   478         QXmlQuery query2;
       
   479         query1 = query2;
       
   480         query1 = query2;
       
   481         query1 = query2;
       
   482 
       
   483         /* Just call a couple of functions to give valgrind
       
   484          * something to check. */
       
   485         QVERIFY(!query1.isValid());
       
   486         query1.messageHandler();
       
   487 
       
   488         /* Just call a couple of functions to give valgrind
       
   489          * something to check. */
       
   490         QVERIFY(!query2.isValid());
       
   491         query2.messageHandler();
       
   492     }
       
   493 
       
   494     /* Create a query, set all the things it stores, and ensure it
       
   495      * travels over to the new instance. */
       
   496     {
       
   497         MessageSilencer silencer;
       
   498         const ReturnURI returnURI;
       
   499         QXmlNamePool namePool;
       
   500 
       
   501         QBuffer documentDevice;
       
   502         documentDevice.setData(QByteArray("<e>a</e>"));
       
   503         QVERIFY(documentDevice.open(QIODevice::ReadOnly));
       
   504 
       
   505         QXmlQuery original(namePool);
       
   506         QXmlName testName(namePool, QLatin1String("somethingToCheck"));
       
   507 
       
   508         original.setMessageHandler(&silencer);
       
   509         original.bindVariable(QLatin1String("var"), QXmlItem(1));
       
   510         original.bindVariable(QLatin1String("device"), &documentDevice);
       
   511         original.setUriResolver(&returnURI);
       
   512         original.setFocus(QXmlItem(3));
       
   513         original.setQuery(QLatin1String("$var, 1 + 1, ., string(doc($device))"));
       
   514 
       
   515         /* Do a copy, and check that everything followed on into the copy. No modification
       
   516          * of the copy. */
       
   517         {
       
   518             QXmlQuery copy;
       
   519 
       
   520             /* We use assignment operator, not copy constructor. */
       
   521             copy = original;
       
   522 
       
   523             QVERIFY(copy.isValid());
       
   524             QCOMPARE(copy.uriResolver(), static_cast<const QAbstractUriResolver *>(&returnURI));
       
   525             QCOMPARE(copy.messageHandler(), &silencer);
       
   526             QCOMPARE(testName.localName(copy.namePool()), QString::fromLatin1("somethingToCheck"));
       
   527 
       
   528             QXmlResultItems result;
       
   529             copy.evaluateTo(&result);
       
   530             QCOMPARE(result.next().toAtomicValue(), QVariant(1));
       
   531             QCOMPARE(result.next().toAtomicValue(), QVariant(2));
       
   532             QCOMPARE(result.next().toAtomicValue(), QVariant(3));
       
   533             QCOMPARE(result.next().toAtomicValue(), QVariant(QString::fromLatin1("a")));
       
   534             QVERIFY(result.next().isNull());
       
   535             QVERIFY(!result.hasError());
       
   536         }
       
   537 
       
   538         /* Copy, and change values. Things should detach. */
       
   539         {
       
   540             /* Evaluate the copy. */
       
   541             {
       
   542                 MessageSilencer secondSilencer;
       
   543                 const ReturnURI secondUriResolver;
       
   544                 QBuffer documentDeviceCopy;
       
   545                 documentDeviceCopy.setData(QByteArray("<e>b</e>"));
       
   546                 QVERIFY(documentDeviceCopy.open(QIODevice::ReadOnly));
       
   547 
       
   548                 QXmlQuery copy;
       
   549                 copy = original;
       
   550 
       
   551                 copy.setMessageHandler(&secondSilencer);
       
   552                 /* Here we rebind variable values. */
       
   553                 copy.bindVariable(QLatin1String("var"), QXmlItem(4));
       
   554                 copy.bindVariable(QLatin1String("device"), &documentDeviceCopy);
       
   555                 copy.setUriResolver(&secondUriResolver);
       
   556                 copy.setFocus(QXmlItem(6));
       
   557                 copy.setQuery(QLatin1String("$var, 1 + 1, ., string(doc($device))"));
       
   558 
       
   559                 /* Check that the copy picked up the new things. */
       
   560                 QVERIFY(copy.isValid());
       
   561                 QCOMPARE(copy.uriResolver(), static_cast<const QAbstractUriResolver *>(&secondUriResolver));
       
   562                 QCOMPARE(copy.messageHandler(), &secondSilencer);
       
   563 
       
   564                 QXmlResultItems resultCopy;
       
   565                 copy.evaluateTo(&resultCopy);
       
   566                 QCOMPARE(resultCopy.next().toAtomicValue(), QVariant(4));
       
   567                 QCOMPARE(resultCopy.next().toAtomicValue(), QVariant(2));
       
   568                 QCOMPARE(resultCopy.next().toAtomicValue(), QVariant(6));
       
   569                 const QString stringedDevice(resultCopy.next().toAtomicValue().toString());
       
   570                 QCOMPARE(stringedDevice, QString::fromLatin1("b"));
       
   571                 QVERIFY(resultCopy.next().isNull());
       
   572                 QVERIFY(!resultCopy.hasError());
       
   573             }
       
   574 
       
   575             /* Evaluate the original. */
       
   576             {
       
   577                 /* Check that the original is unchanged. */
       
   578                 QVERIFY(original.isValid());
       
   579                 QCOMPARE(original.uriResolver(), static_cast<const QAbstractUriResolver *>(&returnURI));
       
   580                 QCOMPARE(original.messageHandler(), &silencer);
       
   581 
       
   582                 QXmlResultItems resultOriginal;
       
   583                 original.evaluateTo(&resultOriginal);
       
   584                 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(1));
       
   585                 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(2));
       
   586                 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(3));
       
   587                 QCOMPARE(resultOriginal.next().toAtomicValue(), QVariant(QString::fromLatin1("a")));
       
   588                 QVERIFY(resultOriginal.next().isNull());
       
   589                 QVERIFY(!resultOriginal.hasError());
       
   590             }
       
   591         }
       
   592     }
       
   593 }
       
   594 
       
   595 /*!
       
   596   Since QXmlQuery doesn't seek devices to position 0, this code triggers a bug
       
   597   where document caching doesn't work. Since the document caching doesn't work,
       
   598   the device will be read twice, and the second time the device is at the end,
       
   599   hence premature end of document.
       
   600  */
       
   601 void tst_QXmlQuery::sequentialExecution() const
       
   602 {
       
   603     QBuffer inBuffer;
       
   604     inBuffer.setData(QByteArray("<input/>"));
       
   605     QVERIFY(inBuffer.open(QIODevice::ReadOnly));
       
   606 
       
   607     QXmlQuery query;
       
   608     query.bindVariable("inputDocument", &inBuffer);
       
   609 
       
   610     QByteArray outArray;
       
   611     QBuffer outBuffer(&outArray);
       
   612     outBuffer.open(QIODevice::WriteOnly);
       
   613 
       
   614     const QString queryString(QLatin1String("doc($inputDocument)"));
       
   615     query.setQuery(queryString);
       
   616 
       
   617     QXmlFormatter formatter(query, &outBuffer);
       
   618 
       
   619     QVERIFY(query.evaluateTo(&formatter));
       
   620 
       
   621     /* If this line is removed, the bug isn't triggered. */
       
   622     query.setQuery(queryString);
       
   623 
       
   624     QVERIFY(query.evaluateTo(&formatter));
       
   625 }
       
   626 
       
   627 void tst_QXmlQuery::isValid() const
       
   628 {
       
   629     /* Check default value. */
       
   630     QXmlQuery query;
       
   631     QVERIFY(!query.isValid());
       
   632 }
       
   633 
       
   634 void tst_QXmlQuery::bindVariableQString() const
       
   635 {
       
   636     {
       
   637         QXmlQuery query;
       
   638         /* Bind with a null QXmlItem. */
       
   639         query.bindVariable(QLatin1String("name"), QXmlItem());
       
   640     }
       
   641 
       
   642     {
       
   643         QXmlQuery query;
       
   644         /* Bind with a null QVariant. */
       
   645         query.bindVariable(QLatin1String("name"), QXmlItem(QVariant()));
       
   646     }
       
   647 
       
   648     {
       
   649         QXmlQuery query;
       
   650         /* Bind with a null QXmlNodeModelIndex. */
       
   651         query.bindVariable(QLatin1String("name"), QXmlItem(QXmlNodeModelIndex()));
       
   652     }
       
   653 }
       
   654 
       
   655 void tst_QXmlQuery::bindVariableQStringNoExternalDeclaration() const
       
   656 {
       
   657     QXmlQuery query;
       
   658     query.bindVariable(QLatin1String("foo"), QXmlItem(QLatin1String("Variable Value")));
       
   659     query.setQuery(QLatin1String("$foo"));
       
   660 
       
   661     QVERIFY(query.isValid());
       
   662 
       
   663     QStringList result;
       
   664     QVERIFY(query.evaluateTo(&result));
       
   665 
       
   666     QCOMPARE(result, QStringList() << QLatin1String("Variable Value"));
       
   667 }
       
   668 
       
   669 void tst_QXmlQuery::bindVariableQXmlName() const
       
   670 {
       
   671     // TODO
       
   672 }
       
   673 
       
   674 void tst_QXmlQuery::bindVariableQXmlNameTriggerWarnings() const
       
   675 {
       
   676     QXmlQuery query;
       
   677 
       
   678     QTest::ignoreMessage(QtWarningMsg, "The variable name cannot be null.");
       
   679     query.bindVariable(QXmlName(), QVariant());
       
   680 }
       
   681 
       
   682 void tst_QXmlQuery::bindVariableQStringQIODeviceWithByteArray() const
       
   683 {
       
   684     QXmlQuery query;
       
   685 
       
   686     QByteArray in("<e/>");
       
   687     QBuffer device(&in);
       
   688     QVERIFY(device.open(QIODevice::ReadOnly));
       
   689 
       
   690     query.bindVariable("doc", &device);
       
   691 
       
   692     query.setQuery(QLatin1String("declare variable $doc external; $doc"));
       
   693 
       
   694     QVERIFY(query.isValid());
       
   695 
       
   696     /* Check the URI corresponding to the variable. */
       
   697     {
       
   698         QXmlResultItems items;
       
   699         query.evaluateTo(&items);
       
   700 
       
   701         QCOMPARE(items.next().toAtomicValue().toString(), QString::fromLatin1("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:doc"));
       
   702     }
       
   703 
       
   704     /* Now, actually load the document. We use the same QXmlQuery just to stress recompilation a bit. */
       
   705     {
       
   706         query.setQuery(QLatin1String("declare variable $doc external; doc($doc)"));
       
   707 
       
   708         QByteArray out;
       
   709         QBuffer outBuffer(&out);
       
   710         QVERIFY(outBuffer.open(QIODevice::WriteOnly));
       
   711 
       
   712         QXmlSerializer serializer(query, &outBuffer);
       
   713 
       
   714         QVERIFY(query.evaluateTo(&serializer));
       
   715         QCOMPARE(out, in);
       
   716     }
       
   717 }
       
   718 
       
   719 void tst_QXmlQuery::bindVariableQStringQIODeviceWithString() const
       
   720 {
       
   721     QXmlQuery query;
       
   722 
       
   723     QString in("<qstring/>");
       
   724     QByteArray inUtf8(in.toUtf8());
       
   725     QBuffer inDevice(&inUtf8);
       
   726 
       
   727     QVERIFY(inDevice.open(QIODevice::ReadOnly));
       
   728 
       
   729     query.bindVariable("doc", &inDevice);
       
   730 
       
   731     query.setQuery(QLatin1String("declare variable $doc external; doc($doc)"));
       
   732 
       
   733     QByteArray out;
       
   734     QBuffer outBuffer(&out);
       
   735     QVERIFY(outBuffer.open(QIODevice::WriteOnly));
       
   736 
       
   737     QXmlSerializer serializer(query, &outBuffer);
       
   738     QVERIFY(query.evaluateTo(&serializer));
       
   739 
       
   740     QCOMPARE(out, inUtf8);
       
   741 }
       
   742 
       
   743 void tst_QXmlQuery::bindVariableQStringQIODeviceWithQFile() const
       
   744 {
       
   745     QXmlQuery query;
       
   746     QFile inDevice(QLatin1String(SRCDIR "input.xml"));
       
   747 
       
   748     QVERIFY(inDevice.open(QIODevice::ReadOnly));
       
   749 
       
   750     query.bindVariable("doc", &inDevice);
       
   751 
       
   752     query.setQuery(QLatin1String("declare variable $doc external; doc($doc)"));
       
   753 
       
   754     QByteArray out;
       
   755     QBuffer outBuffer(&out);
       
   756     QVERIFY(outBuffer.open(QIODevice::WriteOnly));
       
   757 
       
   758     QXmlSerializer serializer(query, &outBuffer);
       
   759     QVERIFY(query.evaluateTo(&serializer));
       
   760     outBuffer.close();
       
   761 
       
   762     QCOMPARE(out, QByteArray("<!-- This is just a file for testing. --><input/>"));
       
   763 }
       
   764 
       
   765 void tst_QXmlQuery::bindVariableQStringQIODevice() const
       
   766 {
       
   767     QXmlQuery query;
       
   768 
       
   769     /* Rebind the variable. */
       
   770     {
       
   771         /* First evaluation. */
       
   772         {
       
   773             QByteArray in1("<e1/>");
       
   774             QBuffer inDevice1(&in1);
       
   775             QVERIFY(inDevice1.open(QIODevice::ReadOnly));
       
   776 
       
   777             query.bindVariable("in", &inDevice1);
       
   778             query.setQuery(QLatin1String("doc($in)"));
       
   779 
       
   780             QByteArray out1;
       
   781             QBuffer outDevice1(&out1);
       
   782             QVERIFY(outDevice1.open(QIODevice::WriteOnly));
       
   783 
       
   784             QXmlSerializer serializer(query, &outDevice1);
       
   785             query.evaluateTo(&serializer);
       
   786             QCOMPARE(out1, in1);
       
   787         }
       
   788 
       
   789         /* Second evaluation, rebind variable. */
       
   790         {
       
   791             QByteArray in2("<e2/>");
       
   792             QBuffer inDevice2(&in2);
       
   793             QVERIFY(inDevice2.open(QIODevice::ReadOnly));
       
   794 
       
   795             query.bindVariable(QLatin1String("in"), &inDevice2);
       
   796 
       
   797             QByteArray out2;
       
   798             QBuffer outDevice2(&out2);
       
   799             QVERIFY(outDevice2.open(QIODevice::WriteOnly));
       
   800 
       
   801             QXmlSerializer serializer(query, &outDevice2);
       
   802             QVERIFY(query.evaluateTo(&serializer));
       
   803             QCOMPARE(out2, in2);
       
   804         }
       
   805     }
       
   806 
       
   807     // TODO trigger recompilation when setting qiodevices., and qiodevice overwritten by other type, etc.
       
   808 }
       
   809 
       
   810 void tst_QXmlQuery::bindVariableQXmlNameQIODevice() const
       
   811 {
       
   812     // TODO
       
   813 }
       
   814 
       
   815 void tst_QXmlQuery::bindVariableQXmlNameQIODeviceTriggerWarnings() const
       
   816 {
       
   817     QXmlNamePool np;
       
   818     QXmlQuery query(np);
       
   819 
       
   820     QBuffer buffer;
       
   821     QTest::ignoreMessage(QtWarningMsg, "A null, or readable QIODevice must be passed.");
       
   822     query.bindVariable(QXmlName(np, QLatin1String("foo")), &buffer);
       
   823 
       
   824     QTest::ignoreMessage(QtWarningMsg, "The variable name cannot be null.");
       
   825     query.bindVariable(QXmlName(), 0);
       
   826 }
       
   827 
       
   828 void tst_QXmlQuery::bindVariableXSLTSuccess() const
       
   829 {
       
   830     QXmlQuery stylesheet(QXmlQuery::XSLT20);
       
   831     stylesheet.setInitialTemplateName(QLatin1String("main"));
       
   832 
       
   833     stylesheet.bindVariable(QLatin1String("variableNoSelectNoBodyBoundWithBindVariable"),
       
   834                                           QVariant(QLatin1String("MUST NOT SHOW 1")));
       
   835 
       
   836     stylesheet.bindVariable(QLatin1String("variableSelectBoundWithBindVariable"),
       
   837                                           QVariant(QLatin1String("MUST NOT SHOW 2")));
       
   838 
       
   839     stylesheet.bindVariable(QLatin1String("variableSelectWithTypeIntBoundWithBindVariable"),
       
   840                                           QVariant(QLatin1String("MUST NOT SHOW 3")));
       
   841 
       
   842     stylesheet.bindVariable(QLatin1String("paramNoSelectNoBodyBoundWithBindVariable"),
       
   843                                           QVariant(QLatin1String("param1")));
       
   844 
       
   845     stylesheet.bindVariable(QLatin1String("paramNoSelectNoBodyBoundWithBindVariableRequired"),
       
   846                                           QVariant(QLatin1String("param1")));
       
   847 
       
   848     stylesheet.bindVariable(QLatin1String("paramSelectBoundWithBindVariable"),
       
   849                                           QVariant(QLatin1String("param2")));
       
   850 
       
   851     stylesheet.bindVariable(QLatin1String("paramSelectBoundWithBindVariableRequired"),
       
   852                                           QVariant(QLatin1String("param3")));
       
   853 
       
   854     stylesheet.bindVariable(QLatin1String("paramSelectWithTypeIntBoundWithBindVariable"),
       
   855                                           QVariant(4));
       
   856 
       
   857     stylesheet.bindVariable(QLatin1String("paramSelectWithTypeIntBoundWithBindVariableRequired"),
       
   858                                           QVariant(QLatin1String("param5")));
       
   859 
       
   860     stylesheet.setQuery(QUrl(inputFile(QLatin1String(SRCDIR "../xmlpatterns/stylesheets/parameters.xsl"))));
       
   861 
       
   862     QVERIFY(stylesheet.isValid());
       
   863 
       
   864     QBuffer deviceOut;
       
   865     QVERIFY(deviceOut.open(QIODevice::ReadWrite));
       
   866 
       
   867     QVERIFY(stylesheet.evaluateTo(&deviceOut));
       
   868 
       
   869     const QString result(QString::fromUtf8(deviceOut.data().constData()));
       
   870 
       
   871     QCOMPARE(result,
       
   872              QString::fromLatin1("Variables:   variableSelectsDefaultValue variableSelectsDefaultValue2 3 4 "
       
   873                                  "Parameters: param1 param1 param2 param3 4 param5"));
       
   874 }
       
   875 
       
   876 void tst_QXmlQuery::bindVariableTemporaryNode() const
       
   877 {
       
   878     /* First we do it with QXmlResultItems staying in scope. */;
       
   879     {
       
   880         QXmlQuery query1;
       
   881         query1.setQuery("<anElement/>");
       
   882 
       
   883         QXmlResultItems result1;
       
   884         query1.evaluateTo(&result1);
       
   885 
       
   886         QXmlQuery query2(query1);
       
   887         query2.bindVariable("fromQuery1", result1.next());
       
   888         query2.setQuery("$fromQuery1");
       
   889 
       
   890         QString output;
       
   891         QVERIFY(query2.evaluateTo(&output));
       
   892 
       
   893         QCOMPARE(output, QString::fromLatin1("<anElement/>\n"));
       
   894     }
       
   895 
       
   896     /* And now with it deallocating, so its internal DynamicContext pointer is
       
   897      * released. This doesn't work in Qt 4.5 and is ok. */
       
   898     {
       
   899         QXmlQuery query1;
       
   900         query1.setQuery("<anElement/>");
       
   901 
       
   902         QXmlQuery query2;
       
   903 
       
   904         {
       
   905             QXmlResultItems result1;
       
   906             query1.evaluateTo(&result1);
       
   907 
       
   908             query2.bindVariable("fromQuery1", result1.next());
       
   909             query2.setQuery("$fromQuery1");
       
   910         }
       
   911 
       
   912         QString output;
       
   913         return; // See comment above.
       
   914         QVERIFY(query2.evaluateTo(&output));
       
   915 
       
   916         QCOMPARE(output, QString::fromLatin1("<anElement/>\n"));
       
   917     }
       
   918 }
       
   919 
       
   920 void tst_QXmlQuery::messageHandler() const
       
   921 {
       
   922     {
       
   923         /* Check default value. */
       
   924         QXmlQuery query;
       
   925         QCOMPARE(query.messageHandler(), static_cast<QAbstractMessageHandler *>(0));
       
   926     }
       
   927 }
       
   928 
       
   929 void tst_QXmlQuery::setMessageHandler() const
       
   930 {
       
   931     QXmlQuery query;
       
   932     MessageSilencer silencer;
       
   933     query.setMessageHandler(&silencer);
       
   934     QCOMPARE(&silencer, query.messageHandler());
       
   935 }
       
   936 
       
   937 void tst_QXmlQuery::evaluateToReceiver()
       
   938 {
       
   939     QFETCH(QString, inputQuery);
       
   940 
       
   941     /* This query prints a URI specific to the local system. */
       
   942     if(inputQuery == QLatin1String("static-base-uri.xq"))
       
   943         return;
       
   944 
       
   945     ++m_pushTestsCount;
       
   946     const QString queryURI(inputFile(QLatin1String(queriesDirectory) + inputQuery));
       
   947     QFile queryFile(queryURI);
       
   948 
       
   949     QVERIFY(queryFile.exists());
       
   950     QVERIFY(queryFile.open(QIODevice::ReadOnly));
       
   951 
       
   952     QXmlQuery query;
       
   953 
       
   954     MessageSilencer receiver;
       
   955     query.setMessageHandler(&receiver);
       
   956     query.setQuery(&queryFile, QUrl::fromLocalFile(queryURI));
       
   957 
       
   958     /* We read all the queries, and some of them are invalid. However, we
       
   959      * only want those that compile. */
       
   960     if(!query.isValid())
       
   961         return;
       
   962 
       
   963     QString produced;
       
   964     QTextStream stream(&produced, QIODevice::WriteOnly);
       
   965     PushBaseliner push(stream, query.namePool());
       
   966     query.evaluateTo(&push);
       
   967 
       
   968     const QString baselineName(inputFile(QLatin1String(SRCDIR "pushBaselines/") + inputQuery.left(inputQuery.length() - 2) + QString::fromLatin1("ref")));
       
   969     QFile baseline(baselineName);
       
   970 
       
   971     if(baseline.exists())
       
   972     {
       
   973         QVERIFY(baseline.open(QIODevice::ReadOnly | QIODevice::Text));
       
   974         const QString stringedBaseline(QString::fromUtf8(baseline.readAll()));
       
   975         QCOMPARE(produced, stringedBaseline);
       
   976     }
       
   977     else
       
   978     {
       
   979         QVERIFY(baseline.open(QIODevice::WriteOnly));
       
   980         /* This is intentionally a warning, don't remove it. Update the baselines instead. */
       
   981         qWarning() << "Generated baseline for:" << baselineName;
       
   982         ++m_generatedBaselines;
       
   983 
       
   984         baseline.write(produced.toUtf8());
       
   985     }
       
   986 }
       
   987 
       
   988 void tst_QXmlQuery::evaluateToReceiver_data() const
       
   989 {
       
   990     QTest::addColumn<QString>("inputQuery");
       
   991 
       
   992     const QStringList qs(queries());
       
   993 
       
   994     for(int i = 0; i < qs.size(); ++i)
       
   995     {
       
   996         /* This outputs a URI specific to the environment, so we can't use it for this
       
   997          * particular test. */
       
   998         if(qs.at(i) != QLatin1String("staticBaseURI.xq"))
       
   999             QTest::newRow(qs.at(i).toUtf8().constData()) << qs.at(i);
       
  1000     }
       
  1001 }
       
  1002 
       
  1003 void tst_QXmlQuery::evaluateToReceiverOnInvalidQuery() const
       
  1004 {
       
  1005     /* Invoke on a default constructed object. */
       
  1006     {
       
  1007         QByteArray out;
       
  1008         QBuffer buffer(&out);
       
  1009         buffer.open(QIODevice::WriteOnly);
       
  1010 
       
  1011         QXmlQuery query;
       
  1012         QXmlSerializer serializer(query, &buffer);
       
  1013         QVERIFY(!query.evaluateTo(&serializer));
       
  1014     }
       
  1015 
       
  1016     /* Invoke on an invalid query; compile time error. */
       
  1017     {
       
  1018         QByteArray out;
       
  1019         QBuffer buffer(&out);
       
  1020         buffer.open(QIODevice::WriteOnly);
       
  1021         MessageSilencer silencer;
       
  1022 
       
  1023         QXmlQuery query;
       
  1024         query.setMessageHandler(&silencer);
       
  1025         query.setQuery(QLatin1String("1 + "));
       
  1026         QXmlSerializer serializer(query, &buffer);
       
  1027         QVERIFY(!query.evaluateTo(&serializer));
       
  1028     }
       
  1029 
       
  1030     /* Invoke on an invalid query; runtime error. */
       
  1031     {
       
  1032         QByteArray out;
       
  1033         QBuffer buffer(&out);
       
  1034         buffer.open(QIODevice::WriteOnly);
       
  1035         MessageSilencer silencer;
       
  1036 
       
  1037         QXmlQuery query;
       
  1038         query.setMessageHandler(&silencer);
       
  1039         query.setQuery(QLatin1String("error()"));
       
  1040         QXmlSerializer serializer(query, &buffer);
       
  1041         QVERIFY(!query.evaluateTo(&serializer));
       
  1042     }
       
  1043 }
       
  1044 
       
  1045 void tst_QXmlQuery::evaluateToQStringTriggerError() const
       
  1046 {
       
  1047     /* Invoke on a default constructed object. */
       
  1048     {
       
  1049         QXmlQuery query;
       
  1050         QString out;
       
  1051         QVERIFY(!query.evaluateTo(&out));
       
  1052     }
       
  1053 
       
  1054     /* Invoke on an invalid query; compile time error. */
       
  1055     {
       
  1056         QXmlQuery query;
       
  1057         MessageSilencer silencer;
       
  1058         query.setMessageHandler(&silencer);
       
  1059 
       
  1060         query.setQuery(QLatin1String("1 + "));
       
  1061 
       
  1062         QString out;
       
  1063         QVERIFY(!query.evaluateTo(&out));
       
  1064     }
       
  1065 
       
  1066     /* Invoke on an invalid query; runtime error. */
       
  1067     {
       
  1068         QXmlQuery query;
       
  1069         MessageSilencer silencer;
       
  1070         query.setMessageHandler(&silencer);
       
  1071 
       
  1072         query.setQuery(QLatin1String("error()"));
       
  1073 
       
  1074         QString out;
       
  1075         QVERIFY(!query.evaluateTo(&out));
       
  1076     }
       
  1077 }
       
  1078 
       
  1079 void tst_QXmlQuery::evaluateToQString() const
       
  1080 {
       
  1081     QFETCH(QString, query);
       
  1082     QFETCH(QString, expectedOutput);
       
  1083 
       
  1084     QXmlQuery queryInstance;
       
  1085     queryInstance.setQuery(query);
       
  1086     QVERIFY(queryInstance.isValid());
       
  1087 
       
  1088     QString result;
       
  1089     QVERIFY(queryInstance.evaluateTo(&result));
       
  1090 
       
  1091     QCOMPARE(result, expectedOutput);
       
  1092 }
       
  1093 
       
  1094 void tst_QXmlQuery::evaluateToQString_data() const
       
  1095 {
       
  1096     QTest::addColumn<QString>("query");
       
  1097     QTest::addColumn<QString>("expectedOutput");
       
  1098 
       
  1099     QTest::newRow("Two atomics")
       
  1100         << QString::fromLatin1("1, 'two'")
       
  1101         << QString::fromLatin1("1 two\n");
       
  1102 
       
  1103     QTest::newRow("An element")
       
  1104         << QString::fromLatin1("<e>{1}</e>")
       
  1105         << QString::fromLatin1("<e>1</e>\n");
       
  1106 }
       
  1107 
       
  1108 void tst_QXmlQuery::evaluateToQStringSignature() const
       
  1109 {
       
  1110     const QXmlQuery query;
       
  1111 
       
  1112     QString output;
       
  1113 
       
  1114     /* evaluateTo(QString *) should be a const function. */
       
  1115     query.evaluateTo(&output);
       
  1116 }
       
  1117 
       
  1118 void tst_QXmlQuery::evaluateToQAbstractXmlReceiverTriggerWarnings() const
       
  1119 {
       
  1120     QXmlQuery query;
       
  1121 
       
  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)),
       
  1125              false);
       
  1126 }
       
  1127 
       
  1128 void tst_QXmlQuery::evaluateToQXmlResultItems() const
       
  1129 {
       
  1130     /* Invoke on a default constructed object. */
       
  1131     {
       
  1132         QXmlQuery query;
       
  1133         QXmlResultItems result;
       
  1134         query.evaluateTo(&result);
       
  1135         QVERIFY(result.next().isNull());
       
  1136     }
       
  1137 }
       
  1138 
       
  1139 void tst_QXmlQuery::evaluateToQXmlResultItemsTriggerWarnings() const
       
  1140 {
       
  1141     QTest::ignoreMessage(QtWarningMsg, "A null pointer cannot be passed.");
       
  1142     QXmlQuery query;
       
  1143     query.evaluateTo(static_cast<QXmlResultItems *>(0));
       
  1144 }
       
  1145 
       
  1146 void tst_QXmlQuery::evaluateToQXmlResultItemsErrorAtEnd() const
       
  1147 {
       
  1148     QXmlQuery query;
       
  1149     MessageSilencer silencer;
       
  1150     query.setMessageHandler(&silencer);
       
  1151     query.setQuery(QLatin1String("1 to 100, fn:error()"));
       
  1152     QVERIFY(query.isValid());
       
  1153 
       
  1154     QXmlResultItems it;
       
  1155     query.evaluateTo(&it);
       
  1156 
       
  1157     while(!it.next().isNull())
       
  1158     {
       
  1159     }
       
  1160 }
       
  1161 
       
  1162 /*!
       
  1163   If baselines were generated, we flag it as a failure such that it gets
       
  1164   attention, and that they are adjusted accordingly.
       
  1165  */
       
  1166 void tst_QXmlQuery::checkGeneratedBaselines() const
       
  1167 {
       
  1168     QCOMPARE(m_generatedBaselines, 0);
       
  1169 
       
  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));
       
  1173 }
       
  1174 
       
  1175 void tst_QXmlQuery::basicXQueryToQtTypeCheck() const
       
  1176 {
       
  1177     QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("allAtomics.xq"));
       
  1178     QVERIFY(queryFile.open(QIODevice::ReadOnly));
       
  1179 
       
  1180     QXmlQuery query;
       
  1181     query.setQuery(&queryFile);
       
  1182     QVERIFY(query.isValid());
       
  1183 
       
  1184     QXmlResultItems it;
       
  1185     query.evaluateTo(&it);
       
  1186 
       
  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. */
       
  1192 
       
  1193     expectedValues.append(QVariant()); /* xs:duration */
       
  1194     expectedValues.append(QVariant()); /* xs:dayTimeDuration */
       
  1195     expectedValues.append(QVariant()); /* xs:yearMonthDuration */
       
  1196 
       
  1197     expectedValues.append(QVariant(double(3e3)));     /* xs:float */
       
  1198     expectedValues.append(QVariant(double(4e4)));     /* xs:double */
       
  1199     expectedValues.append(QVariant(double(2)));       /* xs:decimal */
       
  1200 
       
  1201     /* xs:integer and its sub-types. */
       
  1202     expectedValues.append(QVariant(qlonglong(16)));
       
  1203     expectedValues.append(QVariant(qlonglong(-6)));
       
  1204     expectedValues.append(QVariant(qlonglong(-4)));
       
  1205     expectedValues.append(QVariant(qlonglong(5)));
       
  1206     expectedValues.append(QVariant(qlonglong(6)));
       
  1207     expectedValues.append(QVariant(qlonglong(7)));
       
  1208     expectedValues.append(QVariant(qlonglong(8)));
       
  1209     expectedValues.append(QVariant(qlonglong(9)));
       
  1210     expectedValues.append(QVariant(qulonglong(10)));
       
  1211     expectedValues.append(QVariant(qlonglong(11)));
       
  1212     expectedValues.append(QVariant(qlonglong(12)));
       
  1213     expectedValues.append(QVariant(qlonglong(13)));
       
  1214     expectedValues.append(QVariant(qlonglong(14)));
       
  1215 
       
  1216     expectedValues.append(QVariant());                                                          /* xs:gYearMonth("1976-02"), */
       
  1217     expectedValues.append(QVariant());                                                          /* xs:gYear("2005-12:00"), */
       
  1218     expectedValues.append(QVariant());                                                          /* xs:gMonthDay("--12-25-14:00"), */
       
  1219     expectedValues.append(QVariant());                                                          /* xs:gDay("---25-14:00"), */
       
  1220     expectedValues.append(QVariant());                                                          /* xs:gMonth("--12-14:00"), */
       
  1221     expectedValues.append(true);                                                                /* xs:boolean("true"), */
       
  1222     expectedValues.append(QVariant(QByteArray::fromBase64(QByteArray("aaaa"))));                /* xs:base64Binary("aaaa"), */
       
  1223     expectedValues.append(QVariant(QByteArray::fromHex(QByteArray("FFFF"))));                   /* xs:hexBinary("FFFF"), */
       
  1224     expectedValues.append(QVariant(QString::fromLatin1("http://example.com/")));                /* xs:anyURI("http://example.com/"), */
       
  1225     QXmlNamePool np(query.namePool());
       
  1226     expectedValues.append(QVariant(qVariantFromValue(QXmlName(np, QLatin1String("localName"),
       
  1227                                                               QLatin1String("http://example.com/2"),
       
  1228                                                               QLatin1String("prefix")))));
       
  1229 
       
  1230     expectedValues.append(QVariant(QString::fromLatin1("An xs:string")));
       
  1231     expectedValues.append(QVariant(QString::fromLatin1("normalizedString")));
       
  1232     expectedValues.append(QVariant(QString::fromLatin1("token")));
       
  1233     expectedValues.append(QVariant(QString::fromLatin1("language")));
       
  1234     expectedValues.append(QVariant(QString::fromLatin1("NMTOKEN")));
       
  1235     expectedValues.append(QVariant(QString::fromLatin1("Name")));
       
  1236     expectedValues.append(QVariant(QString::fromLatin1("NCName")));
       
  1237     expectedValues.append(QVariant(QString::fromLatin1("ID")));
       
  1238     expectedValues.append(QVariant(QString::fromLatin1("IDREF")));
       
  1239     expectedValues.append(QVariant(QString::fromLatin1("ENTITY")));
       
  1240 
       
  1241     int i = 0;
       
  1242     QXmlItem item(it.next());
       
  1243 
       
  1244     while(!item.isNull())
       
  1245     {
       
  1246         QVERIFY(item.isAtomicValue());
       
  1247         const QVariant produced(item.toAtomicValue());
       
  1248 
       
  1249         const QVariant &expected = expectedValues.at(i);
       
  1250 
       
  1251         /* For the cases where we can't represent a value in the XDM with Qt,
       
  1252          * we return an invalid QVariant. */
       
  1253         QCOMPARE(expected.isValid(), produced.isValid());
       
  1254 
       
  1255         QCOMPARE(produced.type(), expected.type());
       
  1256 
       
  1257         if(expected.isValid())
       
  1258         {
       
  1259             /* This is only needed for xs:decimal though, for some reason. Probably
       
  1260              * just artifacts created somewhere. */
       
  1261             if(produced.type() == QVariant::Double)
       
  1262                 QVERIFY(qFuzzyCompare(produced.toDouble(), expected.toDouble()));
       
  1263             else if(qVariantCanConvert<QXmlName>(produced))
       
  1264             {
       
  1265                 /* QVariant::operator==() does identity comparison, it doesn't delegate to operator==() of
       
  1266                  * the contained type, unless it's hardcoded into QVariant. */
       
  1267                 const QXmlName n1 = qVariantValue<QXmlName>(produced);
       
  1268                 const QXmlName n2 = qVariantValue<QXmlName>(expected);
       
  1269                 QCOMPARE(n1, n2);
       
  1270             }
       
  1271             else
       
  1272                 QCOMPARE(produced, expected);
       
  1273         }
       
  1274 
       
  1275         ++i;
       
  1276         item = it.next();
       
  1277     }
       
  1278 
       
  1279     QCOMPARE(i, expectedValues.count());
       
  1280 }
       
  1281 
       
  1282 /*!
       
  1283   Send values from Qt into XQuery.
       
  1284  */
       
  1285 void tst_QXmlQuery::basicQtToXQueryTypeCheck() const
       
  1286 {
       
  1287     QFile queryFile(QLatin1String(queriesDirectory) + QLatin1String("allAtomicsExternally.xq"));
       
  1288     QVERIFY(queryFile.exists());
       
  1289     QVERIFY(queryFile.open(QIODevice::ReadOnly));
       
  1290 
       
  1291     QCOMPARE(QVariant(QDate(1999, 9, 10)).type(), QVariant::Date);
       
  1292 
       
  1293     QXmlQuery query;
       
  1294 
       
  1295     QXmlNamePool np(query.namePool());
       
  1296 
       
  1297     const QXmlName name(np, QLatin1String("localname"),
       
  1298                             QLatin1String("http://example.com"),
       
  1299                             QLatin1String("prefix"));
       
  1300 
       
  1301     query.bindVariable(QLatin1String("fromQUrl"), QXmlItem(QUrl(QString::fromLatin1("http://example.com/"))));
       
  1302     query.bindVariable(QLatin1String("fromQByteArray"), QXmlItem(QByteArray("AAAA")));
       
  1303     query.bindVariable(QLatin1String("fromBool"), QXmlItem(bool(true)));
       
  1304     query.bindVariable(QLatin1String("fromQDate"), QXmlItem(QDate(2000, 10, 11)));
       
  1305     // TODO Do with different QDateTime time specs
       
  1306     query.bindVariable(QLatin1String("fromQDateTime"), QXmlItem(QDateTime(QDate(2001, 9, 10), QTime(1, 2, 3))));
       
  1307     query.bindVariable(QLatin1String("fromDouble"), QXmlItem(double(3)));
       
  1308     query.bindVariable(QLatin1String("fromFloat"), QXmlItem(float(4)));
       
  1309     query.bindVariable(QLatin1String("integer"), QXmlItem(5));
       
  1310     query.bindVariable(QLatin1String("fromQString"), QXmlItem(QString::fromLatin1("A QString")));
       
  1311     query.bindVariable(QLatin1String("fromQChar"), QXmlItem(QChar::fromLatin1('C')));
       
  1312 
       
  1313     query.bindVariable(QLatin1String("fromIntLiteral"), QXmlItem(QVariant(654)));
       
  1314 
       
  1315     {
       
  1316         QVariant ui(uint(5));
       
  1317         QCOMPARE(ui.type(), QVariant::UInt);
       
  1318         query.bindVariable(QLatin1String("fromUInt"), ui);
       
  1319     }
       
  1320 
       
  1321     {
       
  1322         QVariant ulnglng(qulonglong(6));
       
  1323         QCOMPARE(ulnglng.type(), QVariant::ULongLong);
       
  1324         query.bindVariable(QLatin1String("fromULongLong"), ulnglng);
       
  1325     }
       
  1326 
       
  1327     {
       
  1328         QVariant qlnglng(qlonglong(7));
       
  1329         QCOMPARE(qlnglng.type(), QVariant::LongLong);
       
  1330         query.bindVariable(QLatin1String("fromLongLong"), qlnglng);
       
  1331     }
       
  1332 
       
  1333     query.setQuery(&queryFile);
       
  1334 
       
  1335     // TODO do queries which declares external variables with types. Tons of combos here.
       
  1336     // TODO ensure that binding with QXmlItem() doesn't make a binding available.
       
  1337     // TODO test rebinding a variable.
       
  1338 
       
  1339     QVERIFY(query.isValid());
       
  1340 
       
  1341     QXmlResultItems it;
       
  1342     query.evaluateTo(&it);
       
  1343     QXmlItem item(it.next());
       
  1344     QVERIFY(!item.isNull());
       
  1345     QVERIFY(item.isAtomicValue());
       
  1346 
       
  1347     QCOMPARE(item.toAtomicValue().toString(),
       
  1348              QLatin1String("4 true 3 654 7 41414141 C 2000-10-11Z 2001-09-10T01:02:03 "
       
  1349                            "A QString http://example.com/ 5 6 true true true true true true true true true true "
       
  1350                            "true true true"));
       
  1351 }
       
  1352 
       
  1353 void tst_QXmlQuery::bindNode() const
       
  1354 {
       
  1355     QXmlQuery query;
       
  1356     TestSimpleNodeModel nodeModel(query.namePool());
       
  1357 
       
  1358     query.bindVariable(QLatin1String("node"), nodeModel.root());
       
  1359     QByteArray out;
       
  1360     QBuffer buff(&out);
       
  1361     QVERIFY(buff.open(QIODevice::WriteOnly));
       
  1362 
       
  1363     query.setQuery(QLatin1String("declare variable $node external; $node"));
       
  1364     QXmlSerializer serializer(query, &buff);
       
  1365 
       
  1366     QVERIFY(query.evaluateTo(&serializer));
       
  1367     QCOMPARE(out, QByteArray("<nodeName/>"));
       
  1368 }
       
  1369 
       
  1370 /*!
       
  1371   Pass in a relative URI, and make sure it is resolved against the current application directory.
       
  1372  */
       
  1373 void tst_QXmlQuery::relativeBaseURI() const
       
  1374 {
       
  1375     QXmlQuery query;
       
  1376     query.setQuery(QLatin1String("fn:static-base-uri()"), QUrl(QLatin1String("a/relative/uri.weirdExtension")));
       
  1377     QVERIFY(query.isValid());
       
  1378 
       
  1379     QByteArray result;
       
  1380     QBuffer buffer(&result);
       
  1381     QVERIFY(buffer.open(QIODevice::ReadWrite));
       
  1382 
       
  1383     QXmlSerializer serializer(query, &buffer);
       
  1384     QVERIFY(query.evaluateTo(&serializer));
       
  1385 
       
  1386     const QUrl loaded(QUrl::fromEncoded(result));
       
  1387     QUrl appPath(QUrl::fromLocalFile(QCoreApplication::applicationFilePath()));
       
  1388 
       
  1389     QVERIFY(loaded.isValid());
       
  1390     QVERIFY(appPath.isValid());
       
  1391     QVERIFY(!loaded.isRelative());
       
  1392     QVERIFY(!appPath.isRelative());
       
  1393 
       
  1394     QFileInfo dir(appPath.toLocalFile());
       
  1395     dir.setFile(QString());
       
  1396 
       
  1397     /* We can't use QUrl::isParentOf() because it doesn't do what we want it to */
       
  1398     if(!loaded.toLocalFile().startsWith(dir.absoluteFilePath()))
       
  1399         QTextStream(stderr) << "dir.absoluteFilePath():" << dir.absoluteFilePath() << "loaded.toLocalFile():" << loaded.toLocalFile();
       
  1400 
       
  1401     checkBaseURI(loaded, dir.absoluteFilePath());
       
  1402 }
       
  1403 
       
  1404 void tst_QXmlQuery::emptyBaseURI() const
       
  1405 {
       
  1406     QXmlQuery query;
       
  1407     query.setQuery(QLatin1String("fn:static-base-uri()"), QUrl());
       
  1408     QVERIFY(query.isValid());
       
  1409 
       
  1410     QByteArray result;
       
  1411     QBuffer buffer(&result);
       
  1412     QVERIFY(buffer.open(QIODevice::ReadWrite));
       
  1413 
       
  1414     QXmlSerializer serializer(query, &buffer);
       
  1415     QVERIFY(query.evaluateTo(&serializer));
       
  1416 
       
  1417     const QUrl loaded(QUrl::fromEncoded(result));
       
  1418     QUrl appPath(QUrl::fromLocalFile(QCoreApplication::applicationFilePath()));
       
  1419 
       
  1420     QVERIFY(loaded.isValid());
       
  1421     QVERIFY(appPath.isValid());
       
  1422     QVERIFY(!loaded.isRelative());
       
  1423     QVERIFY(!appPath.isRelative());
       
  1424 
       
  1425     QFileInfo dir(appPath.toLocalFile());
       
  1426     dir.setFile(QString());
       
  1427 
       
  1428     QCOMPARE(loaded, appPath);
       
  1429 }
       
  1430 
       
  1431 /*!
       
  1432   Ensure that QDate comes out as QDateTime.
       
  1433  */
       
  1434 void tst_QXmlQuery::roundTripDateWithinQXmlItem() const
       
  1435 {
       
  1436     const QDate date(1999, 9, 10);
       
  1437     QVERIFY(date.isValid());
       
  1438 
       
  1439     const QVariant variant(date);
       
  1440     QVERIFY(variant.isValid());
       
  1441     QCOMPARE(variant.type(), QVariant::Date);
       
  1442 
       
  1443     const QXmlItem item(variant);
       
  1444     QVERIFY(!item.isNull());
       
  1445     QVERIFY(item.isAtomicValue());
       
  1446 
       
  1447     const QVariant out(item.toAtomicValue());
       
  1448     QVERIFY(out.isValid());
       
  1449     QCOMPARE(out.type(), QVariant::Date);
       
  1450     QCOMPARE(out.toDate(), date);
       
  1451 }
       
  1452 
       
  1453 /*!
       
  1454  Check whether a query is valid, which uses an unbound variable.
       
  1455  */
       
  1456 void tst_QXmlQuery::bindingMissing() const
       
  1457 {
       
  1458     QXmlQuery query;
       
  1459     MessageSilencer messageHandler;
       
  1460     query.setMessageHandler(&messageHandler);
       
  1461 
       
  1462     QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
       
  1463     QVERIFY(queryFile.open(QIODevice::ReadOnly));
       
  1464     query.setQuery(&queryFile);
       
  1465 
       
  1466     QVERIFY(!query.isValid());
       
  1467 }
       
  1468 
       
  1469 void tst_QXmlQuery::bindDefaultConstructedItem() const
       
  1470 {
       
  1471     QFETCH(QXmlItem, item);
       
  1472 
       
  1473     QXmlQuery query;
       
  1474     MessageSilencer messageHandler;
       
  1475     query.setMessageHandler(&messageHandler);
       
  1476 
       
  1477     QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
       
  1478     QVERIFY(queryFile.open(QIODevice::ReadOnly));
       
  1479     query.setQuery(&queryFile);
       
  1480     query.bindVariable(QLatin1String("externalVariable"), item);
       
  1481 
       
  1482     QVERIFY(!query.isValid());
       
  1483 }
       
  1484 
       
  1485 void tst_QXmlQuery::bindDefaultConstructedItem_data() const
       
  1486 {
       
  1487     QTest::addColumn<QXmlItem>("item");
       
  1488 
       
  1489     QTest::newRow("QXmlItem()") << QXmlItem();
       
  1490     QTest::newRow("QXmlItem(QVariant())") << QXmlItem(QVariant());
       
  1491     QTest::newRow("QXmlItem(QXmlNodeModelIndex())") << QXmlItem(QXmlNodeModelIndex());
       
  1492 }
       
  1493 
       
  1494 /*!
       
  1495   Remove a binding by binding QXmlItem() with the same name.
       
  1496  */
       
  1497 void tst_QXmlQuery::eraseQXmlItemBinding() const
       
  1498 {
       
  1499     QXmlQuery query;
       
  1500     MessageSilencer messageHandler;
       
  1501     query.setMessageHandler(&messageHandler);
       
  1502 
       
  1503     QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
       
  1504     QVERIFY(queryFile.open(QIODevice::ReadOnly));
       
  1505     query.bindVariable(QLatin1String("externalVariable"), QXmlItem(3));
       
  1506     query.setQuery(&queryFile);
       
  1507     QVERIFY(query.isValid());
       
  1508 
       
  1509     QByteArray result;
       
  1510     QBuffer buffer(&result);
       
  1511     QVERIFY(buffer.open(QIODevice::ReadWrite));
       
  1512 
       
  1513     QXmlSerializer serializer(query, &buffer);
       
  1514     QVERIFY(query.evaluateTo(&serializer));
       
  1515 
       
  1516     QCOMPARE(result, QByteArray("3 6<e>3</e>false"));
       
  1517 
       
  1518     query.bindVariable(QLatin1String("externalVariable"), QXmlItem());
       
  1519     QVERIFY(!query.isValid());
       
  1520 }
       
  1521 
       
  1522 /*!
       
  1523  Erase a variable binding
       
  1524  */
       
  1525 void tst_QXmlQuery::eraseDeviceBinding() const
       
  1526 {
       
  1527     /* Erase an existing QIODevice binding with another QIODevice binding. */
       
  1528     {
       
  1529         QXmlQuery query;
       
  1530 
       
  1531         QByteArray doc("<e/>");
       
  1532         QBuffer buffer(&doc);
       
  1533         QVERIFY(buffer.open(QIODevice::ReadOnly));
       
  1534 
       
  1535         query.bindVariable(QLatin1String("in"), &buffer);
       
  1536         query.setQuery(QLatin1String("$in"));
       
  1537         QVERIFY(query.isValid());
       
  1538 
       
  1539         query.bindVariable(QLatin1String("in"), 0);
       
  1540         QVERIFY(!query.isValid());
       
  1541     }
       
  1542 
       
  1543     /* Erase an existing QXmlItem binding with another QIODevice binding. */
       
  1544     {
       
  1545         QXmlQuery query;
       
  1546 
       
  1547         query.bindVariable(QLatin1String("in"), QXmlItem(5));
       
  1548         query.setQuery(QLatin1String("$in"));
       
  1549         QVERIFY(query.isValid());
       
  1550 
       
  1551         query.bindVariable(QLatin1String("in"), 0);
       
  1552         QVERIFY(!query.isValid());
       
  1553     }
       
  1554 }
       
  1555 
       
  1556 /*!
       
  1557  Bind a variable, evaluate, bind with a different value but same type, and evaluate again.
       
  1558  */
       
  1559 void tst_QXmlQuery::rebindVariableSameType() const
       
  1560 {
       
  1561     QXmlQuery query;
       
  1562     MessageSilencer messageHandler;
       
  1563     query.setMessageHandler(&messageHandler);
       
  1564 
       
  1565     query.bindVariable(QLatin1String("externalVariable"), QXmlItem(3));
       
  1566 
       
  1567     {
       
  1568         QFile queryFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariable.xq"));
       
  1569         QVERIFY(queryFile.open(QIODevice::ReadOnly));
       
  1570         query.setQuery(&queryFile);
       
  1571     }
       
  1572 
       
  1573     QVERIFY(query.isValid());
       
  1574 
       
  1575     {
       
  1576         QByteArray result;
       
  1577         QBuffer buffer(&result);
       
  1578         QVERIFY(buffer.open(QIODevice::ReadWrite));
       
  1579 
       
  1580         QXmlSerializer serializer(query, &buffer);
       
  1581         QVERIFY(query.evaluateTo(&serializer));
       
  1582 
       
  1583         QCOMPARE(result, QByteArray("3 6<e>3</e>false"));
       
  1584     }
       
  1585 
       
  1586     {
       
  1587         query.bindVariable(QLatin1String("externalVariable"), QXmlItem(5));
       
  1588         QByteArray result;
       
  1589         QBuffer buffer(&result);
       
  1590         QVERIFY(buffer.open(QIODevice::ReadWrite));
       
  1591 
       
  1592         QXmlSerializer serializer(query, &buffer);
       
  1593         QVERIFY(query.evaluateTo(&serializer));
       
  1594 
       
  1595         QCOMPARE(result, QByteArray("5 8<e>5</e>false"));
       
  1596     }
       
  1597 
       
  1598 }
       
  1599 
       
  1600 void tst_QXmlQuery::rebindVariableDifferentType() const
       
  1601 {
       
  1602     /* Rebind QXmlItem variable with QXmlItem variable. */
       
  1603     {
       
  1604         QXmlQuery query;
       
  1605         query.bindVariable(QLatin1String("in"), QXmlItem(3));
       
  1606         query.setQuery(QLatin1String("$in"));
       
  1607         QVERIFY(query.isValid());
       
  1608 
       
  1609         query.bindVariable(QLatin1String("in"), QXmlItem("A string"));
       
  1610         QVERIFY(!query.isValid());
       
  1611     }
       
  1612 
       
  1613     /* Rebind QIODevice variable with QXmlItem variable. */
       
  1614     {
       
  1615         QXmlQuery query;
       
  1616         QBuffer buffer;
       
  1617         buffer.setData(QByteArray("<e/>"));
       
  1618         QVERIFY(buffer.open(QIODevice::ReadOnly));
       
  1619 
       
  1620         query.bindVariable(QLatin1String("in"), &buffer);
       
  1621         query.setQuery(QLatin1String("$in"));
       
  1622         QVERIFY(query.isValid());
       
  1623 
       
  1624         query.bindVariable(QLatin1String("in"), QXmlItem("A string"));
       
  1625         QVERIFY(!query.isValid());
       
  1626     }
       
  1627 
       
  1628     /* Rebind QXmlItem variable with QIODevice variable. The type of the
       
  1629      * variable changes, so a recompile is necessary. */
       
  1630     {
       
  1631         QXmlQuery query;
       
  1632 
       
  1633         query.bindVariable(QLatin1String("in"), QXmlItem(QLatin1String("A string")));
       
  1634         query.setQuery(QLatin1String("$in"));
       
  1635         QVERIFY(query.isValid());
       
  1636 
       
  1637         QBuffer buffer;
       
  1638         buffer.setData(QByteArray("<e/>"));
       
  1639         QVERIFY(buffer.open(QIODevice::ReadOnly));
       
  1640         query.bindVariable(QLatin1String("in"), &buffer);
       
  1641         QVERIFY(!query.isValid());
       
  1642     }
       
  1643 }
       
  1644 
       
  1645 void tst_QXmlQuery::rebindVariableWithNullItem() const
       
  1646 {
       
  1647     QXmlQuery query;
       
  1648 
       
  1649     query.bindVariable(QLatin1String("name"), QXmlItem(5));
       
  1650     query.bindVariable(QLatin1String("name"), QXmlItem());
       
  1651 }
       
  1652 
       
  1653 void tst_QXmlQuery::constCorrectness() const
       
  1654 {
       
  1655     QXmlResultItems result;
       
  1656     QXmlQuery tmp;
       
  1657     tmp.setQuery(QLatin1String("1")); /* Just so we have a valid query. */
       
  1658     const QXmlQuery query(tmp);
       
  1659 
       
  1660     /* These functions should be const. */
       
  1661     query.isValid();
       
  1662     query.evaluateTo(&result);
       
  1663     query.namePool();
       
  1664     query.uriResolver();
       
  1665     query.messageHandler();
       
  1666 
       
  1667     {
       
  1668         QString dummyString;
       
  1669         QTextStream dummyStream(&dummyString);
       
  1670         PushBaseliner dummy(dummyStream, query.namePool());
       
  1671         query.evaluateTo(&dummy);
       
  1672     }
       
  1673 }
       
  1674 
       
  1675 void tst_QXmlQuery::objectSize() const
       
  1676 {
       
  1677     /* We have a d pointer. */
       
  1678     QCOMPARE(sizeof(QXmlQuery), sizeof(void *));
       
  1679 }
       
  1680 
       
  1681 void tst_QXmlQuery::setUriResolver() const
       
  1682 {
       
  1683     /* Set a null resolver, and make sure it can take a const pointer. */
       
  1684     {
       
  1685         QXmlQuery query;
       
  1686         query.setUriResolver(static_cast<const QAbstractUriResolver *>(0));
       
  1687         QCOMPARE(query.uriResolver(), static_cast<const QAbstractUriResolver *>(0));
       
  1688     }
       
  1689 
       
  1690     {
       
  1691         TestURIResolver resolver;
       
  1692         QXmlQuery query;
       
  1693         query.setUriResolver(&resolver);
       
  1694         QCOMPARE(query.uriResolver(), &resolver);
       
  1695     }
       
  1696 }
       
  1697 
       
  1698 void tst_QXmlQuery::uriResolver() const
       
  1699 {
       
  1700     /* Check default value. */
       
  1701     {
       
  1702         QXmlQuery query;
       
  1703         QCOMPARE(query.uriResolver(), static_cast<const QAbstractUriResolver *>(0));
       
  1704     }
       
  1705 }
       
  1706 
       
  1707 void tst_QXmlQuery::messageXML() const
       
  1708 {
       
  1709     QXmlQuery query;
       
  1710 
       
  1711     MessageValidator messageValidator;
       
  1712     query.setMessageHandler(&messageValidator);
       
  1713 
       
  1714     query.setQuery(QLatin1String("1basicSyntaxError"));
       
  1715 
       
  1716     const QRegExp removeFilename(QLatin1String("Location: file:.*\\#"));
       
  1717     QVERIFY(removeFilename.isValid());
       
  1718 
       
  1719     QVERIFY(messageValidator.success());
       
  1720     QCOMPARE(messageValidator.received().remove(removeFilename),
       
  1721              QString::fromLatin1("Type:3\n"
       
  1722                                  "Description: <html xmlns='http://www.w3.org/1999/xhtml/'><body><p>syntax error, unexpected unknown keyword</p></body></html>\n"
       
  1723                                  "Identifier: http://www.w3.org/2005/xqt-errors#XPST0003\n"
       
  1724                                  "1,1"));
       
  1725 }
       
  1726 
       
  1727 /*!
       
  1728   1. Allocate QXmlResultItems
       
  1729   2. Allocate QXmlQuery
       
  1730   3. evaluate to the QXmlResultItems instance
       
  1731   4. Dellocate the QXmlQuery instance
       
  1732   5. Ensure QXmlResultItems works
       
  1733  */
       
  1734 void tst_QXmlQuery::resultItemsDeallocatedQuery() const
       
  1735 {
       
  1736     QXmlResultItems result;
       
  1737 
       
  1738     {
       
  1739         QXmlQuery query;
       
  1740         query.setQuery(QLatin1String("1, 2, xs:integer(<e>3</e>)"));
       
  1741         query.evaluateTo(&result);
       
  1742     }
       
  1743 
       
  1744     QCOMPARE(result.next().toAtomicValue(), QVariant(1));
       
  1745     QCOMPARE(result.next().toAtomicValue(), QVariant(2));
       
  1746     QCOMPARE(result.next().toAtomicValue(), QVariant(3));
       
  1747     QVERIFY(result.next().isNull());
       
  1748     QVERIFY(!result.hasError());
       
  1749 }
       
  1750 
       
  1751 /*!
       
  1752   1. Bind variable with bindVariable()
       
  1753   2. setQuery that has 'declare variable' with same name.
       
  1754   3. Ensure the value inside the query is used. We don't guarantee this behavior
       
  1755      but that's what we lock.
       
  1756  */
       
  1757 void tst_QXmlQuery::shadowedVariables() const
       
  1758 {
       
  1759     QXmlQuery query;
       
  1760     query.bindVariable("varName", QXmlItem(3));
       
  1761     query.setQuery(QLatin1String("declare variable $varName := 5; $varName"));
       
  1762 
       
  1763     QXmlResultItems result;
       
  1764     query.evaluateTo(&result);
       
  1765 
       
  1766     QCOMPARE(result.next().toAtomicValue(), QVariant(5));
       
  1767 }
       
  1768 
       
  1769 void tst_QXmlQuery::setFocusQXmlItem() const
       
  1770 {
       
  1771     /* Make sure we can take a const reference. */
       
  1772     {
       
  1773         QXmlQuery query;
       
  1774         const QXmlItem item;
       
  1775         query.setFocus(item);
       
  1776     }
       
  1777 
       
  1778     // TODO evaluate with atomic value, check type
       
  1779     // TODO evaluate with node, check type
       
  1780     // TODO ensure that setFocus() triggers query recompilation, as appropriate.
       
  1781     // TODO let the focus be undefined, call isvalid, call evaluate anyway
       
  1782     // TODO let the focus be undefined, call evaluate directly
       
  1783 }
       
  1784 
       
  1785 void tst_QXmlQuery::setFocusQUrl() const
       
  1786 {
       
  1787     /* Load a focus which isn't well-formed. */
       
  1788     {
       
  1789         QXmlQuery query;
       
  1790         MessageSilencer silencer;
       
  1791 
       
  1792         query.setMessageHandler(&silencer);
       
  1793 
       
  1794         QVERIFY(!query.setFocus(QUrl(QLatin1String("data/notWellformed.xml"))));
       
  1795     }
       
  1796 
       
  1797     /* Ensure the same URI resolver is used. */
       
  1798     {
       
  1799         QXmlQuery query(QXmlQuery::XSLT20);
       
  1800 
       
  1801         const TestURIResolver resolver(QUrl(inputFile(QLatin1String(SRCDIR "../xmlpatterns/stylesheets/documentElement.xml"))));
       
  1802         query.setUriResolver(&resolver);
       
  1803 
       
  1804         QVERIFY(query.setFocus(QUrl(QLatin1String("arbitraryURI"))));
       
  1805         query.setQuery(QUrl(inputFile(QLatin1String(SRCDIR "../xmlpatterns/stylesheets/copyWholeDocument.xsl"))));
       
  1806         QVERIFY(query.isValid());
       
  1807 
       
  1808         QBuffer result;
       
  1809         QVERIFY(result.open(QIODevice::ReadWrite));
       
  1810         QXmlSerializer serializer(query, &result);
       
  1811         query.evaluateTo(&serializer);
       
  1812 
       
  1813         QCOMPARE(result.data(), QByteArray("<doc/>"));
       
  1814     }
       
  1815 
       
  1816     // TODO ensure that the focus type doesn't change from XSLT20 on the main instance.
       
  1817 }
       
  1818 
       
  1819 /*!
       
  1820   This code poses a challenge wrt. to internal caching.
       
  1821  */
       
  1822 void tst_QXmlQuery::setFocusQIODevice() const
       
  1823 {
       
  1824     QXmlQuery query;
       
  1825 
       
  1826     {
       
  1827         QBuffer focus;
       
  1828         focus.setData(QByteArray("<e>abc</e>"));
       
  1829         QVERIFY(focus.open(QIODevice::ReadOnly));
       
  1830         query.setFocus(&focus);
       
  1831         query.setQuery(QLatin1String("string()"));
       
  1832         QVERIFY(query.isValid());
       
  1833 
       
  1834         QString output;
       
  1835         query.evaluateTo(&output);
       
  1836 
       
  1837         QCOMPARE(output, QString::fromLatin1("abc\n"));
       
  1838     }
       
  1839 
       
  1840     /* Set a new focus, make sure it changes & works. */
       
  1841     {
       
  1842         QBuffer focus2;
       
  1843         focus2.setData(QByteArray("<e>abc2</e>"));
       
  1844         QVERIFY(focus2.open(QIODevice::ReadOnly));
       
  1845         query.setFocus(&focus2);
       
  1846         QVERIFY(query.isValid());
       
  1847 
       
  1848         QString output;
       
  1849         query.evaluateTo(&output);
       
  1850 
       
  1851         QCOMPARE(output, QString::fromLatin1("abc2\n"));
       
  1852     }
       
  1853 }
       
  1854 
       
  1855 /*!
       
  1856  Since we internally use variable bindings for implementing the focus, we need
       
  1857  to make sure we don't clash in this area.
       
  1858 */
       
  1859 void tst_QXmlQuery::setFocusQIODeviceAvoidVariableClash() const
       
  1860 {
       
  1861     QBuffer buffer;
       
  1862     buffer.setData("<e>focus</e>");
       
  1863     QVERIFY(buffer.open(QIODevice::ReadOnly));
       
  1864 
       
  1865     /* First we bind the variable name, then the focus. */
       
  1866     {
       
  1867         QXmlQuery query;
       
  1868         query.bindVariable(QString(QLatin1Char('u')), QVariant(1));
       
  1869         query.setFocus(&buffer);
       
  1870         query.setQuery(QLatin1String("string()"));
       
  1871 
       
  1872         QString out;
       
  1873         query.evaluateTo(&out);
       
  1874 
       
  1875         QCOMPARE(out, QString::fromLatin1("focus\n"));
       
  1876     }
       
  1877 
       
  1878     /* First we bind the focus, then the variable name. */
       
  1879     {
       
  1880         QXmlQuery query;
       
  1881         QVERIFY(buffer.open(QIODevice::ReadOnly));
       
  1882         query.setFocus(&buffer);
       
  1883         query.bindVariable(QString(QLatin1Char('u')), QVariant(1));
       
  1884         query.setQuery(QLatin1String("string()"));
       
  1885 
       
  1886         QString out;
       
  1887         query.evaluateTo(&out);
       
  1888 
       
  1889         QCOMPARE(out, QString::fromLatin1("focus\n"));
       
  1890     }
       
  1891 }
       
  1892 
       
  1893 void tst_QXmlQuery::setFocusQIODeviceFailure() const
       
  1894 {
       
  1895     /* A not well-formed input document. */
       
  1896     {
       
  1897         QXmlQuery query;
       
  1898 
       
  1899         MessageSilencer silencer;
       
  1900         query.setMessageHandler(&silencer);
       
  1901 
       
  1902         QBuffer input;
       
  1903         input.setData("<e");
       
  1904         QVERIFY(input.open(QIODevice::ReadOnly));
       
  1905 
       
  1906         QCOMPARE(query.setFocus(&input), false);
       
  1907     }
       
  1908 }
       
  1909 
       
  1910 void tst_QXmlQuery::setFocusQString() const
       
  1911 {
       
  1912     QXmlQuery query;
       
  1913 
       
  1914     /* Basic use of focus. */
       
  1915     {
       
  1916         QVERIFY(query.setFocus(QLatin1String("<e>textNode</e>")));
       
  1917         query.setQuery(QLatin1String("string()"));
       
  1918         QVERIFY(query.isValid());
       
  1919         QString out;
       
  1920         query.evaluateTo(&out);
       
  1921         QCOMPARE(out, QString::fromLatin1("textNode\n"));
       
  1922     }
       
  1923 
       
  1924     /* Set to a new focus, make sure it changes and works. */
       
  1925     {
       
  1926         QVERIFY(query.setFocus(QLatin1String("<e>newFocus</e>")));
       
  1927         QString out;
       
  1928         query.evaluateTo(&out);
       
  1929         QCOMPARE(out, QString::fromLatin1("newFocus\n"));
       
  1930     }
       
  1931 }
       
  1932 
       
  1933 void tst_QXmlQuery::setFocusQStringFailure() const
       
  1934 {
       
  1935     QXmlQuery query;
       
  1936     MessageSilencer silencer;
       
  1937 
       
  1938     query.setMessageHandler(&silencer);
       
  1939     QVERIFY(!query.setFocus(QLatin1String("<notWellformed")));
       
  1940 
       
  1941     /* Let's try the slight special case of a null string. */
       
  1942     QVERIFY(!query.setFocus(QString()));
       
  1943 }
       
  1944 
       
  1945 void tst_QXmlQuery::setFocusQStringSignature() const
       
  1946 {
       
  1947     QXmlQuery query;
       
  1948     MessageSilencer silencer;
       
  1949     query.setMessageHandler(&silencer);
       
  1950 
       
  1951     const QString argument;
       
  1952     /* We should take a const ref. */
       
  1953     query.setFocus(argument);
       
  1954 
       
  1955     /* We should return a bool. */
       
  1956     static_cast<bool>(query.setFocus(QString()));
       
  1957 }
       
  1958 
       
  1959 void tst_QXmlQuery::setFocusQIODeviceTriggerWarnings() const
       
  1960 {
       
  1961     /* A null pointer. */
       
  1962     {
       
  1963         QXmlQuery query;
       
  1964 
       
  1965         QTest::ignoreMessage(QtWarningMsg, "A null QIODevice pointer cannot be passed.");
       
  1966         QCOMPARE(query.setFocus(static_cast<QIODevice *>(0)), false);
       
  1967     }
       
  1968 
       
  1969     /* A non opened-device. */
       
  1970     {
       
  1971         QXmlQuery query;
       
  1972 
       
  1973         QBuffer notReadable;
       
  1974         QVERIFY(!notReadable.isReadable());
       
  1975 
       
  1976         QTest::ignoreMessage(QtWarningMsg, "The device must be readable.");
       
  1977         QCOMPARE(query.setFocus(&notReadable), false);
       
  1978     }
       
  1979 }
       
  1980 
       
  1981 void tst_QXmlQuery::fnDocNetworkAccessSuccess() const
       
  1982 {
       
  1983 #if defined(Q_OS_WINCE) && !defined(_X86_)
       
  1984     QStringList testsToSkip;
       
  1985     testsToSkip << "http scheme" << "ftp scheme";
       
  1986     if (testsToSkip.contains(QTest::currentDataTag()))
       
  1987         QSKIP("Network tests are currently unsupported on Windows CE.", SkipSingle);
       
  1988 #endif
       
  1989 
       
  1990     QFETCH(QUrl, uriToOpen);
       
  1991     QFETCH(QByteArray, expectedOutput);
       
  1992 
       
  1993     if(!uriToOpen.isValid())
       
  1994         qDebug() << "uriToOpen:" << uriToOpen;
       
  1995 
       
  1996     QVERIFY(uriToOpen.isValid());
       
  1997 
       
  1998     QXmlQuery query;
       
  1999     query.bindVariable(QLatin1String("uri"), QVariant(uriToOpen));
       
  2000     query.setQuery(QLatin1String("declare variable $uri external;\ndoc($uri)"));
       
  2001     QVERIFY(query.isValid());
       
  2002 
       
  2003     QByteArray result;
       
  2004     QBuffer buffer(&result);
       
  2005     QVERIFY(buffer.open(QIODevice::WriteOnly));
       
  2006 
       
  2007     QXmlSerializer serializer(query, &buffer);
       
  2008     QVERIFY(query.evaluateTo(&serializer));
       
  2009 
       
  2010     QCOMPARE(result, expectedOutput);
       
  2011 }
       
  2012 
       
  2013 void tst_QXmlQuery::fnDocNetworkAccessSuccess_data() const
       
  2014 {
       
  2015     QTest::addColumn<QUrl>("uriToOpen");
       
  2016     QTest::addColumn<QByteArray>("expectedOutput");
       
  2017 
       
  2018     QTest::newRow("file scheme")
       
  2019         << inputFileAsURI(QLatin1String(SRCDIR "input.xml"))
       
  2020         << QByteArray("<!-- This is just a file for testing. --><input/>");
       
  2021 
       
  2022     QTest::newRow("data scheme with ASCII")
       
  2023         /* QUrl::toPercentEncoding(QLatin1String("<e/>")) yields "%3Ce%2F%3E". */
       
  2024         << QUrl::fromEncoded("data:application/xml,%3Ce%2F%3E")
       
  2025         << QByteArray("<e/>");
       
  2026 
       
  2027     QTest::newRow("data scheme with ASCII no MIME type")
       
  2028         << QUrl::fromEncoded("data:,%3Ce%2F%3E")
       
  2029         << QByteArray("<e/>");
       
  2030 
       
  2031     QTest::newRow("data scheme with base 64")
       
  2032         << QUrl::fromEncoded("data:application/xml;base64,PGUvPg==")
       
  2033         << QByteArray("<e/>");
       
  2034 
       
  2035     QTest::newRow("qrc scheme")
       
  2036         << QUrl::fromEncoded("qrc:/QXmlQueryTestData/data/oneElement.xml")
       
  2037         << QByteArray("<oneElement/>");
       
  2038 
       
  2039     if(!m_testNetwork)
       
  2040         return;
       
  2041 
       
  2042     QTest::newRow("http scheme")
       
  2043         << QUrl(QString("http://" + QtNetworkSettings::serverName() + "/qxmlquery/wellFormed.xml"))
       
  2044         << QByteArray("<!-- a comment --><e from=\"http\">Some Text</e>");
       
  2045 
       
  2046     QTest::newRow("ftp scheme")
       
  2047         << QUrl(QString("ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/wellFormed.xml"))
       
  2048         << QByteArray("<!-- a comment --><e from=\"ftp\">Some Text</e>");
       
  2049 
       
  2050 }
       
  2051 
       
  2052 void tst_QXmlQuery::fnDocNetworkAccessFailure() const
       
  2053 {
       
  2054     QFETCH(QUrl, uriToOpen);
       
  2055 
       
  2056     QVERIFY(uriToOpen.isValid());
       
  2057 
       
  2058     QXmlQuery query;
       
  2059     MessageSilencer silencer;
       
  2060     query.setMessageHandler(&silencer);
       
  2061     query.bindVariable(QLatin1String("uri"), QVariant(uriToOpen));
       
  2062     query.setQuery(QLatin1String("declare variable $uri external;\ndoc($uri)"));
       
  2063     QVERIFY(query.isValid());
       
  2064 
       
  2065     QXmlResultItems result;
       
  2066     query.evaluateTo(&result);
       
  2067 
       
  2068     while(!result.next().isNull())
       
  2069     {
       
  2070         /* Just loop until the end. */
       
  2071     }
       
  2072 
       
  2073     // TODO do something that triggers a /timeout/.
       
  2074     QVERIFY(result.hasError());
       
  2075 }
       
  2076 
       
  2077 void tst_QXmlQuery::fnDocNetworkAccessFailure_data() const
       
  2078 {
       
  2079     QTest::addColumn<QUrl>("uriToOpen");
       
  2080 
       
  2081     QTest::newRow("data scheme, not-well-formed")
       
  2082         << QUrl(QLatin1String("data:application/xml;base64,PGUvg==="));
       
  2083 
       
  2084     QTest::newRow("file scheme, non-existant file")
       
  2085         << QUrl(QLatin1String("file:///example.com/does/notExist.xml"));
       
  2086 
       
  2087     QTest::newRow("http scheme, file not found")
       
  2088         << QUrl(QLatin1String("http://www.example.com/does/not/exist.xml"));
       
  2089 
       
  2090     QTest::newRow("http scheme, nonexistent host")
       
  2091         << QUrl(QLatin1String("http://this.host.does.not.exist.I.SWear"));
       
  2092 
       
  2093     QTest::newRow("qrc scheme, not well-formed")
       
  2094         << QUrl(QLatin1String("qrc:/QXmlQueryTestData/notWellformed.xml"));
       
  2095 
       
  2096     QTest::newRow("'qrc:/', non-existing file")
       
  2097         << QUrl(QLatin1String(":/QXmlQueryTestData/data/thisFileDoesNotExist.xml"));
       
  2098 
       
  2099     QTest::newRow("':/', this scheme is not supported")
       
  2100         << QUrl(QLatin1String(":/QXmlQueryTestData/data/notWellformed.xml"));
       
  2101 
       
  2102     if(!m_testNetwork)
       
  2103         return;
       
  2104 
       
  2105     QTest::newRow("http scheme, not well-formed")
       
  2106         << QUrl(QString("http://" + QtNetworkSettings::serverName() + "/qxmlquery/notWellformed.xml"));
       
  2107 
       
  2108     QTest::newRow("https scheme, not well-formed")
       
  2109         << QUrl(QString("https://" + QtNetworkSettings::serverName() + "/qxmlquery/notWellformedViaHttps.xml"));
       
  2110 
       
  2111     QTest::newRow("https scheme, nonexistent host")
       
  2112         << QUrl(QLatin1String("https://this.host.does.not.exist.I.SWear"));
       
  2113 
       
  2114     QTest::newRow("ftp scheme, nonexistent host")
       
  2115         << QUrl(QLatin1String("ftp://this.host.does.not.exist.I.SWear"));
       
  2116 
       
  2117     QTest::newRow("ftp scheme, not well-formed")
       
  2118         << QUrl(QString("ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/notWellFormed.xml"));
       
  2119 }
       
  2120 
       
  2121 /*!
       
  2122   Create a network timeout from a QIODevice binding such
       
  2123   that we ensure we don't hang infinitely.
       
  2124  */
       
  2125 void tst_QXmlQuery::fnDocOnQIODeviceTimeout() const
       
  2126 {
       
  2127     if(!m_testNetwork)
       
  2128         return;
       
  2129 
       
  2130     QTcpServer server;
       
  2131     server.listen(QHostAddress::LocalHost, 1088);
       
  2132 
       
  2133     QTcpSocket client;
       
  2134     client.connectToHost("localhost", 1088);
       
  2135     QVERIFY(client.isReadable());
       
  2136 
       
  2137     QXmlQuery query;
       
  2138 
       
  2139     MessageSilencer silencer;
       
  2140     query.setMessageHandler(&silencer);
       
  2141 
       
  2142     query.bindVariable(QLatin1String("inDevice"), &client);
       
  2143     query.setQuery(QLatin1String("declare variable $inDevice external;\ndoc($inDevice)"));
       
  2144     QVERIFY(query.isValid());
       
  2145 
       
  2146     QXmlResultItems result;
       
  2147     query.evaluateTo(&result);
       
  2148     QXmlItem next(result.next());
       
  2149 
       
  2150     while(!next.isNull())
       
  2151     {
       
  2152         next = result.next();
       
  2153     }
       
  2154 
       
  2155     QVERIFY(result.hasError());
       
  2156 }
       
  2157 
       
  2158 /*!
       
  2159  When changing query, the static context must change too, such that
       
  2160  the source locations are updated.
       
  2161  */
       
  2162 void tst_QXmlQuery::recompilationWithEvaluateToResultFailing() const
       
  2163 {
       
  2164     QXmlQuery query;
       
  2165     MessageSilencer silencer;
       
  2166     query.setMessageHandler(&silencer);
       
  2167 
       
  2168     query.setQuery(QLatin1String("1 + 1")); /* An arbitrary valid query. */
       
  2169     QVERIFY(query.isValid()); /* Trigger query compilation. */
       
  2170 
       
  2171     query.setQuery(QLatin1String("fn:doc('doesNotExist.example.com.xml')")); /* An arbitrary invalid query that make use of a source location. */
       
  2172     QVERIFY(query.isValid()); /* Trigger second compilation. */
       
  2173 
       
  2174     QXmlResultItems items;
       
  2175     query.evaluateTo(&items);
       
  2176     items.next();
       
  2177     QVERIFY(items.hasError());
       
  2178 }
       
  2179 
       
  2180 void tst_QXmlQuery::secondEvaluationWithEvaluateToResultFailing() const
       
  2181 {
       
  2182     QXmlQuery query;
       
  2183     MessageSilencer silencer;
       
  2184     query.setMessageHandler(&silencer);
       
  2185 
       
  2186     query.setQuery(QLatin1String("1 + 1")); /* An arbitrary valid query. */
       
  2187     QVERIFY(query.isValid()); /* Trigger query compilation. */
       
  2188 
       
  2189     query.setQuery(QLatin1String("fn:doc('doesNotExist.example.com.xml')")); /* An arbitrary invalid query that make use of a source location. */
       
  2190     /* We don't call isValid(). */
       
  2191 QXmlResultItems items;
       
  2192     query.evaluateTo(&items);
       
  2193     items.next();
       
  2194     QVERIFY(items.hasError());
       
  2195 }
       
  2196 
       
  2197 /*!
       
  2198  Compilation is triggered in the evaluation function due to no call to QXmlQuery::isValid().
       
  2199  */
       
  2200 void tst_QXmlQuery::recompilationWithEvaluateToReceiver() const
       
  2201 {
       
  2202     QXmlQuery query;
       
  2203     MessageSilencer silencer;
       
  2204     query.setMessageHandler(&silencer);
       
  2205 
       
  2206     query.setQuery(QLatin1String("1 + 1")); /* An arbitrary valid query. */
       
  2207     QVERIFY(query.isValid()); /* Trigger query compilation. */
       
  2208 
       
  2209     query.setQuery(QLatin1String("fn:doc('doesNotExist.example.com.xml')")); /* An arbitrary invalid query that make use of a source location. */
       
  2210     /* We don't call isValid(). */
       
  2211 
       
  2212     QByteArray dummy;
       
  2213     QBuffer buffer(&dummy);
       
  2214     buffer.open(QIODevice::WriteOnly);
       
  2215 
       
  2216     QXmlSerializer serializer(query, &buffer);
       
  2217 
       
  2218     QVERIFY(!query.evaluateTo(&serializer));
       
  2219 }
       
  2220 
       
  2221 void tst_QXmlQuery::evaluateToQStringListOnInvalidQuery() const
       
  2222 {
       
  2223     MessageSilencer silencer;
       
  2224 
       
  2225     /* Invoke on a default constructed object. */
       
  2226     {
       
  2227         QXmlQuery query;
       
  2228         QStringList out;
       
  2229         QVERIFY(!query.evaluateTo(&out));
       
  2230     }
       
  2231 
       
  2232     /* Invoke on a syntactically invalid query. */
       
  2233     {
       
  2234         QXmlQuery query;
       
  2235         QStringList out;
       
  2236         MessageSilencer silencer;
       
  2237 
       
  2238         query.setMessageHandler(&silencer);
       
  2239         query.setQuery(QLatin1String("1 + "));
       
  2240 
       
  2241         QVERIFY(!query.evaluateTo(&out));
       
  2242     }
       
  2243 
       
  2244     /* Invoke on a query with the wrong type, one atomic. */
       
  2245     {
       
  2246         QXmlQuery query;
       
  2247         QStringList out;
       
  2248 
       
  2249         query.setQuery(QLatin1String("1"));
       
  2250         query.setMessageHandler(&silencer);
       
  2251         QVERIFY(!query.evaluateTo(&out));
       
  2252     }
       
  2253 
       
  2254     /* Invoke on a query with the wrong type, one element. */
       
  2255     {
       
  2256         QXmlQuery query;
       
  2257         QStringList out;
       
  2258 
       
  2259         query.setQuery(QLatin1String("<e/>"));
       
  2260         QVERIFY(!query.evaluateTo(&out));
       
  2261     }
       
  2262 
       
  2263     /* Invoke on a query with the wrong type, mixed nodes & atomics. */
       
  2264     {
       
  2265         QXmlQuery query;
       
  2266         QStringList out;
       
  2267 
       
  2268         query.setQuery(QLatin1String("<e/>, 1, 'a string'"));
       
  2269         query.setMessageHandler(&silencer);
       
  2270         QVERIFY(!query.evaluateTo(&out));
       
  2271     }
       
  2272 
       
  2273     /* Evaluate the empty sequence. */
       
  2274     {
       
  2275         QXmlQuery query;
       
  2276         QStringList out;
       
  2277 
       
  2278         query.setQuery(QLatin1String("()"));
       
  2279         QVERIFY(!query.evaluateTo(&out));
       
  2280         QVERIFY(out.isEmpty());
       
  2281     }
       
  2282 }
       
  2283 
       
  2284 void tst_QXmlQuery::evaluateToQStringList() const
       
  2285 {
       
  2286     QFETCH(QString, queryString);
       
  2287     QFETCH(QStringList, expectedOutput);
       
  2288 
       
  2289     QXmlQuery query;
       
  2290     query.setQuery(queryString);
       
  2291     QStringList out;
       
  2292     QVERIFY(query.isValid());
       
  2293 
       
  2294     QVERIFY(query.evaluateTo(&out));
       
  2295 
       
  2296     QCOMPARE(out, expectedOutput);
       
  2297 }
       
  2298 
       
  2299 void tst_QXmlQuery::evaluateToQStringListTriggerWarnings() const
       
  2300 {
       
  2301     QXmlQuery query;
       
  2302 
       
  2303     QTest::ignoreMessage(QtWarningMsg, "A non-null callback must be passed.");
       
  2304     QCOMPARE(query.evaluateTo(static_cast<QStringList *>(0)),
       
  2305              false);
       
  2306 }
       
  2307 
       
  2308 void tst_QXmlQuery::evaluateToQStringList_data() const
       
  2309 {
       
  2310     QTest::addColumn<QString>("queryString");
       
  2311     QTest::addColumn<QStringList>("expectedOutput");
       
  2312 
       
  2313     QTest::newRow("One atomic")
       
  2314         << QString::fromLatin1("(1 + 1) cast as xs:string")
       
  2315         << QStringList(QString::fromLatin1("2"));
       
  2316 
       
  2317     {
       
  2318         QStringList expected;
       
  2319         expected << QLatin1String("2");
       
  2320         expected << QLatin1String("a string");
       
  2321 
       
  2322         QTest::newRow("Two atomics")
       
  2323             << QString::fromLatin1("(1 + 1) cast as xs:string, 'a string'")
       
  2324             << expected;
       
  2325     }
       
  2326 
       
  2327     QTest::newRow("A query which evaluates to sub-types of xs:string.")
       
  2328         << QString::fromLatin1("xs:NCName('NCName'), xs:normalizedString('  a b c   ')")
       
  2329         << (QStringList() << QString::fromLatin1("NCName")
       
  2330                           << QString::fromLatin1("  a b c   "));
       
  2331 
       
  2332     QTest::newRow("A query which evaluates to two elements.")
       
  2333         << QString::fromLatin1("string(<e>theString1</e>), string(<e>theString2</e>)")
       
  2334         << (QStringList() << QString::fromLatin1("theString1")
       
  2335                           << QString::fromLatin1("theString2"));
       
  2336 }
       
  2337 
       
  2338 /*!
       
  2339   Ensure that we don't automatically convert non-xs:string values.
       
  2340  */
       
  2341 void tst_QXmlQuery::evaluateToQStringListNoConversion() const
       
  2342 {
       
  2343     QXmlQuery query;
       
  2344     query.setQuery(QString::fromLatin1("<e/>"));
       
  2345     QVERIFY(query.isValid());
       
  2346     QStringList result;
       
  2347     QVERIFY(!query.evaluateTo(&result));
       
  2348 }
       
  2349 
       
  2350 void tst_QXmlQuery::evaluateToQIODevice() const
       
  2351 {
       
  2352     /* an XQuery, check that no indentation is performed. */
       
  2353     {
       
  2354         QBuffer out;
       
  2355         QVERIFY(out.open(QIODevice::ReadWrite));
       
  2356 
       
  2357         QXmlQuery query;
       
  2358         query.setQuery(QLatin1String("<a><b/></a>"));
       
  2359         QVERIFY(query.isValid());
       
  2360         QVERIFY(query.evaluateTo(&out));
       
  2361         QCOMPARE(out.data(), QByteArray("<a><b/></a>"));
       
  2362     }
       
  2363 }
       
  2364 
       
  2365 void tst_QXmlQuery::evaluateToQIODeviceTriggerWarnings() const
       
  2366 {
       
  2367     QXmlQuery query;
       
  2368 
       
  2369     QTest::ignoreMessage(QtWarningMsg, "The pointer to the device cannot be null.");
       
  2370     QCOMPARE(query.evaluateTo(static_cast<QIODevice *>(0)),
       
  2371              false);
       
  2372 
       
  2373     QBuffer buffer;
       
  2374 
       
  2375     QTest::ignoreMessage(QtWarningMsg, "The device must be writable.");
       
  2376     QCOMPARE(query.evaluateTo(&buffer),
       
  2377              false);
       
  2378 }
       
  2379 
       
  2380 void tst_QXmlQuery::evaluateToQIODeviceSignature() const
       
  2381 {
       
  2382     /* The function should be const. */
       
  2383     {
       
  2384         QBuffer out;
       
  2385         QVERIFY(out.open(QIODevice::ReadWrite));
       
  2386 
       
  2387         const QXmlQuery query;
       
  2388 
       
  2389         query.evaluateTo(&out);
       
  2390     }
       
  2391 }
       
  2392 
       
  2393 void tst_QXmlQuery::evaluateToQIODeviceOnInvalidQuery() const
       
  2394 {
       
  2395     QBuffer out;
       
  2396     QVERIFY(out.open(QIODevice::WriteOnly));
       
  2397 
       
  2398     /* On syntactically invalid query. */
       
  2399     {
       
  2400         QXmlQuery query;
       
  2401         MessageSilencer silencer;
       
  2402         query.setMessageHandler(&silencer);
       
  2403         query.setQuery(QLatin1String("1 +"));
       
  2404         QVERIFY(!query.isValid());
       
  2405         QVERIFY(!query.evaluateTo(&out));
       
  2406     }
       
  2407 
       
  2408     /* On null QXmlQuery instance. */
       
  2409     {
       
  2410         QXmlQuery query;
       
  2411         QVERIFY(!query.evaluateTo(&out));
       
  2412     }
       
  2413 
       
  2414 }
       
  2415 
       
  2416 void tst_QXmlQuery::setQueryQIODeviceQUrl() const
       
  2417 {
       
  2418     /* Basic test. */
       
  2419     {
       
  2420         QBuffer buffer;
       
  2421         buffer.setData("1, 2, 2 + 1");
       
  2422         QVERIFY(buffer.open(QIODevice::ReadOnly));
       
  2423 
       
  2424         QXmlQuery query;
       
  2425         query.setQuery(&buffer);
       
  2426         QVERIFY(query.isValid());
       
  2427 
       
  2428         QXmlResultItems result;
       
  2429         query.evaluateTo(&result);
       
  2430         QCOMPARE(result.next().toAtomicValue(), QVariant(1));
       
  2431         QCOMPARE(result.next().toAtomicValue(), QVariant(2));
       
  2432         QCOMPARE(result.next().toAtomicValue(), QVariant(3));
       
  2433         QVERIFY(result.next().isNull());
       
  2434         QVERIFY(!result.hasError());
       
  2435     }
       
  2436 
       
  2437     /* Set query that is invalid. */
       
  2438     {
       
  2439         QBuffer buffer;
       
  2440         buffer.setData("1, ");
       
  2441         QVERIFY(buffer.open(QIODevice::ReadOnly));
       
  2442 
       
  2443         QXmlQuery query;
       
  2444         MessageSilencer silencer;
       
  2445         query.setMessageHandler(&silencer);
       
  2446         query.setQuery(&buffer);
       
  2447         QVERIFY(!query.isValid());
       
  2448     }
       
  2449 
       
  2450     /* Check that the base URI passes through. */
       
  2451     {
       
  2452         QBuffer buffer;
       
  2453         buffer.setData("string(static-base-uri())");
       
  2454         QVERIFY(buffer.open(QIODevice::ReadOnly));
       
  2455 
       
  2456         QXmlQuery query;
       
  2457         query.setQuery(&buffer, QUrl::fromEncoded("http://www.example.com/QIODeviceQUrl"));
       
  2458         QVERIFY(query.isValid());
       
  2459 
       
  2460         QStringList result;
       
  2461         query.evaluateTo(&result);
       
  2462         QCOMPARE(result, QStringList(QLatin1String("http://www.example.com/QIODeviceQUrl")));
       
  2463     }
       
  2464 }
       
  2465 
       
  2466 void tst_QXmlQuery::setQueryQIODeviceQUrlTriggerWarnings() const
       
  2467 {
       
  2468     QXmlQuery query;
       
  2469     QTest::ignoreMessage(QtWarningMsg, "A null QIODevice pointer cannot be passed.");
       
  2470     query.setQuery(0);
       
  2471 
       
  2472     QBuffer buffer;
       
  2473     QTest::ignoreMessage(QtWarningMsg, "The device must be readable.");
       
  2474     query.setQuery(&buffer);
       
  2475 }
       
  2476 
       
  2477 void tst_QXmlQuery::setQueryQString() const
       
  2478 {
       
  2479     /* Basic test. */
       
  2480     {
       
  2481         QXmlQuery query;
       
  2482         query.setQuery(QLatin1String("1, 2, 2 + 1"));
       
  2483         QVERIFY(query.isValid());
       
  2484 
       
  2485         QXmlResultItems result;
       
  2486         query.evaluateTo(&result);
       
  2487         QCOMPARE(result.next().toAtomicValue(), QVariant(1));
       
  2488         QCOMPARE(result.next().toAtomicValue(), QVariant(2));
       
  2489         QCOMPARE(result.next().toAtomicValue(), QVariant(3));
       
  2490         QVERIFY(result.next().isNull());
       
  2491         QVERIFY(!result.hasError());
       
  2492     }
       
  2493 
       
  2494     /* Set query that is invalid. */
       
  2495     {
       
  2496         MessageSilencer silencer;
       
  2497         QXmlQuery query;
       
  2498         query.setMessageHandler(&silencer);
       
  2499         query.setQuery(QLatin1String("1, "));
       
  2500         QVERIFY(!query.isValid());
       
  2501     }
       
  2502 
       
  2503     /* Check that the base URI passes through. */
       
  2504     {
       
  2505         QXmlQuery query;
       
  2506         query.setQuery(QLatin1String("string(static-base-uri())"), QUrl::fromEncoded("http://www.example.com/QIODeviceQUrl"));
       
  2507         QVERIFY(query.isValid());
       
  2508 
       
  2509         QStringList result;
       
  2510         query.evaluateTo(&result);
       
  2511         QCOMPARE(result, QStringList(QLatin1String("http://www.example.com/QIODeviceQUrl")));
       
  2512     }
       
  2513 }
       
  2514 
       
  2515 void tst_QXmlQuery::setQueryQUrlSuccess() const
       
  2516 {
       
  2517 #if defined(Q_OS_WINCE) && !defined(_X86_)
       
  2518     QStringList testsToSkip;
       
  2519     testsToSkip << "A valid query via the ftp scheme" << "A valid query via the http scheme";
       
  2520     if (testsToSkip.contains(QTest::currentDataTag()))
       
  2521         QSKIP("Network tests are currently unsupported on Windows CE.", SkipSingle);
       
  2522 #endif
       
  2523 
       
  2524     QFETCH(QUrl, queryURI);
       
  2525     QFETCH(QByteArray, expectedOutput);
       
  2526 
       
  2527     QVERIFY(queryURI.isValid());
       
  2528 
       
  2529     QXmlQuery query;
       
  2530 
       
  2531     MessageSilencer silencer;
       
  2532     query.setMessageHandler(&silencer);
       
  2533 
       
  2534     query.setQuery(queryURI);
       
  2535     QVERIFY(query.isValid());
       
  2536 
       
  2537     QByteArray out;
       
  2538     QBuffer buffer(&out);
       
  2539     QVERIFY(buffer.open(QIODevice::WriteOnly));
       
  2540     QXmlSerializer serializer(query, &buffer);
       
  2541 
       
  2542     query.evaluateTo(&serializer);
       
  2543     QCOMPARE(out, expectedOutput);
       
  2544 }
       
  2545 
       
  2546 void tst_QXmlQuery::setQueryQUrlSuccess_data() const
       
  2547 {
       
  2548     QTest::addColumn<QUrl>("queryURI");
       
  2549     QTest::addColumn<QByteArray>("expectedOutput");
       
  2550 
       
  2551     QTest::newRow("A valid query via the data scheme")
       
  2552         << QUrl::fromEncoded("data:application/xml,1%20%2B%201") /* "1 + 1" */
       
  2553         << QByteArray("2");
       
  2554 
       
  2555     QTest::newRow("A valid query via the file scheme")
       
  2556         << QUrl::fromLocalFile(inputFile(QLatin1String(queriesDirectory) + QLatin1String("onePlusOne.xq")))
       
  2557         << QByteArray("2");
       
  2558 
       
  2559     if(!m_testNetwork)
       
  2560         return;
       
  2561 
       
  2562     QTest::newRow("A valid query via the ftp scheme")
       
  2563         << QUrl::fromEncoded(QString("ftp://" + QtNetworkSettings::serverName() + "/pub/qxmlquery/viaFtp.xq").toLatin1())
       
  2564         << QByteArray("This was received via FTP");
       
  2565 
       
  2566     QTest::newRow("A valid query via the http scheme")
       
  2567         << QUrl::fromEncoded(QString("http://" + QtNetworkSettings::serverName() + "/qxmlquery/viaHttp.xq").toLatin1())
       
  2568         << QByteArray("This was received via HTTP.");
       
  2569 }
       
  2570 
       
  2571 void tst_QXmlQuery::setQueryQUrlFailSucceed() const
       
  2572 {
       
  2573     QXmlQuery query;
       
  2574     MessageSilencer silencer;
       
  2575 
       
  2576     query.setMessageHandler(&silencer);
       
  2577 
       
  2578     query.setQuery(QLatin1String("1 + 1"));
       
  2579     QVERIFY(query.isValid());
       
  2580 
       
  2581     query.setQuery(QUrl::fromEncoded("file://example.com/does/not/exist"));
       
  2582     QVERIFY(!query.isValid());
       
  2583 }
       
  2584 
       
  2585 void tst_QXmlQuery::setQueryQUrlFailure() const
       
  2586 {
       
  2587     QFETCH(QUrl, queryURI);
       
  2588 
       
  2589     MessageSilencer silencer;
       
  2590 
       
  2591     QXmlQuery query;
       
  2592     query.setMessageHandler(&silencer);
       
  2593     query.setQuery(queryURI);
       
  2594     QVERIFY(!query.isValid());
       
  2595 }
       
  2596 
       
  2597 void tst_QXmlQuery::setQueryQUrlFailure_data() const
       
  2598 {
       
  2599     QTest::addColumn<QUrl>("queryURI");
       
  2600 
       
  2601     QTest::newRow("Query via file:// that does not exist.")
       
  2602         << QUrl::fromEncoded("file://example.com/does/not/exist");
       
  2603 
       
  2604     QTest::newRow("A query via file:// that is completely empty, but readable.")
       
  2605         << QUrl::fromLocalFile(QCoreApplication::applicationFilePath()).resolved(QUrl("../xmlpatterns/queries/completelyEmptyQuery.xq"));
       
  2606 
       
  2607     {
       
  2608         const QString name(QLatin1String("nonReadableFile.xq"));
       
  2609         QFile outFile(name);
       
  2610         QVERIFY(outFile.open(QIODevice::WriteOnly));
       
  2611         outFile.write(QByteArray("1"));
       
  2612         outFile.close();
       
  2613         /* On some windows versions, this fails, so we don't check that this works with QVERIFY. */
       
  2614         outFile.setPermissions(QFile::Permissions(QFile::Permissions()));
       
  2615 
       
  2616         QTest::newRow("Query via file:/ that does not have read permissions.")
       
  2617             << QUrl::fromLocalFile(QCoreApplication::applicationFilePath()).resolved(QUrl("nonReadableFile.xq"));
       
  2618     }
       
  2619 
       
  2620     if(!m_testNetwork)
       
  2621         return;
       
  2622 
       
  2623     QTest::newRow("Query via HTTP that does not exist.")
       
  2624         << QUrl::fromEncoded("http://example.com/NoQuery/ISWear");
       
  2625 
       
  2626     /*
       
  2627     QTest::newRow("Query via FTP that does not exist.")
       
  2628         << QUrl::fromEncoded("ftp://example.com/NoQuery/ISWear");
       
  2629         */
       
  2630 
       
  2631     QTest::newRow("A query via http:// that is completely empty, but readable.")
       
  2632         << QUrl::fromEncoded(QString(
       
  2633                 "http://" + QtNetworkSettings::serverName() + "/qxmlquery/completelyEmptyQuery.xq").toLatin1());
       
  2634 
       
  2635     QTest::newRow("A query via ftp:// that is completely empty, but readable.")
       
  2636         << QUrl::fromEncoded(QString(
       
  2637                 "ftp://" + QtNetworkSettings::serverName() + "qxmlquery/completelyEmptyQuery.xq").toLatin1());
       
  2638 
       
  2639 }
       
  2640 
       
  2641 void tst_QXmlQuery::setQueryQUrlBaseURI() const
       
  2642 {
       
  2643     QFETCH(QUrl, inputBaseURI);
       
  2644     QFETCH(QUrl, expectedBaseURI);
       
  2645 
       
  2646     QXmlQuery query;
       
  2647 
       
  2648     query.setQuery(QUrl(QLatin1String("qrc:/QXmlQueryTestData/queries/staticBaseURI.xq")), inputBaseURI);
       
  2649     QVERIFY(query.isValid());
       
  2650 
       
  2651     QStringList result;
       
  2652     QVERIFY(query.evaluateTo(&result));
       
  2653     QCOMPARE(result.count(), 1);
       
  2654 
       
  2655     if(qstrcmp(QTest::currentDataTag(), "Relative base URI") == 0)
       
  2656         checkBaseURI(QUrl(result.first()), QCoreApplication::applicationFilePath());
       
  2657     else
       
  2658         QCOMPARE(result.first(), expectedBaseURI.toString());
       
  2659 }
       
  2660 
       
  2661 void tst_QXmlQuery::setQueryQUrlBaseURI_data() const
       
  2662 {
       
  2663     QTest::addColumn<QUrl>("inputBaseURI");
       
  2664     QTest::addColumn<QUrl>("expectedBaseURI");
       
  2665 
       
  2666     QTest::newRow("absolute HTTP")
       
  2667         << QUrl(QLatin1String("http://www.example.com/"))
       
  2668         << QUrl(QLatin1String("http://www.example.com/"));
       
  2669 
       
  2670     QTest::newRow("None, so the query URI is used")
       
  2671         << QUrl()
       
  2672         << QUrl(QLatin1String("qrc:/QXmlQueryTestData/queries/staticBaseURI.xq"));
       
  2673 
       
  2674     QTest::newRow("Relative base URI")
       
  2675         << QUrl(QLatin1String("../data/relative.uri"))
       
  2676         << QUrl();
       
  2677 }
       
  2678 
       
  2679 /*!
       
  2680   1. Create a valid query.
       
  2681   2. Call setQuery(QUrl), with a query file that doesn't exist.
       
  2682   3. Verify that the query has changed state into invalid.
       
  2683  */
       
  2684 void tst_QXmlQuery::setQueryWithNonExistentQUrlOnValidQuery() const
       
  2685 {
       
  2686     QXmlQuery query;
       
  2687 
       
  2688     MessageSilencer messageSilencer;
       
  2689     query.setMessageHandler(&messageSilencer);
       
  2690 
       
  2691     query.setQuery(QLatin1String("1 + 1"));
       
  2692     QVERIFY(query.isValid());
       
  2693 
       
  2694     query.setQuery(QUrl::fromEncoded("qrc:/QXmlQueryTestData/DOESNOTEXIST.xq"));
       
  2695     QVERIFY(!query.isValid());
       
  2696 }
       
  2697 
       
  2698 /*!
       
  2699   1. Create a valid query.
       
  2700   2. Call setQuery(QUrl), with a query file that is invalid.
       
  2701   3. Verify that the query has changed state into invalid.
       
  2702  */
       
  2703 void tst_QXmlQuery::setQueryWithInvalidQueryFromQUrlOnValidQuery() const
       
  2704 {
       
  2705     QXmlQuery query;
       
  2706 
       
  2707     MessageSilencer messageSilencer;
       
  2708     query.setMessageHandler(&messageSilencer);
       
  2709 
       
  2710     query.setQuery(QLatin1String("1 + 1"));
       
  2711     QVERIFY(query.isValid());
       
  2712 
       
  2713     query.setQuery(QUrl::fromEncoded("qrc:/QXmlQueryTestData/queries/syntaxError.xq"));
       
  2714     QVERIFY(!query.isValid());
       
  2715 }
       
  2716 
       
  2717 /*!
       
  2718   This triggered two bugs:
       
  2719 
       
  2720   - First, the DynamicContext wasn't assigned to QXmlResultItems, meaning it went out of
       
  2721     scope and therefore deallocated the document pool, and calls
       
  2722     to QXmlResultItems::next() would use dangling pointers.
       
  2723 
       
  2724   - Conversion between QPatternist::Item and QXmlItem was incorrectly done, leading to nodes
       
  2725     being treated as atomic values, and subsequent crashes.
       
  2726 
       
  2727  */
       
  2728 void tst_QXmlQuery::retrieveNameFromQuery() const
       
  2729 {
       
  2730     QFETCH(QString, queryString);
       
  2731     QFETCH(QString, expectedName);
       
  2732 
       
  2733     QXmlQuery query;
       
  2734     query.setQuery(queryString);
       
  2735     QVERIFY(query.isValid());
       
  2736     QXmlResultItems result;
       
  2737     query.evaluateTo(&result);
       
  2738 
       
  2739     QVERIFY(!result.hasError());
       
  2740 
       
  2741     const QXmlItem item(result.next());
       
  2742     QVERIFY(!result.hasError());
       
  2743     QVERIFY(!item.isNull());
       
  2744     QVERIFY(item.isNode());
       
  2745 
       
  2746     const QXmlNodeModelIndex node(item.toNodeModelIndex());
       
  2747     QVERIFY(!node.isNull());
       
  2748 
       
  2749     QCOMPARE(node.model()->name(node).localName(query.namePool()), expectedName);
       
  2750 }
       
  2751 
       
  2752 void tst_QXmlQuery::retrieveNameFromQuery_data() const
       
  2753 {
       
  2754     QTest::addColumn<QString>("queryString");
       
  2755     QTest::addColumn<QString>("expectedName");
       
  2756 
       
  2757     QTest::newRow("Document-node")
       
  2758         << QString::fromLatin1("document{<elementName/>}")
       
  2759         << QString();
       
  2760 
       
  2761     QTest::newRow("Element")
       
  2762         << QString::fromLatin1("document{<elementName/>}/*")
       
  2763         << QString::fromLatin1("elementName");
       
  2764 }
       
  2765 
       
  2766 /*!
       
  2767  Binding a null QString leads to no variable binding, but an
       
  2768  empty non-null QString is possible.
       
  2769  */
       
  2770 void tst_QXmlQuery::bindEmptyNullString() const
       
  2771 {
       
  2772     MessageSilencer messageHandler;
       
  2773     QXmlQuery query;
       
  2774     query.setMessageHandler(&messageHandler);
       
  2775     query.setQuery(QLatin1String("declare variable $v external; $v"));
       
  2776     /* Here, we effectively pass an invalid QVariant. */
       
  2777     query.bindVariable(QLatin1String("v"), QVariant(QString()));
       
  2778     QVERIFY(!query.isValid());
       
  2779 
       
  2780     QStringList result;
       
  2781     QVERIFY(!query.evaluateTo(&result));
       
  2782 }
       
  2783 
       
  2784 void tst_QXmlQuery::bindEmptyString() const
       
  2785 {
       
  2786     QXmlQuery query;
       
  2787     query.bindVariable(QLatin1String("v"), QVariant(QString(QLatin1String(""))));
       
  2788     query.setQuery(QLatin1String("declare variable $v external; $v"));
       
  2789     QVERIFY(query.isValid());
       
  2790 
       
  2791     QStringList result;
       
  2792     QVERIFY(query.evaluateTo(&result));
       
  2793     QStringList expected((QString()));
       
  2794     QCOMPARE(result, expected);
       
  2795 }
       
  2796 
       
  2797 void tst_QXmlQuery::cleanupTestCase() const
       
  2798 {
       
  2799     /* Remove a weird file we created. */
       
  2800     const QString name(QLatin1String("nonReadableFile.xq"));
       
  2801 
       
  2802     if(QFile::exists(name))
       
  2803     {
       
  2804         QFile file(name);
       
  2805         QVERIFY(file.setPermissions(QFile::WriteOwner));
       
  2806         QVERIFY(file.remove());
       
  2807     }
       
  2808 }
       
  2809 
       
  2810 void tst_QXmlQuery::declareUnavailableExternal() const
       
  2811 {
       
  2812     QXmlQuery query;
       
  2813     MessageSilencer silencer;
       
  2814     query.setMessageHandler(&silencer);
       
  2815     query.setQuery(QLatin1String("declare variable $var external;"
       
  2816                                  "1 + 1"));
       
  2817     /* We do not bind $var with QXmlQuery::bindVariable(). */
       
  2818     QVERIFY(!query.isValid());
       
  2819 }
       
  2820 
       
  2821 /*!
       
  2822  This test triggers an assert in one of the cache iterator
       
  2823  with MSVC 2005 when compiled in debug mode.
       
  2824  */
       
  2825 void tst_QXmlQuery::msvcCacheIssue() const
       
  2826 {
       
  2827     QXmlQuery query;
       
  2828     query.bindVariable(QLatin1String("externalVariable"), QXmlItem("Variable Value"));
       
  2829     query.setQuery(QUrl::fromLocalFile(QLatin1String(queriesDirectory) + QString::fromLatin1("externalVariableUsedTwice.xq")));
       
  2830     QStringList result;
       
  2831     QVERIFY(query.evaluateTo(&result));
       
  2832 
       
  2833     QCOMPARE(result,
       
  2834              QStringList() << QString::fromLatin1("Variable Value") << QString::fromLatin1("Variable Value"));
       
  2835 }
       
  2836 
       
  2837 void tst_QXmlQuery::unavailableExternalVariable() const
       
  2838 {
       
  2839     QXmlQuery query;
       
  2840 
       
  2841     MessageSilencer silencer;
       
  2842     query.setMessageHandler(&silencer);
       
  2843 
       
  2844     query.setQuery(QLatin1String("declare variable $foo external; 1"));
       
  2845 
       
  2846     QVERIFY(!query.isValid());
       
  2847 }
       
  2848 
       
  2849 /*!
       
  2850  Ensure that setUriResolver() affects \c fn:doc() and \c fn:doc-available().
       
  2851  */
       
  2852 void tst_QXmlQuery::useUriResolver() const
       
  2853 {
       
  2854     class TestUriResolver : public QAbstractUriResolver
       
  2855                           , private TestFundament
       
  2856     {
       
  2857     public:
       
  2858         virtual QUrl resolve(const QUrl &relative,
       
  2859                              const QUrl &baseURI) const
       
  2860         {
       
  2861             Q_UNUSED(relative);
       
  2862             return baseURI.resolved(inputFile(QLatin1String(queriesDirectory) + QLatin1String("simpleDocument.xml")));
       
  2863         }
       
  2864     };
       
  2865 
       
  2866     const TestUriResolver uriResolver;
       
  2867     QXmlQuery query;
       
  2868 
       
  2869     query.setUriResolver(&uriResolver);
       
  2870     query.setQuery(QLatin1String("let $i := 'http://www.example.com/DoesNotExist'"
       
  2871                                  "return (string(doc($i)), doc-available($i))"));
       
  2872 
       
  2873 
       
  2874     QXmlResultItems result;
       
  2875     query.evaluateTo(&result);
       
  2876 
       
  2877     QVERIFY(!result.hasError());
       
  2878     QCOMPARE(result.next().toAtomicValue().toString(), QString::fromLatin1("text text node"));
       
  2879     QCOMPARE(result.next().toAtomicValue().toBool(), true);
       
  2880     QVERIFY(result.next().isNull());
       
  2881     QVERIFY(!result.hasError());
       
  2882 }
       
  2883 
       
  2884 void tst_QXmlQuery::queryWithFocusAndVariable() const
       
  2885 {
       
  2886     QXmlQuery query;
       
  2887     query.setFocus(QXmlItem(5));
       
  2888     query.bindVariable(QLatin1String("var"), QXmlItem(2));
       
  2889 
       
  2890     query.setQuery(QLatin1String("string(. * $var)"));
       
  2891 
       
  2892     QStringList result;
       
  2893 
       
  2894     QVERIFY(query.evaluateTo(&result));
       
  2895 
       
  2896     QCOMPARE(result, QStringList(QLatin1String("10")));
       
  2897 }
       
  2898 
       
  2899 void tst_QXmlQuery::undefinedFocus() const
       
  2900 {
       
  2901     QXmlQuery query;
       
  2902 
       
  2903     MessageSilencer silencer;
       
  2904     query.setMessageHandler(&silencer);
       
  2905 
       
  2906     query.setQuery(QLatin1String("."));
       
  2907     QVERIFY(!query.isValid());
       
  2908 }
       
  2909 
       
  2910 void tst_QXmlQuery::basicFocusUsage() const
       
  2911 {
       
  2912     QXmlQuery query;
       
  2913 
       
  2914     MessageSilencer silencer;
       
  2915     query.setMessageHandler(&silencer);
       
  2916 
       
  2917     query.setFocus(QXmlItem(5));
       
  2918     query.setQuery(QLatin1String("string(. * .)"));
       
  2919     QVERIFY(query.isValid());
       
  2920 
       
  2921     QStringList result;
       
  2922     QVERIFY(query.evaluateTo(&result));
       
  2923 
       
  2924     QCOMPARE(result, QStringList(QLatin1String("25")));
       
  2925 }
       
  2926 
       
  2927 /*!
       
  2928   Triggers an ownership related crash.
       
  2929  */
       
  2930 void tst_QXmlQuery::copyCheckMessageHandler() const
       
  2931 {
       
  2932     QXmlQuery query;
       
  2933     QCOMPARE(query.messageHandler(), static_cast<QAbstractMessageHandler *>(0));
       
  2934 
       
  2935     query.setQuery(QLatin1String("doc('qrc:/QXmlQueryTestData/data/oneElement.xml')"));
       
  2936     /* By now, we should have set the builtin message handler. */
       
  2937     const QAbstractMessageHandler *const messageHandler = query.messageHandler();
       
  2938     QVERIFY(messageHandler);
       
  2939 
       
  2940     {
       
  2941         /* This copies QXmlQueryPrivate::m_ownerObject, and its destructor
       
  2942          * will delete it, and hence the builtin message handler attached to it. */
       
  2943         QXmlQuery copy(query);
       
  2944     }
       
  2945 
       
  2946     QXmlResultItems result;
       
  2947     query.evaluateTo(&result);
       
  2948 
       
  2949     while(!result.next().isNull())
       
  2950     {
       
  2951     }
       
  2952     QVERIFY(!result.hasError());
       
  2953 }
       
  2954 
       
  2955 void tst_QXmlQuery::queryLanguage() const
       
  2956 {
       
  2957     /* Check default value. */
       
  2958     {
       
  2959         const QXmlQuery query;
       
  2960         QCOMPARE(query.queryLanguage(), QXmlQuery::XQuery10);
       
  2961     }
       
  2962 
       
  2963     /* Check default value of copies default instance. */
       
  2964     {
       
  2965         const QXmlQuery query1;
       
  2966         const QXmlQuery query2(query1);
       
  2967 
       
  2968         QCOMPARE(query1.queryLanguage(), QXmlQuery::XQuery10);
       
  2969         QCOMPARE(query2.queryLanguage(), QXmlQuery::XQuery10);
       
  2970     }
       
  2971 }
       
  2972 
       
  2973 void tst_QXmlQuery::queryLanguageSignature() const
       
  2974 {
       
  2975     /* This getter should be const. */
       
  2976     QXmlQuery query;
       
  2977     query.queryLanguage();
       
  2978 }
       
  2979 
       
  2980 void tst_QXmlQuery::enumQueryLanguage() const
       
  2981 {
       
  2982     /* These enum values should be possible to OR for future plans. */
       
  2983     QCOMPARE(int(QXmlQuery::XQuery10), 1);
       
  2984     QCOMPARE(int(QXmlQuery::XSLT20), 2);
       
  2985     QCOMPARE(int(QXmlQuery::XmlSchema11IdentityConstraintSelector), 1024);
       
  2986     QCOMPARE(int(QXmlQuery::XmlSchema11IdentityConstraintField), 2048);
       
  2987     QCOMPARE(int(QXmlQuery::XPath20), 4096);
       
  2988 }
       
  2989 
       
  2990 void tst_QXmlQuery::setInitialTemplateNameQXmlName() const
       
  2991 {
       
  2992     QXmlQuery query(QXmlQuery::XSLT20);
       
  2993     QXmlNamePool np(query.namePool());
       
  2994     const QXmlName name(np, QLatin1String("main"));
       
  2995 
       
  2996     query.setInitialTemplateName(name);
       
  2997 
       
  2998     QCOMPARE(query.initialTemplateName(), name);
       
  2999 
       
  3000     query.setQuery(QUrl(inputFile(QLatin1String(SRCDIR "../xmlpatterns/stylesheets/namedTemplate.xsl"))));
       
  3001     QVERIFY(query.isValid());
       
  3002 
       
  3003     QBuffer result;
       
  3004     QVERIFY(result.open(QIODevice::ReadWrite));
       
  3005     QXmlSerializer serializer(query, &result);
       
  3006     query.evaluateTo(&serializer);
       
  3007 
       
  3008     QCOMPARE(result.data(), QByteArray("1 2 3 4 5"));
       
  3009 
       
  3010     // TODO invoke a template which has required params.
       
  3011 }
       
  3012 
       
  3013 void tst_QXmlQuery::setInitialTemplateNameQXmlNameSignature() const
       
  3014 {
       
  3015     QXmlQuery query;
       
  3016     QXmlNamePool np(query.namePool());
       
  3017     const QXmlName name(np, QLatin1String("foo"));
       
  3018 
       
  3019     /* The signature should take a const reference. */
       
  3020     query.setInitialTemplateName(name);
       
  3021 }
       
  3022 
       
  3023 void tst_QXmlQuery::setInitialTemplateNameQString() const
       
  3024 {
       
  3025     QXmlQuery query;
       
  3026     QXmlNamePool np(query.namePool());
       
  3027     query.setInitialTemplateName(QLatin1String("foo"));
       
  3028 
       
  3029     QCOMPARE(query.initialTemplateName(), QXmlName(np, QLatin1String("foo")));
       
  3030 }
       
  3031 
       
  3032 void tst_QXmlQuery::setInitialTemplateNameQStringSignature() const
       
  3033 {
       
  3034     const QString name(QLatin1String("name"));
       
  3035     QXmlQuery query;
       
  3036 
       
  3037     /* We should take a const reference. */
       
  3038     query.setInitialTemplateName(name);
       
  3039 }
       
  3040 
       
  3041 void tst_QXmlQuery::initialTemplateName() const
       
  3042 {
       
  3043     /* Check our default value. */
       
  3044     QXmlQuery query;
       
  3045     QCOMPARE(query.initialTemplateName(), QXmlName());
       
  3046     QVERIFY(query.initialTemplateName().isNull());
       
  3047 }
       
  3048 
       
  3049 void tst_QXmlQuery::initialTemplateNameSignature() const
       
  3050 {
       
  3051     const QXmlQuery query;
       
  3052     /* This should be a const member. */
       
  3053     query.initialTemplateName();
       
  3054 }
       
  3055 
       
  3056 void tst_QXmlQuery::setNetworkAccessManager() const
       
  3057 {
       
  3058 
       
  3059     /* Ensure fn:doc() picks up the right QNetworkAccessManager. */
       
  3060     {
       
  3061         NetworkOverrider networkOverrider(QUrl(QLatin1String("tag:example.com:DOESNOTEXIST")),
       
  3062                                           QUrl(inputFile(QLatin1String(SRCDIR "../xmlpatterns/queries/simpleDocument.xml"))));
       
  3063 
       
  3064         QXmlQuery query;
       
  3065         query.setNetworkAccessManager(&networkOverrider);
       
  3066         query.setQuery(QLatin1String("string(doc('tag:example.com:DOESNOTEXIST'))"));
       
  3067         QVERIFY(query.isValid());
       
  3068 
       
  3069         QStringList result;
       
  3070         QVERIFY(query.evaluateTo(&result));
       
  3071 
       
  3072         QCOMPARE(result, QStringList(QLatin1String("text text node")));
       
  3073     }
       
  3074 
       
  3075     /* Ensure setQuery() is using the right network manager. */
       
  3076     {
       
  3077         NetworkOverrider networkOverrider(QUrl(QLatin1String("tag:example.com:DOESNOTEXIST")),
       
  3078                                           QUrl(inputFile(QLatin1String(SRCDIR "../xmlpatterns/queries/concat.xq"))));
       
  3079 
       
  3080         QXmlQuery query;
       
  3081         query.setNetworkAccessManager(&networkOverrider);
       
  3082         query.setQuery(QUrl("tag:example.com:DOESNOTEXIST"));
       
  3083         QVERIFY(query.isValid());
       
  3084 
       
  3085         QStringList result;
       
  3086         QVERIFY(query.evaluateTo(&result));
       
  3087 
       
  3088         QCOMPARE(result, QStringList(QLatin1String("abcdef")));
       
  3089     }
       
  3090 }
       
  3091 void tst_QXmlQuery::networkAccessManagerSignature() const
       
  3092 {
       
  3093     /* Const object. */
       
  3094     const QXmlQuery query;
       
  3095 
       
  3096     /* The function should be const. */
       
  3097     query.networkAccessManager();
       
  3098 }
       
  3099 
       
  3100 void tst_QXmlQuery::networkAccessManagerDefaultValue() const
       
  3101 {
       
  3102     const QXmlQuery query;
       
  3103 
       
  3104     QCOMPARE(query.networkAccessManager(), static_cast<QNetworkAccessManager *>(0));
       
  3105 }
       
  3106 
       
  3107 void tst_QXmlQuery::networkAccessManager() const
       
  3108 {
       
  3109     /* Test that we return the network manager that was set. */
       
  3110     {
       
  3111         QNetworkAccessManager manager;
       
  3112         QXmlQuery query;
       
  3113         query.setNetworkAccessManager(&manager);
       
  3114         QCOMPARE(query.networkAccessManager(), &manager);
       
  3115     }
       
  3116 }
       
  3117 
       
  3118 /*!
       
  3119  \internal
       
  3120  \since 4.5
       
  3121 
       
  3122   1. Load a document into QXmlQuery's document cache, by executing a query which does it.
       
  3123   2. Set a focus
       
  3124   3. Change query, to one which uses the focus
       
  3125   4. Evaluate
       
  3126 
       
  3127  Used to crash.
       
  3128  */
       
  3129 void tst_QXmlQuery::multipleDocsAndFocus() const
       
  3130 {
       
  3131     QXmlQuery query;
       
  3132 
       
  3133     /* We use string concatenation, since variable bindings might disturb what
       
  3134      * we're testing. */
       
  3135     query.setQuery(QLatin1String("string(doc('") +
       
  3136                    inputFile(QLatin1String(SRCDIR "../xmlpatterns/queries/simpleDocument.xml")) +
       
  3137                    QLatin1String("'))"));
       
  3138     query.setFocus(QUrl(inputFile(QLatin1String(SRCDIR "../xmlpatterns/stylesheets/documentElement.xml"))));
       
  3139     query.setQuery(QLatin1String("string(.)"));
       
  3140 
       
  3141     QStringList result;
       
  3142     QVERIFY(query.evaluateTo(&result));
       
  3143 }
       
  3144 
       
  3145 /*!
       
  3146  \internal
       
  3147  \since 4.5
       
  3148 
       
  3149  1. Set a focus
       
  3150  2. Set a query
       
  3151  3. Evaluate
       
  3152  4. Change focus
       
  3153  5. Evaluate
       
  3154 
       
  3155  Used to crash.
       
  3156  */
       
  3157 void tst_QXmlQuery::multipleEvaluationsWithDifferentFocus() const
       
  3158 {
       
  3159     QXmlQuery query;
       
  3160     QStringList result;
       
  3161 
       
  3162     query.setFocus(QUrl(inputFile(QLatin1String(SRCDIR "../xmlpatterns/stylesheets/documentElement.xml"))));
       
  3163     query.setQuery(QLatin1String("string(.)"));
       
  3164     QVERIFY(query.evaluateTo(&result));
       
  3165 
       
  3166     query.setFocus(QUrl(inputFile(QLatin1String(SRCDIR "../xmlpatterns/stylesheets/documentElement.xml"))));
       
  3167     QVERIFY(query.evaluateTo(&result));
       
  3168 }
       
  3169 
       
  3170 void tst_QXmlQuery::bindVariableQXmlQuery() const
       
  3171 {
       
  3172     QFETCH(QString, query1);
       
  3173     QFETCH(QString, query2);
       
  3174     QFETCH(QString, expectedOutput);
       
  3175     QFETCH(bool, expectedSuccess);
       
  3176 
       
  3177     MessageSilencer silencer;
       
  3178     QXmlQuery xmlQuery1;
       
  3179     xmlQuery1.setMessageHandler(&silencer);
       
  3180     xmlQuery1.setQuery(query1);
       
  3181 
       
  3182     QXmlQuery xmlQuery2(xmlQuery1);
       
  3183     xmlQuery2.bindVariable("query1", xmlQuery1);
       
  3184     xmlQuery2.setQuery(query2);
       
  3185 
       
  3186     QString output;
       
  3187     const bool querySuccess = xmlQuery2.evaluateTo(&output);
       
  3188 
       
  3189     QCOMPARE(querySuccess, expectedSuccess);
       
  3190 
       
  3191     if(querySuccess)
       
  3192         QCOMPARE(output, expectedOutput);
       
  3193 }
       
  3194 
       
  3195 void tst_QXmlQuery::bindVariableQXmlQuery_data() const
       
  3196 {
       
  3197     QTest::addColumn<QString>("query1");
       
  3198     QTest::addColumn<QString>("query2");
       
  3199     QTest::addColumn<QString>("expectedOutput");
       
  3200     QTest::addColumn<bool>("expectedSuccess");
       
  3201 
       
  3202     QTest::newRow("First query has one atomic value.")
       
  3203             << "2"
       
  3204             << "1, $query1, 3"
       
  3205             << "1 2 3\n"
       
  3206             << true;
       
  3207 
       
  3208     QTest::newRow("First query has two atomic values.")
       
  3209             << "2, 3"
       
  3210             << "1, $query1, 4"
       
  3211             << "1 2 3 4\n"
       
  3212             << true;
       
  3213 
       
  3214     QTest::newRow("First query is a node.")
       
  3215             << "<e/>"
       
  3216             << "1, $query1, 3"
       
  3217             << "1<e/>3\n"
       
  3218             << true;
       
  3219 
       
  3220     /* This is a good test, because it triggers the exception in the
       
  3221      * bindVariable() call, as supposed to when the actual evaluation is done.
       
  3222      */
       
  3223     QTest::newRow("First query has a dynamic error.")
       
  3224             << "error()"
       
  3225             << "1, $query1"
       
  3226             << QString() /* We don't care. */
       
  3227             << false;
       
  3228 }
       
  3229 
       
  3230 void tst_QXmlQuery::bindVariableQStringQXmlQuerySignature() const
       
  3231 {
       
  3232     QXmlQuery query1;
       
  3233     query1.setQuery("'dummy'");
       
  3234 
       
  3235     QXmlQuery query2;
       
  3236     const QString name(QLatin1String("name"));
       
  3237 
       
  3238     /* We should be able to take a const QXmlQuery reference. Evaluation never mutate
       
  3239      * QXmlQuery, and evaluation is what we do here. */
       
  3240     query2.bindVariable(name, const_cast<const QXmlQuery &>(query1));
       
  3241 }
       
  3242 
       
  3243 void tst_QXmlQuery::bindVariableQXmlNameQXmlQuerySignature() const
       
  3244 {
       
  3245     QXmlNamePool np;
       
  3246     QXmlQuery query1(np);
       
  3247     query1.setQuery("'dummy'");
       
  3248 
       
  3249     QXmlQuery query2;
       
  3250     const QXmlName name(np, QLatin1String("name"));
       
  3251 
       
  3252     /* We should be able to take a const QXmlQuery reference. Evaluation never mutate
       
  3253      * QXmlQuery, and evaluation is what we do here. */
       
  3254     query2.bindVariable(name, const_cast<const QXmlQuery &>(query1));
       
  3255 }
       
  3256 
       
  3257 /*!
       
  3258   Check that the QXmlName is handled correctly.
       
  3259  */
       
  3260 void tst_QXmlQuery::bindVariableQXmlNameQXmlQuery() const
       
  3261 {
       
  3262     QXmlNamePool np;
       
  3263     QXmlQuery query1;
       
  3264     query1.setQuery(QLatin1String("1"));
       
  3265 
       
  3266     QXmlQuery query2(np);
       
  3267     query2.bindVariable(QXmlName(np, QLatin1String("theName")), query1);
       
  3268     query2.setQuery("$theName");
       
  3269 
       
  3270     QString result;
       
  3271     query2.evaluateTo(&result);
       
  3272 
       
  3273     QCOMPARE(result, QString::fromLatin1("1\n"));
       
  3274 }
       
  3275 
       
  3276 void tst_QXmlQuery::bindVariableQXmlQueryInvalidate() const
       
  3277 {
       
  3278     QXmlQuery query;
       
  3279     query.bindVariable(QLatin1String("name"), QVariant(1));
       
  3280     query.setQuery("$name");
       
  3281     QVERIFY(query.isValid());
       
  3282 
       
  3283     QXmlQuery query2;
       
  3284     query2.setQuery("'query2'");
       
  3285 
       
  3286     query.bindVariable(QLatin1String("name"), query);
       
  3287     QVERIFY(!query.isValid());
       
  3288 }
       
  3289 
       
  3290 void tst_QXmlQuery::unknownSourceLocation() const
       
  3291 {
       
  3292     QBuffer b;
       
  3293     b.setData("<a><b/><b/></a>");
       
  3294     b.open(QIODevice::ReadOnly);
       
  3295 
       
  3296     MessageSilencer silencer;
       
  3297     QXmlQuery query;
       
  3298     query.bindVariable(QLatin1String("inputDocument"), &b);
       
  3299     query.setMessageHandler(&silencer);
       
  3300 
       
  3301     query.setQuery(QLatin1String("doc($inputDocument)/a/(let $v := b/string() return if ($v) then $v else ())"));
       
  3302 
       
  3303     QString output;
       
  3304     query.evaluateTo(&output);
       
  3305 }
       
  3306 
       
  3307 void tst_QXmlQuery::identityConstraintSuccess() const
       
  3308 {
       
  3309     QXmlQuery::QueryLanguage queryLanguage = QXmlQuery::XmlSchema11IdentityConstraintSelector;
       
  3310 
       
  3311     /* We run this code for Selector and Field. */
       
  3312     for(int i = 0; i < 3; ++i)
       
  3313     {
       
  3314         QXmlNamePool namePool;
       
  3315         QXmlResultItems result;
       
  3316         QXmlItem node;
       
  3317 
       
  3318         {
       
  3319             QXmlQuery nodeSource(namePool);
       
  3320             nodeSource.setQuery(QLatin1String("<e/>"));
       
  3321 
       
  3322             nodeSource.evaluateTo(&result);
       
  3323             node = result.next();
       
  3324         }
       
  3325 
       
  3326         /* Basic use:
       
  3327          * 1. The focus is undefined, but it's still valid.
       
  3328          * 2. We never evaluate. */
       
  3329         {
       
  3330             QXmlQuery query(queryLanguage);
       
  3331             query.setQuery(QLatin1String("a"));
       
  3332             QVERIFY(query.isValid());
       
  3333         }
       
  3334 
       
  3335         /* Basic use:
       
  3336          * 1. The focus is undefined, but it's still valid.
       
  3337          * 2. We afterwards set the focus. */
       
  3338         {
       
  3339             QXmlQuery query(queryLanguage, namePool);
       
  3340             query.setQuery(QLatin1String("a"));
       
  3341             query.setFocus(node);
       
  3342             QVERIFY(query.isValid());
       
  3343         }
       
  3344 
       
  3345         /* Basic use:
       
  3346          * 1. The focus is undefined, but it's still valid.
       
  3347          * 2. We afterwards set the focus.
       
  3348          * 3. We evaluate. */
       
  3349         {
       
  3350             QXmlQuery query(queryLanguage, namePool);
       
  3351             query.setQuery(QString(QLatin1Char('.')));
       
  3352             query.setFocus(node);
       
  3353             QVERIFY(query.isValid());
       
  3354 
       
  3355             QString result;
       
  3356             QVERIFY(query.evaluateTo(&result));
       
  3357             QCOMPARE(result, QString::fromLatin1("<e/>\n"));
       
  3358         }
       
  3359 
       
  3360         /* A slightly more complex Field. */
       
  3361         {
       
  3362             QXmlQuery query(queryLanguage);
       
  3363             query.setQuery(QLatin1String("* | .//xml:*/."));
       
  3364             QVERIFY(query.isValid());
       
  3365         }
       
  3366 
       
  3367         /* @ is only allowed in Field. */
       
  3368         if(queryLanguage == QXmlQuery::XmlSchema11IdentityConstraintField)
       
  3369         {
       
  3370             QXmlQuery query(QXmlQuery::XmlSchema11IdentityConstraintField);
       
  3371             query.setQuery(QLatin1String("@abc"));
       
  3372             QVERIFY(query.isValid());
       
  3373         }
       
  3374 
       
  3375         /* Field allows attribute:: and child:: .*/
       
  3376         if(queryLanguage == QXmlQuery::XmlSchema11IdentityConstraintField)
       
  3377         {
       
  3378             QXmlQuery query(QXmlQuery::XmlSchema11IdentityConstraintField);
       
  3379             query.setQuery(QLatin1String("attribute::name | child::name"));
       
  3380             QVERIFY(query.isValid());
       
  3381         }
       
  3382 
       
  3383         /* Selector allows only child:: .*/
       
  3384         {
       
  3385             QXmlQuery query(QXmlQuery::XmlSchema11IdentityConstraintSelector);
       
  3386             query.setQuery(QLatin1String("child::name"));
       
  3387             QVERIFY(query.isValid());
       
  3388         }
       
  3389 
       
  3390         if(i == 0)
       
  3391             queryLanguage = QXmlQuery::XmlSchema11IdentityConstraintField;
       
  3392         else if(i == 1)
       
  3393             queryLanguage = QXmlQuery::XPath20;
       
  3394     }
       
  3395 }
       
  3396 
       
  3397 Q_DECLARE_METATYPE(QXmlQuery::QueryLanguage);
       
  3398 
       
  3399 /*!
       
  3400  We just do some basic tests for boot strapping and sanity checking. The actual regression
       
  3401  testing is in the Schema suite.
       
  3402  */
       
  3403 void tst_QXmlQuery::identityConstraintFailure() const
       
  3404 {
       
  3405     QFETCH(QXmlQuery::QueryLanguage, queryLanguage);
       
  3406     QFETCH(QString, inputQuery);
       
  3407 
       
  3408     QXmlQuery query(queryLanguage);
       
  3409     MessageSilencer silencer;
       
  3410     query.setMessageHandler(&silencer);
       
  3411 
       
  3412     query.setQuery(inputQuery);
       
  3413     QVERIFY(!query.isValid());
       
  3414 }
       
  3415 
       
  3416 void tst_QXmlQuery::identityConstraintFailure_data() const
       
  3417 {
       
  3418     QTest::addColumn<QXmlQuery::QueryLanguage>("queryLanguage");
       
  3419     QTest::addColumn<QString>("inputQuery");
       
  3420 
       
  3421     QTest::newRow("We don't have element constructors in identity constraint pattern, "
       
  3422                   "it's an XQuery feature(Selector).")
       
  3423         << QXmlQuery::XmlSchema11IdentityConstraintSelector
       
  3424         << QString::fromLatin1("<e/>");
       
  3425 
       
  3426     QTest::newRow("We don't have functions in identity constraint pattern, "
       
  3427                   "it's an XPath feature(Selector).")
       
  3428         << QXmlQuery::XmlSchema11IdentityConstraintSelector
       
  3429         << QString::fromLatin1("current-time()");
       
  3430 
       
  3431     QTest::newRow("We don't have element constructors in identity constraint pattern, "
       
  3432                   "it's an XQuery feature(Field).")
       
  3433         << QXmlQuery::XmlSchema11IdentityConstraintSelector
       
  3434         << QString::fromLatin1("<e/>");
       
  3435 
       
  3436     QTest::newRow("We don't have functions in identity constraint pattern, "
       
  3437                   "it's an XPath feature(Field).")
       
  3438         << QXmlQuery::XmlSchema11IdentityConstraintSelector
       
  3439         << QString::fromLatin1("current-time()");
       
  3440 
       
  3441     QTest::newRow("@attributeName is disallowed for the selector.")
       
  3442         << QXmlQuery::XmlSchema11IdentityConstraintSelector
       
  3443         << QString::fromLatin1("@abc");
       
  3444 
       
  3445     QTest::newRow("attribute:: is disallowed for the selector.")
       
  3446         << QXmlQuery::XmlSchema11IdentityConstraintSelector
       
  3447         << QString::fromLatin1("attribute::name");
       
  3448 
       
  3449     QTest::newRow("ancestor::name is disallowed for the selector.")
       
  3450         << QXmlQuery::XmlSchema11IdentityConstraintSelector
       
  3451         << QString::fromLatin1("ancestor::name");
       
  3452 
       
  3453     QTest::newRow("ancestor::name is disallowed for the field.")
       
  3454         << QXmlQuery::XmlSchema11IdentityConstraintField
       
  3455         << QString::fromLatin1("ancestor::name");
       
  3456 }
       
  3457 
       
  3458 QTEST_MAIN(tst_QXmlQuery)
       
  3459 
       
  3460 #include "tst_qxmlquery.moc"
       
  3461 #else //QTEST_XMLPATTERNS
       
  3462 QTEST_NOOP_MAIN
       
  3463 #endif