|
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 & 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 & 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 & 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 & 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 & 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><b>foo</b>>]]></body>\n" |
|
250 "</message>\n") |
|
251 << QStringList() << QStringList() |
|
252 << QString("<message>\n" |
|
253 " <body><b>foo</b>>]]></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=\" 
	 \"/>\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=\"\">
\nasd\nasd
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" |