diff options
Diffstat (limited to 'tests/auto/xml/dom')
-rw-r--r-- | tests/auto/xml/dom/CMakeLists.txt | 3 | ||||
-rw-r--r-- | tests/auto/xml/dom/qdom/CMakeLists.txt | 12 | ||||
-rw-r--r-- | tests/auto/xml/dom/qdom/tst_qdom.cpp | 456 |
3 files changed, 398 insertions, 73 deletions
diff --git a/tests/auto/xml/dom/CMakeLists.txt b/tests/auto/xml/dom/CMakeLists.txt index 08a7621e88..daa837c2cf 100644 --- a/tests/auto/xml/dom/CMakeLists.txt +++ b/tests/auto/xml/dom/CMakeLists.txt @@ -1,3 +1,4 @@ -# Generated from dom.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause add_subdirectory(qdom) diff --git a/tests/auto/xml/dom/qdom/CMakeLists.txt b/tests/auto/xml/dom/qdom/CMakeLists.txt index d72ef57332..4eea988cc3 100644 --- a/tests/auto/xml/dom/qdom/CMakeLists.txt +++ b/tests/auto/xml/dom/qdom/CMakeLists.txt @@ -1,9 +1,16 @@ -# Generated from qdom.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qdom Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qdom LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + # Collect test data file(GLOB_RECURSE test_data_glob RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} @@ -15,7 +22,8 @@ list(APPEND test_data "umlaut.xml") qt_internal_add_test(tst_qdom SOURCES tst_qdom.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Xml + Qt::XmlPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/xml/dom/qdom/tst_qdom.cpp b/tests/auto/xml/dom/qdom/tst_qdom.cpp index c44626e161..b73dbc49e2 100644 --- a/tests/auto/xml/dom/qdom/tst_qdom.cpp +++ b/tests/auto/xml/dom/qdom/tst_qdom.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QBuffer> @@ -34,15 +9,19 @@ #include <QFile> #include <QList> #include <QRegularExpression> +#include <QScopeGuard> #include <QTextStream> #include <QTest> #include <QtXml> #include <QVariant> #include <cmath> +#include <QtXml/private/qdom_p.h> QT_FORWARD_DECLARE_CLASS(QDomDocument) QT_FORWARD_DECLARE_CLASS(QDomNode) +using namespace Qt::StringLiterals; + class tst_QDom : public QObject { Q_OBJECT @@ -52,6 +31,11 @@ private slots: void namespacedAttributes() const; void setContent_data(); void setContent(); + void setContentOverloads(); + void parseOptions(); + void spacingOnlyNodes_data() const; + void spacingOnlyNodes() const; + void parseResult(); void toString_01_data(); void toString_01(); void toString_02_data(); @@ -85,8 +69,10 @@ private slots: void invalidQualifiedName(); void invalidCharData_data(); void invalidCharData(); + void nonBMPCharacters(); void roundTripAttributes() const; + void roundTripCDATA() const; void normalizeEndOfLine() const; void normalizeAttributes() const; void serializeWeirdEOL() const; @@ -111,12 +97,17 @@ private slots: void checkIntOverflow() const; void setContentWhitespace() const; void setContentWhitespace_data() const; + void setContentUnopenedQIODevice() const; void taskQTBUG4595_dontAssertWhenDocumentSpecifiesUnknownEncoding() const; void cloneDTD_QTBUG8398() const; void DTDNotationDecl(); void DTDEntityDecl(); + void DTDInternalSubset() const; + void DTDInternalSubset_data() const; void QTBUG49113_dontCrashWithNegativeIndex() const; + void standalone(); + void splitTextLeakMemory() const; void cleanupTestCase() const; @@ -190,7 +181,11 @@ void tst_QDom::setContent() QDomDocument domDoc; QXmlStreamReader reader(doc); - QVERIFY(domDoc.setContent(&reader, true)); +#if QT_DEPRECATED_SINCE(6, 8) + QT_IGNORE_DEPRECATIONS(domDoc.setContent(&reader, true);) +#else + QVERIFY(domDoc.setContent(&reader, QDomDocument::ParseOption::UseNamespaceProcessing)); +#endif // QT_DEPRECATED_SINCE(6, 8) QString eRes; QTextStream ts( &eRes, QIODevice::WriteOnly ); @@ -204,6 +199,190 @@ void tst_QDom::setContent() QVERIFY( domDoc1.setContent( doc ) ); QVERIFY( domDoc2.setContent( eRes ) ); QVERIFY( compareDocuments( domDoc1, domDoc2 ) ); + + // Test overload taking a QAnyStringView + QDomDocument domFromStringView; + QStringView stringView(doc); + QVERIFY(domFromStringView.setContent(stringView)); + QVERIFY(compareDocuments(domFromStringView, domDoc)); + + // Test overload taking a QByteArray + QDomDocument domFromByteArary; + QByteArray byteArray = doc.toUtf8(); + QVERIFY(domFromByteArary.setContent(byteArray)); + QVERIFY(compareDocuments(domFromByteArary, domDoc)); + + // Test overload taking a QIODevice + QDomDocument domFromIODevice; + QBuffer buffer(&byteArray); + QVERIFY(buffer.open(QIODevice::ReadOnly)); + QVERIFY(domFromIODevice.setContent(&buffer)); + QVERIFY(compareDocuments(domFromIODevice, domDoc)); +} + +void tst_QDom::setContentOverloads() +{ + QDomDocument doc; + QString errorMessage; + + QByteArray data("<a>test</a>"); + QString text = QString::fromLatin1(data); + QXmlStreamReader reader(data); + + QBuffer buffer(&data); + QVERIFY(buffer.open(QIODevice::ReadOnly)); + + QVERIFY(doc.setContent(data)); + QVERIFY(doc.setContent(data.data())); + QVERIFY(doc.setContent(text)); + QVERIFY(doc.setContent(&reader)); + QVERIFY(doc.setContent(&buffer)); + buffer.reset(); + + // With parse options + QVERIFY(doc.setContent(data, QDomDocument::ParseOption::Default)); + QVERIFY(doc.setContent(data.data(), QDomDocument::ParseOption::Default)); + QVERIFY(doc.setContent(text, QDomDocument::ParseOption::Default)); + QVERIFY(doc.setContent(&reader, QDomDocument::ParseOption::Default)); + QVERIFY(doc.setContent(&buffer, QDomDocument::ParseOption::Default)); + buffer.reset(); + +#if QT_DEPRECATED_SINCE(6, 8) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED + // With output param + QVERIFY(doc.setContent(data, &errorMessage)); + QVERIFY(doc.setContent(text, &errorMessage)); + QVERIFY(doc.setContent(&buffer, &errorMessage)); + buffer.reset(); + // There's no setContent(QXmlStreamReader *, QString *, int *, int *) overload + // QVERIFY(doc.setContent(&reader, &errorMessage)); + + // With namespace processing param + QVERIFY(doc.setContent(data, false)); + QVERIFY(doc.setContent(text, false)); + QVERIFY(doc.setContent(&reader, false)); + QVERIFY(doc.setContent(&buffer, false)); + buffer.reset(); + + // With namespace processing and output params + QVERIFY(doc.setContent(data, false, &errorMessage)); + QVERIFY(doc.setContent(text, false, &errorMessage)); + QVERIFY(doc.setContent(&reader, false, &errorMessage)); + QVERIFY(doc.setContent(&buffer, false, &errorMessage)); + buffer.reset(); +QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 8) +} + +void tst_QDom::parseOptions() +{ + QString input = u"<doc xmlns:ns='http://example.com/'>" + "<ns:nested/>" + "</doc>"_s; + { + QDomDocument document; + QVERIFY(document.setContent(input, QDomDocument::ParseOption::Default)); + const QDomElement docElement = document.firstChildElement("doc"); + QVERIFY(!docElement.isNull()); + const QDomElement nestedElement = docElement.firstChildElement(); + QCOMPARE(nestedElement.nodeName(), "ns:nested"); + QVERIFY(!nestedElement.isNull()); + QVERIFY(nestedElement.localName().isEmpty()); + QVERIFY(nestedElement.prefix().isEmpty()); + QVERIFY(nestedElement.namespaceURI().isEmpty()); + } + { + QDomDocument document; + QVERIFY(document.setContent(input, QDomDocument::ParseOption::UseNamespaceProcessing)); + const QDomElement docElement = document.firstChildElement("doc"); + QVERIFY(!docElement.isNull()); + const QDomElement nestedElement = docElement.firstChildElement("nested"); + QVERIFY(!nestedElement.isNull()); + QCOMPARE(nestedElement.nodeName(), "ns:nested"); + QCOMPARE(nestedElement.localName(), "nested"); + QCOMPARE(nestedElement.prefix(), "ns"); + QCOMPARE(nestedElement.namespaceURI(), "http://example.com/"); + } +} + +void tst_QDom::spacingOnlyNodes_data() const +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("expected"); + QTest::addColumn<QDomDocument::ParseOption>("options"); + + QTest::newRow("spacing-only-remove") + << u"<a> \t \n \r</a>"_s + << u"<a/>"_s + << QDomDocument::ParseOption::Default; + // \r is translated to \n, see https://www.w3.org/TR/xml11/#sec-line-ends + QTest::newRow("spacing-only-preserve") + << u"<a> \t \n \r</a>"_s + << u"<a> \t \n \n</a>"_s + << QDomDocument::ParseOption::PreserveSpacingOnlyNodes; + QTest::newRow("mixed-text-remove") + << u"<a> abc \t \n \r</a>"_s + << u"<a> abc \t \n \n</a>"_s + << QDomDocument::ParseOption::Default; + QTest::newRow("mixed-text-preserve") + << u"<a> abc \t \n \r</a>"_s + << u"<a> abc \t \n \n</a>"_s + << QDomDocument::ParseOption::PreserveSpacingOnlyNodes; + + // QDomDocument treats all chacarcters below as spaces (see QTBUG-105348) + static constexpr char16_t spaces[] = { + QChar::Space, QChar::Tabulation, QChar::LineFeed, + QChar::CarriageReturn, QChar::Nbsp, + 0x2002, // EN SPACE + 0x2003, // EM SPACE + 0x2009 // THIN SPACE + }; + + for (char16_t space : spaces) { + QTest::addRow("spacing-remove-u%04x", space) + << u"<a>"_s + space + u"</a>"_s + << u"<a/>"_s + << QDomDocument::ParseOption::Default; + + // \r is translated to \n, see https://www.w3.org/TR/xml11/#sec-line-ends + char16_t expected = (space == QChar::CarriageReturn) ? char16_t(QChar::LineFeed) : space; + QTest::addRow("spacing-preserve-u%04x", space) + << u"<a>"_s + space + u"</a>"_s + << u"<a>"_s + expected + u"</a>"_s + << QDomDocument::ParseOption::PreserveSpacingOnlyNodes; + } +} + +void tst_QDom::spacingOnlyNodes() const +{ + QFETCH(QString, input); + QFETCH(QString, expected); + QFETCH(QDomDocument::ParseOption, options); + + QDomDocument doc; + QVERIFY(doc.setContent(input, options)); + QCOMPARE(doc.toString(-1), expected); +} + +void tst_QDom::parseResult() +{ + QString input = u"<doc xmlns:b='http://example.com/'>" + "<b:element/>"_s; + + QDomDocument document; + QDomDocument::ParseResult result = document.setContent(input); + QVERIFY(!result); + QVERIFY(!result.errorMessage.isEmpty()); + QVERIFY(result.errorLine); + QVERIFY(result.errorColumn); + + input.append("</doc>"); + result = document.setContent(input); + QVERIFY(result); + QVERIFY(result.errorMessage.isEmpty()); + QVERIFY(!result.errorLine); + QVERIFY(!result.errorColumn); } void tst_QDom::toString_01_data() @@ -242,13 +421,11 @@ void tst_QDom::toString_01() QVERIFY2(f.open(QIODevice::ReadOnly), qPrintable(QString::fromLatin1("Failed to open file %1, file error: %2").arg(fileName).arg(f.error()))); QDomDocument doc; - QString errorMsg; - int errorLine; - int errorCol; - - QVERIFY(doc.setContent( &f, &errorMsg, &errorLine, &errorCol )); /*, - QString("QDomDocument::setContent() failed: %1 in line %2, column %3") - .arg( errorMsg ).arg( errorLine ).arg( errorCol )); */ + QDomDocument::ParseResult result = doc.setContent(&f, QDomDocument::ParseOption::Default); + QVERIFY2(result, + qPrintable(u"QDomDocument::setContent() failed (%1:%2): %3"_s.arg(result.errorLine) + .arg(result.errorColumn) + .arg(result.errorMessage))); // test toString()'s invariant with different indenting depths for ( int i=0; i<5; i++ ) { QString toStr = doc.toString( i ); @@ -508,17 +685,14 @@ void tst_QDom::saveWithSerialization() const QVERIFY(readDevice.open(QIODevice::ReadOnly)); QDomDocument result; + QDomDocument::ParseResult parseResult = + result.setContent(&readDevice, QDomDocument::ParseOption::Default); - QString msg; - int line = 0; - int column = 0; - - QVERIFY2(result.setContent(&readDevice, &msg, &line, &column), + QVERIFY2(parseResult, qPrintable(QString::fromLatin1("Failed: line %2, column %3: %4, content: %5") - .arg(QString::number(line), - QString::number(column), - msg, - QString::fromUtf8(storage)))); + .arg(QString::number(parseResult.errorLine), + QString::number(parseResult.errorColumn), + parseResult.errorMessage, QString::fromUtf8(storage)))); if (!compareDocuments(doc, result)) { QCOMPARE(doc.toString(), result.toString()); @@ -1363,6 +1537,10 @@ void tst_QDom::invalidCharData_data() QTest::newRow( "f<o&o" ) << QString("f<o&o") << true << true << true << QString("f<o&o"); QTest::newRow( "empty" ) << QString() << true << true << true << QString(); QTest::newRow("f\\x07o\\x02")<< QString("f\x07o\x02")<< true << true << false << QString("fo"); + + const QChar pair[2] = { QChar(0xdc00), QChar(0xe000) }; + QString invalid(pair, 2); + QTest::newRow("\\xdc00\\xe000") << invalid << true << true << false << invalid.last(1); } void tst_QDom::invalidCharData() @@ -1406,6 +1584,20 @@ void tst_QDom::invalidCharData() } } +void tst_QDom::nonBMPCharacters() +{ + const auto invalidDataPolicy = QDomImplementation::invalidDataPolicy(); + auto resetInvalidDataPolicy = qScopeGuard( + [invalidDataPolicy] { QDomImplementation::setInvalidDataPolicy(invalidDataPolicy); }); + QDomImplementation::setInvalidDataPolicy(QDomImplementation::DropInvalidChars); + + const QString input = u"<text>Supplementary Plane: 𝄞 😂 🀄 🀶 🃪 🃋</text>"_s; + + QDomDocument doc; + QVERIFY(doc.setContent(input, QDomDocument::ParseOption::Default)); + QCOMPARE(doc.toString(-1), input); +} + void tst_QDom::roundTripAttributes() const { /* Create an attribute via the QDom API with weird whitespace content. */ @@ -1440,6 +1632,15 @@ void tst_QDom::roundTripAttributes() const QCOMPARE(QString::fromLatin1(serialized.constData()), QString::fromLatin1(expected.constData())); } +void tst_QDom::roundTripCDATA() const +{ + const QString input = u"<?xml version='1.0' encoding='UTF-8'?>\n" + "<content><![CDATA[]]></content>\n"_s; + QDomDocument doc; + QVERIFY(doc.setContent(input, QDomDocument::ParseOption::Default)); + QCOMPARE(doc.toString(), input); +} + void tst_QDom::normalizeEndOfLine() const { QByteArray input("<a>\r\nc\rc\ra\na</a>"); @@ -1448,7 +1649,7 @@ void tst_QDom::normalizeEndOfLine() const QVERIFY(buffer.open(QIODevice::ReadOnly)); QDomDocument doc; - QVERIFY(doc.setContent(&buffer, true)); + QVERIFY(doc.setContent(&buffer, QDomDocument::ParseOption::UseNamespaceProcessing)); const QString expected(QLatin1String("<a>\nc\nc\na\na</a>")); @@ -1465,7 +1666,7 @@ void tst_QDom::normalizeAttributes() const QVERIFY(buffer.open(QIODevice::ReadOnly)); QDomDocument doc; - QVERIFY(doc.setContent(&buffer, true)); + QVERIFY(doc.setContent(&buffer, QDomDocument::ParseOption::UseNamespaceProcessing)); QCOMPARE(doc.documentElement().attribute(QLatin1String("attribute")), QString::fromLatin1("a a")); } @@ -1509,17 +1710,18 @@ void tst_QDom::serializeNamespaces() const QDomDocument doc; QByteArray ba(input); QXmlStreamReader streamReader(input); - QVERIFY(doc.setContent(&streamReader, true)); + QVERIFY(doc.setContent(&streamReader, QDomDocument::ParseOption::UseNamespaceProcessing)); const QByteArray serialized(doc.toByteArray()); QDomDocument doc2; - QVERIFY(doc2.setContent(doc.toString(), true)); + QVERIFY(doc2.setContent(doc.toString(), QDomDocument::ParseOption::UseNamespaceProcessing)); /* Here we test that it roundtrips. */ QVERIFY(isDeepEqual(doc2, doc)); QDomDocument doc3; - QVERIFY(doc3.setContent(QString::fromLatin1(serialized.constData()), true)); + QVERIFY(doc3.setContent(QString::fromLatin1(serialized.constData()), + QDomDocument::ParseOption::UseNamespaceProcessing)); QVERIFY(isDeepEqual(doc3, doc)); } @@ -1545,7 +1747,7 @@ void tst_QDom::flagUndeclaredNamespace() const QDomDocument doc; QByteArray ba(input); QXmlStreamReader streamReader(ba); - QVERIFY(!doc.setContent(&streamReader, true)); + QVERIFY(!doc.setContent(&streamReader, QDomDocument::ParseOption::UseNamespaceProcessing)); } void tst_QDom::indentComments() const @@ -1610,7 +1812,7 @@ void tst_QDom::checkLiveness() const void tst_QDom::reportDuplicateAttributes() const { QDomDocument dd; - bool isSuccess = dd.setContent(QLatin1String("<test x=\"1\" x=\"2\"/>")); + bool isSuccess = bool(dd.setContent(QLatin1String("<test x=\"1\" x=\"2\"/>"))); QVERIFY2(!isSuccess, "Duplicate attributes are well-formedness errors, and should be reported as such."); } @@ -1627,12 +1829,12 @@ void tst_QDom::namespacedAttributes() const "</xan:td>\n"; QDomDocument one("document"); - QString error; - bool docParsed = one.setContent(QByteArray(xml), true, &error); - QVERIFY2(docParsed, qPrintable(error)); + QDomDocument::ParseResult result = + one.setContent(QByteArray(xml), QDomDocument::ParseOption::UseNamespaceProcessing); + QVERIFY2(result, qPrintable(result.errorMessage)); QDomDocument two("document2"); - docParsed = two.setContent(one.toByteArray(2), true, &error); - QVERIFY2(docParsed, qPrintable(error)); + result = two.setContent(one.toByteArray(2), QDomDocument::ParseOption::UseNamespaceProcessing); + QVERIFY2(result, qPrintable(result.errorMessage)); QVERIFY(isDeepEqual(one, two)); } @@ -1750,7 +1952,7 @@ void tst_QDom::germanUmlautToFile() const QString name(QLatin1String("german")); name += QChar(0xFC); name += QLatin1String("umlaut"); - QCOMPARE(name.length(), 13); + QCOMPARE(name.size(), 13); QDomDocument d("test"); d.appendChild(d.createElement(name)); @@ -1769,7 +1971,7 @@ void tst_QDom::germanUmlautToFile() const const QByteArray in(inFile.readAll()); /* Check that it was wwritten out correctly. */ - QCOMPARE(in.length(), 34); + QCOMPARE(in.size(), 34); QCOMPARE(in, baseline.toUtf8()); inFile.close(); @@ -1794,7 +1996,8 @@ void tst_QDom::crashInSetContent() const QDomImplementation::setInvalidDataPolicy(QDomImplementation::ReturnNullNode); QDomDocument docImport; - QCOMPARE(docImport.setContent(QLatin1String("<a:>text</a:>"), true), false); + QVERIFY(!docImport.setContent(QLatin1String("<a:>text</a:>"), + QDomDocument::ParseOption::UseNamespaceProcessing)); QVERIFY(docImport.setContent(QLatin1String("<?xml version=\"1.0\"?><e/>"))); } @@ -1809,24 +2012,17 @@ void tst_QDom::doubleNamespaceDeclarations() const QVERIFY(file.open(QIODevice::ReadOnly)); QXmlStreamReader streamReader(&file); - QVERIFY(doc.setContent(&streamReader, true)); + QVERIFY(doc.setContent(&streamReader, QDomDocument::ParseOption::UseNamespaceProcessing)); - // tst_QDom relies on a specific QHash ordering, see QTBUG-25071 QString docAsString = doc.toString(0); - QVERIFY(docAsString == QString::fromLatin1("<a>\n<b p:c=\"\" xmlns:p=\"NS\" p:d=\"\"/>\n</a>\n") || - docAsString == QString::fromLatin1("<a>\n<b p:c=\"\" p:d=\"\" xmlns:p=\"NS\"/>\n</a>\n") || - docAsString == QString::fromLatin1("<a>\n<b p:d=\"\" p:c=\"\" xmlns:p=\"NS\"/>\n</a>\n") || - docAsString == QString::fromLatin1("<a>\n<b p:d=\"\" xmlns:p=\"NS\" p:c=\"\"/>\n</a>\n") || - docAsString == QString::fromLatin1("<a>\n<b xmlns:p=\"NS\" p:c=\"\" p:d=\"\"/>\n</a>\n") || - docAsString == QString::fromLatin1("<a>\n<b xmlns:p=\"NS\" p:d=\"\" p:c=\"\"/>\n</a>\n") - ); + QCOMPARE(docAsString, "<a>\n<b p:c=\"\" p:d=\"\" xmlns:p=\"NS\"/>\n</a>\n"); } void tst_QDom::setContentQXmlReaderOverload() const { QDomDocument doc; QXmlStreamReader streamReader(QByteArray("<e/>")); - doc.setContent(&streamReader, true); + doc.setContent(&streamReader, QDomDocument::ParseOption::UseNamespaceProcessing); QCOMPARE(doc.documentElement().nodeName(), QString::fromLatin1("e")); } @@ -1878,7 +2074,7 @@ void tst_QDom::setContentWhitespace() const QDomDocument domDoc; - QCOMPARE(domDoc.setContent(doc), expectedValidity); + QCOMPARE(bool(domDoc.setContent(doc)), expectedValidity); if(expectedValidity) QCOMPARE(domDoc.documentElement().nodeName(), QString::fromLatin1("e")); @@ -1919,6 +2115,23 @@ void tst_QDom::setContentWhitespace_data() const QTest::newRow("data25") << QString::fromLatin1("\t\t\t\t<?xml version='1.0' ?><e/>") << false; } +void tst_QDom::setContentUnopenedQIODevice() const +{ + QByteArray data("<foo>bar</foo>"); + QBuffer buffer(&data); + + QDomDocument doc; + + QTest::ignoreMessage(QtWarningMsg, + "QDomDocument called with unopened QIODevice. " + "This will not be supported in future Qt versions."); + + // Note: the check below is expected to fail in Qt 7. + // Fix the test and remove the obsolete code from setContent(). + QVERIFY(doc.setContent(&buffer, QDomDocument::ParseOption::UseNamespaceProcessing)); + QCOMPARE(doc.toString().trimmed(), data); +} + void tst_QDom::taskQTBUG4595_dontAssertWhenDocumentSpecifiesUnknownEncoding() const { QString xmlWithUnknownEncoding("<?xml version='1.0' encoding='unknown-encoding'?>" @@ -2015,5 +2228,108 @@ void tst_QDom::QTBUG49113_dontCrashWithNegativeIndex() const QVERIFY(node.isNull()); } +void tst_QDom::standalone() +{ + { + QDomDocument doc; + const QString dtd("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" + "<Test/>\n"); + doc.setContent(dtd); + QVERIFY(doc.toString().contains("standalone=\'no\'")); + } + { + QDomDocument doc; + const QString dtd("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<Test/>\n"); + doc.setContent(dtd); + QVERIFY(!doc.toString().contains("standalone")); + } + { + QDomDocument doc; + const QString dtd("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" + "<Test/>\n"); + doc.setContent(dtd); + QVERIFY(doc.toString().contains("standalone=\'yes\'")); + } +} + +void tst_QDom::DTDInternalSubset() const +{ + QFETCH( QString, doc ); + QFETCH( QString, internalSubset ); + QXmlStreamReader reader(doc); + QDomDocument document; + QVERIFY(document.setContent(&reader, QDomDocument::ParseOption::UseNamespaceProcessing)); + + QCOMPARE(document.doctype().internalSubset(), internalSubset); +} + +void tst_QDom::DTDInternalSubset_data() const +{ + QTest::addColumn<QString>("doc"); + QTest::addColumn<QString>("internalSubset"); + + QTest::newRow("data1") << "<?xml version='1.0'?>\n" + "<!DOCTYPE note SYSTEM '/[abcd].dtd'>\n" + "<note/>\n" + << "" ; + + QTest::newRow("data2") << "<?xml version='1.0'?>\n" + "<!DOCTYPE note PUBLIC '-/freedesktop' 'https://[abcd].dtd'>\n" + "<note/>\n" + << "" ; + + const QString internalSubset0( + "<!-- open brackets comment [ -->\n" + "<!-- colse brackets comment ] -->\n" + ); + QTest::newRow("data3") << "<?xml version='1.0'?>\n" + "<!DOCTYPE note [" + + internalSubset0 + + "]>\n" + "<note/>\n" + << internalSubset0; + + const QString internalSubset1( + "<!ENTITY obra '['>\n" + "<!ENTITY cbra ']'>\n" + ); + QTest::newRow("data4") << "<?xml version='1.0'?>\n" + "<!DOCTYPE note [" + + internalSubset1 + + "]>\n" + "<note/>\n" + << internalSubset1; + + QTest::newRow("data5") << "<?xml version='1.0'?>\n" + "<!DOCTYPE note PUBLIC '-/freedesktop' 'https://[abcd].dtd' [" + + internalSubset0 + + "]>\n" + "<note/>\n" + << internalSubset0; + + QTest::newRow("data6") << "<?xml version='1.0'?>\n" + "<!DOCTYPE note PUBLIC '-/freedesktop' " + "'2001:db8:130F:0000:0000:09C0:876A:130B://[abcd].dtd' [" + + internalSubset0 + + "]>\n" + "<note/>\n" + << internalSubset0; +} + +void tst_QDom::splitTextLeakMemory() const +{ + QDomDocument doc; + QDomElement top = doc.createElement("top"); + QDomText text = doc.createTextNode("abcdefgh"); + top.appendChild(text); + QDomText end = text.splitText(2); + QCOMPARE(text.data(), "ab"_L1); + QCOMPARE(end.data(), "cdefgh"_L1); + // only the parent node and the document have a reference on the nodes + QCOMPARE(text.impl->ref.loadRelaxed(), 2); + QCOMPARE(end.impl->ref.loadRelaxed(), 2); +} + QTEST_MAIN(tst_QDom) #include "tst_qdom.moc" |