tests/auto/qdom/tst_qdom.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 <QBuffer>
       
    44 #include <QByteArray>
       
    45 #include <QCoreApplication>
       
    46 #include <QDebug>
       
    47 #include <QFile>
       
    48 #include <QList>
       
    49 #include <QRegExp>
       
    50 #include <QTextStream>
       
    51 #include <QtTest/QtTest>
       
    52 #include <QtXml>
       
    53 #include <QVariant>
       
    54 
       
    55 #if defined(Q_OS_SYMBIAN)
       
    56 # define SRCDIR ""
       
    57 #endif
       
    58 
       
    59 //TESTED_CLASS=
       
    60 //TESTED_FILES=
       
    61 
       
    62 QT_FORWARD_DECLARE_CLASS(QDomDocument)
       
    63 QT_FORWARD_DECLARE_CLASS(QDomNode)
       
    64 
       
    65 class tst_QDom : public QObject
       
    66 {
       
    67     Q_OBJECT
       
    68 
       
    69 private slots:
       
    70     void initTestCase();
       
    71     void namespacedAttributes() const;
       
    72     void setContent_data();
       
    73     void setContent();
       
    74     void toString_01_data();
       
    75     void toString_01();
       
    76     void toString_02_data();
       
    77     void toString_02();
       
    78     void hasAttributes_data();
       
    79     void hasAttributes();
       
    80     void save_data();
       
    81     void save();
       
    82     void saveWithSerialization() const;
       
    83     void saveWithSerialization_data() const;
       
    84     void cloneNode_data();
       
    85     void cloneNode();
       
    86     void ownerDocument_data();
       
    87     void ownerDocument();
       
    88     void ownerDocumentTask27424_data();
       
    89     void ownerDocumentTask27424();
       
    90     void parentNode_data();
       
    91     void parentNode();
       
    92     void documentCreationTask27424_data();
       
    93     void documentCreationTask27424();
       
    94     void browseElements();
       
    95     void ownerElementTask45192_data();
       
    96     void ownerElementTask45192();
       
    97     void domNodeMapAndList();
       
    98 
       
    99     void nullDocument();
       
   100     void invalidName_data();
       
   101     void invalidName();
       
   102     void invalidQualifiedName_data();
       
   103     void invalidQualifiedName();
       
   104     void invalidCharData_data();
       
   105     void invalidCharData();
       
   106 
       
   107     void roundTripAttributes() const;
       
   108     void normalizeEndOfLine() const;
       
   109     void normalizeAttributes() const;
       
   110     void serializeWeirdEOL() const;
       
   111     void reparentAttribute() const;
       
   112     void serializeNamespaces() const;
       
   113     void flagInvalidNamespaces() const;
       
   114     void flagUndeclaredNamespace() const;
       
   115 
       
   116     void indentComments() const;
       
   117     void checkLiveness() const;
       
   118     void reportDuplicateAttributes() const;
       
   119     void appendChildFromToDocument() const;
       
   120     void iterateCDATA() const;
       
   121     void appendDocumentNode() const;
       
   122     void germanUmlautToByteArray() const;
       
   123     void germanUmlautToFile() const;
       
   124     void setInvalidDataPolicy() const;
       
   125     void crashInSetContent() const;
       
   126     void doubleNamespaceDeclarations() const;
       
   127     void setContentQXmlReaderOverload() const;
       
   128     void toStringWithoutNewlines() const;
       
   129     void checkIntOverflow() const;
       
   130     void setContentWhitespace() const;
       
   131     void setContentWhitespace_data() const;
       
   132 
       
   133     void taskQTBUG4595_dontAssertWhenDocumentSpecifiesUnknownEncoding() const;
       
   134 
       
   135     void cleanupTestCase() const;
       
   136 
       
   137 private:
       
   138     static QDomDocument generateRequest();
       
   139     static QDomDocument doc(const QString &title, const QByteArray &ba);
       
   140     static int hasAttributesHelper( const QDomNode& node );
       
   141     static bool compareDocuments( const QDomDocument &doc1, const QDomDocument &doc2 );
       
   142     static bool compareNodes( const QDomNode &node1, const QDomNode &node2, bool deep );
       
   143     static QDomNode findDomNode( const QDomDocument &doc, const QList<QVariant> &pathToNode );
       
   144     static QString onNullWarning(const char *const functionName);
       
   145     static bool isDeepEqual(const QDomNode &n1, const QDomNode &n2);
       
   146     static bool isFakeXMLDeclaration(const QDomNode &node);
       
   147 
       
   148     QList<QByteArray> m_excludedCodecs;
       
   149 };
       
   150 
       
   151 Q_DECLARE_METATYPE(QList<QVariant>)
       
   152 
       
   153 void tst_QDom::setContent_data()
       
   154 {
       
   155     const QString doc01(
       
   156         "<!DOCTYPE a1 [ <!ENTITY blubber 'and'> ]>\n"
       
   157         "<a1>\n"
       
   158         " <b1>\n"
       
   159         "  <c1>foo</c1>\n"
       
   160         "  <c2>bar</c2>\n"
       
   161         "  <c3>foo &amp; bar</c3>\n"
       
   162         "  <c4>foo &blubber; bar</c4>\n"
       
   163         " </b1>\n"
       
   164         " <b2> </b2>\n"
       
   165         " <b3>\n"
       
   166         "  <c1/>\n"
       
   167         " </b3>\n"
       
   168         "</a1>\n"
       
   169         );
       
   170 
       
   171     QTest::addColumn<QString>("doc");
       
   172     QTest::addColumn<QStringList>("featuresTrue");
       
   173     QTest::addColumn<QStringList>("featuresFalse");
       
   174     QTest::addColumn<QString>("res");
       
   175 
       
   176 /*    QTest::newRow( "01" ) << doc01
       
   177                        << QStringList()
       
   178                        << QString("http://trolltech.com/xml/features/report-whitespace-only-CharData").split(' ')
       
   179                        << QString("<!DOCTYPE a1>\n"
       
   180                                    "<a1>\n"
       
   181                                    "    <b1>\n"
       
   182                                    "        <c1>foo</c1>\n"
       
   183                                    "        <c2>bar</c2>\n"
       
   184                                    "        <c3>foo &amp; bar</c3>\n"
       
   185                                    "        <c4>foo and bar</c4>\n"
       
   186                                    "    </b1>\n"
       
   187                                    "    <b2/>\n"
       
   188                                    "    <b3>\n"
       
   189                                    "        <c1/>\n"
       
   190                                    "    </b3>\n"
       
   191                                    "</a1>\n");
       
   192 
       
   193     QTest::newRow( "02" ) << doc01
       
   194                        << QString("http://trolltech.com/xml/features/report-whitespace-only-CharData").split(' ')
       
   195                        << QStringList()
       
   196                        << QString("<!DOCTYPE a1>\n"
       
   197                                    "<a1>\n"
       
   198                                    " <b1>\n"
       
   199                                    "  <c1>foo</c1>\n"
       
   200                                    "  <c2>bar</c2>\n"
       
   201                                    "  <c3>foo &amp; bar</c3>\n"
       
   202                                    "  <c4>foo and bar</c4>\n"
       
   203                                    " </b1>\n"
       
   204                                    " <b2> </b2>\n"
       
   205                                    " <b3>\n"
       
   206                                    "  <c1/>\n"
       
   207                                    " </b3>\n"
       
   208                                    "</a1>\n");
       
   209 
       
   210     QTest::newRow( "03" ) << doc01
       
   211                        << QString("http://trolltech.com/xml/features/report-start-end-entity").split(' ')
       
   212                        << QString("http://trolltech.com/xml/features/report-whitespace-only-CharData").split(' ')
       
   213                        << QString("<!DOCTYPE a1 [\n"
       
   214                                    "<!ENTITY blubber \"and\">\n"
       
   215                                    "]>\n"
       
   216                                    "<a1>\n"
       
   217                                    "    <b1>\n"
       
   218                                    "        <c1>foo</c1>\n"
       
   219                                    "        <c2>bar</c2>\n"
       
   220                                    "        <c3>foo &amp; bar</c3>\n"
       
   221                                    "        <c4>foo &blubber; bar</c4>\n"
       
   222                                    "    </b1>\n"
       
   223                                    "    <b2/>\n"
       
   224                                    "    <b3>\n"
       
   225                                    "        <c1/>\n"
       
   226                                    "    </b3>\n"
       
   227                                    "</a1>\n");
       
   228 
       
   229     QTest::newRow( "04" ) << doc01
       
   230                        << QString("http://trolltech.com/xml/features/report-whitespace-only-CharData http://trolltech.com/xml/features/report-start-end-entity").split(' ')
       
   231                        << QStringList()
       
   232                        << QString("<!DOCTYPE a1 [\n"
       
   233                                    "<!ENTITY blubber \"and\">\n"
       
   234                                    "]>\n"
       
   235                                    "<a1>\n"
       
   236                                    " <b1>\n"
       
   237                                    "  <c1>foo</c1>\n"
       
   238                                    "  <c2>bar</c2>\n"
       
   239                                    "  <c3>foo &amp; bar</c3>\n"
       
   240                                    "  <c4>foo &blubber; bar</c4>\n"
       
   241                                    " </b1>\n"
       
   242                                    " <b2> </b2>\n"
       
   243                                    " <b3>\n"
       
   244                                    "  <c1/>\n"
       
   245                                    " </b3>\n"
       
   246                                    "</a1>\n");
       
   247 
       
   248   */   QTest::newRow("05") << QString("<message>\n"
       
   249                                 "    <body>&lt;b&gt;foo&lt;/b&gt;>]]&gt;</body>\n"
       
   250                                 "</message>\n")
       
   251                      << QStringList() << QStringList()
       
   252                      << QString("<message>\n"
       
   253                                 "    <body>&lt;b>foo&lt;/b>>]]&gt;</body>\n"
       
   254                                 "</message>\n");
       
   255 
       
   256 }
       
   257 
       
   258 void tst_QDom::setContent()
       
   259 {
       
   260     QFETCH( QString, doc );
       
   261 
       
   262     QXmlInputSource source;
       
   263     source.setData( doc );
       
   264 
       
   265     QFETCH( QStringList, featuresTrue );
       
   266     QFETCH( QStringList, featuresFalse );
       
   267     QXmlSimpleReader reader;
       
   268     QStringList::Iterator it;
       
   269     for ( it = featuresTrue.begin(); it != featuresTrue.end(); ++it ) {
       
   270         QVERIFY( reader.hasFeature( *it ) );
       
   271         reader.setFeature( *it, TRUE );
       
   272     }
       
   273     for ( it = featuresFalse.begin(); it != featuresFalse.end(); ++it ) {
       
   274         QVERIFY( reader.hasFeature( *it ) );
       
   275         reader.setFeature( *it, FALSE );
       
   276     }
       
   277 
       
   278     QDomDocument domDoc;
       
   279     QVERIFY( domDoc.setContent( &source, &reader ) );
       
   280 
       
   281     QString eRes;
       
   282     QTextStream ts( &eRes, QIODevice::WriteOnly );
       
   283     domDoc.save( ts, 4 );
       
   284 
       
   285     QTEST( eRes, "res" );
       
   286 
       
   287     // make sure that if we parse our output again, we get the same document
       
   288     QDomDocument domDoc1;
       
   289     QDomDocument domDoc2;
       
   290     QVERIFY( domDoc1.setContent( doc ) );
       
   291     QVERIFY( domDoc2.setContent( eRes ) );
       
   292     QVERIFY( compareDocuments( domDoc1, domDoc2 ) );
       
   293 }
       
   294 
       
   295 void tst_QDom::toString_01_data()
       
   296 {
       
   297     QTest::addColumn<QString>("fileName");
       
   298 
       
   299     QTest::newRow( "01" ) << QString(SRCDIR "testdata/toString_01/doc01.xml");
       
   300     QTest::newRow( "02" ) << QString(SRCDIR "testdata/toString_01/doc02.xml");
       
   301     QTest::newRow( "03" ) << QString(SRCDIR "testdata/toString_01/doc03.xml");
       
   302     QTest::newRow( "04" ) << QString(SRCDIR "testdata/toString_01/doc04.xml");
       
   303     QTest::newRow( "05" ) << QString(SRCDIR "testdata/toString_01/doc05.xml");
       
   304 
       
   305     QTest::newRow( "euc-jp" ) << QString(SRCDIR "testdata/toString_01/doc_euc-jp.xml");
       
   306     QTest::newRow( "iso-2022-jp" ) << QString(SRCDIR "testdata/toString_01/doc_iso-2022-jp.xml");
       
   307     QTest::newRow( "little-endian" ) << QString(SRCDIR "testdata/toString_01/doc_little-endian.xml");
       
   308     QTest::newRow( "utf-16" ) << QString(SRCDIR "testdata/toString_01/doc_utf-16.xml");
       
   309     QTest::newRow( "utf-8" ) << QString(SRCDIR "testdata/toString_01/doc_utf-8.xml");
       
   310 
       
   311 }
       
   312 
       
   313 /*! \internal
       
   314 
       
   315   This function tests that the QDomDocument::toString() function results in the
       
   316   same XML document. The meaning of "same" in this context means that the
       
   317   "information" in the resulting XML file is the same as in the original, i.e.
       
   318   we are not intrested in different formatting, etc.
       
   319 
       
   320   To achieve this, the XML document of the toString() function is parsed again
       
   321   and the two QDomDocuments are compared.
       
   322 */
       
   323 void tst_QDom::toString_01()
       
   324 {
       
   325     QFAIL("make test fail instead of timing out, will be fixed later (QT-2357)");
       
   326     QFETCH(QString, fileName);
       
   327 
       
   328     QFile f(fileName);
       
   329     QVERIFY2(f.open(QIODevice::ReadOnly), qPrintable(QString::fromLatin1("Failed to open file %1, file error: %2").arg(fileName).arg(f.error())));
       
   330 
       
   331     QDomDocument doc;
       
   332     QString errorMsg;
       
   333     int errorLine;
       
   334     int errorCol;
       
   335 
       
   336     QVERIFY(doc.setContent( &f, &errorMsg, &errorLine, &errorCol )); /*,
       
   337         QString("QDomDocument::setContent() failed: %1 in line %2, column %3")
       
   338                         .arg( errorMsg ).arg( errorLine ).arg( errorCol )); */
       
   339     // test toString()'s invariant with different indenting depths
       
   340     for ( int i=0; i<5; i++ ) {
       
   341         QString toStr = doc.toString( i );
       
   342 
       
   343         QDomDocument res;
       
   344         QVERIFY( res.setContent( toStr ) );
       
   345 
       
   346         QVERIFY( compareDocuments( doc, res ) );
       
   347     }
       
   348 }
       
   349 
       
   350 void tst_QDom::toString_02_data()
       
   351 {
       
   352     save_data();
       
   353 }
       
   354 
       
   355 /*
       
   356   Tests the new QDomDocument::toString(int) overload (basically the same test
       
   357   as save()).
       
   358 */
       
   359 void tst_QDom::toString_02()
       
   360 {
       
   361     QFETCH( QString, doc );
       
   362     QFETCH( int, indent );
       
   363 
       
   364     QDomDocument domDoc;
       
   365     QVERIFY( domDoc.setContent( doc ) );
       
   366     QTEST( domDoc.toString(indent), "res" );
       
   367 }
       
   368 
       
   369 
       
   370 void tst_QDom::hasAttributes_data()
       
   371 {
       
   372     QTest::addColumn<int>("visitedNodes");
       
   373     QTest::addColumn<QByteArray>("xmlDoc");
       
   374 
       
   375     QByteArray doc1("<top>Make a <blubb>stupid</blubb>, useless test sentence.</top>");
       
   376     QByteArray doc2("<top a=\"a\">Make a <blubb a=\"a\">stupid</blubb>, useless test sentence.</top>");
       
   377     QByteArray doc3("<!-- just a useless comment -->\n"
       
   378                     "<?pi foo bar?>\n"
       
   379                     "<foo>\n"
       
   380                     "<bar fnord=\"snafu\" hmpf=\"grmpf\">\n"
       
   381                     "<foobar/>\n"
       
   382                     "</bar>\n"
       
   383                     "<bar>blubber</bar>\n"
       
   384                     "more text, pretty unintresting, though\n"
       
   385                     "<hmpfl blubber=\"something\" />\n"
       
   386                     "<![CDATA[ foo bar @!<>] ]]>\n"
       
   387                     "</foo>\n"
       
   388                     "<!-- just a useless comment -->\n"
       
   389                     "<?pi foo bar?>\n");
       
   390 
       
   391     QTest::newRow( "01" ) << 6 << doc1;
       
   392     QTest::newRow( "02" ) << 6 << doc2;
       
   393     QTest::newRow( "03" ) << 13 << doc3;
       
   394 }
       
   395 
       
   396 /*
       
   397   This function tests that QDomNode::hasAttributes() returns TRUE if and only
       
   398   if the node has attributes (i.e. QDomNode::attributes() returns a list with
       
   399   attributes in it).
       
   400 */
       
   401 void tst_QDom::hasAttributes()
       
   402 {
       
   403     QFETCH( QByteArray, xmlDoc );
       
   404 
       
   405     QDomDocument doc;
       
   406     QVERIFY( doc.setContent( xmlDoc ) );
       
   407 
       
   408     int visitedNodes = hasAttributesHelper( doc );
       
   409     QTEST( visitedNodes, "visitedNodes" );
       
   410 }
       
   411 
       
   412 int tst_QDom::hasAttributesHelper( const QDomNode& node )
       
   413 {
       
   414     int visitedNodes = 1;
       
   415     if ( node.hasAttributes() ) {
       
   416             if (node.attributes().count() == 0)
       
   417             return -1;
       
   418 //        QVERIFY( node.attributes().count() > 0 );
       
   419     } else {
       
   420             if (node.attributes().count() != 0)
       
   421             return -1;
       
   422 //        QVERIFY( node.attributes().count() == 0 );
       
   423     }
       
   424 
       
   425     QDomNodeList children = node.childNodes();
       
   426     for ( int i=0; i<children.count(); i++ ) {
       
   427             int j = hasAttributesHelper( children.item(i) );
       
   428         if (j < 0)
       
   429             return -1;
       
   430         visitedNodes += j;
       
   431     }
       
   432     return visitedNodes;
       
   433 }
       
   434 
       
   435 
       
   436 void tst_QDom::save_data()
       
   437 {
       
   438     const QString doc01(
       
   439             "<a1>\n"
       
   440             " <b1>\n"
       
   441             "  <c1>\n"
       
   442             "   <d1/>\n"
       
   443             "  </c1>\n"
       
   444             "  <c2/>\n"
       
   445             " </b1>\n"
       
   446             " <b2/>\n"
       
   447             " <b3>\n"
       
   448             "  <c1/>\n"
       
   449             " </b3>\n"
       
   450             "</a1>\n"
       
   451             );
       
   452 
       
   453     QTest::addColumn<QString>("doc");
       
   454     QTest::addColumn<int>("indent");
       
   455     QTest::addColumn<QString>("res");
       
   456 
       
   457     QTest::newRow( "01" ) << doc01 << 0 << QString(doc01).replace( QRegExp(" "), "" );
       
   458     QTest::newRow( "02" ) << doc01 << 1 << doc01;
       
   459     QTest::newRow( "03" ) << doc01 << 2 << QString(doc01).replace( QRegExp(" "), "  " );
       
   460     QTest::newRow( "04" ) << doc01 << 10 << QString(doc01).replace( QRegExp(" "), "          " );
       
   461 }
       
   462 
       
   463 void tst_QDom::save()
       
   464 {
       
   465     QFETCH( QString, doc );
       
   466     QFETCH( int, indent );
       
   467 
       
   468     QDomDocument domDoc;
       
   469     QVERIFY( domDoc.setContent( doc ) );
       
   470 
       
   471     QString eRes;
       
   472     QTextStream ts( &eRes, QIODevice::WriteOnly );
       
   473     domDoc.save( ts, indent );
       
   474 
       
   475     QTEST( eRes, "res" );
       
   476 }
       
   477 
       
   478 void tst_QDom::initTestCase()
       
   479 {
       
   480 #ifdef Q_CC_MINGW
       
   481     QSKIP("Our current test machine, arsia, is too slow for this auto test.", SkipAll);
       
   482 #endif
       
   483 
       
   484     QFile file(SRCDIR "testdata/excludedCodecs.txt");
       
   485     QVERIFY(file.open(QIODevice::ReadOnly|QIODevice::Text));
       
   486 
       
   487     QByteArray codecName;
       
   488 
       
   489     m_excludedCodecs = file.readAll().split('\n');
       
   490 
       
   491 }
       
   492 
       
   493 void tst_QDom::saveWithSerialization() const
       
   494 {
       
   495     QFETCH(QString, fileName);
       
   496 
       
   497     QFile f(fileName);
       
   498     QVERIFY(f.open(QIODevice::ReadOnly));
       
   499 
       
   500     QDomDocument doc;
       
   501 
       
   502     // Read the document
       
   503     QVERIFY(doc.setContent(&f));
       
   504 
       
   505     const QList<QByteArray> codecs(QTextCodec::availableCodecs());
       
   506     QByteArray codecName;
       
   507 
       
   508     foreach(codecName, codecs) {
       
   509 
       
   510         /* Avoid codecs that can't handle the files we have. */
       
   511         if(m_excludedCodecs.contains(codecName.toLower()))
       
   512             continue;
       
   513 
       
   514         /* Write out doc in the specified codec. */
       
   515         QByteArray storage;
       
   516         QBuffer writeDevice(&storage);
       
   517         QVERIFY(writeDevice.open(QIODevice::WriteOnly));
       
   518 
       
   519         QTextStream s(&writeDevice);
       
   520         QTextCodec *codec = QTextCodec::codecForName(codecName);
       
   521         QVERIFY2(codec, qPrintable(QString::fromLatin1("Failed to load codec %1, even though it was in QTextCodec::availableCodecs()")
       
   522                                    .arg(QString::fromLatin1(codecName.constData()))));
       
   523         s.setCodec(codec);
       
   524 
       
   525         doc.save(s, 0, QDomNode::EncodingFromTextStream);
       
   526         s.flush();
       
   527         writeDevice.close();
       
   528 
       
   529         QBuffer readDevice(&storage);
       
   530         QVERIFY(readDevice.open(QIODevice::ReadOnly));
       
   531 
       
   532         QDomDocument result;
       
   533 
       
   534         QString msg;
       
   535         int line = 0;
       
   536         int column = 0;
       
   537 
       
   538         QVERIFY2(result.setContent(&readDevice, &msg, &line, &column),
       
   539                  qPrintable(QString::fromLatin1("Failed for codec %1: line %2, column %3: %4, content: %5")
       
   540                                                 .arg(QString::fromLatin1(codecName.constData()),
       
   541                                                      QString::number(line),
       
   542                                                      QString::number(column),
       
   543                                                      msg,
       
   544                                                      codec->toUnicode(storage))));
       
   545         if(!compareDocuments(doc, result))
       
   546         {
       
   547             QCOMPARE(doc.toString(), result.toString());
       
   548 
       
   549             /* We put this one here as well, in case the QCOMPARE above for some strange reason
       
   550              * nevertheless succeeds. */
       
   551             QVERIFY2(false, qPrintable(QString::fromLatin1("Failed for codec %1").arg(QString::fromLatin1(codecName.constData()))));
       
   552         }
       
   553     }
       
   554 }
       
   555 
       
   556 void tst_QDom::saveWithSerialization_data() const
       
   557 {
       
   558     QTest::addColumn<QString>("fileName");
       
   559 
       
   560     QTest::newRow("doc01.xml") << QString(SRCDIR "testdata/toString_01/doc01.xml");
       
   561     QTest::newRow("doc01.xml") << QString(SRCDIR "testdata/toString_01/doc01.xml");
       
   562     QTest::newRow("doc02.xml") << QString(SRCDIR "testdata/toString_01/doc02.xml");
       
   563     QTest::newRow("doc03.xml") << QString(SRCDIR "testdata/toString_01/doc03.xml");
       
   564     QTest::newRow("doc04.xml") << QString(SRCDIR "testdata/toString_01/doc04.xml");
       
   565     QTest::newRow("doc05.xml") << QString(SRCDIR "testdata/toString_01/doc05.xml");
       
   566 
       
   567     QTest::newRow("doc_euc-jp.xml") << QString(SRCDIR "testdata/toString_01/doc_euc-jp.xml");
       
   568     QTest::newRow("doc_iso-2022-jp.xml") << QString(SRCDIR "testdata/toString_01/doc_iso-2022-jp.xml");
       
   569     QTest::newRow("doc_little-endian.xml") << QString(SRCDIR "testdata/toString_01/doc_little-endian.xml");
       
   570     QTest::newRow("doc_utf-16.xml") << QString(SRCDIR "testdata/toString_01/doc_utf-16.xml");
       
   571     QTest::newRow("doc_utf-8.xml") << QString(SRCDIR "testdata/toString_01/doc_utf-8.xml");
       
   572 }
       
   573 
       
   574 void tst_QDom::cloneNode_data()
       
   575 {
       
   576     const QString doc01(
       
   577             "<a1>\n"
       
   578             " <b1>\n"
       
   579             "  <c1>\n"
       
   580             "   <d1/>\n"
       
   581             "  </c1>\n"
       
   582             "  <c2/>\n"
       
   583             " </b1>\n"
       
   584             " <b2/>\n"
       
   585             " <b3>\n"
       
   586             "  <c1/>\n"
       
   587             " </b3>\n"
       
   588             "</a1>\n"
       
   589             );
       
   590     QList<QVariant> nodeB1;
       
   591     nodeB1 << 0;
       
   592 
       
   593     QList<QVariant> nodeC1;
       
   594     nodeC1 << 0 << 0;
       
   595 
       
   596     QList<QVariant> nodeC2;
       
   597     nodeC2 << 0 << 1;
       
   598 
       
   599     QTest::addColumn<QString>("doc");
       
   600     QTest::addColumn<QList<QVariant> >("pathToNode");
       
   601     QTest::addColumn<bool>("deep");
       
   602 
       
   603     QTest::newRow( "noDeep_01" ) << doc01 << nodeB1 << (bool)FALSE;
       
   604     QTest::newRow( "noDeep_02" ) << doc01 << nodeC1 << (bool)FALSE;
       
   605     QTest::newRow( "noDeep_03" ) << doc01 << nodeC2 << (bool)FALSE;
       
   606 
       
   607     QTest::newRow( "deep_01" ) << doc01 << nodeB1 << (bool)TRUE;
       
   608     QTest::newRow( "deep_02" ) << doc01 << nodeC1 << (bool)TRUE;
       
   609     QTest::newRow( "deep_03" ) << doc01 << nodeC2 << (bool)TRUE;
       
   610 }
       
   611 
       
   612 void tst_QDom::cloneNode()
       
   613 {
       
   614     QFETCH( QString, doc );
       
   615     QFETCH( QList<QVariant>, pathToNode );
       
   616     QFETCH( bool, deep );
       
   617     QDomDocument domDoc;
       
   618     QVERIFY( domDoc.setContent( doc ) );
       
   619     QDomNode node = findDomNode( domDoc, pathToNode );
       
   620     QVERIFY(!node.isNull());
       
   621 
       
   622     QDomNode clonedNode = node.cloneNode( deep );
       
   623     QVERIFY( compareNodes( node, clonedNode, deep ) );
       
   624 
       
   625     QDomNode parent = node.parentNode();
       
   626     if ( !parent.isNull() ) {
       
   627         node = parent.replaceChild( clonedNode, node ); // swap the nodes
       
   628         QVERIFY( !node.isNull() );
       
   629         QVERIFY( compareNodes( node, clonedNode, deep ) );
       
   630     }
       
   631 }
       
   632 
       
   633 
       
   634 void tst_QDom::ownerElementTask45192_data()
       
   635 {
       
   636     const QString doc(
       
   637         "<root>\n"
       
   638         " <item name=\"test\" >\n"
       
   639         " </item>\n"
       
   640         "</root>"
       
   641     );
       
   642 
       
   643     QTest::addColumn<QString>("doc");
       
   644     QTest::newRow("doc") << doc;
       
   645 }
       
   646 
       
   647 void tst_QDom::ownerElementTask45192()
       
   648 {
       
   649     QFETCH( QString, doc );
       
   650     QDomDocument domDoc;
       
   651     QVERIFY( domDoc.setContent( doc ) );
       
   652 
       
   653     QDomNode item = domDoc.documentElement().firstChild();
       
   654     QDomNode clone = item.cloneNode(false);
       
   655 
       
   656     QVERIFY( clone == clone.attributes().namedItem("name").toAttr().ownerElement() );
       
   657 }
       
   658 
       
   659 void tst_QDom::ownerDocument_data()
       
   660 {
       
   661     cloneNode_data();
       
   662 }
       
   663 
       
   664 #define OWNERDOCUMENT_CREATE_TEST( t, x ) \
       
   665 { \
       
   666     t n = x; \
       
   667     QVERIFY( n.ownerDocument() == domDoc ); \
       
   668 }
       
   669 
       
   670 #define OWNERDOCUMENT_IMPORTNODE_TEST( t, x ) \
       
   671 { \
       
   672     QDomNode importedNode; \
       
   673     t n = x; \
       
   674     QVERIFY( n.ownerDocument() != domDoc ); \
       
   675     importedNode = domDoc.importNode( n, deep ); \
       
   676     QVERIFY( n.ownerDocument() != domDoc ); \
       
   677     QVERIFY( importedNode.ownerDocument() == domDoc ); \
       
   678 }
       
   679 
       
   680 void tst_QDom::ownerDocument()
       
   681 {
       
   682     QFETCH( QString, doc );
       
   683     QFETCH( QList<QVariant>, pathToNode );
       
   684     QFETCH( bool, deep );
       
   685     QDomDocument domDoc;
       
   686     QVERIFY( domDoc.setContent( doc ) );
       
   687     QDomNode node = findDomNode( domDoc, pathToNode );
       
   688     QVERIFY(!node.isNull());
       
   689 
       
   690     QVERIFY( node.ownerDocument() == domDoc );
       
   691 
       
   692     // Does cloneNode() keep the ownerDocument()?
       
   693     {
       
   694         QDomNode clonedNode = node.cloneNode( deep );
       
   695         QVERIFY( node.ownerDocument() == domDoc );
       
   696         QVERIFY( clonedNode.ownerDocument() == domDoc );
       
   697     }
       
   698 
       
   699     // If the original DOM node is replaced with the cloned node, does this
       
   700     // keep the ownerDocument()?
       
   701     {
       
   702         QDomNode clonedNode = node.cloneNode( deep );
       
   703         QDomNode parent = node.parentNode();
       
   704         if ( !parent.isNull() ) {
       
   705             node = parent.replaceChild( clonedNode, node ); // swap the nodes
       
   706             QVERIFY( node.ownerDocument() == domDoc );
       
   707             QVERIFY( clonedNode.ownerDocument() == domDoc );
       
   708         }
       
   709     }
       
   710 
       
   711     // test QDomDocument::create...()
       
   712     {
       
   713         OWNERDOCUMENT_CREATE_TEST( QDomAttr,                    domDoc.createAttribute( "foo" ) );
       
   714         OWNERDOCUMENT_CREATE_TEST( QDomAttr,                    domDoc.createAttributeNS( "foo", "bar" ) );
       
   715         OWNERDOCUMENT_CREATE_TEST( QDomCDATASection,            domDoc.createCDATASection( "foo" ) );
       
   716         OWNERDOCUMENT_CREATE_TEST( QDomComment,                 domDoc.createComment( "foo" ) );
       
   717         OWNERDOCUMENT_CREATE_TEST( QDomDocumentFragment,        domDoc.createDocumentFragment() );
       
   718         OWNERDOCUMENT_CREATE_TEST( QDomElement,                 domDoc.createElement( "foo" ) );
       
   719         OWNERDOCUMENT_CREATE_TEST( QDomElement,                 domDoc.createElementNS( "foo", "bar" ) );
       
   720         OWNERDOCUMENT_CREATE_TEST( QDomEntityReference,         domDoc.createEntityReference( "foo" ) );
       
   721         OWNERDOCUMENT_CREATE_TEST( QDomProcessingInstruction,   domDoc.createProcessingInstruction( "foo", "bar" ) );
       
   722         OWNERDOCUMENT_CREATE_TEST( QDomText,                    domDoc.createTextNode( "foo" ) );
       
   723     }
       
   724 
       
   725     // test importNode()
       
   726     {
       
   727         QDomDocument doc2;
       
   728         OWNERDOCUMENT_IMPORTNODE_TEST( QDomAttr,                    doc2.createAttribute( "foo" ) );
       
   729         OWNERDOCUMENT_IMPORTNODE_TEST( QDomAttr,                    doc2.createAttributeNS( "foo", "bar" ) );
       
   730         OWNERDOCUMENT_IMPORTNODE_TEST( QDomCDATASection,            doc2.createCDATASection( "foo" ) );
       
   731         OWNERDOCUMENT_IMPORTNODE_TEST( QDomComment,                 doc2.createComment( "foo" ) );
       
   732         OWNERDOCUMENT_IMPORTNODE_TEST( QDomDocumentFragment,        doc2.createDocumentFragment() );
       
   733         OWNERDOCUMENT_IMPORTNODE_TEST( QDomElement,                 doc2.createElement( "foo" ) );
       
   734         OWNERDOCUMENT_IMPORTNODE_TEST( QDomElement,                 doc2.createElementNS( "foo", "bar" ) );
       
   735         OWNERDOCUMENT_IMPORTNODE_TEST( QDomEntityReference,         doc2.createEntityReference( "foo" ) );
       
   736         OWNERDOCUMENT_IMPORTNODE_TEST( QDomProcessingInstruction,   doc2.createProcessingInstruction( "foo", "bar" ) );
       
   737         OWNERDOCUMENT_IMPORTNODE_TEST( QDomText,                    doc2.createTextNode( "foo" ) );
       
   738     }
       
   739 }
       
   740 
       
   741 void tst_QDom::ownerDocumentTask27424_data()
       
   742 {
       
   743     QTest::addColumn<bool>("insertLevel1AfterCstr");
       
   744     QTest::addColumn<bool>("insertLevel2AfterCstr");
       
   745     QTest::addColumn<bool>("insertLevel3AfterCstr");
       
   746 
       
   747     QTest::newRow( "000" ) << (bool)FALSE << (bool)FALSE << (bool)FALSE;
       
   748     QTest::newRow( "001" ) << (bool)FALSE << (bool)FALSE << (bool)TRUE;
       
   749     QTest::newRow( "010" ) << (bool)FALSE << (bool)TRUE  << (bool)FALSE;
       
   750     QTest::newRow( "011" ) << (bool)FALSE << (bool)TRUE  << (bool)TRUE;
       
   751     QTest::newRow( "100" ) << (bool)TRUE  << (bool)FALSE << (bool)FALSE;
       
   752     QTest::newRow( "101" ) << (bool)TRUE  << (bool)FALSE << (bool)TRUE;
       
   753     QTest::newRow( "110" ) << (bool)TRUE  << (bool)TRUE  << (bool)FALSE;
       
   754     QTest::newRow( "111" ) << (bool)TRUE  << (bool)TRUE  << (bool)TRUE;
       
   755 }
       
   756 
       
   757 void tst_QDom::ownerDocumentTask27424()
       
   758 {
       
   759     QFETCH( bool, insertLevel1AfterCstr );
       
   760     QFETCH( bool, insertLevel2AfterCstr );
       
   761     QFETCH( bool, insertLevel3AfterCstr );
       
   762 
       
   763     QDomDocument doc("TestXML");
       
   764 
       
   765     QDomElement level1 = doc.createElement("Level_1");
       
   766     QVERIFY( level1.ownerDocument() == doc );
       
   767 
       
   768     if ( insertLevel1AfterCstr ) {
       
   769         doc.appendChild(level1);
       
   770         QVERIFY( level1.ownerDocument() == doc );
       
   771     }
       
   772 
       
   773     QDomElement level2 = level1.ownerDocument().createElement("Level_2");
       
   774     QVERIFY( level1.ownerDocument() == doc );
       
   775     QVERIFY( level2.ownerDocument() == doc );
       
   776 
       
   777     if ( insertLevel2AfterCstr ) {
       
   778         level1.appendChild(level2);
       
   779         QVERIFY( level1.ownerDocument() == doc );
       
   780         QVERIFY( level2.ownerDocument() == doc );
       
   781     }
       
   782 
       
   783     QDomElement level3 = level2.ownerDocument().createElement("Level_3");
       
   784     QVERIFY( level1.ownerDocument() == doc );
       
   785     QVERIFY( level2.ownerDocument() == doc );
       
   786     QVERIFY( level3.ownerDocument() == doc );
       
   787 
       
   788     if ( insertLevel3AfterCstr ) {
       
   789         level2.appendChild(level3);
       
   790         QVERIFY( level1.ownerDocument() == doc );
       
   791         QVERIFY( level2.ownerDocument() == doc );
       
   792         QVERIFY( level3.ownerDocument() == doc );
       
   793     }
       
   794 
       
   795     QDomNode level4 = level3.ownerDocument().createTextNode("This_is_a_value!");
       
   796     QVERIFY( level4.ownerDocument() == doc );
       
   797 
       
   798     level3.appendChild(level4);
       
   799     QVERIFY( level1.ownerDocument() == doc );
       
   800     QVERIFY( level2.ownerDocument() == doc );
       
   801     QVERIFY( level3.ownerDocument() == doc );
       
   802     QVERIFY( level4.ownerDocument() == doc );
       
   803 
       
   804     if ( !insertLevel3AfterCstr ) {
       
   805         level2.appendChild(level3);
       
   806         QVERIFY( level1.ownerDocument() == doc );
       
   807         QVERIFY( level2.ownerDocument() == doc );
       
   808         QVERIFY( level3.ownerDocument() == doc );
       
   809         QVERIFY( level4.ownerDocument() == doc );
       
   810     }
       
   811 
       
   812     if ( !insertLevel2AfterCstr ) {
       
   813         level1.appendChild(level2);
       
   814         QVERIFY( level1.ownerDocument() == doc );
       
   815         QVERIFY( level2.ownerDocument() == doc );
       
   816         QVERIFY( level3.ownerDocument() == doc );
       
   817         QVERIFY( level4.ownerDocument() == doc );
       
   818     }
       
   819 
       
   820     if ( !insertLevel1AfterCstr ) {
       
   821         doc.appendChild(level1);
       
   822         QVERIFY( level1.ownerDocument() == doc );
       
   823         QVERIFY( level2.ownerDocument() == doc );
       
   824         QVERIFY( level3.ownerDocument() == doc );
       
   825         QVERIFY( level4.ownerDocument() == doc );
       
   826     }
       
   827 }
       
   828 
       
   829 void tst_QDom::parentNode_data()
       
   830 {
       
   831     cloneNode_data();
       
   832 }
       
   833 
       
   834 #define PARENTNODE_CREATE_TEST( t, x ) \
       
   835 { \
       
   836     t n = x; \
       
   837     QVERIFY( n.parentNode().isNull() ); \
       
   838 }
       
   839 
       
   840 void tst_QDom::parentNode()
       
   841 {
       
   842     QFETCH( QString, doc );
       
   843     QFETCH( QList<QVariant>, pathToNode );
       
   844     QFETCH( bool, deep );
       
   845     QDomDocument domDoc;
       
   846     QVERIFY( domDoc.setContent( doc ) );
       
   847     QDomNode node = findDomNode( domDoc, pathToNode );
       
   848     QVERIFY(!node.isNull());
       
   849     Q_UNUSED(deep);
       
   850 
       
   851     // test QDomDocument::create...()
       
   852     {
       
   853         PARENTNODE_CREATE_TEST( QDomAttr,                   domDoc.createAttribute( "foo" ) );
       
   854         PARENTNODE_CREATE_TEST( QDomAttr,                   domDoc.createAttributeNS( "foo", "bar" ) );
       
   855         PARENTNODE_CREATE_TEST( QDomCDATASection,           domDoc.createCDATASection( "foo" ) );
       
   856         PARENTNODE_CREATE_TEST( QDomComment,                domDoc.createComment( "foo" ) );
       
   857         PARENTNODE_CREATE_TEST( QDomDocumentFragment,       domDoc.createDocumentFragment() );
       
   858         PARENTNODE_CREATE_TEST( QDomElement,                domDoc.createElement( "foo" ) );
       
   859         PARENTNODE_CREATE_TEST( QDomElement,                domDoc.createElementNS( "foo", "bar" ) );
       
   860         PARENTNODE_CREATE_TEST( QDomEntityReference,        domDoc.createEntityReference( "foo" ) );
       
   861         PARENTNODE_CREATE_TEST( QDomProcessingInstruction,  domDoc.createProcessingInstruction( "foo", "bar" ) );
       
   862         PARENTNODE_CREATE_TEST( QDomText,                   domDoc.createTextNode( "foo" ) );
       
   863     }
       
   864 }
       
   865 
       
   866 
       
   867 void tst_QDom::documentCreationTask27424_data()
       
   868 {
       
   869     QTest::addColumn<bool>("insertLevel1AfterCstr");
       
   870     QTest::addColumn<bool>("insertLevel2AfterCstr");
       
   871     QTest::addColumn<bool>("insertLevel3AfterCstr");
       
   872 
       
   873     QTest::newRow( "000" ) << (bool)FALSE << (bool)FALSE << (bool)FALSE;
       
   874     QTest::newRow( "001" ) << (bool)FALSE << (bool)FALSE << (bool)TRUE;
       
   875     QTest::newRow( "010" ) << (bool)FALSE << (bool)TRUE  << (bool)FALSE;
       
   876     QTest::newRow( "011" ) << (bool)FALSE << (bool)TRUE  << (bool)TRUE;
       
   877     QTest::newRow( "100" ) << (bool)TRUE  << (bool)FALSE << (bool)FALSE;
       
   878     QTest::newRow( "101" ) << (bool)TRUE  << (bool)FALSE << (bool)TRUE;
       
   879     QTest::newRow( "110" ) << (bool)TRUE  << (bool)TRUE  << (bool)FALSE;
       
   880     QTest::newRow( "111" ) << (bool)TRUE  << (bool)TRUE  << (bool)TRUE;
       
   881 }
       
   882 
       
   883 void tst_QDom::documentCreationTask27424()
       
   884 {
       
   885     QFETCH( bool, insertLevel1AfterCstr );
       
   886     QFETCH( bool, insertLevel2AfterCstr );
       
   887     QFETCH( bool, insertLevel3AfterCstr );
       
   888 
       
   889     QDomDocument docRes;
       
   890     QVERIFY( docRes.setContent( QString(
       
   891                 "<!DOCTYPE TestXML>\n"
       
   892                 "<Level_1>\n"
       
   893                 " <Level_2>\n"
       
   894                 "  <Level_3>This_is_a_value!</Level_3>\n"
       
   895                 " </Level_2>\n"
       
   896                 "</Level_1>"
       
   897                 ) ) );
       
   898 
       
   899     QDomDocument doc("TestXML");
       
   900 
       
   901     QDomElement level1 = doc.createElement("Level_1");
       
   902     if ( insertLevel1AfterCstr )
       
   903         doc.appendChild(level1);
       
   904 
       
   905     QDomElement level2 = level1.ownerDocument().createElement("Level_2");
       
   906     if ( insertLevel2AfterCstr )
       
   907         level1.appendChild(level2);
       
   908 
       
   909     QDomElement level3 = level2.ownerDocument().createElement("Level_3");
       
   910     if ( insertLevel3AfterCstr )
       
   911         level2.appendChild(level3);
       
   912 
       
   913     QDomNode level4 = level3.ownerDocument().createTextNode("This_is_a_value!");
       
   914     level3.appendChild(level4);
       
   915 
       
   916     if ( !insertLevel3AfterCstr )
       
   917         level2.appendChild(level3);
       
   918     if ( !insertLevel2AfterCstr )
       
   919         level1.appendChild(level2);
       
   920     if ( !insertLevel1AfterCstr )
       
   921         doc.appendChild(level1);
       
   922 
       
   923     QVERIFY( compareDocuments( doc, docRes ) );
       
   924 }
       
   925 
       
   926 
       
   927 bool tst_QDom::isFakeXMLDeclaration(const QDomNode &node)
       
   928 {
       
   929     return node.isProcessingInstruction() &&
       
   930            node.nodeName() == QLatin1String("xml");
       
   931 }
       
   932 
       
   933 bool tst_QDom::isDeepEqual(const QDomNode &n1, const QDomNode &n2)
       
   934 {
       
   935     const QDomNode::NodeType nt = n1.nodeType();
       
   936 
       
   937     if(nt != n2.nodeType())
       
   938         return false;
       
   939 
       
   940     if(n1.nodeName() != n2.nodeName()
       
   941        || n1.namespaceURI() != n2.namespaceURI()
       
   942        || n1.nodeValue() != n2.nodeValue())
       
   943         return false;
       
   944 
       
   945     /* Check the children. */
       
   946     const QDomNodeList children1(n1.childNodes());
       
   947     const QDomNodeList children2(n2.childNodes());
       
   948     uint len1 = children1.length();
       
   949     uint len2 = children2.length();
       
   950     uint i1 = 0;
       
   951     uint i2 = 0;
       
   952 
       
   953     if(len1 != 0 && isFakeXMLDeclaration(children1.at(0)))
       
   954             ++i1;
       
   955 
       
   956     if(len2 != 0 && isFakeXMLDeclaration(children2.at(0)))
       
   957             ++i2;
       
   958 
       
   959     if(len1 - i1 != len2 - i2)
       
   960         return false;
       
   961 
       
   962     // We jump over the first to skip the processing instructions that
       
   963     // are (incorrectly) used as XML declarations.
       
   964     for(; i1 < len1; ++i1)
       
   965     {
       
   966         if(!isDeepEqual(children1.at(i1), children2.at(i2)))
       
   967             return false;
       
   968 
       
   969         ++i2;
       
   970     }
       
   971 
       
   972     return true;
       
   973 }
       
   974 
       
   975 /*
       
   976     Returns TRUE if \a doc1 and \a doc2 represent the same XML document, i.e.
       
   977     they have the same informational content. Otherwise, this function returns
       
   978     FALSE.
       
   979 */
       
   980 bool tst_QDom::compareDocuments( const QDomDocument &doc1, const QDomDocument &doc2 )
       
   981 {
       
   982     return isDeepEqual(doc1, doc2);
       
   983 }
       
   984 
       
   985 /*
       
   986     Returns TRUE if \a node1 and \a node2 represent the same XML node, i.e.
       
   987     they have the same informational content. Otherwise, this function returns
       
   988     FALSE.
       
   989 
       
   990     If \a deep is TRUE, children of the nodes are also tested. If \a deep is
       
   991     FALSE, only \a node1 and \a node 2 are compared.
       
   992 */
       
   993 bool tst_QDom::compareNodes( const QDomNode &node1, const QDomNode &node2, bool deep )
       
   994 {
       
   995     if ( deep ) {
       
   996         QString str1;
       
   997         {
       
   998             QTextStream stream( &str1 );
       
   999             stream << node1;
       
  1000         }
       
  1001         QString str2;
       
  1002         {
       
  1003             QTextStream stream( &str2 );
       
  1004             stream << node2;
       
  1005         }
       
  1006         return str1 == str2;
       
  1007     }
       
  1008 
       
  1009     if ( node1.isNull() && node2.isNull() )
       
  1010         return TRUE;
       
  1011     // ### I am not sure if this test is complete
       
  1012     bool equal =     node1.nodeName() == node2.nodeName();
       
  1013     equal = equal && node1.nodeType() == node2.nodeType();
       
  1014     equal = equal && node1.localName() == node2.localName();
       
  1015     equal = equal && node1.nodeValue() == node2.nodeValue();
       
  1016     equal = equal && node1.prefix() == node2.prefix();
       
  1017 
       
  1018     return equal;
       
  1019 }
       
  1020 
       
  1021 /*
       
  1022     \a pathToNode is a list of indices to wanted node in \a doc. Returns the
       
  1023     wanted node.
       
  1024 */
       
  1025 QDomNode tst_QDom::findDomNode( const QDomDocument &doc, const QList<QVariant> &pathToNode )
       
  1026 {
       
  1027     QDomNode node = doc;
       
  1028     QList<QVariant>::const_iterator it;
       
  1029     for ( it = pathToNode.begin(); it != pathToNode.end(); ++it ) {
       
  1030         QDomNodeList children = node.childNodes();
       
  1031         node = children.item( (*it).toInt() );
       
  1032 //        QVERIFY( !node.isNull() );
       
  1033     }
       
  1034     return node;
       
  1035 }
       
  1036 
       
  1037 void tst_QDom::browseElements()
       
  1038 {
       
  1039     QDomDocument doc;
       
  1040     QDomElement root = doc.createElement("foo");
       
  1041     doc.appendChild(root);
       
  1042     root.appendChild(doc.createElement("bar"));
       
  1043     root.appendChild(doc.createElement("bop"));
       
  1044     root.appendChild(doc.createElement("bar"));
       
  1045     root.appendChild(doc.createElement("bop"));
       
  1046 
       
  1047     QVERIFY(doc.firstChildElement("ding").isNull());
       
  1048     QDomElement foo = doc.firstChildElement("foo");
       
  1049     QVERIFY(!foo.isNull());
       
  1050     QVERIFY(foo.firstChildElement("ding").isNull());
       
  1051     QVERIFY(foo.nextSiblingElement("foo").isNull());
       
  1052     QVERIFY(foo.previousSiblingElement("bar").isNull());
       
  1053     QVERIFY(foo.nextSiblingElement().isNull());
       
  1054     QVERIFY(foo.previousSiblingElement().isNull());
       
  1055 
       
  1056     QDomElement bar = foo.firstChildElement("bar");
       
  1057     QVERIFY(!bar.isNull());
       
  1058     QVERIFY(bar.previousSiblingElement("bar").isNull());
       
  1059     QVERIFY(bar.previousSiblingElement().isNull());
       
  1060     QVERIFY(bar.nextSiblingElement("bar").tagName() == "bar");
       
  1061     QVERIFY(bar.nextSiblingElement("bar").nextSiblingElement("bar").isNull());
       
  1062 
       
  1063     QDomElement bop = foo.firstChildElement("bop");
       
  1064     QVERIFY(!bop.isNull());
       
  1065     QVERIFY(bar.nextSiblingElement() == bop);
       
  1066     QVERIFY(bop.nextSiblingElement("bop") == foo.lastChildElement("bop"));
       
  1067     QVERIFY(bop.previousSiblingElement("bar") == foo.firstChildElement("bar"));
       
  1068     QVERIFY(bop.previousSiblingElement("bar") == foo.firstChildElement());
       
  1069 }
       
  1070 
       
  1071 void tst_QDom::domNodeMapAndList()
       
  1072 {
       
  1073     QString xml_str = QString::fromLatin1("<foo ding='dong'></foo>");
       
  1074 
       
  1075     QDomDocument doc;
       
  1076     QVERIFY(doc.setContent(xml_str));
       
  1077 
       
  1078     QDomNamedNodeMap map = doc.documentElement().attributes();
       
  1079     QCOMPARE(map.item(0).nodeName(), QString("ding"));
       
  1080     QCOMPARE(map.item(1).nodeName(), QString()); // Make sure we don't assert
       
  1081 
       
  1082     QDomNodeList list = doc.elementsByTagName("foo");
       
  1083     QCOMPARE(list.item(0).nodeName(), QString("foo"));
       
  1084     QCOMPARE(list.item(1).nodeName(), QString()); // Make sure we don't assert
       
  1085 }
       
  1086 
       
  1087 // Verifies that a default-constructed QDomDocument is null, and that calling
       
  1088 // any of the factory functions causes it to be non-null.
       
  1089 #define TEST_NULL_DOCUMENT(func) \
       
  1090 { \
       
  1091     QDomDocument doc; \
       
  1092     QVERIFY(doc.isNull()); \
       
  1093     QVERIFY(!doc.func.isNull()); \
       
  1094     QVERIFY(!doc.isNull()); \
       
  1095 }
       
  1096 
       
  1097 void tst_QDom::nullDocument()
       
  1098 {
       
  1099     TEST_NULL_DOCUMENT(createAttribute("foo"))
       
  1100     TEST_NULL_DOCUMENT(createAttributeNS("http://foo/", "bar"))
       
  1101     TEST_NULL_DOCUMENT(createCDATASection("foo"))
       
  1102     TEST_NULL_DOCUMENT(createComment("foo"))
       
  1103     TEST_NULL_DOCUMENT(createDocumentFragment())
       
  1104     TEST_NULL_DOCUMENT(createElement("foo"))
       
  1105     TEST_NULL_DOCUMENT(createElementNS("http://foo/", "foo"))
       
  1106     TEST_NULL_DOCUMENT(createEntityReference("foo"))
       
  1107     TEST_NULL_DOCUMENT(createProcessingInstruction("foo", "bar"))
       
  1108     TEST_NULL_DOCUMENT(createTextNode("foo"))
       
  1109     QDomDocument doc2;
       
  1110     QDomElement elt = doc2.createElement("foo");
       
  1111     doc2.appendChild(elt);
       
  1112     TEST_NULL_DOCUMENT(importNode(elt, true))
       
  1113 }
       
  1114 
       
  1115 #undef TEST_NULL_DOCUMENT
       
  1116 
       
  1117 void tst_QDom::invalidName_data()
       
  1118 {
       
  1119     QTest::addColumn<QString>("in_name");
       
  1120     QTest::addColumn<bool>("ok_AcceptInvalidChars");
       
  1121     QTest::addColumn<bool>("ok_DropInvalidChars");
       
  1122     QTest::addColumn<bool>("ok_ReturnNullNode");
       
  1123     QTest::addColumn<QString>("out_name");
       
  1124 
       
  1125     QTest::newRow( "foo" )     << QString("foo")     << true  << true  << true  << QString("foo");
       
  1126     QTest::newRow( "_f.o-o:" ) << QString("_f.o-o:") << true  << true  << true  << QString("_f.o-o:");
       
  1127     QTest::newRow( "...:." )   << QString("...:.")   << true  << true  << false << QString(":.");
       
  1128     QTest::newRow( "empty" )   << QString()          << false << false << false << QString();
       
  1129     QTest::newRow( "~f~o~o~" ) << QString("~f~o~o~") << true  << true  << false << QString("foo");
       
  1130     QTest::newRow( "~" )       << QString("~")       << true  << false << false << QString();
       
  1131     QTest::newRow( "..." )     << QString("...")     << true  << false << false << QString();
       
  1132 }
       
  1133 
       
  1134 void tst_QDom::invalidName()
       
  1135 {
       
  1136     QFETCH( QString, in_name );
       
  1137     QFETCH( bool, ok_AcceptInvalidChars );
       
  1138     QFETCH( bool, ok_DropInvalidChars );
       
  1139     QFETCH( bool, ok_ReturnNullNode );
       
  1140     QFETCH( QString, out_name );
       
  1141 
       
  1142     QDomImplementation impl;
       
  1143     QDomDocument doc;
       
  1144 
       
  1145     QDomImplementation::setInvalidDataPolicy(QDomImplementation::AcceptInvalidChars);
       
  1146 
       
  1147     {
       
  1148         QDomElement elt = doc.createElement(in_name);
       
  1149         QDomElement elt_ns = doc.createElementNS("foo", "foo:" + in_name);
       
  1150         QDomAttr attr = doc.createAttribute(in_name);
       
  1151         QDomAttr attr_ns = doc.createAttributeNS("foo",  "foo:" + in_name);
       
  1152         QDomEntityReference ref = doc.createEntityReference(in_name);
       
  1153 
       
  1154         QCOMPARE(!elt.isNull(), ok_AcceptInvalidChars);
       
  1155         QCOMPARE(!elt_ns.isNull(), ok_AcceptInvalidChars);
       
  1156         QCOMPARE(!attr.isNull(), ok_AcceptInvalidChars);
       
  1157         QCOMPARE(!attr_ns.isNull(), ok_AcceptInvalidChars);
       
  1158         QCOMPARE(!ref.isNull(), ok_AcceptInvalidChars);
       
  1159 
       
  1160         if (ok_AcceptInvalidChars) {
       
  1161             QCOMPARE(elt.tagName(), in_name);
       
  1162             QCOMPARE(elt_ns.tagName(), in_name);
       
  1163             QCOMPARE(attr.name(), in_name);
       
  1164             QCOMPARE(attr_ns.name(), in_name);
       
  1165             QCOMPARE(ref.nodeName(), in_name);
       
  1166         }
       
  1167     }
       
  1168 
       
  1169     QDomImplementation::setInvalidDataPolicy(QDomImplementation::DropInvalidChars);
       
  1170 
       
  1171     {
       
  1172         QDomElement elt = doc.createElement(in_name);
       
  1173         QDomElement elt_ns = doc.createElementNS("foo", "foo:" + in_name);
       
  1174         QDomAttr attr = doc.createAttribute(in_name);
       
  1175         QDomAttr attr_ns = doc.createAttributeNS("foo", "foo:" + in_name);
       
  1176         QDomEntityReference ref = doc.createEntityReference(in_name);
       
  1177 
       
  1178         QCOMPARE(!elt.isNull(), ok_DropInvalidChars);
       
  1179         QCOMPARE(!elt_ns.isNull(), ok_DropInvalidChars);
       
  1180         QCOMPARE(!attr.isNull(), ok_DropInvalidChars);
       
  1181         QCOMPARE(!attr_ns.isNull(), ok_DropInvalidChars);
       
  1182         QCOMPARE(!ref.isNull(), ok_DropInvalidChars);
       
  1183 
       
  1184         if (ok_DropInvalidChars) {
       
  1185             QCOMPARE(elt.tagName(), out_name);
       
  1186             QCOMPARE(elt_ns.tagName(), out_name);
       
  1187             QCOMPARE(attr.name(), out_name);
       
  1188             QCOMPARE(attr_ns.name(), out_name);
       
  1189             QCOMPARE(ref.nodeName(), out_name);
       
  1190         }
       
  1191     }
       
  1192 
       
  1193     QDomImplementation::setInvalidDataPolicy(QDomImplementation::ReturnNullNode);
       
  1194 
       
  1195     {
       
  1196         QDomElement elt = doc.createElement(in_name);
       
  1197         QDomElement elt_ns = doc.createElementNS("foo", "foo:" + in_name);
       
  1198         QDomAttr attr = doc.createAttribute(in_name);
       
  1199         QDomAttr attr_ns = doc.createAttributeNS("foo", "foo:" + in_name);
       
  1200         QDomEntityReference ref = doc.createEntityReference(in_name);
       
  1201 
       
  1202         QCOMPARE(!elt.isNull(), ok_ReturnNullNode);
       
  1203         QCOMPARE(!elt_ns.isNull(), ok_ReturnNullNode);
       
  1204         QCOMPARE(!attr.isNull(), ok_ReturnNullNode);
       
  1205         QCOMPARE(!attr_ns.isNull(), ok_ReturnNullNode);
       
  1206         QCOMPARE(!ref.isNull(), ok_ReturnNullNode);
       
  1207 
       
  1208         if (ok_ReturnNullNode) {
       
  1209             QCOMPARE(elt.tagName(), in_name);
       
  1210             QCOMPARE(elt_ns.tagName(), in_name);
       
  1211             QCOMPARE(attr.name(), in_name);
       
  1212             QCOMPARE(attr_ns.name(), in_name);
       
  1213             QCOMPARE(ref.nodeName(), in_name);
       
  1214         }
       
  1215     }
       
  1216 }
       
  1217 
       
  1218 void tst_QDom::invalidQualifiedName_data()
       
  1219 {
       
  1220     QTest::addColumn<QString>("in_name");
       
  1221     QTest::addColumn<bool>("ok_AcceptInvalidChars");
       
  1222     QTest::addColumn<bool>("ok_DropInvalidChars");
       
  1223     QTest::addColumn<bool>("ok_ReturnNullNode");
       
  1224     QTest::addColumn<QString>("out_name");
       
  1225 
       
  1226     QTest::newRow( "foo" )     << QString("foo")      << true  << true  << true  << QString("foo");
       
  1227     QTest::newRow( "foo:bar" ) << QString("foo:bar")  << true  << true  << true  << QString("foo:bar");
       
  1228     QTest::newRow( "bar:" )    << QString("bar:")     << false << false << false << QString();
       
  1229     QTest::newRow( ":" )       << QString(":")        << false << false << false << QString();
       
  1230     QTest::newRow( "empty" )   << QString()           << false << false << false << QString();
       
  1231     QTest::newRow("foo:...:.") << QString("foo:...:.")<< true  << true  << false << QString("foo::.");
       
  1232     QTest::newRow("foo:~")     << QString("foo:~")    << true  << false << false << QString();
       
  1233     QTest::newRow("foo:.~")    << QString("foo:.~")   << true  << false << false << QString();
       
  1234 }
       
  1235 
       
  1236 void tst_QDom::invalidQualifiedName()
       
  1237 {
       
  1238     QFETCH( QString, in_name );
       
  1239     QFETCH( bool, ok_AcceptInvalidChars );
       
  1240     QFETCH( bool, ok_DropInvalidChars );
       
  1241     QFETCH( bool, ok_ReturnNullNode );
       
  1242     QFETCH( QString, out_name );
       
  1243 
       
  1244     QDomImplementation impl;
       
  1245     QDomDocument doc;
       
  1246 
       
  1247     QDomImplementation::setInvalidDataPolicy(QDomImplementation::AcceptInvalidChars);
       
  1248 
       
  1249     {
       
  1250         QDomElement elt_ns = doc.createElementNS("foo", in_name);
       
  1251         QDomAttr attr_ns = doc.createAttributeNS("foo", in_name);
       
  1252         QDomDocumentType doctype = impl.createDocumentType(in_name, "foo", "bar");
       
  1253         QDomDocument doc2 = impl.createDocument("foo", in_name, doctype);
       
  1254 
       
  1255         QCOMPARE(!elt_ns.isNull(), ok_AcceptInvalidChars);
       
  1256         QCOMPARE(!attr_ns.isNull(), ok_AcceptInvalidChars);
       
  1257         QCOMPARE(!doctype.isNull(), ok_AcceptInvalidChars);
       
  1258         QCOMPARE(!doc2.isNull(), ok_AcceptInvalidChars);
       
  1259 
       
  1260         if (ok_AcceptInvalidChars) {
       
  1261             QCOMPARE(elt_ns.nodeName(), in_name);
       
  1262             QCOMPARE(attr_ns.nodeName(), in_name);
       
  1263             QCOMPARE(doctype.name(), in_name);
       
  1264             QCOMPARE(doc2.documentElement().nodeName(), in_name);
       
  1265         }
       
  1266     }
       
  1267 
       
  1268     QDomImplementation::setInvalidDataPolicy(QDomImplementation::DropInvalidChars);
       
  1269 
       
  1270     {
       
  1271         QDomElement elt_ns = doc.createElementNS("foo", in_name);
       
  1272         QDomAttr attr_ns = doc.createAttributeNS("foo", in_name);
       
  1273         QDomDocumentType doctype = impl.createDocumentType(in_name, "foo", "bar");
       
  1274         QDomDocument doc2 = impl.createDocument("foo", in_name, doctype);
       
  1275 
       
  1276         QCOMPARE(!elt_ns.isNull(), ok_DropInvalidChars);
       
  1277         QCOMPARE(!attr_ns.isNull(), ok_DropInvalidChars);
       
  1278         QCOMPARE(!doctype.isNull(), ok_DropInvalidChars);
       
  1279         QCOMPARE(!doc2.isNull(), ok_DropInvalidChars);
       
  1280 
       
  1281         if (ok_DropInvalidChars) {
       
  1282             QCOMPARE(elt_ns.nodeName(), out_name);
       
  1283             QCOMPARE(attr_ns.nodeName(), out_name);
       
  1284             QCOMPARE(doctype.name(), out_name);
       
  1285             QCOMPARE(doc2.documentElement().nodeName(), out_name);
       
  1286         }
       
  1287     }
       
  1288 
       
  1289     QDomImplementation::setInvalidDataPolicy(QDomImplementation::ReturnNullNode);
       
  1290 
       
  1291     {
       
  1292         QDomElement elt_ns = doc.createElementNS("foo", in_name);
       
  1293         QDomAttr attr_ns = doc.createAttributeNS("foo", in_name);
       
  1294         QDomDocumentType doctype = impl.createDocumentType(in_name, "foo", "bar");
       
  1295         QDomDocument doc2 = impl.createDocument("foo", in_name, doctype);
       
  1296 
       
  1297         QCOMPARE(!elt_ns.isNull(), ok_ReturnNullNode);
       
  1298         QCOMPARE(!attr_ns.isNull(), ok_ReturnNullNode);
       
  1299         QCOMPARE(!doctype.isNull(), ok_ReturnNullNode);
       
  1300         QCOMPARE(!doc2.isNull(), ok_ReturnNullNode);
       
  1301 
       
  1302         if (ok_ReturnNullNode) {
       
  1303             QCOMPARE(elt_ns.nodeName(), in_name);
       
  1304             QCOMPARE(attr_ns.nodeName(), in_name);
       
  1305             QCOMPARE(doctype.name(), in_name);
       
  1306             QCOMPARE(doc2.documentElement().nodeName(), in_name);
       
  1307         }
       
  1308     }
       
  1309 }
       
  1310 
       
  1311 void tst_QDom::invalidCharData_data()
       
  1312 {
       
  1313     QTest::addColumn<QString>("in_text");
       
  1314     QTest::addColumn<bool>("ok_AcceptInvalidChars");
       
  1315     QTest::addColumn<bool>("ok_DropInvalidChars");
       
  1316     QTest::addColumn<bool>("ok_ReturnNullNode");
       
  1317     QTest::addColumn<QString>("out_text");
       
  1318 
       
  1319     QTest::newRow( "foo" )     << QString("foo")       << true  << true  << true  << QString("foo");
       
  1320     QTest::newRow( "f<o&o" )   << QString("f<o&o")     << true  << true  << true  << QString("f<o&o");
       
  1321     QTest::newRow( "empty" )   << QString()            << true  << true  << true  << QString();
       
  1322     QTest::newRow("f\\x07o\\x02")<< QString("f\x07o\x02")<< true  << true  << false << QString("fo");
       
  1323 }
       
  1324 
       
  1325 void tst_QDom::invalidCharData()
       
  1326 {
       
  1327     QFETCH( QString, in_text );
       
  1328     QFETCH( bool, ok_AcceptInvalidChars );
       
  1329     QFETCH( bool, ok_DropInvalidChars );
       
  1330     QFETCH( bool, ok_ReturnNullNode );
       
  1331     QFETCH( QString, out_text );
       
  1332 
       
  1333     QDomDocument doc;
       
  1334 
       
  1335     QDomImplementation::setInvalidDataPolicy(QDomImplementation::AcceptInvalidChars);
       
  1336 
       
  1337     {
       
  1338         QDomText text_elt = doc.createTextNode(in_text);
       
  1339         QCOMPARE(!text_elt.isNull(), ok_AcceptInvalidChars);
       
  1340         if (ok_AcceptInvalidChars) {
       
  1341             QCOMPARE(text_elt.nodeValue(), in_text);
       
  1342         }
       
  1343     }
       
  1344 
       
  1345     QDomImplementation::setInvalidDataPolicy(QDomImplementation::DropInvalidChars);
       
  1346 
       
  1347     {
       
  1348         QDomText text_elt = doc.createTextNode(in_text);
       
  1349         QCOMPARE(!text_elt.isNull(), ok_DropInvalidChars);
       
  1350         if (ok_DropInvalidChars) {
       
  1351             QCOMPARE(text_elt.nodeValue(), out_text);
       
  1352         }
       
  1353     }
       
  1354 
       
  1355     QDomImplementation::setInvalidDataPolicy(QDomImplementation::ReturnNullNode);
       
  1356 
       
  1357     {
       
  1358         QDomText text_elt = doc.createTextNode(in_text);
       
  1359         QCOMPARE(!text_elt.isNull(), ok_ReturnNullNode);
       
  1360         if (ok_ReturnNullNode) {
       
  1361             QCOMPARE(text_elt.nodeValue(), in_text);
       
  1362         }
       
  1363     }
       
  1364 }
       
  1365 
       
  1366 void tst_QDom::roundTripAttributes() const
       
  1367 {
       
  1368     /* Create an attribute via the QDom API with weird whitespace content. */
       
  1369     QDomImplementation impl;
       
  1370 
       
  1371     QDomDocument doc(impl.createDocument("", "localName", QDomDocumentType()));
       
  1372 
       
  1373     QDomElement e(doc.documentElement());
       
  1374 
       
  1375     QString ws;
       
  1376     ws.reserve(8);
       
  1377     ws.append(QChar(0x20));
       
  1378     ws.append(QChar(0x20));
       
  1379     ws.append(QChar(0x20));
       
  1380     ws.append(QChar(0xD));
       
  1381     ws.append(QChar(0xA));
       
  1382     ws.append(QChar(0x9));
       
  1383     ws.append(QChar(0x20));
       
  1384     ws.append(QChar(0x20));
       
  1385 
       
  1386     e.setAttribute("attr", ws);
       
  1387 
       
  1388     QByteArray serialized;
       
  1389     QBuffer buffer(&serialized);
       
  1390     buffer.open(QIODevice::WriteOnly);
       
  1391     QTextStream stream(&buffer);
       
  1392 
       
  1393     doc.save(stream, 0);
       
  1394     stream.flush();
       
  1395 
       
  1396     const QByteArray expected("<localName xmlns=\"\" attr=\"   &#xd;&#xa;&#x9;  \"/>\n");
       
  1397     QCOMPARE(QString::fromLatin1(serialized.constData()), QString::fromLatin1(expected.constData()));
       
  1398 }
       
  1399 
       
  1400 void tst_QDom::normalizeEndOfLine() const
       
  1401 {
       
  1402     QByteArray input("<a>\r\nc\rc\ra\na</a>");
       
  1403 
       
  1404     QBuffer buffer(&input);
       
  1405     QVERIFY(buffer.open(QIODevice::ReadOnly));
       
  1406 
       
  1407     QDomDocument doc;
       
  1408     QVERIFY(doc.setContent(&buffer, true));
       
  1409 
       
  1410     const QString expected(QLatin1String("<a>\nc\nc\na\na</a>"));
       
  1411 
       
  1412     // ### Qt 5: fix this, if we keep QDom at all
       
  1413     QEXPECT_FAIL("", "The parser doesn't perform newline normalization. Fixing that would change behavior.", Continue);
       
  1414     QCOMPARE(doc.documentElement().text(), expected);
       
  1415 }
       
  1416 
       
  1417 void tst_QDom::normalizeAttributes() const
       
  1418 {
       
  1419     QByteArray data("<element attribute=\"a\na\"/>");
       
  1420     QBuffer buffer(&data);
       
  1421 
       
  1422     QVERIFY(buffer.open(QIODevice::ReadOnly));
       
  1423 
       
  1424     QDomDocument doc;
       
  1425     QVERIFY(doc.setContent(&buffer, true));
       
  1426 
       
  1427     // ### Qt 5: fix this, if we keep QDom at all
       
  1428     QEXPECT_FAIL("", "The parser doesn't perform Attribute Value Normalization. Fixing that would change behavior.", Continue);
       
  1429     QCOMPARE(doc.documentElement().attribute(QLatin1String("attribute")), QString::fromLatin1("a a"));
       
  1430 }
       
  1431 
       
  1432 void tst_QDom::serializeWeirdEOL() const
       
  1433 {
       
  1434     QDomImplementation impl;
       
  1435 
       
  1436     QDomDocument doc(impl.createDocument("", "name", QDomDocumentType()));
       
  1437     QDomElement ele(doc.documentElement());
       
  1438     ele.appendChild(doc.createTextNode(QLatin1String("\r\nasd\nasd\rasd\n")));
       
  1439 
       
  1440     QByteArray output;
       
  1441     QBuffer writeBuffer(&output);
       
  1442     QVERIFY(writeBuffer.open(QIODevice::WriteOnly));
       
  1443     QTextStream stream(&writeBuffer);
       
  1444 
       
  1445     const QByteArray expected("<name xmlns=\"\">&#xd;\nasd\nasd&#xd;asd\n</name>\n");
       
  1446     doc.save(stream, 0);
       
  1447     QCOMPARE(QString::fromLatin1(output.constData()), QString::fromLatin1(expected.constData()));
       
  1448 }
       
  1449 
       
  1450 void tst_QDom::reparentAttribute() const
       
  1451 {
       
  1452     QDomImplementation impl;
       
  1453     QDomDocument doc(impl.createDocument("", "localName", QDomDocumentType()));
       
  1454 
       
  1455     QDomElement ele(doc.documentElement());
       
  1456     QDomAttr attr(doc.createAttribute("localName"));
       
  1457     ele.setAttributeNode(attr);
       
  1458 
       
  1459     QVERIFY(attr.ownerElement() == ele);
       
  1460     QVERIFY(attr.parentNode() == ele);
       
  1461 }
       
  1462 
       
  1463 void tst_QDom::serializeNamespaces() const
       
  1464 {
       
  1465     const char *const input = "<doc xmlns:b='http://example.com/'>"
       
  1466                               "<b:element b:name=''/>"
       
  1467                               "</doc>";
       
  1468 
       
  1469     QByteArray ba(input);
       
  1470     QBuffer buffer(&ba);
       
  1471 
       
  1472     QVERIFY(buffer.open(QIODevice::ReadOnly));
       
  1473 
       
  1474     QXmlInputSource source(&buffer);
       
  1475     QXmlSimpleReader reader;
       
  1476     reader.setFeature("http://xml.org/sax/features/namespaces", true);
       
  1477     reader.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
       
  1478 
       
  1479     QDomDocument doc;
       
  1480     QVERIFY(doc.setContent(&source, &reader));
       
  1481 
       
  1482     const QByteArray serialized(doc.toByteArray());
       
  1483 
       
  1484     QDomDocument doc2;
       
  1485     QVERIFY(doc2.setContent(doc.toString(), true));
       
  1486 
       
  1487     /* Here we test that it roundtrips. */
       
  1488     QVERIFY(isDeepEqual(doc2, doc));
       
  1489 
       
  1490     QDomDocument doc3;
       
  1491     QVERIFY(doc3.setContent(QString::fromLatin1(serialized.constData()), true));
       
  1492 
       
  1493     QVERIFY(isDeepEqual(doc3, doc));
       
  1494 }
       
  1495 
       
  1496 void tst_QDom::flagInvalidNamespaces() const
       
  1497 {
       
  1498     const char *const input = "<doc>"
       
  1499                               "<b:element xmlns:b='http://example.com/' b:name='' xmlns:b='http://example.com/'/>"
       
  1500                               "</doc>";
       
  1501 
       
  1502     QDomDocument doc;
       
  1503     QVERIFY(!doc.setContent(QString::fromLatin1(input, true)));
       
  1504     QEXPECT_FAIL("", "The parser doesn't flag identical qualified attribute names. Fixing this would change behavior.", Continue);
       
  1505     QVERIFY(!doc.setContent(QString::fromLatin1(input)));
       
  1506 }
       
  1507 
       
  1508 void tst_QDom::flagUndeclaredNamespace() const
       
  1509 {
       
  1510     /* Note, prefix 'a' is not declared. */
       
  1511     const char *const input = "<a:doc xmlns:b='http://example.com/'>"
       
  1512                               "<b:element b:name=''/>"
       
  1513                               "</a:doc>";
       
  1514 
       
  1515     QByteArray ba(input);
       
  1516     QBuffer buffer(&ba);
       
  1517 
       
  1518     QVERIFY(buffer.open(QIODevice::ReadOnly));
       
  1519 
       
  1520     QXmlInputSource source(&buffer);
       
  1521     QXmlSimpleReader reader;
       
  1522     reader.setFeature("http://xml.org/sax/features/namespaces", true);
       
  1523     reader.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
       
  1524 
       
  1525     QDomDocument doc;
       
  1526     QEXPECT_FAIL("", "The parser doesn't flag not declared prefixes. Fixing this would change behavior.", Continue);
       
  1527     QVERIFY(!doc.setContent(&source, &reader));
       
  1528 }
       
  1529 
       
  1530 void tst_QDom::indentComments() const
       
  1531 {
       
  1532     /* We test that:
       
  1533      *
       
  1534      * - Whitespace is not added if a text node appears after a comment.
       
  1535      * - Whitespace is not added if a text node appears before a comment.
       
  1536      * - Indentation depth is linear with level depth.
       
  1537      */
       
  1538     const char *const input = "<e>"
       
  1539                                   "<!-- A Comment -->"
       
  1540                                   "<b><!-- deep --></b>"
       
  1541                                   "textNode"
       
  1542                                   "<!-- Another Comment -->"
       
  1543                                   "<!-- Another Comment2 -->"
       
  1544                                   "textNode2"
       
  1545                               "</e>";
       
  1546     const char *const expected = "<e>\n"
       
  1547                                  "     <!-- A Comment -->\n"
       
  1548                                  "     <b>\n"
       
  1549                                  "          <!-- deep -->\n"
       
  1550                                  "     </b>"
       
  1551                                  "textNode"
       
  1552                                  "<!-- Another Comment -->\n"
       
  1553                                  "     <!-- Another Comment2 -->"
       
  1554                                  "textNode2"
       
  1555                                  "</e>\n";
       
  1556     QDomDocument doc;
       
  1557     QVERIFY(doc.setContent(QString::fromLatin1(input)));
       
  1558 
       
  1559     const QString serialized(doc.toString(5));
       
  1560 
       
  1561     QCOMPARE(serialized, QString::fromLatin1(expected));
       
  1562 }
       
  1563 
       
  1564 void tst_QDom::checkLiveness() const
       
  1565 {
       
  1566     QDomImplementation impl;
       
  1567 
       
  1568     QDomDocument doc(impl.createDocument(QString(), "doc", QDomDocumentType()));
       
  1569     QDomElement ele(doc.documentElement());
       
  1570 
       
  1571     const QDomElement e1(doc.createElement("name"));
       
  1572     const QDomElement e2(doc.createElement("name"));
       
  1573     const QDomText t1(doc.createTextNode("content"));
       
  1574 
       
  1575     ele.appendChild(e1);
       
  1576     ele.appendChild(t1);
       
  1577     ele.appendChild(e2);
       
  1578 
       
  1579     const QDomNodeList children(ele.childNodes());
       
  1580     QCOMPARE(children.count(), 3);
       
  1581 
       
  1582     ele.removeChild(e1);
       
  1583 
       
  1584     QCOMPARE(children.count(), 2);
       
  1585     QCOMPARE(children.at(0), static_cast<const QDomNode &>(t1));
       
  1586     QCOMPARE(children.at(1), static_cast<const QDomNode &>(e2));
       
  1587 }
       
  1588 
       
  1589 void tst_QDom::reportDuplicateAttributes() const
       
  1590 {
       
  1591     QDomDocument dd;
       
  1592     bool isSuccess = dd.setContent(QLatin1String("<test x=\"1\" x=\"2\"/>"));
       
  1593 
       
  1594     QEXPECT_FAIL("", "The parser doesn't flag duplicate attributes. Fixing this would change behavior.", Continue);
       
  1595     QVERIFY2(!isSuccess, "Duplicate attributes are well-formedness errors, and should be reported as such.");
       
  1596 }
       
  1597 
       
  1598 QDomDocument tst_QDom::doc(const QString &title, const QByteArray &ba)
       
  1599 {
       
  1600     QDomDocument doc(title);
       
  1601     const bool ret = doc.setContent(ba, true);
       
  1602     Q_ASSERT(ret);
       
  1603     return doc;
       
  1604 }
       
  1605 
       
  1606 void tst_QDom::namespacedAttributes() const
       
  1607 {
       
  1608     static const char *const xml =
       
  1609         "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>\n"
       
  1610         "<xan:td xmlns:xan=\"http://www.someurl.com/Something\" "
       
  1611         "        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
       
  1612         "        xsi:schemaLocation=\"http://www.someurl.com/Something/../../xml/td.xsd\" "
       
  1613         "        xmlns:xi=\"http://www.w3.org/2001/XInclude\" "
       
  1614         "        xmlns=\"http://www.someurl.com/Something\">\n"
       
  1615         "  <Title displayLabel='Title' >>>> SIMPLE BASIC OP - SEND - DUT AS SINK</Title>\n"
       
  1616         "</xan:td>\n";
       
  1617 
       
  1618     QDomDocument one = doc("document", xml);
       
  1619     QDomDocument two = doc("document2", one.toByteArray(2));
       
  1620 
       
  1621     QVERIFY(isDeepEqual(one, two));
       
  1622 }
       
  1623 
       
  1624 void tst_QDom::appendChildFromToDocument() const
       
  1625 {
       
  1626     QDomDocument doc;
       
  1627     const QByteArray input("<e/>");
       
  1628 
       
  1629     doc.setContent(input);
       
  1630 
       
  1631     QDomDocument doc2(doc.documentElement().toDocument());
       
  1632     QDomElement element = doc2.createElement("name");
       
  1633     element.setAttribute("name", "value");
       
  1634     doc.documentElement().appendChild(element);
       
  1635 }
       
  1636 
       
  1637 void tst_QDom::iterateCDATA() const
       
  1638 {
       
  1639     const QByteArray input("<e><![CDATA[data]]></e>");
       
  1640 
       
  1641     QDomDocument doc;
       
  1642     QVERIFY(doc.setContent(input));
       
  1643     QCOMPARE(doc.toString(), QString("<e><![CDATA[data]]></e>\n"));
       
  1644 
       
  1645     const QDomElement element(doc.documentElement());
       
  1646     QVERIFY(!element.isNull());
       
  1647 
       
  1648     /* The node at element.childNodes().at(0) is not an element,
       
  1649      * it's a CDATA section. */
       
  1650     const QDomElement child(element.childNodes().at(0).toElement());
       
  1651     QVERIFY(child.isNull());
       
  1652 
       
  1653     QVERIFY(element.childNodes().at(0).isCDATASection());
       
  1654 }
       
  1655 
       
  1656 /*!
       
  1657   \internal
       
  1658   \since 4.4
       
  1659   \brief This function cannot be factored into appendDocumentNode(). The
       
  1660          invocation of constructors/destructors is part of triggering the bug.
       
  1661  */
       
  1662 QDomDocument tst_QDom::generateRequest()
       
  1663 {
       
  1664     QDomDocument doc;
       
  1665     QDomElement elem = doc.createElement("test_elem");
       
  1666 
       
  1667     elem.setAttribute("name", "value");
       
  1668     doc.appendChild(elem);
       
  1669     return doc;
       
  1670 }
       
  1671 
       
  1672 void tst_QDom::appendDocumentNode() const
       
  1673 {
       
  1674     QDomDocument doc;
       
  1675     QDomDocument xml = generateRequest();
       
  1676     QDomElement elem = doc.createElement("document");
       
  1677 
       
  1678     doc.appendChild(elem);
       
  1679 
       
  1680     Q_ASSERT(!xml.isNull());
       
  1681     const QString expected(QLatin1String("<document>\n<test_elem name=\"value\"/>\n</document>\n"));
       
  1682 
       
  1683     elem.appendChild(xml);
       
  1684     QCOMPARE(doc.childNodes().count(), 1);
       
  1685     QCOMPARE(doc.toString(0), expected);
       
  1686 
       
  1687     elem.appendChild(xml.firstChild());
       
  1688     QCOMPARE(doc.childNodes().count(), 1);
       
  1689     QCOMPARE(doc.toString(0), expected);
       
  1690 }
       
  1691 
       
  1692 static const QChar umlautName[] =
       
  1693 {
       
  1694     'a', 0xfc, 'b'
       
  1695 };
       
  1696 
       
  1697 /*!
       
  1698   \internal
       
  1699  
       
  1700   Write a german umlaut to a QByteArray, via a QTextStream.
       
  1701  */
       
  1702 void tst_QDom::germanUmlautToByteArray() const
       
  1703 {
       
  1704     QCOMPARE(ulong(sizeof(umlautName) /  sizeof(QChar)), ulong(3));
       
  1705     const QString name(umlautName, 3);
       
  1706 
       
  1707     QDomDocument d;
       
  1708     d.appendChild(d.createElement(name));
       
  1709     QByteArray data;
       
  1710     QBuffer buffer(&data);
       
  1711     QVERIFY(buffer.open(QIODevice::WriteOnly));
       
  1712     QTextStream ts(&buffer);
       
  1713     ts.setCodec("UTF-8");
       
  1714     ts << d.toString();
       
  1715     buffer.close();
       
  1716     
       
  1717     QByteArray baseline("<a");
       
  1718 
       
  1719     /* http://www.fileformat.info/info/unicode/char/00FC/index.htm */
       
  1720     baseline += 0xC3;
       
  1721     baseline += 0xBC;
       
  1722     baseline += "b/>\n";
       
  1723 
       
  1724     QCOMPARE(data, baseline);
       
  1725 }
       
  1726 
       
  1727 /*!
       
  1728   \internal
       
  1729  
       
  1730   Write a german umlaut to a QFile, via a QTextStream.
       
  1731  */
       
  1732 void tst_QDom::germanUmlautToFile() const
       
  1733 {
       
  1734     /* http://www.fileformat.info/info/unicode/char/00FC/index.htm */
       
  1735     QString name(QLatin1String("german"));
       
  1736     name += QChar(0xFC);
       
  1737     name += QLatin1String("umlaut");
       
  1738     QCOMPARE(name.length(), 13);
       
  1739 
       
  1740     QDomDocument d("test");
       
  1741     d.appendChild(d.createElement(name));
       
  1742     QFile file("germanUmlautToFile.xml");
       
  1743     QVERIFY(file.open(QIODevice::WriteOnly));
       
  1744     QTextStream ts(&file);
       
  1745     ts.setCodec("UTF-8");
       
  1746     ts << d.toString();
       
  1747     file.close();
       
  1748 
       
  1749     QFile inFile("germanUmlautToFile.xml");
       
  1750     QVERIFY(inFile.open(QIODevice::ReadOnly));
       
  1751 
       
  1752     QString baseline(QLatin1String("<!DOCTYPE test>\n<german"));
       
  1753     baseline += QChar(0xFC);
       
  1754     baseline += QLatin1String("umlaut/>\n");
       
  1755 
       
  1756     const QByteArray in(inFile.readAll());
       
  1757     /* Check that it was wwritten out correctly. */
       
  1758     QCOMPARE(in.length(), 34);
       
  1759     QCOMPARE(in, baseline.toUtf8());
       
  1760     inFile.close();
       
  1761 
       
  1762     /* Check that we read it in correctly with QDomDocument::setContent(). */
       
  1763     QVERIFY(inFile.open(QIODevice::ReadOnly));
       
  1764     QDomDocument dd;
       
  1765     QVERIFY(dd.setContent(&inFile));
       
  1766 
       
  1767     QCOMPARE(dd.toString(), baseline);
       
  1768 }
       
  1769 
       
  1770 void tst_QDom::setInvalidDataPolicy() const
       
  1771 {
       
  1772     QDomImplementation::setInvalidDataPolicy(QDomImplementation::ReturnNullNode); 
       
  1773     QDomDocument doc; 
       
  1774     QDomElement elem = doc.createElement("invalid name"); 
       
  1775     QVERIFY(elem.isNull());
       
  1776 }
       
  1777 
       
  1778 void tst_QDom::crashInSetContent() const
       
  1779 {
       
  1780     QDomImplementation::setInvalidDataPolicy(QDomImplementation::ReturnNullNode); 
       
  1781     QDomDocument docImport;
       
  1782 
       
  1783     QVERIFY(docImport.setContent(QLatin1String("<?xml version=\"1.0\"?><e/>")));
       
  1784 }
       
  1785 
       
  1786 void tst_QDom::doubleNamespaceDeclarations() const
       
  1787 {
       
  1788     QDomDocument doc; 
       
  1789 
       
  1790     QFile file(SRCDIR "doubleNamespaces.xml" );
       
  1791     QVERIFY(file.open(QIODevice::ReadOnly));
       
  1792 
       
  1793     QXmlSimpleReader reader; 
       
  1794 
       
  1795     QXmlInputSource source(&file);
       
  1796     QVERIFY(doc.setContent(&source, &reader));
       
  1797 
       
  1798     QVERIFY(doc.toString(0) == QString::fromLatin1("<a>\n<b p:c=\"\" xmlns:p=\"NS\" p:d=\"\"/>\n</a>\n") ||
       
  1799             doc.toString(0) == QString::fromLatin1("<a>\n<b p:c=\"\" p:d=\"\" xmlns:p=\"NS\"/>\n</a>\n"));
       
  1800 }
       
  1801 
       
  1802 void tst_QDom::setContentQXmlReaderOverload() const
       
  1803 {
       
  1804     QDomDocument doc;
       
  1805 
       
  1806     QXmlSimpleReader reader;
       
  1807     QXmlInputSource data;
       
  1808     data.setData(QByteArray("<e/>"));
       
  1809 
       
  1810     doc.setContent(&data, true);
       
  1811     QCOMPARE(doc.documentElement().nodeName(), QString::fromLatin1("e"));
       
  1812 }
       
  1813 
       
  1814 void tst_QDom::cleanupTestCase() const
       
  1815 {
       
  1816     QFile::remove("germanUmlautToFile.xml");
       
  1817 }
       
  1818 
       
  1819 void tst_QDom::toStringWithoutNewlines() const
       
  1820 {
       
  1821     QDomDocument doc;
       
  1822     doc.setContent(QLatin1String("<doc><e/></doc>"));
       
  1823 
       
  1824     QCOMPARE(doc.toString(0), QString::fromLatin1("<doc>\n<e/>\n</doc>\n"));
       
  1825     QCOMPARE(doc.toString(-1), QString::fromLatin1("<doc><e/></doc>"));
       
  1826 }
       
  1827 
       
  1828 void tst_QDom::checkIntOverflow() const
       
  1829 {
       
  1830     /* This test takes a *very* long time to run, so it is at best a manual
       
  1831      * test. */
       
  1832     return;
       
  1833 
       
  1834     /* QDom used an internal global int which overflowed. So iterate until an
       
  1835      * uint wrapsaround. */
       
  1836     const QString xmlMessage(QLatin1String("<test/>"));
       
  1837 
       
  1838     bool hasWrapped = false;
       
  1839     for(uint i = 1; i != 0; ++i)
       
  1840     {
       
  1841         /* We want to exit the second time, not loop infinitely. */
       
  1842         if(i == 1 && hasWrapped)
       
  1843             break;
       
  1844         else
       
  1845             hasWrapped = true;
       
  1846 
       
  1847         QDomDocument doc;
       
  1848         QVERIFY(doc.setContent(xmlMessage));
       
  1849 
       
  1850         const QDomNodeList nl(doc.elementsByTagName(QLatin1String("test")));
       
  1851         QCOMPARE(nl.length(), uint(1));
       
  1852     }
       
  1853 }
       
  1854 
       
  1855 void tst_QDom::setContentWhitespace() const
       
  1856 {
       
  1857     QFETCH(QString, doc);
       
  1858     QFETCH(bool, expectedValidity);
       
  1859 
       
  1860     QDomDocument domDoc;
       
  1861 
       
  1862     QCOMPARE(domDoc.setContent(doc), expectedValidity);
       
  1863 
       
  1864     if(expectedValidity)
       
  1865         QCOMPARE(domDoc.documentElement().nodeName(), QString::fromLatin1("e"));
       
  1866 }
       
  1867 
       
  1868 void tst_QDom::setContentWhitespace_data() const
       
  1869 {
       
  1870     QTest::addColumn<QString>("doc");
       
  1871     QTest::addColumn<bool>("expectedValidity");
       
  1872 
       
  1873     QTest::newRow("") << QString::fromLatin1(" <e/>")           << true;
       
  1874     QTest::newRow("") << QString::fromLatin1("  <e/>")          << true;
       
  1875     QTest::newRow("") << QString::fromLatin1("   <e/>")         << true;
       
  1876     QTest::newRow("") << QString::fromLatin1("    <e/>")        << true;
       
  1877     QTest::newRow("") << QString::fromLatin1("\n<e/>")          << true;
       
  1878     QTest::newRow("") << QString::fromLatin1("\n\n<e/>")        << true;
       
  1879     QTest::newRow("") << QString::fromLatin1("\n\n\n<e/>")      << true;
       
  1880     QTest::newRow("") << QString::fromLatin1("\n\n\n\n<e/>")    << true;
       
  1881     QTest::newRow("") << QString::fromLatin1("\t<e/>")          << true;
       
  1882     QTest::newRow("") << QString::fromLatin1("\t\t<e/>")        << true;
       
  1883     QTest::newRow("") << QString::fromLatin1("\t\t\t<e/>")      << true;
       
  1884     QTest::newRow("") << QString::fromLatin1("\t\t\t\t<e/>")    << true;
       
  1885 
       
  1886     /* With XML prolog. */
       
  1887     QTest::newRow("") << QString::fromLatin1("<?xml version='1.0' ?><e/>")          << true;
       
  1888 
       
  1889     QTest::newRow("") << QString::fromLatin1(" <?xml version='1.0' ?><e/>")         << false;
       
  1890     QTest::newRow("") << QString::fromLatin1("  <?xml version='1.0' ?><e/>")        << false;
       
  1891     QTest::newRow("") << QString::fromLatin1("   <?xml version='1.0' ?><e/>")       << false;
       
  1892     QTest::newRow("") << QString::fromLatin1("    <?xml version='1.0' ?><e/>")      << false;
       
  1893     QTest::newRow("") << QString::fromLatin1("\n<?xml version='1.0' ?><e/>")        << false;
       
  1894     QTest::newRow("") << QString::fromLatin1("\n\n<?xml version='1.0' ?><e/>")      << false;
       
  1895     QTest::newRow("") << QString::fromLatin1("\n\n\n<?xml version='1.0' ?><e/>")    << false;
       
  1896     QTest::newRow("") << QString::fromLatin1("\n\n\n\n<?xml version='1.0' ?><e/>")  << false;
       
  1897     QTest::newRow("") << QString::fromLatin1("\t<?xml version='1.0' ?><e/>")        << false;
       
  1898     QTest::newRow("") << QString::fromLatin1("\t\t<?xml version='1.0' ?><e/>")      << false;
       
  1899     QTest::newRow("") << QString::fromLatin1("\t\t\t<?xml version='1.0' ?><e/>")    << false;
       
  1900     QTest::newRow("") << QString::fromLatin1("\t\t\t\t<?xml version='1.0' ?><e/>")  << false;
       
  1901 }
       
  1902 
       
  1903 void tst_QDom::taskQTBUG4595_dontAssertWhenDocumentSpecifiesUnknownEncoding() const
       
  1904 {
       
  1905     QString xmlWithUnknownEncoding("<?xml version='1.0' encoding='unknown-encoding'?>"
       
  1906                                    "<foo>"
       
  1907                                    " <bar>How will this sentence be handled?</bar>"
       
  1908                                    "</foo>");
       
  1909     QDomDocument d;
       
  1910     QVERIFY(d.setContent(xmlWithUnknownEncoding));
       
  1911 
       
  1912     QString dontAssert = d.toString(); // this should not assert
       
  1913     QVERIFY(true);
       
  1914 }
       
  1915 
       
  1916 QTEST_MAIN(tst_QDom)
       
  1917 #include "tst_qdom.moc"