diff options
Diffstat (limited to 'tests/auto/gui/text')
91 files changed, 4070 insertions, 1753 deletions
diff --git a/tests/auto/gui/text/CMakeLists.txt b/tests/auto/gui/text/CMakeLists.txt index b7262f7c00..bad13de7dc 100644 --- a/tests/auto/gui/text/CMakeLists.txt +++ b/tests/auto/gui/text/CMakeLists.txt @@ -1,4 +1,5 @@ -# Generated from text.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause add_subdirectory(qabstracttextdocumentlayout) add_subdirectory(qfont) @@ -13,9 +14,10 @@ add_subdirectory(qtextcursor) add_subdirectory(qtextdocumentfragment) add_subdirectory(qtextdocumentlayout) add_subdirectory(qtextformat) +add_subdirectory(qtextimagehandler) add_subdirectory(qtextlist) add_subdirectory(qtextobject) -# add_subdirectory(qtextscriptengine) # disable until system_harfbuzz feature is available # special case +# add_subdirectory(qtextscriptengine) # disable until system_harfbuzz feature is available add_subdirectory(qtexttable) add_subdirectory(qinputcontrol) if(QT_FEATURE_private_tests AND TARGET Qt::Xml) @@ -24,11 +26,9 @@ endif() if(QT_FEATURE_private_tests) add_subdirectory(qfontcache) add_subdirectory(qtextlayout) - add_subdirectory(qzip) add_subdirectory(qtextodfwriter) endif() -# QTBUG-87671 # special case -if(TARGET Qt::Xml AND NOT ANDROID) +if(TARGET Qt::Xml) add_subdirectory(qtextdocument) endif() if(QT_FEATURE_private_tests AND UNIX) diff --git a/tests/auto/gui/text/qabstracttextdocumentlayout/CMakeLists.txt b/tests/auto/gui/text/qabstracttextdocumentlayout/CMakeLists.txt index f78e1d81c7..316b9cd3c6 100644 --- a/tests/auto/gui/text/qabstracttextdocumentlayout/CMakeLists.txt +++ b/tests/auto/gui/text/qabstracttextdocumentlayout/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qabstracttextdocumentlayout.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qabstracttextdocumentlayout Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qabstracttextdocumentlayout LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qabstracttextdocumentlayout SOURCES tst_qabstracttextdocumentlayout.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui ) diff --git a/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp b/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp index cdd2b9cd44..2ae2ccda0a 100644 --- a/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp +++ b/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.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 <QTest> @@ -151,7 +126,7 @@ void tst_QAbstractTextDocumentLayout::anchorAt() QAbstractTextDocumentLayout *documentLayout = doc.documentLayout(); QTextBlock firstBlock = doc.begin(); QTextLayout *layout = firstBlock.layout(); - layout->setPreeditArea(doc.toPlainText().length(), "xxx"); + layout->setPreeditArea(doc.toPlainText().size(), "xxx"); doc.setPageSize(QSizeF(1000, 1000)); QFontMetrics metrics(layout->font()); @@ -181,7 +156,7 @@ void tst_QAbstractTextDocumentLayout::imageAt() QAbstractTextDocumentLayout *documentLayout = doc.documentLayout(); QTextBlock firstBlock = doc.begin(); QTextLayout *layout = firstBlock.layout(); - layout->setPreeditArea(doc.toPlainText().length(), "xxx"); + layout->setPreeditArea(doc.toPlainText().size(), "xxx"); doc.setPageSize(QSizeF(1000, 1000)); QFontMetrics metrics(layout->font()); @@ -206,7 +181,7 @@ void tst_QAbstractTextDocumentLayout::formatAt() QAbstractTextDocumentLayout *documentLayout = doc.documentLayout(); QTextBlock firstBlock = doc.begin(); QTextLayout *layout = firstBlock.layout(); - layout->setPreeditArea(doc.toPlainText().length(), "xxx"); + layout->setPreeditArea(doc.toPlainText().size(), "xxx"); doc.setPageSize(QSizeF(1000, 1000)); QFontMetrics metrics(layout->font()); diff --git a/tests/auto/gui/text/qcssparser/CMakeLists.txt b/tests/auto/gui/text/qcssparser/CMakeLists.txt index adb3e6269c..e766ec5484 100644 --- a/tests/auto/gui/text/qcssparser/CMakeLists.txt +++ b/tests/auto/gui/text/qcssparser/CMakeLists.txt @@ -1,57 +1,28 @@ -# Generated from qcssparser.pro. - -if(NOT QT_FEATURE_private_tests) - return() -endif() +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qcssparser Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qcssparser LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + # Collect test data -list(APPEND test_data "testdata") +file(GLOB_RECURSE test_data + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + testdata/* +) qt_internal_add_test(tst_qcssparser SOURCES tst_qcssparser.cpp - DEFINES - SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\" - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::GuiPrivate Qt::Xml TESTDATA ${test_data} ) - -#### Keys ignored in scope 1:.:.:qcssparser.pro:<TRUE>: -# _REQUIREMENTS = "qtConfig(private_tests)" - -## Scopes: -##################################################################### - -if(ANDROID) - # Resources: - set(testdata_resource_files - "testdata/scanner/comments/input" - "testdata/scanner/comments/output" - "testdata/scanner/comments2/input" - "testdata/scanner/comments2/output" - "testdata/scanner/comments3/input" - "testdata/scanner/comments3/output" - "testdata/scanner/comments4/input" - "testdata/scanner/comments4/output" - "testdata/scanner/quotedstring/input" - "testdata/scanner/quotedstring/output" - "testdata/scanner/simple/input" - "testdata/scanner/simple/output" - "testdata/scanner/unicode/input" - "testdata/scanner/unicode/output" - ) - - qt_internal_add_resource(tst_qcssparser "testdata" - PREFIX - "/" - FILES - ${testdata_resource_files} - ) -endif() diff --git a/tests/auto/gui/text/qcssparser/testdata.qrc b/tests/auto/gui/text/qcssparser/testdata.qrc deleted file mode 100644 index 56e45cfbb0..0000000000 --- a/tests/auto/gui/text/qcssparser/testdata.qrc +++ /dev/null @@ -1,18 +0,0 @@ -<RCC> - <qresource prefix="/"> - <file>testdata/scanner/comments/input</file> - <file>testdata/scanner/comments/output</file> - <file>testdata/scanner/comments2/input</file> - <file>testdata/scanner/comments2/output</file> - <file>testdata/scanner/comments3/input</file> - <file>testdata/scanner/comments3/output</file> - <file>testdata/scanner/comments4/input</file> - <file>testdata/scanner/comments4/output</file> - <file>testdata/scanner/quotedstring/input</file> - <file>testdata/scanner/quotedstring/output</file> - <file>testdata/scanner/simple/input</file> - <file>testdata/scanner/simple/output</file> - <file>testdata/scanner/unicode/input</file> - <file>testdata/scanner/unicode/output</file> - </qresource> -</RCC> diff --git a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp index ef86d06cb4..a438d7ebc8 100644 --- a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp +++ b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp @@ -1,30 +1,6 @@ -/**************************************************************************** -** -** 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 <QTest> #include <QtXml/QtXml> #include <QtGui/QFontInfo> @@ -90,11 +66,12 @@ void tst_QCssParser::scanner_data() #if defined(Q_OS_ANDROID) QDir d(":/"); #else - QDir d(SRCDIR); + QDir d(QT_TESTCASE_SOURCEDIR); #endif d.cd("testdata"); d.cd("scanner"); - foreach (QFileInfo test, d.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { + const auto entries = d.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const QFileInfo &test : entries) { QString dir = test.absoluteFilePath() + QDir::separator(); QTest::newRow(qPrintable(test.baseName())) << dir + "input" @@ -151,7 +128,7 @@ static const char *tokenName(QCss::TokenType t) static void debug(const QList<QCss::Symbol> &symbols, int index = -1) { qDebug() << "all symbols:"; - for (int i = 0; i < symbols.count(); ++i) + for (int i = 0; i < symbols.size(); ++i) qDebug() << '(' << i << "); Token:" << tokenName(symbols.at(i).token) << "; Lexem:" << symbols.at(i).lexem(); if (index != -1) qDebug() << "failure at index" << index; @@ -169,10 +146,10 @@ void tst_QCssParser::scanner() QList<QCss::Symbol> symbols; QCss::Scanner::scan(QCss::Scanner::preprocess(QString::fromUtf8(inputFile.readAll())), &symbols); - QVERIFY(symbols.count() > 1); + QVERIFY(symbols.size() > 1); QCOMPARE(symbols.last().token, QCss::S); QCOMPARE(symbols.last().lexem(), QLatin1String("\n")); - symbols.remove(symbols.count() - 1, 1); + symbols.remove(symbols.size() - 1, 1); QFile outputFile(output); QVERIFY(outputFile.open(QIODevice::ReadOnly|QIODevice::Text)); @@ -184,14 +161,14 @@ void tst_QCssParser::scanner() lines.append(line); } - if (lines.count() != symbols.count()) { + if (lines.size() != symbols.size()) { debug(symbols); - QCOMPARE(lines.count(), symbols.count()); + QCOMPARE(lines.size(), symbols.size()); } - for (int i = 0; i < lines.count(); ++i) { + for (int i = 0; i < lines.size(); ++i) { QStringList l = lines.at(i).split(QChar::fromLatin1('|')); - QCOMPARE(l.count(), 2); + QCOMPARE(l.size(), 2); const QString expectedToken = l.at(0); const QString expectedLexem = l.at(1); QString actualToken = QString::fromLatin1(tokenName(symbols.at(i).token)); @@ -375,9 +352,9 @@ void tst_QCssParser::expr() QVERIFY(parser.testExpr()); QCOMPARE(parser.parseExpr(&values), parseSuccess); if (parseSuccess) { - QCOMPARE(values.count(), expectedValues.count()); + QCOMPARE(values.size(), expectedValues.size()); - for (int i = 0; i < values.count(); ++i) { + for (int i = 0; i < values.size(); ++i) { QCOMPARE(int(values.at(i).type), int(expectedValues.at(i).type)); QCOMPARE(values.at(i).variant, expectedValues.at(i).variant); } @@ -396,7 +373,7 @@ void tst_QCssParser::import() QVERIFY(parser.testImport()); QVERIFY(parser.parseImport(&rule)); QCOMPARE(rule.href, QString("www.kde.org")); - QCOMPARE(rule.media.count(), 2); + QCOMPARE(rule.media.size(), 2); QCOMPARE(rule.media.at(0), QString("print")); QCOMPARE(rule.media.at(1), QString("screen")); } @@ -407,7 +384,7 @@ void tst_QCssParser::media() QVERIFY(parser.testMedia()); QCss::MediaRule rule; QVERIFY(parser.parseMedia(&rule)); - QCOMPARE(rule.media.count(), 2); + QCOMPARE(rule.media.size(), 2); QCOMPARE(rule.media.at(0), QString("print")); QCOMPARE(rule.media.at(1), QString("screen")); QVERIFY(rule.styleRules.isEmpty()); @@ -430,8 +407,8 @@ void tst_QCssParser::ruleset() QVERIFY(parser.testRuleset()); QCss::StyleRule rule; QVERIFY(parser.parseRuleset(&rule)); - QCOMPARE(rule.selectors.count(), 1); - QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.size(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.size(), 1); QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("p")); QVERIFY(rule.declarations.isEmpty()); } @@ -441,10 +418,10 @@ void tst_QCssParser::ruleset() QVERIFY(parser.testRuleset()); QCss::StyleRule rule; QVERIFY(parser.parseRuleset(&rule)); - QCOMPARE(rule.selectors.count(), 2); - QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.size(), 2); + QCOMPARE(rule.selectors.at(0).basicSelectors.size(), 1); QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("p")); - QCOMPARE(rule.selectors.at(1).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(1).basicSelectors.size(), 1); QCOMPARE(rule.selectors.at(1).basicSelectors.at(0).elementName, QString("div")); QVERIFY(rule.declarations.isEmpty()); } @@ -454,14 +431,14 @@ void tst_QCssParser::ruleset() QVERIFY(parser.testRuleset()); QCss::StyleRule rule; QVERIFY(parser.parseRuleset(&rule)); - QCOMPARE(rule.selectors.count(), 2); + QCOMPARE(rule.selectors.size(), 2); - QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); - QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).pseudos.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.size(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).pseudos.size(), 1); QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).pseudos.at(0).name, QString("before")); - QCOMPARE(rule.selectors.at(1).basicSelectors.count(), 1); - QCOMPARE(rule.selectors.at(1).basicSelectors.at(0).pseudos.count(), 1); + QCOMPARE(rule.selectors.at(1).basicSelectors.size(), 1); + QCOMPARE(rule.selectors.at(1).basicSelectors.at(0).pseudos.size(), 1); QCOMPARE(rule.selectors.at(1).basicSelectors.at(0).pseudos.at(0).name, QString("after")); QVERIFY(rule.declarations.isEmpty()); @@ -713,21 +690,21 @@ void tst_QCssParser::selector() QCss::Selector selector; QVERIFY(parser.parseSelector(&selector)); - QCOMPARE(selector.basicSelectors.count(), expectedSelector.basicSelectors.count()); - for (int i = 0; i < selector.basicSelectors.count(); ++i) { + QCOMPARE(selector.basicSelectors.size(), expectedSelector.basicSelectors.size()); + for (int i = 0; i < selector.basicSelectors.size(); ++i) { const QCss::BasicSelector sel = selector.basicSelectors.at(i); const QCss::BasicSelector expectedSel = expectedSelector.basicSelectors.at(i); QCOMPARE(sel.elementName, expectedSel.elementName); QCOMPARE(int(sel.relationToNext), int(expectedSel.relationToNext)); - QCOMPARE(sel.pseudos.count(), expectedSel.pseudos.count()); - for (int i = 0; i < sel.pseudos.count(); ++i) { + QCOMPARE(sel.pseudos.size(), expectedSel.pseudos.size()); + for (int i = 0; i < sel.pseudos.size(); ++i) { QCOMPARE(sel.pseudos.at(i).name, expectedSel.pseudos.at(i).name); QCOMPARE(sel.pseudos.at(i).function, expectedSel.pseudos.at(i).function); } - QCOMPARE(sel.attributeSelectors.count(), expectedSel.attributeSelectors.count()); - for (int i = 0; i < sel.attributeSelectors.count(); ++i) { + QCOMPARE(sel.attributeSelectors.size(), expectedSel.attributeSelectors.size()); + for (int i = 0; i < sel.attributeSelectors.size(); ++i) { QCOMPARE(sel.attributeSelectors.at(i).name, expectedSel.attributeSelectors.at(i).name); QCOMPARE(sel.attributeSelectors.at(i).value, expectedSel.attributeSelectors.at(i).value); QCOMPARE(int(sel.attributeSelectors.at(i).valueMatchCriterium), int(expectedSel.attributeSelectors.at(i).valueMatchCriterium)); @@ -785,13 +762,13 @@ void tst_QCssParser::malformedDeclarations() QCss::StyleRule rule; QVERIFY(parser.parseRuleset(&rule)); - QCOMPARE(rule.selectors.count(), 1); - QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.size(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.size(), 1); QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("p")); - QVERIFY(rule.declarations.count() >= 1); + QVERIFY(rule.declarations.size() >= 1); QCOMPARE(int(rule.declarations.last().d->propertyId), int(QCss::Color)); - QCOMPARE(rule.declarations.last().d->values.count(), 1); + QCOMPARE(rule.declarations.last().d->values.size(), 1); QCOMPARE(int(rule.declarations.last().d->values.at(0).type), int(QCss::Value::Identifier)); QCOMPARE(rule.declarations.last().d->values.at(0).variant.toString(), QString("green")); } @@ -811,17 +788,17 @@ void tst_QCssParser::invalidAtKeywords() QCss::StyleSheet sheet; QVERIFY(parser.parse(&sheet)); - QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCOMPARE(sheet.styleRules.size() + sheet.nameIndex.size(), 1); QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? sheet.styleRules.at(0) : *sheet.nameIndex.begin(); - QCOMPARE(rule.selectors.count(), 1); - QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.size(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.size(), 1); QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("h1")); - QCOMPARE(rule.declarations.count(), 1); + QCOMPARE(rule.declarations.size(), 1); QCOMPARE(int(rule.declarations.at(0).d->propertyId), int(QCss::Color)); - QCOMPARE(rule.declarations.at(0).d->values.count(), 1); + QCOMPARE(rule.declarations.at(0).d->values.size(), 1); QCOMPARE(int(rule.declarations.at(0).d->values.at(0).type), int(QCss::Value::Identifier)); QCOMPARE(rule.declarations.at(0).d->values.at(0).variant.toString(), QString("blue")); } @@ -844,11 +821,11 @@ void tst_QCssParser::colorValue_data() QTest::newRow("hsva") << "color: hsva(10, 20, 30, 40)" << QColor::fromHsv(10, 20, 30, 40); // the percent and float values are well chosen to not get in trouble due to rounding errors QTest::newRow("hsva-percent") << "color: hsva(100%, 20%, 40%, 60%)" << QColor::fromHsv(359, 51, 102, 153); - QTest::newRow("hsva-float") << "color: hsva(180, 20%, 40%, 0.6)" << QColor::fromHsvF(0.5, 0.2, 0.4, 0.6); + QTest::newRow("hsva-float") << "color: hsva(180, 20%, 40%, 0.6)" << QColor::fromHsvF(0.5f, 0.2f, 0.4f, 0.6f); QTest::newRow("hsl") << "color: hsl(60, 100%, 50%)" << QColor::fromHsl(60., 255, 127); QTest::newRow("hsla") << "color: hsla(240, 255, 127, 192)" << QColor::fromHsl(240, 255, 127, 192); QTest::newRow("hsla-percent") << "color: hsla(100%, 80%, 40%, 0%)" << QColor::fromHsl(359, 204, 102, 0); - QTest::newRow("hsla-float") << "color: hsla(252, 40%, 60%, 0.2)" << QColor::fromHslF(0.7, 0.4, 0.6, 0.2); + QTest::newRow("hsla-float") << "color: hsla(252, 40%, 60%, 0.2)" << QColor::fromHslF(0.7f, 0.4f, 0.6f, 0.2f); QTest::newRow("invalid1") << "color: rgb(why, does, it, always, rain, on, me)" << QColor(); QTest::newRow("invalid2") << "color: rgba(i, meant, norway)" << QColor(); QTest::newRow("invalid3") << "color: rgb(21)" << QColor(); @@ -886,32 +863,34 @@ public: styleSheets.append(sheet); } - virtual QStringList nodeNames(NodePtr node) const override { return QStringList(reinterpret_cast<QDomElement *>(node.ptr)->tagName()); } - virtual QString attribute(NodePtr node, const QString &name) const override { return reinterpret_cast<QDomElement *>(node.ptr)->attribute(name); } - virtual bool hasAttribute(NodePtr node, const QString &name) const { return reinterpret_cast<QDomElement *>(node.ptr)->hasAttribute(name); } - virtual bool hasAttributes(NodePtr node) const override { return reinterpret_cast<QDomElement *>(node.ptr)->hasAttributes(); } - - virtual bool isNullNode(NodePtr node) const override { - return reinterpret_cast<QDomElement *>(node.ptr)->isNull(); - } - virtual NodePtr parentNode(NodePtr node) const override { + QStringList nodeNames(NodePtr node) const override + { return QStringList(reinterpret_cast<QDomElement *>(node.ptr)->tagName()); } + QString attributeValue(NodePtr node, const QCss::AttributeSelector &aSel) const override + { return reinterpret_cast<QDomElement *>(node.ptr)->attribute(aSel.name); } + bool hasAttribute(NodePtr node, const QString &name) const + { return reinterpret_cast<QDomElement *>(node.ptr)->hasAttribute(name); } + bool hasAttributes(NodePtr node) const override + { return reinterpret_cast<QDomElement *>(node.ptr)->hasAttributes(); } + + bool isNullNode(NodePtr node) const override + { return reinterpret_cast<QDomElement *>(node.ptr)->isNull(); } + NodePtr parentNode(NodePtr node) const override { NodePtr parent; parent.ptr = new QDomElement(reinterpret_cast<QDomElement *>(node.ptr)->parentNode().toElement()); return parent; } - virtual NodePtr duplicateNode(NodePtr node) const override { + NodePtr duplicateNode(NodePtr node) const override { NodePtr n; n.ptr = new QDomElement(*reinterpret_cast<QDomElement *>(node.ptr)); return n; } - virtual NodePtr previousSiblingNode(NodePtr node) const override { + NodePtr previousSiblingNode(NodePtr node) const override { NodePtr sibling; sibling.ptr = new QDomElement(reinterpret_cast<QDomElement *>(node.ptr)->previousSiblingElement()); return sibling; } - virtual void freeNode(NodePtr node) const override { - delete reinterpret_cast<QDomElement *>(node.ptr); - } + void freeNode(NodePtr node) const override + { delete reinterpret_cast<QDomElement *>(node.ptr); } private: QDomDocument doc; @@ -1164,9 +1143,9 @@ void tst_QCssParser::styleSelector() QList<QCss::Declaration> decls = testSelector.declarationsForNode(n); if (match) { - QCOMPARE(decls.count(), 1); + QCOMPARE(decls.size(), 1); QCOMPARE(int(decls.at(0).d->propertyId), int(QCss::BackgroundColor)); - QCOMPARE(decls.at(0).d->values.count(), 1); + QCOMPARE(decls.at(0).d->values.size(), 1); QCOMPARE(int(decls.at(0).d->values.at(0).type), int(QCss::Value::Identifier)); QCOMPARE(decls.at(0).d->values.at(0).variant.toString(), QString("green")); } else { @@ -1206,11 +1185,11 @@ void tst_QCssParser::specificity() QCss::StyleSheet sheet; QVERIFY(parser.parse(&sheet)); - QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count() + sheet.idIndex.count() , 1); + QCOMPARE(sheet.styleRules.size() + sheet.nameIndex.size() + sheet.idIndex.size() , 1); QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? sheet.styleRules.at(0) : (!sheet.nameIndex.isEmpty()) ? *sheet.nameIndex.begin() : *sheet.idIndex.begin(); - QCOMPARE(rule.selectors.count(), 1); + QCOMPARE(rule.selectors.size(), 1); QTEST(rule.selectors.at(0).specificity(), "specificity"); } @@ -1259,15 +1238,15 @@ void tst_QCssParser::specificitySort() n.ptr = &e; QList<QCss::Declaration> decls = testSelector.declarationsForNode(n); - QCOMPARE(decls.count(), 2); + QCOMPARE(decls.size(), 2); QCOMPARE(int(decls.at(0).d->propertyId), int(QCss::Color)); - QCOMPARE(decls.at(0).d->values.count(), 1); + QCOMPARE(decls.at(0).d->values.size(), 1); QCOMPARE(int(decls.at(0).d->values.at(0).type), int(QCss::Value::Identifier)); QCOMPARE(decls.at(0).d->values.at(0).variant.toString(), QString("green")); QCOMPARE(int(decls.at(1).d->propertyId), int(QCss::Color)); - QCOMPARE(decls.at(1).d->values.count(), 1); + QCOMPARE(decls.at(1).d->values.size(), 1); QCOMPARE(int(decls.at(1).d->values.at(0).type), int(QCss::Value::Identifier)); QCOMPARE(decls.at(1).d->values.at(0).variant.toString(), QString("red")); } @@ -1342,7 +1321,7 @@ void tst_QCssParser::rulesForNode() QList<QCss::StyleRule> rules = testSelector.styleRulesForNode(n); QList<QCss::Declaration> decls; - for (int i = 0; i < rules.count(); i++) { + for (int i = 0; i < rules.size(); i++) { const QCss::Selector &selector = rules.at(i).selectors.at(0); quint64 negated = 0; quint64 cssClass = selector.pseudoClass(&negated); @@ -1351,7 +1330,7 @@ void tst_QCssParser::rulesForNode() decls += rules.at(i).declarations; } - QCOMPARE(decls.count(), declCount); + QCOMPARE(decls.size(), declCount); if (declCount > 0) QCOMPARE(decls.at(0).d->values.at(0).variant.toString(), value0); @@ -1478,14 +1457,14 @@ void tst_QCssParser::pseudoElement() n.ptr = &e; QList<QCss::StyleRule> rules = testSelector.styleRulesForNode(n); QList<QCss::Declaration> decls; - for (int i = 0; i < rules.count(); i++) { + for (int i = 0; i < rules.size(); i++) { const QCss::Selector& selector = rules.at(i).selectors.at(0); if (pseudoElement.compare(selector.pseudoElement(), Qt::CaseInsensitive) != 0) continue; decls += rules.at(i).declarations; } - QCOMPARE(decls.count(), declCount); + QCOMPARE(decls.size(), declCount); } void tst_QCssParser::gradient_data() @@ -1566,20 +1545,26 @@ void tst_QCssParser::gradient() QList<QCss::StyleRule> rules = testSelector.styleRulesForNode(n); QList<QCss::Declaration> decls = rules.at(0).declarations; QCss::ValueExtractor ve(decls); - QBrush fg, sfg; - QBrush sbg, abg; - QVERIFY(ve.extractPalette(&fg, &sfg, &sbg, &abg)); + QBrush foreground; + QBrush selectedForeground; + QBrush selectedBackground; + QBrush alternateBackground; + QBrush placeHolderTextForeground; + QBrush accent; + QVERIFY(ve.extractPalette(&foreground, &selectedForeground, &selectedBackground, + &alternateBackground, &placeHolderTextForeground, &accent)); + if (type == "linear") { - QCOMPARE(sbg.style(), Qt::LinearGradientPattern); - const QLinearGradient *lg = static_cast<const QLinearGradient *>(sbg.gradient()); + QCOMPARE(selectedBackground.style(), Qt::LinearGradientPattern); + const auto *lg = static_cast<const QLinearGradient *>(selectedBackground.gradient()); QCOMPARE(lg->start(), start); QCOMPARE(lg->finalStop(), finalStop); } else if (type == "conical") { - QCOMPARE(sbg.style(), Qt::ConicalGradientPattern); - const QConicalGradient *cg = static_cast<const QConicalGradient *>(sbg.gradient()); + QCOMPARE(selectedBackground.style(), Qt::ConicalGradientPattern); + const auto *cg = static_cast<const QConicalGradient *>(selectedBackground.gradient()); QCOMPARE(cg->center(), start); } - const QGradient *g = sbg.gradient(); + const QGradient *g = selectedBackground.gradient(); QCOMPARE(g->spread(), QGradient::Spread(spread)); QCOMPARE(g->stops().at(0).first, stop0); QCOMPARE(g->stops().at(0).second, color0); @@ -1619,7 +1604,7 @@ void tst_QCssParser::extractFontFamily() QCss::StyleSheet sheet; QVERIFY(parser.parse(&sheet)); - QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCOMPARE(sheet.styleRules.size() + sheet.nameIndex.size(), 1); QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? sheet.styleRules.at(0) : *sheet.nameIndex.begin(); @@ -1677,7 +1662,7 @@ void tst_QCssParser::extractBorder() QCss::StyleSheet sheet; QVERIFY(parser.parse(&sheet)); - QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCOMPARE(sheet.styleRules.size() + sheet.nameIndex.size(), 1); QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? sheet.styleRules.at(0) : *sheet.nameIndex.begin(); const QList<QCss::Declaration> decls = rule.declarations; @@ -1707,7 +1692,7 @@ void tst_QCssParser::noTextDecoration() QCss::StyleSheet sheet; QVERIFY(parser.parse(&sheet)); - QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCOMPARE(sheet.styleRules.size() + sheet.nameIndex.size(), 1); QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? sheet.styleRules.at(0) : *sheet.nameIndex.begin(); const QList<QCss::Declaration> decls = rule.declarations; @@ -1732,7 +1717,7 @@ void tst_QCssParser::quotedAndUnquotedIdentifiers() QCss::StyleSheet sheet; QVERIFY(parser.parse(&sheet)); - QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCOMPARE(sheet.styleRules.size() + sheet.nameIndex.size(), 1); QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? sheet.styleRules.at(0) : *sheet.nameIndex.begin(); const QList<QCss::Declaration> decls = rule.declarations; diff --git a/tests/auto/gui/text/qfont/BLACKLIST b/tests/auto/gui/text/qfont/BLACKLIST index 80f0bf2a3f..f85d8ceebb 100644 --- a/tests/auto/gui/text/qfont/BLACKLIST +++ b/tests/auto/gui/text/qfont/BLACKLIST @@ -1,8 +1,8 @@ [defaultFamily:cursive] -ubuntu-20.04 centos b2qt +rhel [defaultFamily:fantasy] -ubuntu-20.04 centos b2qt +rhel diff --git a/tests/auto/gui/text/qfont/CMakeLists.txt b/tests/auto/gui/text/qfont/CMakeLists.txt index 05c6ca8270..88ae9959e4 100644 --- a/tests/auto/gui/text/qfont/CMakeLists.txt +++ b/tests/auto/gui/text/qfont/CMakeLists.txt @@ -1,36 +1,38 @@ -# Generated from qfont.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qfont Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qfont LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +# Resources: +set(testfont_resource_files + "datastream.515" + "weirdfont.otf" +) + qt_internal_add_test(tst_qfont SOURCES tst_qfont.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::TestPrivate + TESTDATA ${testfont_resource_files} + BUILTIN_TESTDATA ) -# Resources: -set(testfont_resource_files - "weirdfont.otf" -) - -qt_internal_add_resource(tst_qfont "testfont" - PREFIX - "/" - FILES - ${testfont_resource_files} -) - - ## Scopes: ##################################################################### qt_internal_extend_target(tst_qfont CONDITION TARGET Qt::Widgets - PUBLIC_LIBRARIES + LIBRARIES Qt::Widgets ) diff --git a/tests/auto/gui/text/qfont/datastream.515 b/tests/auto/gui/text/qfont/datastream.515 Binary files differnew file mode 100644 index 0000000000..acd99e7e9b --- /dev/null +++ b/tests/auto/gui/text/qfont/datastream.515 diff --git a/tests/auto/gui/text/qfont/testfont.qrc b/tests/auto/gui/text/qfont/testfont.qrc deleted file mode 100644 index cf51e4a2b4..0000000000 --- a/tests/auto/gui/text/qfont/testfont.qrc +++ /dev/null @@ -1,5 +0,0 @@ -<RCC> - <qresource prefix="/"> - <file>weirdfont.otf</file> - </qresource> -</RCC> diff --git a/tests/auto/gui/text/qfont/tst_qfont.cpp b/tests/auto/gui/text/qfont/tst_qfont.cpp index aa9f8a8ce4..5426d7b117 100644 --- a/tests/auto/gui/text/qfont/tst_qfont.cpp +++ b/tests/auto/gui/text/qfont/tst_qfont.cpp @@ -1,35 +1,14 @@ -/**************************************************************************** -** -** 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 + +#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses #include <QTest> #include <QBuffer> #include <QtEndian> +#if QT_CONFIG(process) #include <QProcess> +#endif #include <qfont.h> #include <private/qfont_p.h> @@ -42,6 +21,9 @@ #endif #include <qlist.h> #include <QtTest/private/qemulationdetector_p.h> +#include <private/qcomparisontesthelper_p.h> + +using namespace Qt::StringLiterals; class tst_QFont : public QObject { @@ -60,6 +42,7 @@ private slots: void insertAndRemoveSubstitutions(); void serialize_data(); void serialize(); + void deserializeQt515(); void styleName(); void defaultFamily_data(); @@ -76,6 +59,9 @@ private slots: void setFamilies(); void setFamiliesAndFamily_data(); void setFamiliesAndFamily(); + void featureAccessors(); + void tagCompares_data(); + void tagCompares(); }; // Testing get/set functions @@ -172,7 +158,7 @@ void tst_QFont::italicOblique() continue; } QFont f = QFontDatabase::font(family, style, 12); - QVERIFY(f.italic()); + QVERIFY2(f.italic(), qPrintable(QString::asprintf("Failed for font \"%ls\"", qUtf16Printable(f.family())))); } } } @@ -347,9 +333,6 @@ void tst_QFont::resetFont() QCOMPARE(firstChild.font().resolveMask(), QFont::SizeResolved); QCOMPARE(secondChild.font().resolveMask(), QFont::SizeResolved); -#ifdef Q_OS_ANDROID - QEXPECT_FAIL("", "QTBUG-69214", Continue); -#endif QCOMPARE(firstChild.font().pointSize(), parent.font().pointSize()); QCOMPARE(secondChild.font().pointSize(), parent.font().pointSize()); QVERIFY(parent.font().resolveMask() != 0); @@ -382,15 +365,15 @@ void tst_QFont::insertAndRemoveSubstitutions() // inserting Foo QFont::insertSubstitution("BogusFontFamily", "Foo"); - QCOMPARE(QFont::substitutes("BogusFontFamily").count(), 1); - QCOMPARE(QFont::substitutes("bogusfontfamily").count(), 1); + QCOMPARE(QFont::substitutes("BogusFontFamily").size(), 1); + QCOMPARE(QFont::substitutes("bogusfontfamily").size(), 1); // inserting Bar and Baz QStringList moreFonts; moreFonts << "Bar" << "Baz"; QFont::insertSubstitutions("BogusFontFamily", moreFonts); - QCOMPARE(QFont::substitutes("BogusFontFamily").count(), 3); - QCOMPARE(QFont::substitutes("bogusfontfamily").count(), 3); + QCOMPARE(QFont::substitutes("BogusFontFamily").size(), 3); + QCOMPARE(QFont::substitutes("bogusfontfamily").size(), 3); QFont::removeSubstitutions("BogusFontFamily"); // make sure it is empty again @@ -417,7 +400,7 @@ void tst_QFont::serialize_data() QTest::newRow("defaultConstructed") << font << QDataStream::Qt_1_0; font.setLetterSpacing(QFont::AbsoluteSpacing, 105); - QTest::newRow("letterSpacing") << font << QDataStream::Qt_4_5; + QTest::newRow("letterSpacing=105") << font << QDataStream::Qt_4_5; font = basicFont; font.setWordSpacing(50.0); @@ -461,7 +444,7 @@ void tst_QFont::serialize_data() font = basicFont; font.setLetterSpacing(QFont::AbsoluteSpacing, 10); // Fails for 4.4 because letterSpacing wasn't read until 4.5. - QTest::newRow("letterSpacing") << font << QDataStream::Qt_4_5; + QTest::newRow("letterSpacing=10") << font << QDataStream::Qt_4_5; font = basicFont; font.setKerning(false); @@ -512,6 +495,43 @@ void tst_QFont::serialize() } } +void tst_QFont::deserializeQt515() +{ + QFile file; + file.setFileName(QFINDTESTDATA("datastream.515")); + QVERIFY(file.open(QIODevice::ReadOnly)); + + QFont font; + { + QDataStream stream(&file); + stream.setVersion(QDataStream::Qt_5_15); + stream >> font; + } + + QCOMPARE(font.family(), QStringLiteral("FirstFamily")); + QCOMPARE(font.families().size(), 3); + QCOMPARE(font.families().at(0), QStringLiteral("FirstFamily")); + QCOMPARE(font.families().at(1), QStringLiteral("OtherFamily1")); + QCOMPARE(font.families().at(2), QStringLiteral("OtherFamily2")); + QCOMPARE(font.pointSize(), 12); + + QVERIFY(file.reset()); + QByteArray fileContent = file.readAll(); + QByteArray serializedContent; + { + QBuffer buffer(&serializedContent); + QVERIFY(buffer.open(QIODevice::WriteOnly)); + + QDataStream stream(&buffer); + stream.setVersion(QDataStream::Qt_5_15); + stream << font; + } + + QCOMPARE(serializedContent, fileContent); + + file.close(); +} + void tst_QFont::styleName() { #if !defined(Q_OS_MAC) @@ -577,6 +597,11 @@ void tst_QFont::defaultFamily() break; } } + +#if defined(Q_OS_UNIX) && defined(QT_NO_FONTCONFIG) + QSKIP("This platform does not support checking for default font acceptability"); +#endif + #ifdef Q_PROCESSOR_ARM_32 if (QTestPrivate::isRunningArmOnX86()) QEXPECT_FAIL("", "Fails on ARMv7 QEMU (QTQAINFRA-4127)", Continue); @@ -824,5 +849,83 @@ void tst_QFont::setFamiliesAndFamily() QFontDatabase::removeApplicationFont(weirdFontId); } +void tst_QFont::featureAccessors() +{ + const QFont::Tag abcdTag("abcd"); + QCOMPARE(abcdTag.toString(), "abcd"); + QVERIFY(abcdTag.isValid()); + + QFont font; + QVERIFY(font.featureTags().isEmpty()); + font.setFeature("abcd", 0xc0ffee); + + QVERIFY(font.isFeatureSet(abcdTag)); + QVERIFY(!font.isFeatureSet("bcde")); + QCOMPARE(font.featureTags().size(), 1); + QCOMPARE(font.featureTags().first(), abcdTag); + QCOMPARE(font.featureTags().first(), "abcd"); + QCOMPARE(font.featureValue(abcdTag), 0xc0ffeeU); + QCOMPARE(font.featureValue("bcde"), 0U); + font.setFeature(abcdTag, 0xf00d); + QCOMPARE(font.featureTags().size(), 1); + QCOMPARE(font.featureValue(abcdTag), 0xf00dU); + + QFont::Tag invalidTag; + QVERIFY(!invalidTag.isValid()); + font.setFeature(invalidTag, 0xcaca0); + QVERIFY(!font.isFeatureSet(invalidTag)); + QCOMPARE(font.featureTags().size(), 1); + QFont font2 = font; + + font.unsetFeature("abcd"); + QVERIFY(!font.isFeatureSet("abcd")); + QVERIFY(font.featureTags().isEmpty()); + + QVERIFY(font2.isFeatureSet("abcd")); + font2.clearFeatures(); + QVERIFY(font.featureTags().isEmpty()); + + // various constructor compile tests + QFont::Tag tag; + tag = QFont::Tag("1234"); + QVERIFY(QFont::Tag::fromString(QByteArray("abcd"))); + QVERIFY(QFont::Tag::fromString(u"frac"_s)); + + // named constructors with invalid input + QTest::ignoreMessage(QtWarningMsg, "The tag name must be exactly 4 characters long!"); + QVERIFY(!QFont::Tag::fromString(u"fraction"_s)); + QVERIFY(!QFont::Tag::fromValue(0)); + QVERIFY(QFont::Tag::fromValue(abcdTag.value())); + + enum Features { + Frac = QFont::Tag("frac").value() + }; +} + +void tst_QFont::tagCompares_data() +{ + QTestPrivate::testAllComparisonOperatorsCompile<QFont::Tag>(); + + QTest::addColumn<QFont::Tag>("lhs"); + QTest::addColumn<QFont::Tag>("rhs"); + QTest::addColumn<Qt::strong_ordering>("expectedOrder"); + + auto row = [](QFont::Tag left, QFont::Tag right) { + QTest::addRow("%s<=>%s", left.toString().constData(), right.toString().constData()) + << left << right << Qt::compareThreeWay(left.value(), right.value()); + }; + row("frac", "wght"); +} + +void tst_QFont::tagCompares() +{ + QFETCH(QFont::Tag, lhs); + QFETCH(QFont::Tag, rhs); + QFETCH(Qt::strong_ordering, expectedOrder); + + QVERIFY(comparesEqual(lhs, lhs)); + QCOMPARE(compareThreeWay(lhs, rhs), expectedOrder); +} + QTEST_MAIN(tst_QFont) #include "tst_qfont.moc" diff --git a/tests/auto/gui/text/qfontcache/CMakeLists.txt b/tests/auto/gui/text/qfontcache/CMakeLists.txt index fb93c91e0c..d9645c115a 100644 --- a/tests/auto/gui/text/qfontcache/CMakeLists.txt +++ b/tests/auto/gui/text/qfontcache/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qfontcache.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qfontcache Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qfontcache LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qfontcache SOURCES tst_qfontcache.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/gui/text/qfontcache/tst_qfontcache.cpp b/tests/auto/gui/text/qfontcache/tst_qfontcache.cpp index 3a7eebdc64..79f24a2f0d 100644 --- a/tests/auto/gui/text/qfontcache/tst_qfontcache.cpp +++ b/tests/auto/gui/text/qfontcache/tst_qfontcache.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 <QTest> @@ -47,6 +22,7 @@ private slots: void engineData(); void engineDataFamilies_data(); void engineDataFamilies(); + void threadedAccess(); void clear(); }; @@ -227,5 +203,51 @@ for (int i = 0; i < leakedEngines.size(); ++i) qWarning() << i << leakedEngines. #endif } +struct MessageHandler +{ + MessageHandler() + { + oldMessageHandler = qInstallMessageHandler(myMessageHandler); + messages.clear(); + } + ~MessageHandler() + { + qInstallMessageHandler(oldMessageHandler); + } + + inline static bool receivedMessage = false; + inline static QtMessageHandler oldMessageHandler = nullptr; + inline static QStringList messages; + static void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &text) + { + if (!text.startsWith("Populating font family aliases took")) { + receivedMessage = true; + messages += text; + } + if (oldMessageHandler) + oldMessageHandler(type, context, text); + } +}; + + +void tst_QFontCache::threadedAccess() +{ + MessageHandler messageHandler; + auto lambda = []{ + for (const auto &family : QFontDatabase::families()) { + QFont font(family); + QFontMetrics fontMetrics(font); + fontMetrics.height(); + } + }; + auto *qThread = QThread::create(lambda); + qThread->start(); + qThread->wait(); + + std::thread stdThread(lambda); + stdThread.join(); + QVERIFY2(!messageHandler.receivedMessage, qPrintable(messageHandler.messages.join('\n'))); +} + QTEST_MAIN(tst_QFontCache) #include "tst_qfontcache.moc" diff --git a/tests/auto/gui/text/qfontdatabase/BLACKLIST b/tests/auto/gui/text/qfontdatabase/BLACKLIST index 95494d6111..88aa9e9c79 100644 --- a/tests/auto/gui/text/qfontdatabase/BLACKLIST +++ b/tests/auto/gui/text/qfontdatabase/BLACKLIST @@ -1,5 +1,4 @@ -[systemFixedFont] # QTBUG-54623 -b2qt -# QTBUG-87405 [systemFixedFont] -android +b2qt +# QTBUG-100948 +qnx diff --git a/tests/auto/gui/text/qfontdatabase/CMakeLists.txt b/tests/auto/gui/text/qfontdatabase/CMakeLists.txt index 73ab56d49f..18b96ded5d 100644 --- a/tests/auto/gui/text/qfontdatabase/CMakeLists.txt +++ b/tests/auto/gui/text/qfontdatabase/CMakeLists.txt @@ -1,16 +1,23 @@ -# Generated from qfontdatabase.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qfontdatabase Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qfontdatabase LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + # Collect test data list(APPEND test_data "LED_REAL.TTF") qt_internal_add_test(tst_qfontdatabase SOURCES tst_qfontdatabase.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate @@ -30,11 +37,15 @@ set_source_files_properties("../../../shared/resources/testfont_italic.ttf" set_source_files_properties("../../../shared/resources/testfont_open.otf" PROPERTIES QT_RESOURCE_ALIAS "testfont_open.otf" ) +set_source_files_properties("../../../shared/resources/testfont_variable.ttf" + PROPERTIES QT_RESOURCE_ALIAS "testfont_variable.ttf" +) set(testdata_resource_files "../../../shared/resources/testfont.ttf" "../../../shared/resources/testfont_condensed.ttf" "../../../shared/resources/testfont_italic.ttf" "../../../shared/resources/testfont_open.otf" + "../../../shared/resources/testfont_variable.ttf" "LED_REAL.TTF" ) diff --git a/tests/auto/gui/text/qfontdatabase/testdata.qrc b/tests/auto/gui/text/qfontdatabase/testdata.qrc deleted file mode 100644 index a590099b20..0000000000 --- a/tests/auto/gui/text/qfontdatabase/testdata.qrc +++ /dev/null @@ -1,9 +0,0 @@ -<RCC> - <qresource prefix="/"> - <file>LED_REAL.TTF</file> - <file alias="testfont.ttf">../../../shared/resources/testfont.ttf</file> - <file alias="testfont_condensed.ttf">../../../shared/resources/testfont_condensed.ttf</file> - <file alias="testfont_italic.ttf">../../../shared/resources/testfont_italic.ttf</file> - <file alias="testfont_open.otf">../../../shared/resources/testfont_open.otf</file> - </qresource> -</RCC> diff --git a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp index 2f63221d54..849e7432d1 100644 --- a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp +++ b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.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 <QTest> #include <QSignalSpy> @@ -34,7 +9,14 @@ #include <qfontmetrics.h> #include <qtextlayout.h> #include <private/qrawfont_p.h> +#include <private/qfont_p.h> +#include <private/qfontengine_p.h> #include <qpa/qplatformfontdatabase.h> +#include <qpa/qplatformintegration.h> + +#include <QtGui/private/qguiapplication_p.h> + +using namespace Qt::StringLiterals; Q_LOGGING_CATEGORY(lcTests, "qt.text.tests") @@ -80,11 +62,22 @@ private slots: void registerOpenTypePreferredNamesSystem(); void registerOpenTypePreferredNamesApplication(); + void stretchRespected(); + + void variableFont(); + +#ifdef Q_OS_WIN + void findCourier(); +#endif + + void addApplicationFontFallback(); + private: QString m_ledFont; QString m_testFont; QString m_testFontCondensed; QString m_testFontItalic; + QString m_testFontVariable; }; tst_QFontDatabase::tst_QFontDatabase() @@ -97,10 +90,12 @@ void tst_QFontDatabase::initTestCase() m_testFont = QFINDTESTDATA("testfont.ttf"); m_testFontCondensed = QFINDTESTDATA("testfont_condensed.ttf"); m_testFontItalic = QFINDTESTDATA("testfont_italic.ttf"); + m_testFontVariable = QFINDTESTDATA("testfont_variable.ttf"); QVERIFY(!m_ledFont.isEmpty()); QVERIFY(!m_testFont.isEmpty()); QVERIFY(!m_testFontCondensed.isEmpty()); QVERIFY(!m_testFontItalic.isEmpty()); + QVERIFY(!m_testFontVariable.isEmpty()); } void tst_QFontDatabase::styles_data() @@ -238,7 +233,7 @@ void tst_QFontDatabase::addAppFont() int id; if (useMemoryFont) { QFile fontfile(m_ledFont); - fontfile.open(QIODevice::ReadOnly); + QVERIFY(fontfile.open(QIODevice::ReadOnly)); QByteArray fontdata = fontfile.readAll(); QVERIFY(!fontdata.isEmpty()); id = QFontDatabase::addApplicationFontFromData(fontdata); @@ -251,7 +246,7 @@ void tst_QFontDatabase::addAppFont() QCOMPARE(id, -1); return; #endif - QCOMPARE(fontDbChangedSpy.count(), 1); + QCOMPARE(fontDbChangedSpy.size(), 1); if (id == -1) QSKIP("Skip the test since app fonts are not supported on this system"); @@ -260,9 +255,9 @@ void tst_QFontDatabase::addAppFont() const QStringList newFamilies = QFontDatabase::families(); QVERIFY(!newFamilies.isEmpty()); - QVERIFY(newFamilies.count() >= oldFamilies.count()); + QVERIFY(newFamilies.size() >= oldFamilies.size()); - for (int i = 0; i < addedFamilies.count(); ++i) { + for (int i = 0; i < addedFamilies.size(); ++i) { QString family = addedFamilies.at(i); QVERIFY(newFamilies.contains(family)); QFont qfont(family); @@ -271,9 +266,9 @@ void tst_QFontDatabase::addAppFont() } QVERIFY(QFontDatabase::removeApplicationFont(id)); - QCOMPARE(fontDbChangedSpy.count(), 2); + QCOMPARE(fontDbChangedSpy.size(), 2); - QCOMPARE(QFontDatabase::families(), oldFamilies); + QVERIFY(QFontDatabase::families().size() <= oldFamilies.size()); } void tst_QFontDatabase::addTwoAppFontsFromFamily() @@ -334,8 +329,8 @@ void tst_QFontDatabase::fallbackFonts() layout.createLine(); layout.endLayout(); - QList<QGlyphRun> runs = layout.glyphRuns(0, 1); - foreach (QGlyphRun run, runs) { + const QList<QGlyphRun> runs = layout.glyphRuns(0, 1); + for (QGlyphRun run : runs) { QRawFont rawFont = run.rawFont(); QVERIFY(rawFont.isValid()); @@ -349,6 +344,28 @@ static QString testString() return QStringLiteral("foo bar"); } +void tst_QFontDatabase::stretchRespected() +{ + int italicId = QFontDatabase::addApplicationFont(m_testFontItalic); + QVERIFY(italicId != -1); + + QVERIFY(!QFontDatabase::applicationFontFamilies(italicId).isEmpty()); + + QString italicFontName = QFontDatabase::applicationFontFamilies(italicId).first(); + + QFont italicFont = QFontDatabase::font(italicFontName, + QString::fromLatin1("Italic"), 14); + QVERIFY(italicFont.italic()); + + QFont italicStretchedFont = italicFont; + italicStretchedFont.setStretch( 400 ); + + QVERIFY(QFontMetricsF(italicFont).horizontalAdvance(QStringLiteral("foobar")) < + QFontMetricsF(italicStretchedFont).horizontalAdvance(QStringLiteral("foobar"))); + + QFontDatabase::removeApplicationFont(italicId); +} + void tst_QFontDatabase::condensedFontWidthNoFontMerging() { int regularFontId = QFontDatabase::addApplicationFont(m_testFont); @@ -405,12 +422,15 @@ void tst_QFontDatabase::condensedFontMatching() tfcByStyleName.setStyleName("Condensed"); #ifdef Q_OS_WIN - QEXPECT_FAIL("","No matching of sub-family by stretch on Windows", Continue); + QFont f; + f.setStyleStrategy(QFont::NoFontMerging); + QFontPrivate *font_d = QFontPrivate::get(f); + if (font_d->engineForScript(QChar::Script_Common)->type() != QFontEngine::Freetype + && font_d->engineForScript(QChar::Script_Common)->type() != QFontEngine::DirectWrite) { + QEXPECT_FAIL("","No matching of sub-family by stretch on Windows", Continue); + } #endif -#ifdef Q_OS_ANDROID - QEXPECT_FAIL("", "QTBUG-69216", Continue); -#endif QCOMPARE(QFontMetrics(tfcByStretch).horizontalAdvance(testString()), QFontMetrics(tfcByStyleName).horizontalAdvance(testString())); @@ -470,5 +490,150 @@ void tst_QFontDatabase::registerOpenTypePreferredNamesApplication() QFontDatabase::removeApplicationFont(id); } +#ifdef Q_OS_WIN +void tst_QFontDatabase::findCourier() +{ + QFont font = QFontDatabase::font(u"Courier"_s, u""_s, 16); + QFontInfo info(font); + QCOMPARE(info.family(), u"Courier New"_s); + QCOMPARE(info.pointSize(), 16); + + font = QFontDatabase::font("Courier", "", 64); + info = font; + QCOMPARE(info.family(), u"Courier New"_s); + QCOMPARE(info.pointSize(), 64); + + // By setting "PreferBitmap" we should get Courier itself. + font.setStyleStrategy(QFont::PreferBitmap); + info = font; + QCOMPARE(info.family(), u"Courier"_s); + // Which has an upper bound on point size + QCOMPARE(info.pointSize(), 19); + + font.setStyleStrategy(QFont::PreferDefault); + info = font; + QCOMPARE(info.family(), u"Courier New"_s); + QCOMPARE(info.pointSize(), 64); +} +#endif + +void tst_QFontDatabase::variableFont() +{ + { + QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); + if (!pfdb->supportsVariableApplicationFonts()) + QSKIP("Variable application fonts not supported on this platform"); + } + + int id = QFontDatabase::addApplicationFont(m_testFontVariable); + if (id == -1) + QSKIP("Skip the test since app fonts are not supported on this system"); + + QString family = QFontDatabase::applicationFontFamilies(id).first(); + { + QFont font(family); + QCOMPARE(QFontInfo(font).styleName(), u"Regular"_s); + QCOMPARE(QFontInfo(font).weight(), QFont::Normal); + } + + { + QFont font(family); + font.setWeight(QFont::Black); + QCOMPARE(QFontInfo(font).styleName(), u"QtExtraBold"_s); + QCOMPARE(QFontInfo(font).weight(), int(QFont::Black)); + } + + { + QFont regularFont(family); + QFont extraBoldFont(family); + extraBoldFont.setStyleName(u"QtExtraBold"_s); + + QFontMetricsF regularFm(regularFont); + QFontMetricsF extraBoldFm(extraBoldFont); + + QVERIFY(regularFm.horizontalAdvance(QLatin1Char('1')) < extraBoldFm.horizontalAdvance(QLatin1Char('1'))); + } + + QFontDatabase::removeApplicationFont(id); +} + +void tst_QFontDatabase::addApplicationFontFallback() +{ + int ledId = -1; + int id = -1; + auto cleanup = qScopeGuard([&id, &ledId] { + if (id >= 0) + QFontDatabase::removeApplicationFont(id); + if (ledId >= 0) + QFontDatabase::removeApplicationFont(ledId); + }); + + const QChar hebrewChar(0x05D0); // Hebrew 'aleph' + + ledId = QFontDatabase::addApplicationFont(m_ledFont); + if (ledId < 0) + QSKIP("Skip the test since app fonts are not supported on this system"); + + auto getHebrewFont = [&]() { + QTextLayout layout; + layout.setText(hebrewChar); + layout.setFont(QFont(u"LED Real"_s)); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList<QGlyphRun> glyphRuns = layout.glyphRuns(); + if (glyphRuns.isEmpty()) + return QString{}; + + return glyphRuns.first().rawFont().familyName(); + }; + + QString defaultHebrewFont = getHebrewFont(); + if (defaultHebrewFont.isEmpty()) + QSKIP("Skip the test since Hebrew is not supported on this system"); + + QVERIFY(QFontDatabase::applicationFallbackFontFamilies(QChar::Script_Hebrew).isEmpty()); + QFontDatabase::addApplicationFallbackFontFamily(QChar::Script_Hebrew, u"QtBidiTestFont"_s); + + QCOMPARE(QFontDatabase::applicationFallbackFontFamilies(QChar::Script_Hebrew).size(), 1); + QCOMPARE(QFontDatabase::applicationFallbackFontFamilies(QChar::Script_Hebrew).first(), u"QtBidiTestFont"_s); + + { + QString hebrewFontNow = getHebrewFont(); + QCOMPARE(hebrewFontNow, defaultHebrewFont); + } + + id = QFontDatabase::addApplicationFont(m_testFont); + QVERIFY(id >= 0); + + { + QString hebrewFontNow = getHebrewFont(); + QCOMPARE(hebrewFontNow, u"QtBidiTestFont"_s); + } + + QFontDatabase::removeApplicationFallbackFontFamily(QChar::Script_Hebrew, u"QtBidiTestFont"_s); + + { + QString hebrewFontNow = getHebrewFont(); + QCOMPARE(hebrewFontNow, defaultHebrewFont); + } + + QFontDatabase::setApplicationFallbackFontFamilies(QChar::Script_Hebrew, QStringList(u"QtBidiTestFont"_s)); + + { + QString hebrewFontNow = getHebrewFont(); + QCOMPARE(hebrewFontNow, u"QtBidiTestFont"_s); + } + + QFontDatabase::setApplicationFallbackFontFamilies(QChar::Script_Hebrew, QStringList{}); + + { + QString hebrewFontNow = getHebrewFont(); + QCOMPARE(hebrewFontNow, defaultHebrewFont); + } + +} + QTEST_MAIN(tst_QFontDatabase) #include "tst_qfontdatabase.moc" diff --git a/tests/auto/gui/text/qfontmetrics/CMakeLists.txt b/tests/auto/gui/text/qfontmetrics/CMakeLists.txt index d7a22671d6..d014d27d46 100644 --- a/tests/auto/gui/text/qfontmetrics/CMakeLists.txt +++ b/tests/auto/gui/text/qfontmetrics/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qfontmetrics.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qfontmetrics Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qfontmetrics LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qfontmetrics SOURCES tst_qfontmetrics.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/gui/text/qfontmetrics/testfont.qrc b/tests/auto/gui/text/qfontmetrics/testfont.qrc deleted file mode 100644 index 30b4a3f82e..0000000000 --- a/tests/auto/gui/text/qfontmetrics/testfont.qrc +++ /dev/null @@ -1,6 +0,0 @@ -<RCC> - <qresource prefix="/fonts"> - <file>ucs4font.ttf</file> - <file alias="testfont.ttf">../../../shared/resources/testfont.ttf</file> - </qresource> -</RCC> diff --git a/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp b/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp index c78475a76f..9471c1d93f 100644 --- a/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp +++ b/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.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 <QTest> @@ -43,6 +18,7 @@ private slots: void same(); void metrics(); void boundingRect(); + void boundingRect2(); void elidedText_data(); void elidedText(); void veryNarrowElidedText(); @@ -56,6 +32,10 @@ private slots: void leadingBelowLine(); void elidedMetrics(); void zeroWidthMetrics(); + void verticalMetrics_data(); + void verticalMetrics(); + void largeText_data(); + void largeText(); // QTBUG-123339 }; void tst_QFontMetrics::same() @@ -149,6 +129,21 @@ void tst_QFontMetrics::boundingRect() QVERIFY(r.top() < 0); } +void tst_QFontMetrics::boundingRect2() +{ + QFont f; + f.setPixelSize(16); + QFontMetricsF fm(f); + QString str("AVAVAVA vvvvvvvvvv fffffffff file"); + QRectF br = fm.boundingRect(str); + QRectF tbr = fm.tightBoundingRect(str); + qreal advance = fm.horizontalAdvance(str); + // Bounding rect plus bearings should be similar to advance + qreal bearings = fm.leftBearing(QChar('A')) + fm.rightBearing(QChar('e')); + QVERIFY(qAbs(br.width() + bearings - advance) < fm.averageCharWidth()/2.0); + QVERIFY(qAbs(tbr.width() + bearings - advance) < fm.averageCharWidth()/2.0); +} + void tst_QFontMetrics::elidedText_data() { QTest::addColumn<QFont>("font"); @@ -268,7 +263,7 @@ void tst_QFontMetrics::inFontUcs4() glyphs.glyphs[0] = 0; QVERIFY(engine->stringToCMap(string.constData(), string.size(), &glyphs, &glyphs.numGlyphs, - QFontEngine::GlyphIndicesOnly)); + QFontEngine::GlyphIndicesOnly) > 0); QCOMPARE(glyphs.numGlyphs, 1); QCOMPARE(glyphs.glyphs[0], uint(1)); } @@ -280,7 +275,7 @@ void tst_QFontMetrics::inFontUcs4() glyphs.glyphs[0] = 0; QVERIFY(engine->stringToCMap(string.constData(), string.size(), &glyphs, &glyphs.numGlyphs, - QFontEngine::GlyphIndicesOnly)); + QFontEngine::GlyphIndicesOnly) >= 0); QVERIFY(glyphs.glyphs[0] != 1); } } @@ -374,6 +369,45 @@ void tst_QFontMetrics::zeroWidthMetrics() QCOMPARE(fm.horizontalAdvance(string3), fm.horizontalAdvance(string4)); QCOMPARE(fm.boundingRect(string1).width(), fm.boundingRect(string2).width()); QCOMPARE(fm.boundingRect(string3).width(), fm.boundingRect(string4).width()); + QCOMPARE(fm.tightBoundingRect(string1).width(), fm.tightBoundingRect(string2).width()); + QCOMPARE(fm.tightBoundingRect(string3).width(), fm.tightBoundingRect(string4).width()); +} + +void tst_QFontMetrics::verticalMetrics_data() +{ + QTest::addColumn<QFont>("font"); + QStringList families = QFontDatabase::families(); + for (const QString &family : families) { + QFont font(family); + QTest::newRow(family.toUtf8()) << font; + } +} + +void tst_QFontMetrics::verticalMetrics() +{ + QFETCH(QFont, font); + QFontMetrics fm(font); + QVERIFY(fm.ascent() != 0 || fm.descent() != 0); +} + +void tst_QFontMetrics::largeText_data() +{ + QTest::addColumn<qsizetype>("size"); + for (int i = 1; i < 20; ++i) { + qsizetype size = qsizetype(1) << i; + QByteArray rowText = QByteArray::number(size); + QTest::newRow(rowText.constData()) << size; + } +} + +void tst_QFontMetrics::largeText() +{ + QFont font; + QFontMetrics fm(font); + QFETCH(qsizetype, size); + QString string(size, QLatin1Char('A')); + QRect boundingRect = fm.boundingRect(string); + QVERIFY(boundingRect.isValid()); } QTEST_MAIN(tst_QFontMetrics) diff --git a/tests/auto/gui/text/qglyphrun/BLACKLIST b/tests/auto/gui/text/qglyphrun/BLACKLIST deleted file mode 100644 index d8fefd3d9f..0000000000 --- a/tests/auto/gui/text/qglyphrun/BLACKLIST +++ /dev/null @@ -1,3 +0,0 @@ -[mixedScripts] -ubuntu-18.04 -ubuntu-20.04 diff --git a/tests/auto/gui/text/qglyphrun/CMakeLists.txt b/tests/auto/gui/text/qglyphrun/CMakeLists.txt index b0585af16f..a9ffd3729d 100644 --- a/tests/auto/gui/text/qglyphrun/CMakeLists.txt +++ b/tests/auto/gui/text/qglyphrun/CMakeLists.txt @@ -1,15 +1,15 @@ -# Generated from qglyphrun.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qglyphrun Test: ##################################################################### -qt_internal_add_test(tst_qglyphrun - SOURCES - tst_qglyphrun.cpp - PUBLIC_LIBRARIES - Qt::Gui -) +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qglyphrun LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() # Resources: set_source_files_properties("../../../shared/resources/test.ttf" @@ -17,12 +17,15 @@ set_source_files_properties("../../../shared/resources/test.ttf" ) set(testdata_resource_files "../../../shared/resources/test.ttf" + "Ligatures.otf" ) -qt_internal_add_resource(tst_qglyphrun "testdata" - PREFIX - "/" - FILES - ${testdata_resource_files} +qt_internal_add_test(tst_qglyphrun + SOURCES + tst_qglyphrun.cpp + LIBRARIES + Qt::Gui + TESTDATA ${testdata_resource_files} + BUILTIN_TESTDATA ) diff --git a/tests/auto/gui/text/qglyphrun/Ligatures.otf b/tests/auto/gui/text/qglyphrun/Ligatures.otf Binary files differnew file mode 100644 index 0000000000..194218a0f6 --- /dev/null +++ b/tests/auto/gui/text/qglyphrun/Ligatures.otf diff --git a/tests/auto/gui/text/qglyphrun/testdata.qrc b/tests/auto/gui/text/qglyphrun/testdata.qrc deleted file mode 100644 index 25cadc477e..0000000000 --- a/tests/auto/gui/text/qglyphrun/testdata.qrc +++ /dev/null @@ -1,5 +0,0 @@ -<RCC> - <qresource prefix="/"> - <file alias="test.ttf">../../../shared/resources/test.ttf</file> - </qresource> -</RCC> diff --git a/tests/auto/gui/text/qglyphrun/tst_qglyphrun.cpp b/tests/auto/gui/text/qglyphrun/tst_qglyphrun.cpp index 119ec7a19d..8c0c0324c9 100644 --- a/tests/auto/gui/text/qglyphrun/tst_qglyphrun.cpp +++ b/tests/auto/gui/text/qglyphrun/tst_qglyphrun.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 <QTest> @@ -64,6 +39,10 @@ private slots: void mixedScripts(); void multiLineBoundingRect(); void defaultIgnorables(); + void stringIndexes(); + void retrievalFlags_data(); + void retrievalFlags(); + void objectReplacementCharacter(); private: int m_testFontId; @@ -429,7 +408,7 @@ void tst_QGlyphRun::drawMultiScriptText1() QPixmap drawGlyphs(1000, 1000); drawGlyphs.fill(Qt::white); - QList<QGlyphRun> glyphsList = textLayout.glyphRuns(); + const QList<QGlyphRun> glyphsList = textLayout.glyphRuns(); QCOMPARE(glyphsList.size(), 1); { @@ -439,8 +418,7 @@ void tst_QGlyphRun::drawMultiScriptText1() { QPainter p(&drawGlyphs); - foreach (QGlyphRun glyphs, glyphsList) - p.drawGlyphRun(QPointF(50, 50), glyphs); + p.drawGlyphRun(QPointF(50, 50), glyphsList.first()); } #if defined(DEBUG_SAVE_IMAGE) @@ -470,7 +448,7 @@ void tst_QGlyphRun::drawMultiScriptText2() QPixmap drawGlyphs(1000, 1000); drawGlyphs.fill(Qt::white); - QList<QGlyphRun> glyphsList = textLayout.glyphRuns(); + const QList<QGlyphRun> glyphsList = textLayout.glyphRuns(); QCOMPARE(glyphsList.size(), 2); { @@ -480,7 +458,7 @@ void tst_QGlyphRun::drawMultiScriptText2() { QPainter p(&drawGlyphs); - foreach (QGlyphRun glyphs, glyphsList) + for (const QGlyphRun &glyphs : glyphsList) p.drawGlyphRun(QPointF(50, 50), glyphs); } @@ -585,6 +563,9 @@ void tst_QGlyphRun::boundingRect() void tst_QGlyphRun::mixedScripts() { + if (QFontDatabase::families(QFontDatabase::Korean).isEmpty()) + QSKIP("This test requires support for Hangul text"); + QString s; s += QChar(0x31); // The character '1' s += QChar(0xbc14); // Hangul character @@ -630,17 +611,365 @@ void tst_QGlyphRun::multiLineBoundingRect() void tst_QGlyphRun::defaultIgnorables() { + { + QTextLayout layout; + layout.setFont(QFont("QtsSpecialTestFont")); + layout.setText(QChar(0x200D)); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList<QGlyphRun> runs = layout.glyphRuns(); + QCOMPARE(runs.size(), 0); + } + + { + QTextLayout layout; + layout.setFont(QFont("QtsSpecialTestFont")); + layout.setText(QStringLiteral("AAA") + QChar(0xFE0F) + QStringLiteral("111")); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList<QGlyphRun> runs = layout.glyphRuns(); + QVERIFY(!runs.isEmpty()); + + bool hasFullMainFontRun = false; + for (const QGlyphRun &run : runs) { + // QtsSpecialFont will be used for at least five characters: AA[...]111 + // Depending on the font selected for the 0xFE0F variant selector, the + // third 'A' may be in QtsSpecialFont or in the fallback. This is platform-specific, + // so we accept either. + if (run.rawFont().familyName() == QStringLiteral("QtsSpecialTestFont") + && run.glyphIndexes().size() >= 5) { + hasFullMainFontRun = true; + break; + } + } + QVERIFY(hasFullMainFontRun); + } +} + +void tst_QGlyphRun::stringIndexes() +{ + int ligatureFontId = QFontDatabase::addApplicationFont(QFINDTESTDATA("Ligatures.otf")); + QVERIFY(ligatureFontId >= 0); + + QFont ligatureFont = QFont("QtLigatures"); + QCOMPARE(QFontInfo(ligatureFont).family(), QString::fromLatin1("QtLigatures")); + + QTextLayout::GlyphRunRetrievalFlags retrievalFlags + = QTextLayout::RetrieveGlyphIndexes | QTextLayout::RetrieveStringIndexes; + + // Three characters -> three glyphs + { + QTextLayout layout; + layout.setText("f i"); + layout.setFont(ligatureFont); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + { + QList<QGlyphRun> glyphRuns = layout.glyphRuns(-1, -1, retrievalFlags); + QCOMPARE(glyphRuns.size(), 1); + + QList<qsizetype> stringIndexes = glyphRuns.at(0).stringIndexes(); + QCOMPARE(stringIndexes.size(), 3); + QCOMPARE(stringIndexes.at(0), 0); + QCOMPARE(stringIndexes.at(1), 1); + QCOMPARE(stringIndexes.at(2), 2); + } + + { + QList<QGlyphRun> glyphRuns = layout.glyphRuns(2, -1, retrievalFlags); + QCOMPARE(glyphRuns.size(), 1); + + QList<qsizetype> stringIndexes = glyphRuns.at(0).stringIndexes(); + QCOMPARE(stringIndexes.size(), 1); + QCOMPARE(stringIndexes.at(0), 2); + } + } + + // Two characters -> one glyph + { + QTextLayout layout; + layout.setText("fi"); + layout.setFont(ligatureFont); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + { + QList<QGlyphRun> glyphRuns = layout.glyphRuns(-1, -1, retrievalFlags); + QCOMPARE(glyphRuns.size(), 1); + + QCOMPARE(glyphRuns.at(0).glyphIndexes().size(), 1); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(0), uint(233)); + + QList<qsizetype> stringIndexes = glyphRuns.at(0).stringIndexes(); + QCOMPARE(stringIndexes.size(), 1); + QCOMPARE(stringIndexes.at(0), 0); + } + + { + QList<QGlyphRun> glyphRuns = layout.glyphRuns(1, -1, retrievalFlags); + QCOMPARE(glyphRuns.size(), 1); + + QCOMPARE(glyphRuns.at(0).glyphIndexes().size(), 1); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(0), uint(233)); + + QList<qsizetype> stringIndexes = glyphRuns.at(0).stringIndexes(); + QCOMPARE(stringIndexes.size(), 1); + QCOMPARE(stringIndexes.at(0), 1); + } + } + + // Four characters -> three glyphs + { + QTextLayout layout; + layout.setText("ffii"); + layout.setFont(ligatureFont); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + { + QList<QGlyphRun> glyphRuns = layout.glyphRuns(-1, -1, retrievalFlags); + QCOMPARE(glyphRuns.size(), 1); + + QCOMPARE(glyphRuns.at(0).glyphIndexes().size(), 3); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(0), uint(71)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(1), uint(233)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(2), uint(74)); + + QList<qsizetype> stringIndexes = glyphRuns.at(0).stringIndexes(); + QCOMPARE(stringIndexes.size(), 3); + QCOMPARE(stringIndexes.at(0), uint(0)); + QCOMPARE(stringIndexes.at(1), uint(1)); + QCOMPARE(stringIndexes.at(2), uint(3)); + } + + { + QList<QGlyphRun> glyphRuns = layout.glyphRuns(1, 1, retrievalFlags); + QCOMPARE(glyphRuns.size(), 1); + + QCOMPARE(glyphRuns.at(0).glyphIndexes().size(), 1); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(0), uint(233)); + + QList<qsizetype> stringIndexes = glyphRuns.at(0).stringIndexes(); + QCOMPARE(stringIndexes.size(), 1); + QCOMPARE(stringIndexes.at(0), uint(1)); + } + + { + QList<QGlyphRun> glyphRuns = layout.glyphRuns(1, 2, retrievalFlags); + QCOMPARE(glyphRuns.size(), 1); + + QCOMPARE(glyphRuns.at(0).glyphIndexes().size(), 1); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(0), uint(233)); + + QList<qsizetype> stringIndexes = glyphRuns.at(0).stringIndexes(); + QCOMPARE(stringIndexes.size(), 1); + QCOMPARE(stringIndexes.at(0), uint(1)); + } + + { + QList<QGlyphRun> glyphRuns = layout.glyphRuns(1, 3, retrievalFlags); + QCOMPARE(glyphRuns.size(), 1); + + QCOMPARE(glyphRuns.at(0).glyphIndexes().size(), 2); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(0), uint(233)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(1), uint(74)); + + QList<qsizetype> stringIndexes = glyphRuns.at(0).stringIndexes(); + QCOMPARE(stringIndexes.size(), 2); + QCOMPARE(stringIndexes.at(0), 1); + QCOMPARE(stringIndexes.at(1), 3); + } + + } + + // One character -> two glyphs + { + QTextLayout layout; + layout.setText(QChar(0xe6)); // LATIN SMALL LETTER AE + layout.setFont(ligatureFont); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList<QGlyphRun> glyphRuns = layout.glyphRuns(-1, -1, retrievalFlags); + QCOMPARE(glyphRuns.size(), 1); + + QCOMPARE(glyphRuns.at(0).glyphIndexes().size(), 2); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(0), uint(66)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(1), uint(70)); + + QList<qsizetype> stringIndexes = glyphRuns.at(0).stringIndexes(); + QCOMPARE(stringIndexes.size(), 2); + QCOMPARE(stringIndexes.at(0), uint(0)); + QCOMPARE(stringIndexes.at(1), uint(0)); + } + + // Three characters -> four glyphs + { + QTextLayout layout; + layout.setText(QString('f') + QChar(0xe6) + QChar('i')); + layout.setFont(ligatureFont); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + { + QList<QGlyphRun> glyphRuns = layout.glyphRuns(-1, -1, retrievalFlags); + QCOMPARE(glyphRuns.size(), 1); + + QCOMPARE(glyphRuns.at(0).glyphIndexes().size(), 4); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(0), uint(71)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(1), uint(66)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(2), uint(70)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(3), uint(74)); + + QList<qsizetype> stringIndexes = glyphRuns.at(0).stringIndexes(); + QCOMPARE(stringIndexes.size(), 4); + QCOMPARE(stringIndexes.at(0), 0); + QCOMPARE(stringIndexes.at(1), 1); + QCOMPARE(stringIndexes.at(2), 1); + QCOMPARE(stringIndexes.at(3), 2); + } + + { + QList<QGlyphRun> glyphRuns = layout.glyphRuns(1, -1, retrievalFlags); + QCOMPARE(glyphRuns.size(), 1); + + QCOMPARE(glyphRuns.at(0).glyphIndexes().size(), 3); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(0), uint(66)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(1), uint(70)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(2), uint(74)); + + QList<qsizetype> stringIndexes = glyphRuns.at(0).stringIndexes(); + QCOMPARE(stringIndexes.size(), 3); + QCOMPARE(stringIndexes.at(0), 1); + QCOMPARE(stringIndexes.at(1), 1); + QCOMPARE(stringIndexes.at(2), 2); + } + + { + QList<QGlyphRun> glyphRuns = layout.glyphRuns(0, 2, retrievalFlags); + QCOMPARE(glyphRuns.size(), 1); + + QCOMPARE(glyphRuns.at(0).glyphIndexes().size(), 3); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(0), uint(71)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(1), uint(66)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(2), uint(70)); + + QList<qsizetype> stringIndexes = glyphRuns.at(0).stringIndexes(); + QCOMPARE(stringIndexes.size(), 3); + QCOMPARE(stringIndexes.at(0), 0); + QCOMPARE(stringIndexes.at(1), 1); + QCOMPARE(stringIndexes.at(2), 1); + } + + + } + + // Five characters -> five glyphs + { + QTextLayout layout; + layout.setText(QLatin1String("ffi") + QChar(0xe6) + QLatin1Char('i')); + layout.setFont(ligatureFont); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList<QGlyphRun> glyphRuns = layout.glyphRuns(-1, -1, retrievalFlags); + QCOMPARE(glyphRuns.size(), 1); + + QCOMPARE(glyphRuns.at(0).glyphIndexes().size(), 5); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(0), uint(71)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(1), uint(233)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(2), uint(66)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(3), uint(70)); + QCOMPARE(glyphRuns.at(0).glyphIndexes().at(4), uint(74)); + + QList<qsizetype> stringIndexes = glyphRuns.at(0).stringIndexes(); + QCOMPARE(stringIndexes.size(), 5); + QCOMPARE(stringIndexes.at(0), 0); + QCOMPARE(stringIndexes.at(1), 1); + QCOMPARE(stringIndexes.at(2), 3); + QCOMPARE(stringIndexes.at(3), 3); + QCOMPARE(stringIndexes.at(4), 4); + } + +} + +void tst_QGlyphRun::retrievalFlags_data() +{ + QTest::addColumn<QTextLayout::GlyphRunRetrievalFlags>("flags"); + QTest::addColumn<bool>("expectedGlyphIndexes"); + QTest::addColumn<bool>("expectedStringIndexes"); + QTest::addColumn<bool>("expectedString"); + QTest::addColumn<bool>("expectedGlyphPositions"); + + QTest::newRow("Glyph indexes") + << QTextLayout::GlyphRunRetrievalFlags(QTextLayout::RetrieveGlyphIndexes) + << true << false << false << false; + QTest::newRow("Glyph Positions") + << QTextLayout::GlyphRunRetrievalFlags(QTextLayout::RetrieveGlyphPositions) + << false << false << false << true; + QTest::newRow("String indexes") + << QTextLayout::GlyphRunRetrievalFlags(QTextLayout::RetrieveStringIndexes) + << false << true << false << false; + QTest::newRow("String") + << QTextLayout::GlyphRunRetrievalFlags(QTextLayout::RetrieveString) + << false << false << true << false; + + QTest::newRow("Default") + << QTextLayout::GlyphRunRetrievalFlags(QTextLayout::DefaultRetrievalFlags) + << true << false << false << true; + QTest::newRow("All") + << QTextLayout::GlyphRunRetrievalFlags(QTextLayout::RetrieveAll) + << true << true << true << true; +} + +void tst_QGlyphRun::retrievalFlags() +{ + QFETCH(QTextLayout::GlyphRunRetrievalFlags, flags); + QFETCH(bool, expectedGlyphIndexes); + QFETCH(bool, expectedStringIndexes); + QFETCH(bool, expectedString); + QFETCH(bool, expectedGlyphPositions); + QTextLayout layout; - layout.setFont(QFont("QtsSpecialTestFont")); - layout.setText(QChar(0x200D)); + layout.setText(QLatin1String("abc")); layout.beginLayout(); layout.createLine(); layout.endLayout(); - QList<QGlyphRun> runs = layout.glyphRuns(); - QCOMPARE(runs.size(), 1); - QCOMPARE(runs.at(0).glyphIndexes().size(), 1); - QCOMPARE(runs.at(0).glyphIndexes()[0], uint(0)); + QList<QGlyphRun> glyphRuns = layout.glyphRuns(-1, -1, flags); + QVERIFY(!glyphRuns.isEmpty()); + + QGlyphRun firstGlyphRun = glyphRuns.first(); + QCOMPARE(firstGlyphRun.glyphIndexes().isEmpty(), !expectedGlyphIndexes); + QCOMPARE(firstGlyphRun.stringIndexes().isEmpty(), !expectedStringIndexes); + QCOMPARE(firstGlyphRun.sourceString().isEmpty(), !expectedString); + QCOMPARE(firstGlyphRun.positions().isEmpty(), !expectedGlyphPositions); +} + +void tst_QGlyphRun::objectReplacementCharacter() +{ + QTextLayout layout; + layout.setFont(m_testFont); + layout.setText(QStringLiteral("\uFFFC")); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList<QGlyphRun> glyphRuns = layout.glyphRuns(); + QCOMPARE(glyphRuns.size(), 1); + QCOMPARE(glyphRuns.first().glyphIndexes().size(), 1); + QCOMPARE(glyphRuns.first().glyphIndexes().first(), uint(5)); } #endif // QT_NO_RAWFONT diff --git a/tests/auto/gui/text/qinputcontrol/CMakeLists.txt b/tests/auto/gui/text/qinputcontrol/CMakeLists.txt index 048a96ef77..75fc85bc39 100644 --- a/tests/auto/gui/text/qinputcontrol/CMakeLists.txt +++ b/tests/auto/gui/text/qinputcontrol/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qinputcontrol.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qinputcontrol Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qinputcontrol LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qinputcontrol SOURCES tst_qinputcontrol.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::GuiPrivate ) diff --git a/tests/auto/gui/text/qinputcontrol/tst_qinputcontrol.cpp b/tests/auto/gui/text/qinputcontrol/tst_qinputcontrol.cpp index 3e64c3c09a..678f4491c4 100644 --- a/tests/auto/gui/text/qinputcontrol/tst_qinputcontrol.cpp +++ b/tests/auto/gui/text/qinputcontrol/tst_qinputcontrol.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 <QTest> diff --git a/tests/auto/gui/text/qrawfont/BLACKLIST b/tests/auto/gui/text/qrawfont/BLACKLIST deleted file mode 100644 index 44b3d7d481..0000000000 --- a/tests/auto/gui/text/qrawfont/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -# QTBUG-85364 -windows-10 gcc cmake diff --git a/tests/auto/gui/text/qrawfont/CMakeLists.txt b/tests/auto/gui/text/qrawfont/CMakeLists.txt index 04db8d8760..d2a318a2a3 100644 --- a/tests/auto/gui/text/qrawfont/CMakeLists.txt +++ b/tests/auto/gui/text/qrawfont/CMakeLists.txt @@ -1,17 +1,15 @@ -# Generated from qrawfont.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qrawfont Test: ##################################################################### -qt_internal_add_test(tst_qrawfont - SOURCES - tst_qrawfont.cpp - PUBLIC_LIBRARIES - Qt::CorePrivate - Qt::Gui - Qt::GuiPrivate -) +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qrawfont LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() # Resources: set_source_files_properties("../../../shared/resources/testfont.ttf" @@ -23,10 +21,14 @@ set(testdata_resource_files "testfont_os2_v1.ttf" ) -qt_internal_add_resource(tst_qrawfont "testdata" - PREFIX - "/" - FILES - ${testdata_resource_files} +qt_internal_add_test(tst_qrawfont + SOURCES + tst_qrawfont.cpp + LIBRARIES + Qt::CorePrivate + Qt::Gui + Qt::GuiPrivate + TESTDATA ${testdata_resource_files} + BUILTIN_TESTDATA ) diff --git a/tests/auto/gui/text/qrawfont/testdata.qrc b/tests/auto/gui/text/qrawfont/testdata.qrc deleted file mode 100644 index c7ac9641d1..0000000000 --- a/tests/auto/gui/text/qrawfont/testdata.qrc +++ /dev/null @@ -1,7 +0,0 @@ -<RCC> - <qresource prefix="/"> - <file>testfont_bold_italic.ttf</file> - <file>testfont_os2_v1.ttf</file> - <file alias="testfont.ttf">../../../shared/resources/testfont.ttf</file> - </qresource> -</RCC> diff --git a/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp index c324aa3549..5ec2536718 100644 --- a/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp +++ b/tests/auto/gui/text/qrawfont/tst_qrawfont.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 <QTest> #include <QtGui/QFontDatabase> @@ -121,7 +96,7 @@ void tst_QRawFont::initTestCase() if (testFont.isEmpty() || testFontBoldItalic.isEmpty()) QFAIL("qrawfont unittest font files not found!"); - if (QFontDatabase::families().count() == 0) + if (QFontDatabase::families().size() == 0) QSKIP("No fonts available!!!"); } @@ -423,13 +398,13 @@ void tst_QRawFont::textLayout() void tst_QRawFont::fontTable_data() { - QTest::addColumn<QByteArray>("tagName"); + QTest::addColumn<QFont::Tag>("tag"); QTest::addColumn<QFont::HintingPreference>("hintingPreference"); QTest::addColumn<int>("offset"); QTest::addColumn<quint32>("expectedValue"); QTest::newRow("Head table, magic number, default hinting") - << QByteArray("head") + << QFont::Tag("head") << QFont::PreferDefaultHinting << 12 << (QSysInfo::ByteOrder == QSysInfo::BigEndian @@ -437,7 +412,7 @@ void tst_QRawFont::fontTable_data() : 0xF53C0F5F); QTest::newRow("Head table, magic number, no hinting") - << QByteArray("head") + << QFont::Tag("head") << QFont::PreferNoHinting << 12 << (QSysInfo::ByteOrder == QSysInfo::BigEndian @@ -445,7 +420,7 @@ void tst_QRawFont::fontTable_data() : 0xF53C0F5F); QTest::newRow("Head table, magic number, vertical hinting") - << QByteArray("head") + << QFont::Tag("head") << QFont::PreferVerticalHinting << 12 << (QSysInfo::ByteOrder == QSysInfo::BigEndian @@ -453,7 +428,7 @@ void tst_QRawFont::fontTable_data() : 0xF53C0F5F); QTest::newRow("Head table, magic number, full hinting") - << QByteArray("head") + << QFont::Tag("head") << QFont::PreferFullHinting << 12 << (QSysInfo::ByteOrder == QSysInfo::BigEndian @@ -463,7 +438,7 @@ void tst_QRawFont::fontTable_data() void tst_QRawFont::fontTable() { - QFETCH(QByteArray, tagName); + QFETCH(QFont::Tag, tag); QFETCH(QFont::HintingPreference, hintingPreference); QFETCH(int, offset); QFETCH(quint32, expectedValue); @@ -471,11 +446,13 @@ void tst_QRawFont::fontTable() QRawFont font(testFont, 10, hintingPreference); QVERIFY(font.isValid()); - QByteArray table = font.fontTable(tagName); + QByteArray table = font.fontTable(tag); QVERIFY(!table.isEmpty()); const quint32 *value = reinterpret_cast<const quint32 *>(table.constData() + offset); QCOMPARE(*value, expectedValue); + + QCOMPARE(font.fontTable(tag.toString()), table); } typedef QList<QFontDatabase::WritingSystem> WritingSystemList; @@ -515,7 +492,7 @@ void tst_QRawFont::supportedWritingSystems_data() void tst_QRawFont::supportedWritingSystems() { QFETCH(QString, fileName); - QFETCH(WritingSystemList, writingSystems); + QFETCH(const WritingSystemList, writingSystems); QFETCH(QFont::HintingPreference, hintingPreference); QRawFont font(fileName, 10, hintingPreference); @@ -524,7 +501,7 @@ void tst_QRawFont::supportedWritingSystems() WritingSystemList actualWritingSystems = font.supportedWritingSystems(); QCOMPARE(actualWritingSystems.size(), writingSystems.size()); - foreach (QFontDatabase::WritingSystem writingSystem, writingSystems) + for (QFontDatabase::WritingSystem writingSystem : writingSystems) QVERIFY(actualWritingSystems.contains(writingSystem)); } @@ -652,6 +629,7 @@ void tst_QRawFont::fromFont_data() QTest::addColumn<QFont::HintingPreference>("hintingPreference"); QTest::addColumn<QString>("familyName"); QTest::addColumn<QFontDatabase::WritingSystem>("writingSystem"); + QTest::addColumn<QFont::StyleStrategy>("styleStrategy"); for (int i=QFont::PreferDefaultHinting; i<=QFont::PreferFullHinting; ++i) { QString titleBase = QString::fromLatin1("%2, hintingPreference=%1, writingSystem=%3") @@ -665,7 +643,8 @@ void tst_QRawFont::fromFont_data() << fileName << QFont::HintingPreference(i) << "QtBidiTestFont" - << writingSystem; + << writingSystem + << QFont::PreferDefault; } { @@ -677,7 +656,8 @@ void tst_QRawFont::fromFont_data() << fileName << QFont::HintingPreference(i) << "QtBidiTestFont" - << writingSystem; + << writingSystem + << QFont::PreferDefault; } { @@ -689,9 +669,24 @@ void tst_QRawFont::fromFont_data() << fileName << QFont::HintingPreference(i) << "QtBidiTestFont" - << writingSystem; + << writingSystem + << QFont::PreferDefault; } } + + { + QString fileName = testFont; + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Arabic; + + QString title = QStringLiteral("No font merging + unsupported script"); + QTest::newRow(qPrintable(title)) + << fileName + << QFont::PreferDefaultHinting + << "QtBidiTestFont" + << writingSystem + << QFont::NoFontMerging; + } + } void tst_QRawFont::fromFont() @@ -700,6 +695,7 @@ void tst_QRawFont::fromFont() QFETCH(QFont::HintingPreference, hintingPreference); QFETCH(QString, familyName); QFETCH(QFontDatabase::WritingSystem, writingSystem); + QFETCH(QFont::StyleStrategy, styleStrategy); int id = QFontDatabase::addApplicationFont(fileName); QVERIFY(id >= 0); @@ -707,6 +703,8 @@ void tst_QRawFont::fromFont() QFont font(familyName); font.setHintingPreference(hintingPreference); font.setPixelSize(26.0); + if (styleStrategy != QFont::PreferDefault) + font.setStyleStrategy(styleStrategy); QRawFont rawFont = QRawFont::fromFont(font, writingSystem); QVERIFY(rawFont.isValid()); @@ -1056,7 +1054,7 @@ void tst_QRawFont::qtbug65923_partal_clone_data() void tst_QRawFont::qtbug65923_partal_clone() { QFile file(testFont); - file.open(QIODevice::ReadOnly); + QVERIFY(file.open(QIODevice::ReadOnly)); QByteArray fontData = file.readAll(); QRawFont outerFont; diff --git a/tests/auto/gui/text/qstatictext/CMakeLists.txt b/tests/auto/gui/text/qstatictext/CMakeLists.txt index a7ba4e392a..bdad2609fe 100644 --- a/tests/auto/gui/text/qstatictext/CMakeLists.txt +++ b/tests/auto/gui/text/qstatictext/CMakeLists.txt @@ -1,21 +1,28 @@ -# Generated from qstatictext.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qstatictext Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qstatictext LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qstatictext SOURCES tst_qstatictext.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui ) ## Scopes: ##################################################################### -qt_internal_extend_target(tst_qstatictext CONDITION QT_FEATURE_private_tests - PUBLIC_LIBRARIES +qt_internal_extend_target(tst_qstatictext CONDITION QT_FEATURE_developer_build + LIBRARIES Qt::CorePrivate Qt::GuiPrivate ) diff --git a/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp b/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp index fe7396ae4c..add2303199 100644 --- a/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp @@ -1,32 +1,8 @@ -/**************************************************************************** -** -** 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 <QTest> +#include <QtCore/QSet> #include <QtGui/QGuiApplication> #include <QtGui/QPainter> #include <QtGui/QImage> @@ -74,10 +50,6 @@ private slots: void rotatedPainter(); void scaledPainter(); void projectedPainter(); -#if 0 - void rotatedScaledAndTranslatedPainter_data(); - void rotatedScaledAndTranslatedPainter(); -#endif void transformationChanged(); void plainTextVsRichText(); @@ -261,8 +233,8 @@ void tst_QStaticText::compareToDrawText() #if defined(DEBUG_SAVE_IMAGE) imageDrawText.save("compareToDrawText_imageDrawText.png"); - imageDrawStaticText.save("compareToDrawText_imageDrawStaticPlainText.png"); - imageDrawStaticText.save("compareToDrawText_imageDrawStaticRichText.png"); + imageDrawStaticPlainText.save("compareToDrawText_imageDrawStaticPlainText.png"); + imageDrawStaticRichText.save("compareToDrawText_imageDrawStaticRichText.png"); #endif QVERIFY(imageDrawText.toImage() != m_whiteSquare); @@ -461,9 +433,6 @@ void tst_QStaticText::rotatedPainter() QVERIFY(imageDrawText.toImage() != m_whiteSquare); -#ifdef Q_OS_ANDROID - QEXPECT_FAIL("", "QTBUG-69218", Continue); -#endif if (!supportsTransformations()) QEXPECT_FAIL("", "Graphics system does not support transformed text on this platform", Abort); QCOMPARE(imageDrawStaticText, imageDrawText); @@ -528,61 +497,6 @@ void tst_QStaticText::projectedPainter() QCOMPARE(imageDrawStaticText, imageDrawText); } -#if 0 -void tst_QStaticText::rotatedScaledAndTranslatedPainter_data() -{ - QTest::addColumn<qreal>("offset"); - - for (int i=0; i<100; ++i) { - qreal offset = 300 + i / 100.; - QTest::newRow(QByteArray::number(offset).constData()) << offset; - } -} - -void tst_QStaticText::rotatedScaledAndTranslatedPainter() -{ - QFETCH(qreal, offset); - - QPixmap imageDrawText(1000, 1000); - imageDrawText.fill(Qt::white); - { - QPainter p(&imageDrawText); - p.translate(offset, 0); - p.rotate(45.0); - p.scale(2.0, 2.0); - p.translate(100, 200); - - p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - } - - QPixmap imageDrawStaticText(1000, 1000); - imageDrawStaticText.fill(Qt::white); - { - QPainter p(&imageDrawStaticText); - p.translate(offset, 0); - p.rotate(45.0); - p.scale(2.0, 2.0); - p.translate(100, 200); - - QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - text.setTextFormat(Qt::PlainText); - - p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); - } - -#if defined(DEBUG_SAVE_IMAGE) - imageDrawText.save("rotatedScaledAndPainter_imageDrawText.png"); - imageDrawStaticText.save("rotatedScaledAndPainter_imageDrawStaticText.png"); -#endif - - QVERIFY(imageDrawText.toImage() != m_whiteSquare); - - if (!supportsTransformations()) - QEXPECT_FAIL("", "Graphics system does not support transformed text on this platform", Abort); - QCOMPARE(imageDrawStaticText, imageDrawText); -} -#endif - void tst_QStaticText::transformationChanged() { QPixmap imageDrawText(1000, 1000); @@ -621,9 +535,6 @@ void tst_QStaticText::transformationChanged() QVERIFY(imageDrawText.toImage() != m_whiteSquare); -#ifdef Q_OS_ANDROID - QEXPECT_FAIL("", "QTBUG-69220", Continue); -#endif if (!supportsTransformations()) QEXPECT_FAIL("", "Graphics system does not support transformed text on this platform", Abort); QCOMPARE(imageDrawStaticText, imageDrawText); diff --git a/tests/auto/gui/text/qsyntaxhighlighter/CMakeLists.txt b/tests/auto/gui/text/qsyntaxhighlighter/CMakeLists.txt index 9ac732cee0..f1c9146ce1 100644 --- a/tests/auto/gui/text/qsyntaxhighlighter/CMakeLists.txt +++ b/tests/auto/gui/text/qsyntaxhighlighter/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qsyntaxhighlighter.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qsyntaxhighlighter Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsyntaxhighlighter LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qsyntaxhighlighter SOURCES tst_qsyntaxhighlighter.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui ) @@ -15,6 +22,6 @@ qt_internal_add_test(tst_qsyntaxhighlighter ##################################################################### qt_internal_extend_target(tst_qsyntaxhighlighter CONDITION TARGET Qt::Widgets - PUBLIC_LIBRARIES + LIBRARIES Qt::Widgets ) diff --git a/tests/auto/gui/text/qsyntaxhighlighter/tst_qsyntaxhighlighter.cpp b/tests/auto/gui/text/qsyntaxhighlighter/tst_qsyntaxhighlighter.cpp index 43086a1c14..748f494a41 100644 --- a/tests/auto/gui/text/qsyntaxhighlighter/tst_qsyntaxhighlighter.cpp +++ b/tests/auto/gui/text/qsyntaxhighlighter/tst_qsyntaxhighlighter.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 <QTest> @@ -125,7 +100,7 @@ public: virtual void highlightBlock(const QString &text) override { - for (int i = 0; i < formats.count(); ++i) { + for (int i = 0; i < formats.size(); ++i) { const QTextLayout::FormatRange &range = formats.at(i); setFormat(range.start, range.length, range.format); } @@ -186,7 +161,7 @@ public: commentFormat.setForeground(Qt::darkGreen); commentFormat.setFontWeight(QFont::StyleItalic); commentFormat.setFontFixedPitch(true); - int textLength = text.length(); + int textLength = text.size(); if (text.startsWith(QLatin1Char(';'))){ // The entire line is a comment @@ -439,7 +414,7 @@ void tst_QSyntaxHighlighter::preservePreeditArea() QCOMPARE(hl->callCount, 1); formats = layout->formats(); - QCOMPARE(formats.count(), 3); + QCOMPARE(formats.size(), 3); range = formats.at(0); @@ -518,7 +493,7 @@ void tst_QSyntaxHighlighter::noContentsChangedDuringHighlight() QSignalSpy contentsChangedSpy(doc, SIGNAL(contentsChanged())); cursor.insertText("Hello World"); - QCOMPARE(contentsChangedSpy.count(), 1); + QCOMPARE(contentsChangedSpy.size(), 1); QVERIFY(hl->highlighted); QVERIFY(lout->documentChangedCalled); } diff --git a/tests/auto/gui/text/qtextblock/CMakeLists.txt b/tests/auto/gui/text/qtextblock/CMakeLists.txt index aedd6c27a3..83cc1ce08e 100644 --- a/tests/auto/gui/text/qtextblock/CMakeLists.txt +++ b/tests/auto/gui/text/qtextblock/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qtextblock.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtextblock Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextblock LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qtextblock SOURCES tst_qtextblock.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/gui/text/qtextblock/tst_qtextblock.cpp b/tests/auto/gui/text/qtextblock/tst_qtextblock.cpp index 0d638706eb..50331ddef2 100644 --- a/tests/auto/gui/text/qtextblock/tst_qtextblock.cpp +++ b/tests/auto/gui/text/qtextblock/tst_qtextblock.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 <QtTest/QTest> diff --git a/tests/auto/gui/text/qtextcursor/CMakeLists.txt b/tests/auto/gui/text/qtextcursor/CMakeLists.txt index a82dc928e9..487965f9f8 100644 --- a/tests/auto/gui/text/qtextcursor/CMakeLists.txt +++ b/tests/auto/gui/text/qtextcursor/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qtextcursor.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtextcursor Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextcursor LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qtextcursor SOURCES tst_qtextcursor.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/gui/text/qtextcursor/tst_qtextcursor.cpp b/tests/auto/gui/text/qtextcursor/tst_qtextcursor.cpp index 17d2336b74..6984cd1bd2 100644 --- a/tests/auto/gui/text/qtextcursor/tst_qtextcursor.cpp +++ b/tests/auto/gui/text/qtextcursor/tst_qtextcursor.cpp @@ -1,34 +1,11 @@ -/**************************************************************************** -** -** 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 <QTest> +#include <QLoggingCategory> +#include <qfontinfo.h> #include <qtextdocument.h> #include <qtexttable.h> #include <qvariant.h> @@ -41,6 +18,8 @@ #include <private/qtextcursor_p.h> +Q_LOGGING_CATEGORY(lcTests, "qt.gui.tests") + QT_FORWARD_DECLARE_CLASS(QTextDocument) class tst_QTextCursor : public QObject @@ -110,6 +89,14 @@ private slots: void selectVisually(); void insertText(); +#ifndef QT_NO_TEXTHTMLPARSER + void insertHtml_data(); + void insertHtml(); +#endif +#if QT_CONFIG(textmarkdownreader) + void insertMarkdown_data(); + void insertMarkdown(); +#endif void insertFragmentShouldUseCurrentCharFormat(); @@ -1428,6 +1415,221 @@ void tst_QTextCursor::insertText() QCOMPARE(cursor.block().text(), QString("yoyodyne")); } + +#ifndef QT_NO_TEXTHTMLPARSER + +void tst_QTextCursor::insertHtml_data() +{ + QTest::addColumn<QString>("initialText"); + QTest::addColumn<int>("expectedInitialBlockCount"); + QTest::addColumn<bool>("insertBlock"); + QTest::addColumn<bool>("insertAsPlainText"); + QTest::addColumn<int>("insertPosition"); + QTest::addColumn<QString>("insertText"); + QTest::addColumn<QString>("expectedSelText"); + QTest::addColumn<QString>("expectedText"); + QTest::addColumn<QString>("expectedMarkdown"); + + const QString htmlHeadingString("<h1>Hello World</h1>"); + + QTest::newRow("insert as html at end of heading") + << htmlHeadingString << 1 + << false << false << 11 << QString("Other\ntext") + << QString("Hello WorldOther text") + << QString("Hello WorldOther text") + << QString("# Hello WorldOther text\n\n"); + + QTest::newRow("insert as html in new block at end of heading") + << htmlHeadingString << 1 + << false << true << 11 << QString("Other\ntext") + << QString("Hello WorldOther\u2029text") + << QString("Hello WorldOther\ntext") + << QString("# Hello WorldOther\n\n# text\n\n"); + + QTest::newRow("insert as html in middle of heading") + << htmlHeadingString << 1 + << false << false << 6 << QString("\n\nOther\ntext\n\n") + << QString("Hello Other text World") + << QString("Hello Other text World") + << QString("# Hello Other text World\n\n"); + + QTest::newRow("insert as text at end of heading") + << htmlHeadingString << 1 + << true << false << 11 << QString("\n\nOther\ntext") + << QString("Hello World\u2029Other text") + << QString("Hello World\nOther text") + << QString("# Hello World\n\nOther text\n\n"); + + QTest::newRow("insert as text in new block at end of heading") + << htmlHeadingString << 1 + << true << true << 11 << QString("\n\nOther\ntext") + << QString("Hello World\u2029\u2029\u2029Other\u2029text") + << QString("Hello World\n\n\nOther\ntext") + << QString("# Hello World\n\n**Other**\n\n**text**\n\n"); + + QTest::newRow("insert as text in middle of heading") + << htmlHeadingString << 1 + << true << false << 6 << QString("Other\ntext") + << QString("Hello \u2029Other textWorld") + << QString("Hello \nOther textWorld") + << QString("# Hello \n\nOther text**World**\n\n"); +} + +void tst_QTextCursor::insertHtml() +{ + QFETCH(QString, initialText); + QFETCH(int, expectedInitialBlockCount); + QFETCH(bool, insertBlock); + QFETCH(bool, insertAsPlainText); + QFETCH(int, insertPosition); + QFETCH(QString, insertText); + QFETCH(QString, expectedSelText); + QFETCH(QString, expectedText); + QFETCH(QString, expectedMarkdown); + + cursor.insertHtml(initialText); + QCOMPARE(blockCount(), expectedInitialBlockCount); + cursor.setPosition(insertPosition); + if (insertBlock) + cursor.insertBlock(QTextBlockFormat()); + qCDebug(lcTests) << "pos" << cursor.position() << "block" << cursor.blockNumber() + << "heading" << cursor.blockFormat().headingLevel(); + if (insertAsPlainText) + cursor.insertText(insertText); + else + cursor.insertHtml(insertText); + cursor.select(QTextCursor::Document); + qCDebug(lcTests) << "sel text after insertion" << cursor.selectedText(); + qCDebug(lcTests) << "text after insertion" << cursor.document()->toPlainText(); + qCDebug(lcTests) << "html after insertion" << cursor.document()->toHtml(); + qCDebug(lcTests) << "markdown after insertion" << cursor.document()->toMarkdown(); + QCOMPARE(cursor.selectedText(), expectedSelText); + QCOMPARE(cursor.document()->toPlainText(), expectedText); + if (auto defaultFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont); QFontInfo(defaultFont).fixedPitch()) { + qWarning() << defaultFont << "is QFontDatabase::GeneralFont, and is fixedPitch"; + QSKIP("cannot reliably distinguish normal and monospace markdown spans on this system (QTBUG-103484)"); + } + QCOMPARE(cursor.document()->toMarkdown(), expectedMarkdown); +} + +#endif // QT_NO_TEXTHTMLPARSER + +#if QT_CONFIG(textmarkdownreader) + +void tst_QTextCursor::insertMarkdown_data() +{ + QTest::addColumn<QString>("initialText"); + QTest::addColumn<int>("expectedInitialBlockCount"); + QTest::addColumn<int>("insertPosition"); + QTest::addColumn<QString>("insertText"); + QTest::addColumn<QString>("expectedSelText"); + QTest::addColumn<QString>("expectedText"); + QTest::addColumn<QString>("expectedMarkdown"); + + QTest::newRow("bold fragment in italic span") + << "someone said *hello world*" << 1 + << 19 << QString(" **crazy** ") + << QString("someone said hello crazyworld") + << QString("someone said hello crazyworld") + << QString("someone said *hello ***crazy***world*\n\n"); // explicit B+I: not necessary but OK + + QTest::newRow("list in a paragraph") + << "hello list with 3 items" << 1 + << 10 << QString("1. one\n2. two\n") + << QString("hello list\u2029one\u2029two\u2029 with 3 items") + << QString("hello list\none\ntwo\n with 3 items") + << QString("hello list\n\n1. one\n2. two\n3. with 3 items\n"); + + QTest::newRow("list in a list") + << "1) bread\n2) milk\n" << 2 + << 6 << QString("0) eggs\n1) maple syrup\n") + << QString("bread\u2029eggs\u2029maple syrup\u2029milk") + << QString("bread\neggs\nmaple syrup\nmilk") + << QString("1) bread\n2) eggs\n0) maple syrup\n1) milk\n"); + // Renumbering would happen if we re-read the whole document. + // Currently insertion only uses the new list format after a paragraph separator. + // For that reason "bread" and "eggs" use the original list format, while "maple syrup" and + // "milk" use the format from the just inserted list. + + QTest::newRow("list after a list") + << "1) bread\n2) milk\n\n" << 2 + << 13 << QString("\n0) eggs\n1) maple syrup\n") + << QString("bread\u2029milk\u2029eggs\u2029maple syrup") + << QString("bread\nmilk\neggs\nmaple syrup") + << QString("1) bread\n2) milk\n3) eggs\n0) maple syrup\n"); + // Same behavior as above. "eggs" uses the original list format, but "maple syrup" uses the + // format of the inserted list, which means "maple syrup" now has a start of 0. + + const QString markdownHeadingString("# Hello\nWorld\n"); + + QTest::newRow("markdown heading at end of markdown heading") + << markdownHeadingString << 2 + << 11 << QString("\n\n## Other text") + << QString("Hello\u2029World\u2029Other text") + << QString("Hello\nWorld\nOther text") + << QString("# Hello\n\nWorld\n\n## Other text\n\n"); + + QTest::newRow("markdown heading into middle of markdown heading") + << markdownHeadingString << 2 + << 6 << QString("## Other\ntext\n\n") + << QString("Hello\u2029Other\u2029text\u2029World") + << QString("Hello\nOther\ntext\nWorld") + << QString("# Hello\n\n**Other**\n\ntext\n\nWorld\n\n"); + + QTest::newRow("markdown heading without trailing newline into middle of markdown heading") + << markdownHeadingString << 2 + << 6 << QString("## Other\ntext") + << QString("Hello\u2029Other\u2029textWorld") + << QString("Hello\nOther\ntextWorld") + << QString("# Hello\n\n**Other**\n\ntextWorld\n\n"); + + QTest::newRow("text into middle of markdown heading after newline") + << markdownHeadingString << 2 + << 6 << QString("Other ") + << QString("Hello\u2029OtherWorld") + << QString("Hello\nOtherWorld") + << QString("# Hello\n\nOtherWorld\n\n"); + + QTest::newRow("text into middle of markdown heading before newline") + << markdownHeadingString << 2 + << 5 << QString(" Other ") + << QString("HelloOther\u2029World") + << QString("HelloOther\nWorld") + << QString("# HelloOther\n\nWorld\n\n"); +} + +void tst_QTextCursor::insertMarkdown() +{ + QFETCH(QString, initialText); + QFETCH(int, expectedInitialBlockCount); + QFETCH(int, insertPosition); + QFETCH(QString, insertText); + QFETCH(QString, expectedSelText); + QFETCH(QString, expectedText); + QFETCH(QString, expectedMarkdown); + + cursor.insertMarkdown(initialText); + QCOMPARE(blockCount(), expectedInitialBlockCount); + cursor.setPosition(insertPosition); + qCDebug(lcTests) << "pos" << cursor.position() << "block" << cursor.blockNumber() + << "heading" << cursor.blockFormat().headingLevel(); + cursor.insertMarkdown(insertText); + cursor.select(QTextCursor::Document); + qCDebug(lcTests) << "sel text after insertion" << cursor.selectedText(); + qCDebug(lcTests) << "text after insertion" << cursor.document()->toPlainText(); + qCDebug(lcTests) << "html after insertion" << cursor.document()->toHtml(); + qCDebug(lcTests) << "markdown after insertion" << cursor.document()->toMarkdown(); + QCOMPARE(cursor.selectedText(), expectedSelText); + QCOMPARE(cursor.document()->toPlainText(), expectedText); + if (auto defaultFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont); QFontInfo(defaultFont).fixedPitch()) { + qWarning() << defaultFont << "is QFontDatabase::GeneralFont, and is fixedPitch"; + QSKIP("cannot reliably distinguish normal and monospace markdown spans on this system (QTBUG-103484)"); + } + QCOMPARE(cursor.document()->toMarkdown(), expectedMarkdown); +} + +#endif // textmarkdownreader + void tst_QTextCursor::insertFragmentShouldUseCurrentCharFormat() { QTextDocumentFragment fragment = QTextDocumentFragment::fromPlainText("Hello World"); @@ -1557,26 +1759,26 @@ void tst_QTextCursor::update_data() QTest::newRow("removeInsideSelection") << text << /*position*/ 0 - << /*anchor*/ int(text.length()) + << /*anchor*/ int(text.size()) // delete 'big' << 6 << 6 + charsToDelete << QString() // don't insert anything, just remove << /*expectedPosition*/ 0 - << /*expectedAnchor*/ int(text.length() - charsToDelete) + << /*expectedAnchor*/ int(text.size() - charsToDelete) ; text = "Hello big world"; charsToDelete = 3; QTest::newRow("removeInsideSelectionWithSwappedAnchorAndPosition") << text - << /*position*/ int(text.length()) + << /*position*/ int(text.size()) << /*anchor*/ 0 // delete 'big' << 6 << 6 + charsToDelete << QString() // don't insert anything, just remove - << /*expectedPosition*/ int(text.length() - charsToDelete) + << /*expectedPosition*/ int(text.size() - charsToDelete) << /*expectedAnchor*/ 0 ; @@ -1587,13 +1789,13 @@ void tst_QTextCursor::update_data() QTest::newRow("replaceInsideSelection") << text << /*position*/ 0 - << /*anchor*/ int(text.length()) + << /*anchor*/ int(text.size()) // delete 'big' ... << 6 << 6 + charsToDelete << textToInsert // ... and replace 'big' with 'small' << /*expectedPosition*/ 0 - << /*expectedAnchor*/ int(text.length() - charsToDelete + textToInsert.length()) + << /*expectedAnchor*/ int(text.size() - charsToDelete + textToInsert.size()) ; text = "Hello big world"; @@ -1601,13 +1803,13 @@ void tst_QTextCursor::update_data() textToInsert = "small"; QTest::newRow("replaceInsideSelectionWithSwappedAnchorAndPosition") << text - << /*position*/ int(text.length()) + << /*position*/ int(text.size()) << /*anchor*/ 0 // delete 'big' ... << 6 << 6 + charsToDelete << textToInsert // ... and replace 'big' with 'small' - << /*expectedPosition*/ int(text.length() - charsToDelete + textToInsert.length()) + << /*expectedPosition*/ int(text.size() - charsToDelete + textToInsert.size()) << /*expectedAnchor*/ 0 ; @@ -1616,14 +1818,14 @@ void tst_QTextCursor::update_data() charsToDelete = 3; QTest::newRow("removeBeforeSelection") << text - << /*position*/ int(text.length() - 5) - << /*anchor*/ int(text.length()) + << /*position*/ int(text.size() - 5) + << /*anchor*/ int(text.size()) // delete 'big' << 6 << 6 + charsToDelete << QString() // don't insert anything, just remove - << /*expectedPosition*/ int(text.length() - 5 - charsToDelete) - << /*expectedAnchor*/ int(text.length() - charsToDelete) + << /*expectedPosition*/ int(text.size() - 5 - charsToDelete) + << /*expectedAnchor*/ int(text.size() - charsToDelete) ; text = "Hello big world"; diff --git a/tests/auto/gui/text/qtextdocument/CMakeLists.txt b/tests/auto/gui/text/qtextdocument/CMakeLists.txt index bff5cabfb7..62fa1d46ca 100644 --- a/tests/auto/gui/text/qtextdocument/CMakeLists.txt +++ b/tests/auto/gui/text/qtextdocument/CMakeLists.txt @@ -1,14 +1,21 @@ -# Generated from qtextdocument.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtextdocument Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextdocument LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qtextdocument SOURCES common.h tst_qtextdocument.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/gui/text/qtextdocument/common.h b/tests/auto/gui/text/qtextdocument/common.h index 11ad99cfa0..3c05913008 100644 --- a/tests/auto/gui/text/qtextdocument/common.h +++ b/tests/auto/gui/text/qtextdocument/common.h @@ -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 <QAbstractTextDocumentLayout> #include <private/qtextdocument_p.h> diff --git a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp index 4e0b7f46df..335ee06e2f 100644 --- a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp +++ b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.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 <QTest> @@ -47,7 +22,6 @@ #include <qimage.h> #include <qtextlayout.h> #include <QDomDocument> -#include <qurlresourceprovider.h> #include "common.h" // #define DEBUG_WRITE_OUTPUT @@ -97,6 +71,7 @@ private slots: void toHtml2(); void setFragmentMarkersInHtmlExport(); + void setMediaRule(); void toHtmlBodyBgColor(); void toHtmlBodyBgColorRgba(); @@ -104,6 +79,7 @@ private slots: void toHtmlRootFrameProperties(); void toHtmlLineHeightProperties(); void toHtmlDefaultFontSpacingProperties(); + void toHtmlTextDecorationUnderline(); void capitalizationHtmlInExport(); void wordspacingHtmlExport(); @@ -124,7 +100,10 @@ private slots: void clonePreservesIndentWidth(); void clonePreservesFormatsWhenEmpty(); void blockCount(); + void defaultStyleSheet(); + void defaultTableStyle_data(); + void defaultTableStyle(); void resolvedFontInEmptyFormat(); @@ -195,6 +174,18 @@ private slots: void resourceProvider(); + void contentsChangeIndices_data(); + void contentsChangeIndices(); + + void insertHtmlWithComments_data(); + void insertHtmlWithComments(); + + void delayedLayout(); + void undoContentChangeIndices(); + + void restoreStrokeFromHtml(); + void restoreForegroundGradientFromHtml(); + private: void backgroundImage_checkExpectedHtml(const QTextDocument &doc); void buildRegExpData(); @@ -286,6 +277,9 @@ void tst_QTextDocument::init() "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" + "hr { height: 1px; border-width: 0; }\n" + "li.unchecked::marker { content: \"\\2610\"; }\n" + "li.checked::marker { content: \"\\2612\"; }\n" "</style></head>" "<body style=\" font-family:'%1'; font-size:%2; font-weight:%3; font-style:%4;\">\n"); htmlHead = htmlHead.arg(defaultFont.family()) @@ -475,17 +469,17 @@ void tst_QTextDocument::basicIsModifiedChecks() QVERIFY(!doc->isModified()); cursor.insertText("Hello World"); QVERIFY(doc->isModified()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(spy.takeFirst().at(0).toBool()); doc->undo(); QVERIFY(!doc->isModified()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(!spy.takeFirst().at(0).toBool()); doc->redo(); QVERIFY(doc->isModified()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(spy.takeFirst().at(0).toBool()); } @@ -576,16 +570,16 @@ void tst_QTextDocument::noundo_basicIsModifiedChecks() QVERIFY(!doc->isModified()); cursor.insertText("Hello World"); QVERIFY(doc->isModified()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(spy.takeFirst().at(0).toBool()); doc->undo(); QVERIFY(doc->isModified()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); doc->redo(); QVERIFY(doc->isModified()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); } void tst_QTextDocument::task240325() @@ -605,9 +599,6 @@ void tst_QTextDocument::task240325() QCOMPARE(doc->blockCount(), 1); for (QTextBlock block = doc->begin() ; block!=doc->end() ; block = block.next()) { QTextLayout *layout = block.layout(); -#ifdef Q_OS_ANDROID - QEXPECT_FAIL("", "QTBUG-69242", Abort); -#endif QCOMPARE(layout->lineCount(), 4); for (int lineIdx=0;lineIdx<layout->lineCount();++lineIdx) { @@ -756,6 +747,9 @@ void tst_QTextDocument::mightBeRichText_data() " PUBLIC ""-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n" "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">"; QVERIFY(Qt::mightBeRichText(QString::fromLatin1(qtDocuHeader))); + QVERIFY(Qt::mightBeRichText(QLatin1StringView(qtDocuHeader))); + QVERIFY(QUtf8StringView(qtDocuHeader).isValidUtf8()); + QVERIFY(Qt::mightBeRichText(QUtf8StringView(qtDocuHeader))); QTest::addColumn<QString>("input"); QTest::addColumn<bool>("result"); @@ -775,6 +769,10 @@ void tst_QTextDocument::mightBeRichText() QFETCH(QString, input); QFETCH(bool, result); QCOMPARE(result, Qt::mightBeRichText(input)); + QCOMPARE(result, Qt::mightBeRichText(QStringView(input))); + QCOMPARE(result, Qt::mightBeRichText(QUtf8StringView(input.toUtf8()))); + QVERIFY(QtPrivate::isLatin1(input)); + QCOMPARE(result, Qt::mightBeRichText(QLatin1StringView(input.toLatin1()))); } Q_DECLARE_METATYPE(QTextDocumentFragment) @@ -1174,7 +1172,7 @@ void tst_QTextDocument::toHtml_data() cursor.insertTable(2, 2); QTest::newRow("simpletable") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); @@ -1188,7 +1186,7 @@ void tst_QTextDocument::toHtml_data() table->mergeCells(0, 2, 1, 2); QTest::newRow("tablespans") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td colspan=\"2\"></td>\n<td colspan=\"2\"></td></tr>" "</table>"); } @@ -1207,7 +1205,7 @@ void tst_QTextDocument::toHtml_data() cursor.insertTable(2, 2, fmt); QTest::newRow("tableattrs") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" style=\" float: right;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">" + << QString("<table border=\"1\" style=\" float: right; border-collapse:collapse;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">" "\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); @@ -1229,7 +1227,7 @@ void tst_QTextDocument::toHtml_data() cursor.insertTable(2, 2, fmt); QTest::newRow("tableattrs2") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" style=\" float: right; margin-top:0px; margin-bottom:35px; margin-left:25px; margin-right:0px;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">" + << QString("<table border=\"1\" style=\" float: right; margin-top:0px; margin-bottom:35px; margin-left:25px; margin-right:0px; border-collapse:collapse;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">" "\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); @@ -1243,7 +1241,7 @@ void tst_QTextDocument::toHtml_data() cursor.insertTable(4, 2, fmt); QTest::newRow("tableheader") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "<thead>\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr></thead>" "\n<tr>\n<td></td>\n<td></td></tr>" @@ -1259,8 +1257,8 @@ void tst_QTextDocument::toHtml_data() subTable->cellAt(0, 0).firstCursorPosition().insertText("Hey"); QTest::newRow("nestedtable") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" - "\n<tr>\n<td></td>\n<td>\n<table border=\"1\" cellspacing=\"2\">\n<tr>\n<td>\n<p DEFAULTBLOCKSTYLE>Hey</p></td></tr></table></td></tr>" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" + "\n<tr>\n<td></td>\n<td>\n<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">\n<tr>\n<td>\n<p DEFAULTBLOCKSTYLE>Hey</p></td></tr></table></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); } @@ -1277,7 +1275,7 @@ void tst_QTextDocument::toHtml_data() cursor.insertTable(1, 3, fmt); QTest::newRow("colwidths") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td></td>\n<td width=\"30%\"></td>\n<td width=\"40\"></td></tr>" "</table>"); } @@ -1294,7 +1292,7 @@ void tst_QTextDocument::toHtml_data() cellCurs.mergeBlockCharFormat(fmt); QTest::newRow("cellproperties") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td bgcolor=\"#ffffff\"></td></tr>" "</table>"); } @@ -1386,7 +1384,7 @@ void tst_QTextDocument::toHtml_data() QTest::newRow("lists") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + - QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blubb</li>\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>"); + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n<li DEFAULTBLOCKSTYLE>Blubb</li>\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>"); } { @@ -1409,7 +1407,7 @@ void tst_QTextDocument::toHtml_data() QTest::newRow("charfmt-for-list-item") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + - QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blubb</li>\n<li style=\" color:#0000ff;\" DEFAULTBLOCKSTYLE><span style=\" color:#ff0000;\">Blah</span></li></ul>"); + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n<li DEFAULTBLOCKSTYLE>Blubb</li>\n<li style=\" color:#0000ff;\" DEFAULTBLOCKSTYLE><span style=\" color:#ff0000;\">Blah</span></li></ul>"); } { @@ -1439,7 +1437,7 @@ void tst_QTextDocument::toHtml_data() QTest::newRow("list-indent") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + - QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 4;\"><li DEFAULTBLOCKSTYLE>Blah</li></ul>"); + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 4;\">\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>"); } { @@ -1498,7 +1496,19 @@ void tst_QTextDocument::toHtml_data() QTest::newRow("horizontal-ruler-with-width") << QTextDocumentFragment::fromHtml("<hr width=\"50%\"/>") << QString("EMPTYBLOCK") + - QString("<hr width=\"50%\"/>"); + QString("<hr width=\"50%\" />"); + } + { + QTest::newRow("horizontal-ruler-with-color") << QTextDocumentFragment::fromHtml("<hr style=\"background-color:green;\"/>") + << + QString("EMPTYBLOCK") + + QString("<hr style=\"background-color:#008000;\"/>"); + } + { + QTest::newRow("horizontal-ruler-with-width-and-color") << QTextDocumentFragment::fromHtml("<hr width=\"50%\" style=\"background-color:green;\"/>") + << + QString("EMPTYBLOCK") + + QString("<hr width=\"50%\" style=\"background-color:#008000;\"/>"); } { CREATE_DOC_AND_CURSOR(); @@ -1549,7 +1559,7 @@ void tst_QTextDocument::toHtml_data() table->setFormat(fmt); QTest::newRow("mergedtablecolwidths") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td colspan=\"2\"></td></tr>" "\n<tr>\n<td width=\"20\"></td>\n<td width=\"40\"></td></tr>" "</table>"); @@ -1612,7 +1622,7 @@ void tst_QTextDocument::toHtml_data() table->cellAt(0, 0).firstCursorPosition().insertText("Blah"); QTest::newRow("table-vertical-alignment") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td style=\" vertical-align:middle;\">\n" "<p DEFAULTBLOCKSTYLE>Blah</p></td>" "\n<td style=\" vertical-align:top;\"></td></tr>" @@ -1641,7 +1651,7 @@ void tst_QTextDocument::toHtml_data() table->cellAt(0, 0).firstCursorPosition().insertText("Blah"); QTest::newRow("table-cell-paddings") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td style=\" padding-left:1;\">\n" "<p DEFAULTBLOCKSTYLE>Blah</p></td>" "\n<td style=\" padding-right:1;\"></td></tr>" @@ -1659,7 +1669,7 @@ void tst_QTextDocument::toHtml_data() cursor.insertTable(2, 2, fmt); QTest::newRow("tableborder") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" style=\" border-color:#0000ff; border-style:solid;\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-color:#0000ff; border-style:solid; border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); @@ -1701,7 +1711,7 @@ void tst_QTextDocument::toHtml_data() << QString("EMPTYBLOCK") + QString("<p OPENDEFAULTBLOCKSTYLE page-break-before:always;\">Foo</p>" "\n<p OPENDEFAULTBLOCKSTYLE page-break-before:always; page-break-after:always;\">Bar</p>" - "\n<table border=\"1\" style=\" page-break-after:always;\" cellspacing=\"2\">\n<tr>\n<td></td></tr></table>"); + "\n<table border=\"1\" style=\" page-break-after:always; border-collapse:collapse;\" cellpadding=\"4\">\n<tr>\n<td></td></tr></table>"); } { @@ -1715,7 +1725,87 @@ void tst_QTextDocument::toHtml_data() QTest::newRow("list-ul-margin") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + - QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blah</li></ul>"); + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>"); + } + { + CREATE_DOC_AND_CURSOR(); + const QString listHtml = "<ul><li>item-1</li><li>item-2<ul><li>item-2.1</li><li>item-2.2" + "<ul><li>item-2.2.1</li></ul></li><li>item-2.3<ul><li>item-2.3.1" + "</li></ul></li></ul></li><li>item-3</li></ul>"; + cursor.insertHtml(listHtml); + + QTest::newRow("nested-lists-one") << QTextDocumentFragment(&doc) + << QString("<ul DEFAULTULSTYLE 1;\">\n<li style=\" margin-top:12px; margin-bottom:0px; " + "margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" + "item-1</li>\n<li DEFAULTBLOCKSTYLE>item-2\n<ul DEFAULTULSTYLE 2;\">\n<li " + "DEFAULTBLOCKSTYLE>item-2.1</li>\n<li DEFAULTBLOCKSTYLE>item-2.2\n<ul " + "DEFAULTULSTYLE 3;\">\n<li DEFAULTBLOCKSTYLE>item-2.2.1</li></ul></li>\n" + "<li DEFAULTBLOCKSTYLE>item-2.3\n<ul DEFAULTULSTYLE 3;\">\n<li DEFAULTBLOCKSTYLE>" + "item-2.3.1</li></ul></li></ul></li>\n<li DEFAULTLASTLISTYLE>item-3</li></ul>"); + } + { + CREATE_DOC_AND_CURSOR(); + const QString listHtml = "<ul><li>item-1</li><li>item-2<ul><li>item-2.1</li></ul></li></ul>"; + cursor.insertHtml(listHtml); + + QTest::newRow("nested-lists-two") << QTextDocumentFragment(&doc) + << QString("<ul DEFAULTULSTYLE 1;\">\n<li style=\" margin-top:12px; margin-bottom:0px; " + "margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" + "item-1</li>\n<li DEFAULTLASTLISTYLE>item-2\n<ul DEFAULTULSTYLE 2;\">\n<li " + "DEFAULTBLOCKSTYLE>item-2.1</li></ul></li></ul>"); + } + { + CREATE_DOC_AND_CURSOR(); + const QString listHtml = "<ul><li>item-1</li><li>item-2<ul><li>item-2.1</li><li>item-2.2" + "</li></ul></li></ul>"; + cursor.insertHtml(listHtml); + + QTest::newRow("nested-lists-three") << QTextDocumentFragment(&doc) + << QString("<ul DEFAULTULSTYLE 1;\">\n<li style=\" margin-top:12px; margin-bottom:0px; " + "margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" + "item-1</li>\n<li DEFAULTLASTLISTYLE>item-2\n<ul DEFAULTULSTYLE 2;\">\n<li " + "DEFAULTBLOCKSTYLE>item-2.1</li>\n<li DEFAULTBLOCKSTYLE>item-2.2</li></ul>" + "</li></ul>"); + } + { + CREATE_DOC_AND_CURSOR(); + const QString listHtml = "<ul><li>item-1.1</li><li>item-1.2<li></ul>" + "<ul><li>item-2.1</li></ul>"; + cursor.insertHtml(listHtml); + + QTest::newRow("not-nested-list") << QTextDocumentFragment(&doc) + << QString("<ul DEFAULTULSTYLE 1;\">\n<li style=\" margin-top:12px; margin-bottom:0px; " + "margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" + "item-1.1</li>\n<li DEFAULTBLOCKSTYLE>item-1.2</li></ul>\n<ul DEFAULTULSTYLE 1;\">\n" + "<li style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; " + "margin-right:0px; -qt-block-indent:0; text-indent:0px;\">item-2.1</li></ul>"); + } + { + CREATE_DOC_AND_CURSOR(); + const QString listHtml = "<ul><li>bullet</li><li class=\"unchecked\">unchecked item</li><li class=\"checked\">checked item</li></ul>"; + cursor.insertHtml(listHtml); + + QTest::newRow("list with and without checkboxes") << QTextDocumentFragment(&doc) + << QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n" + "<li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">bullet</li>\n" + "<li class=\"unchecked\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">unchecked item</li>\n" + "<li class=\"checked\" style=\" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">checked item</li></ul>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextListFormat fmt; + fmt.setStyle(QTextListFormat::ListDecimal); + fmt.setStart(4); + cursor.insertList(fmt); + cursor.insertText("Blah"); + cursor.insertBlock(); + cursor.insertText("Bleh"); + + QTest::newRow("ordered list with start") << QTextDocumentFragment(&doc) + << QString("EMPTYBLOCK") + + QString("<ol start=\"4\" style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n<li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</li>\n<li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Bleh</li></ol>"); } } @@ -1731,6 +1821,11 @@ void tst_QTextDocument::toHtml() expectedOutput.replace("OPENDEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"); expectedOutput.replace("DEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\""); expectedOutput.replace("EMPTYBLOCK", "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p>\n"); + expectedOutput.replace("DEFAULTULSTYLE", "style=\"margin-top: 0px; margin-bottom: 0px; " + "margin-left: 0px; margin-right: 0px; -qt-list-indent:"); + expectedOutput.replace("DEFAULTLASTLISTYLE", "style=\" margin-top:0px; margin-bottom:12px; " + "margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\""); + if (expectedOutput.endsWith(QLatin1Char('\n'))) expectedOutput.chop(1); expectedOutput.append(htmlTail); @@ -1742,12 +1837,10 @@ void tst_QTextDocument::toHtml() QCOMPARE(output, expectedOutput); QDomDocument document; -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QEXPECT_FAIL("charfmt-for-list-item", "The attribute \"style\" is redefined in the generated HTML, which is not valid " "according to XML standard. The new QDomDocument implementation follows the XML " "standard.", Continue); -#endif QVERIFY2(document.setContent(output), "Output was not valid XML"); } @@ -1835,6 +1928,39 @@ void tst_QTextDocument::setFragmentMarkersInHtmlExport() } } +void tst_QTextDocument::setMediaRule() +{ + { + CREATE_DOC_AND_CURSOR(); + doc.setDefaultStyleSheet("@media screen { p { background:#000000 } } @media print { p { background:#ffffff } }"); + doc.setHtml("<p>Hello World</p>"); + + QString expected = htmlHead; + expected += QString("<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#000000;\"><span style=\" background-color:#000000;\">Hello World</span></p>") + htmlTail; + QCOMPARE(doc.toHtml(), expected); + } + { + CREATE_DOC_AND_CURSOR(); + doc.setDefaultStyleSheet("@media screen { p { background:#000000 } } @media print { p { background:#ffffff } }"); + doc.setMetaInformation(QTextDocument::CssMedia, "screen"); + doc.setHtml("<p>Hello World</p>"); + + QString expected = htmlHead; + expected += QString("<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#000000;\"><span style=\" background-color:#000000;\">Hello World</span></p>") + htmlTail; + QCOMPARE(doc.toHtml(), expected); + } + { + CREATE_DOC_AND_CURSOR(); + doc.setDefaultStyleSheet("@media screen { p { background:#000000 } } @media print { p { background:#ffffff } }"); + doc.setMetaInformation(QTextDocument::CssMedia, "print"); + doc.setHtml("<p>Hello World</p>"); + + QString expected = htmlHead; + expected += QString("<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#ffffff;\"><span style=\" background-color:#ffffff;\">Hello World</span></p>") + htmlTail; + QCOMPARE(doc.toHtml(), expected); + } +} + void tst_QTextDocument::toHtmlBodyBgColor() { CREATE_DOC_AND_CURSOR(); @@ -1845,20 +1971,12 @@ void tst_QTextDocument::toHtmlBodyBgColor() fmt.setBackground(QColor("#0000ff")); doc.rootFrame()->setFrameFormat(fmt); - QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " - "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" - "<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n" - "p, li { white-space: pre-wrap; }\n" - "</style></head>" - "<body style=\" font-family:'%1'; font-size:%2; font-weight:%3; font-style:%4;\"" - " bgcolor=\"#0000ff\">\n" - "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" - "</body></html>"); + QString expectedHtml = htmlHead; + expectedHtml.insert(htmlHead.size() - 2, " bgcolor=\"#0000ff\""); + expectedHtml += "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" + + htmlTail; - expectedHtml = expectedHtml.arg(defaultFont.family()) - .arg(cssFontSizeString(defaultFont)) - .arg(defaultFont.weight()) - .arg((defaultFont.italic() ? "italic" : "normal")); + writeActualAndExpected(QTest::currentDataTag(), doc.toHtml(), expectedHtml); QCOMPARE(doc.toHtml(), expectedHtml); } @@ -1873,20 +1991,12 @@ void tst_QTextDocument::toHtmlBodyBgColorRgba() fmt.setBackground(QColor(255, 0, 0, 51)); doc.rootFrame()->setFrameFormat(fmt); - QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " - "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" - "<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n" - "p, li { white-space: pre-wrap; }\n" - "</style></head>" - "<body style=\" font-family:'%1'; font-size:%2; font-weight:%3; font-style:%4;\"" - " bgcolor=\"rgba(255,0,0,0.2)\">\n" - "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" - "</body></html>"); + QString expectedHtml = htmlHead; + expectedHtml.insert(htmlHead.size() - 2, " bgcolor=\"rgba(255,0,0,0.2)\""); + expectedHtml += "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" + + htmlTail; - expectedHtml = expectedHtml.arg(defaultFont.family()) - .arg(cssFontSizeString(defaultFont)) - .arg(defaultFont.weight()) - .arg((defaultFont.italic() ? "italic" : "normal")); + writeActualAndExpected(QTest::currentDataTag(), doc.toHtml(), expectedHtml); QCOMPARE(doc.toHtml(), expectedHtml); } @@ -1901,20 +2011,12 @@ void tst_QTextDocument::toHtmlBodyBgColorTransparent() fmt.setBackground(QColor(255, 0, 0, 0)); doc.rootFrame()->setFrameFormat(fmt); - QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " - "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" - "<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n" - "p, li { white-space: pre-wrap; }\n" - "</style></head>" - "<body style=\" font-family:'%1'; font-size:%2; font-weight:%3; font-style:%4;\"" - " bgcolor=\"transparent\">\n" - "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" - "</body></html>"); + QString expectedHtml = htmlHead; + expectedHtml.insert(htmlHead.size() - 2, " bgcolor=\"transparent\""); + expectedHtml += "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" + + htmlTail; - expectedHtml = expectedHtml.arg(defaultFont.family()) - .arg(cssFontSizeString(defaultFont)) - .arg(defaultFont.weight()) - .arg((defaultFont.italic() ? "italic" : "normal")); + writeActualAndExpected(QTest::currentDataTag(), doc.toHtml(), expectedHtml); QCOMPARE(doc.toHtml(), expectedHtml); } @@ -1975,21 +2077,50 @@ void tst_QTextDocument::toHtmlDefaultFontSpacingProperties() fnt.setWordSpacing(15); doc.setDefaultFont(fnt); - QString expectedOutput = QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " - "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" - "<html><head><meta name=\"qrichtext\" content=\"1\" />" - "<meta charset=\"utf-8\" /><style type=\"text/css\">\n" - "p, li { white-space: pre-wrap; }\n" - "</style></head>" - "<body style=\" font-family:'%1'; font-size:%2; " - "font-weight:%3; font-style:%4; letter-spacing:13px; " - "word-spacing:15px;\">\n" - "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" - "</body></html>"); - expectedOutput = expectedOutput.arg(defaultFont.family()) - .arg(cssFontSizeString(defaultFont)) - .arg(defaultFont.weight()) - .arg((defaultFont.italic() ? "italic" : "normal")); + QString expectedOutput = htmlHead; + expectedOutput.insert(htmlHead.size() - 3, " letter-spacing:13px; word-spacing:15px;"); + expectedOutput += + "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" + + htmlTail; + + writeActualAndExpected(QTest::currentTestFunction(), doc.toHtml(), expectedOutput); + + QCOMPARE(doc.toHtml(), expectedOutput); +} + +void tst_QTextDocument::toHtmlTextDecorationUnderline() +{ + CREATE_DOC_AND_CURSOR(); + + cursor.insertText("Some text"); + QFont fnt = doc.defaultFont(); + fnt.setUnderline(true); + doc.setDefaultFont(fnt); + + QString expectedOutput = htmlHead; + expectedOutput.insert(htmlHead.size() - 3, " text-decoration: underline;"); + expectedOutput += + "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Some text</p>" + + htmlTail; + + writeActualAndExpected("toHtmlTextDecorationUnderline1", doc.toHtml(), expectedOutput); + + QCOMPARE(doc.toHtml(), expectedOutput); + + QTextCharFormat format; + format.setFontUnderline(false); + cursor.select(QTextCursor::Document); + cursor.mergeCharFormat(format); + + expectedOutput = htmlHead; + expectedOutput.insert(htmlHead.size() - 3, " text-decoration: underline;"); + expectedOutput += + "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; " + "margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" + "<span style=\" text-decoration:none;\">Some text</span></p>" + + htmlTail; + + writeActualAndExpected("toHtmlTextDecorationUnderline2", doc.toHtml(), expectedOutput); QCOMPARE(doc.toHtml(), expectedOutput); } @@ -2214,14 +2345,18 @@ void tst_QTextDocument::clonePreservesMetaInformation() { const QString title("Foobar"); const QString url("about:blank"); + const QString media("print"); doc->setHtml("<html><head><title>" + title + "</title></head><body>Hrm</body></html>"); doc->setMetaInformation(QTextDocument::DocumentUrl, url); + doc->setMetaInformation(QTextDocument::CssMedia, media); QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), title); QCOMPARE(doc->metaInformation(QTextDocument::DocumentUrl), url); + QCOMPARE(doc->metaInformation(QTextDocument::CssMedia), media); QTextDocument *clone = doc->clone(); QCOMPARE(clone->metaInformation(QTextDocument::DocumentTitle), title); QCOMPARE(clone->metaInformation(QTextDocument::DocumentUrl), url); + QCOMPARE(clone->metaInformation(QTextDocument::CssMedia), media); delete clone; } @@ -2536,6 +2671,127 @@ void tst_QTextDocument::defaultStyleSheet() QVERIFY(fmt.background().color() != QColor("green")); } +void tst_QTextDocument::defaultTableStyle_data() +{ + QTest::addColumn<QString>("css"); + QTest::addColumn<QString>("html"); + QTest::addColumn<QList<QBrush>>("borderBrushes"); + + const QString htmlHeader(R"( + <tr> + <th>1</th> <th>2</th> + </tr> + )"); + + const QString htmlCells(R"( + <tr> + <td>A</td> <td>B</td> + </tr> + )"); + + const QString cssEachSide = R"({ + border-top-color: red; + border-bottom-color: blue; + border-left-color: green; + border-right-color: yellow; + })"; + const QString cssOneColor = R"({ border-color: red; })"; + const QString cssFourColors = R"({ border-color: red blue green yellow; })"; + + QTest::addRow("td, each side") << QString("td ") + cssEachSide + << htmlCells + << QList<QBrush>{Qt::red, Qt::blue, QColor("green"), Qt::yellow}; + + QTest::addRow("th, each side") << QString("th ") + cssEachSide + << htmlHeader + << QList<QBrush>{Qt::red, Qt::blue, QColor("green"), Qt::yellow}; + + QTest::addRow("th+td, each side") << QString("th %1 td %1").arg(cssEachSide) + << htmlHeader + htmlCells + << QList<QBrush>{Qt::red, Qt::blue, QColor("green"), Qt::yellow}; + + QTest::addRow("td, one color") << QString("td ") + cssOneColor + << htmlCells + << QList<QBrush>{Qt::red, Qt::red, Qt::red, Qt::red}; + + QTest::addRow("th, one color") << QString("th ") + cssOneColor + << htmlHeader + << QList<QBrush>{Qt::red, Qt::red, Qt::red, Qt::red}; + + QTest::addRow("th+td, one color") << QString("th %1 td %1").arg(cssOneColor) + << htmlHeader + htmlCells + << QList<QBrush>{Qt::red, Qt::red, Qt::red, Qt::red}; + + // css order is top, right, bottom, left + QTest::addRow("td, four colors") << QString("td ") + cssFourColors + << htmlCells + << QList<QBrush>{Qt::red, QColor("green"), Qt::yellow, Qt::blue}; + +} + +void tst_QTextDocument::defaultTableStyle() +{ + QFETCH(QString, css); + QFETCH(QString, html); + QFETCH(QList<QBrush>, borderBrushes); + + CREATE_DOC_AND_CURSOR(); + doc.setDefaultStyleSheet(css); + doc.setHtml(QString("<html><body><table>%1</table></body></html>").arg(html)); + + const QTextFrame *frame = doc.rootFrame(); + const QTextTable *table = nullptr; + for (auto it = frame->begin(); !table && !it.atEnd(); ++it) + table = qobject_cast<const QTextTable*>(it.currentFrame()); + QVERIFY(table); + + const QList<QTextFormat::Property> brushProperties = { + QTextFormat::TableCellTopBorderBrush, + QTextFormat::TableCellBottomBorderBrush, + QTextFormat::TableCellLeftBorderBrush, + QTextFormat::TableCellRightBorderBrush + }; + + for (int row = 0; row < table->rows(); ++row) { + for (int column = 0; column < table->columns(); ++column) { + auto cellDetails = qScopeGuard([&]{ + qWarning("Failure was in cell %d/%d", row, column); + }); + const QTextTableCell cell = table->cellAt(row, column); + const QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); + QList<QBrush> brushes; + for (const auto side : brushProperties) { + QVariant sideProperty = cellFormat.property(side); + QVERIFY(sideProperty.isValid()); + QVERIFY(sideProperty.typeId() == qMetaTypeId<QBrush>()); + brushes << sideProperty.value<QBrush>(); + } + auto errorDetails = qScopeGuard([&]{ + if (brushes.size() != borderBrushes.size()) { + qWarning("Different count: %lld vs %lld", brushes.size(), borderBrushes.size()); + return; + } + for (int i = 0; i < brushes.size(); ++i) { + QString side; + QDebug(&side) << QTextFormat::Property(QTextFormat::TableCellTopBorderBrush + i); + QString actual; + QDebug(&actual) << brushes.at(i); + QString expected; + QDebug(&expected) << borderBrushes.at(i); + if (expected != actual) { + qWarning("\n %s:\n\tActual: %s\n\tExpected:%s", qPrintable(side), + qPrintable(actual), qPrintable(expected)); + } + } + }); + QVERIFY2(borderBrushes == brushes, // QCOMPARE doesn't generate helpful output anyway + qPrintable(QString("for cell %1/%2").arg(row).arg(column))); + errorDetails.dismiss(); + cellDetails.dismiss(); + } + } +} + void tst_QTextDocument::maximumBlockCount() { QCOMPARE(doc->maximumBlockCount(), 0); @@ -2639,13 +2895,13 @@ void tst_QTextDocument::blockCountChanged() doc->setPlainText("Foo"); QCOMPARE(doc->blockCount(), 1); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); doc->setPlainText("Foo\nBar"); QCOMPARE(doc->blockCount(), 2); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).value(0).toInt(), 2); spy.clear(); @@ -2653,16 +2909,16 @@ void tst_QTextDocument::blockCountChanged() cursor.movePosition(QTextCursor::End); cursor.insertText("Blahblah"); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); cursor.insertBlock(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).value(0).toInt(), 3); spy.clear(); doc->undo(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).value(0).toInt(), 2); } @@ -2749,21 +3005,11 @@ const QString backgroundImage_html("<body><table><tr><td background=\"foo.png\"> void tst_QTextDocument::backgroundImage_checkExpectedHtml(const QTextDocument &doc) { - QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " - "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" - "<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n" - "p, li { white-space: pre-wrap; }\n" - "</style></head>" - "<body style=\" font-family:'%1'; font-size:%2; font-weight:%3; font-style:%4;\">\n" + QString expectedHtml = htmlHead + "<table border=\"0\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;\" cellspacing=\"2\" cellpadding=\"0\">" "\n<tr>\n<td background=\"foo.png\">" "\n<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" - "</td></tr></table></body></html>"); - - expectedHtml = expectedHtml.arg(defaultFont.family()) - .arg(cssFontSizeString(defaultFont)) - .arg(defaultFont.weight()) - .arg((defaultFont.italic() ? "italic" : "normal")); + "</td></tr></table>" + htmlTail; writeActualAndExpected(QTest::currentTestFunction(), doc.toHtml(), expectedHtml); @@ -2851,12 +3097,12 @@ void tst_QTextDocument::characterAt() QString text("12345\n67890"); cursor.insertText(text); int length = doc.characterCount(); - QCOMPARE(length, text.length() + 1); + QCOMPARE(length, text.size() + 1); QCOMPARE(doc.characterAt(length-1), QChar(QChar::ParagraphSeparator)); QCOMPARE(doc.characterAt(-1), QChar()); QCOMPARE(doc.characterAt(length), QChar()); QCOMPARE(doc.characterAt(length + 1), QChar()); - for (int i = 0; i < text.length(); ++i) { + for (int i = 0; i < text.size(); ++i) { QChar c = text.at(i); if (c == QLatin1Char('\n')) c = QChar(QChar::ParagraphSeparator); @@ -2936,11 +3182,11 @@ void tst_QTextDocument::testUndoCommandAdded() QVERIFY(spy.isEmpty()); cursor.insertText("a"); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); cursor.insertText("b"); // should be merged - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); cursor.insertText("c"); // should be merged - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(doc->toPlainText(), QString("abc")); doc->undo(); QCOMPARE(doc->toPlainText(), QString("")); @@ -2948,11 +3194,11 @@ void tst_QTextDocument::testUndoCommandAdded() doc->clear(); spy.clear(); cursor.insertText("aaa"); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); cursor.insertText("aaaa\nbcd"); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); cursor.beginEditBlock(); @@ -2962,11 +3208,11 @@ void tst_QTextDocument::testUndoCommandAdded() cursor.insertText("\nccc"); QVERIFY(spy.isEmpty()); cursor.endEditBlock(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); cursor.insertBlock(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); cursor.setPosition(5); @@ -2978,18 +3224,18 @@ void tst_QTextDocument::testUndoCommandAdded() QTextCharFormat cf; cf.setFontItalic(true); cursor.mergeCharFormat(cf); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); doc->undo(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); doc->undo(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); doc->redo(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); doc->redo(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); } void tst_QTextDocument::testUndoBlocks() @@ -3569,7 +3815,7 @@ void tst_QTextDocument::mergeFontFamilies() QTextCursor cursor = QTextCursor(&td); cursor.setPosition(0); - cursor.setPosition(QByteArray("Hello World").length(), QTextCursor::KeepAnchor); + cursor.setPosition(QByteArray("Hello World").size(), QTextCursor::KeepAnchor); cursor.mergeCharFormat(newFormat); QVERIFY(td.toHtml().contains(QLatin1String("font-family:'Jokerman';"))); @@ -3596,27 +3842,320 @@ void tst_QTextDocument::clearUndoRedoStacks() QVERIFY(!doc.isUndoAvailable()); } -class UrlResourceProvider : public QUrlResourceProvider +void tst_QTextDocument::resourceProvider() +{ + + int providerCalled = 0; + QUrl providerUrl; + auto provider = [&](const QUrl &url){ + providerUrl = url; + ++providerCalled; + return QVariant(42); + }; + const QUrl url("test://img"); + const QString html = QLatin1String("<img src='%1'/>").arg(url.toString()); + + QTextDocument doc; + QVERIFY(!doc.resourceProvider()); + doc.setResourceProvider(provider); + QVERIFY(doc.resourceProvider()); + + doc.setHtml(html); + const QVariant res = doc.resource(QTextDocument::UserResource, url); + QVERIFY(res.isValid()); + QCOMPARE(providerUrl, url); + QCOMPARE(providerCalled, 1); + + QVERIFY(!QTextDocument::defaultResourceProvider()); + QTextDocument::setDefaultResourceProvider(provider); + QVERIFY(QTextDocument::defaultResourceProvider()); + + QTextDocument doc2; + QVERIFY(!doc2.resourceProvider()); + doc2.setHtml(html); + QVariant res2 = doc2.resource(QTextDocument::UserResource, url); + QCOMPARE(res2, res); + QCOMPARE(providerCalled, 2); +} + +void tst_QTextDocument::contentsChangeIndices_data() { -public: - QVariant resource(const QUrl &url) override - { - resourseUrl = url; - return QVariant(); + QTest::addColumn<QString>("html"); + // adding list entries change the entire block, so change position is + // not the same as the cursor position if this value is >= 0 + QTest::addColumn<int>("expectedBegin"); + + QTest::addRow("text") << "Test" << -1; + QTest::addRow("unnumbered list") << "<ul><li>Test</li></ul>" << 0; + QTest::addRow("numbered list") << "<ol><li>Test</li></ol>" << 0; + QTest::addRow("table") << "<table><tr><td>Test</td></tr></table>" << -1; +} + +void tst_QTextDocument::contentsChangeIndices() +{ + QFETCH(QString, html); + QFETCH(int, expectedBegin); + + QTextDocument doc; + QTestDocumentLayout *layout = new QTestDocumentLayout(&doc); + doc.setDocumentLayout(layout); + doc.setHtml(QString("<html><body>%1</body></html>").arg(html)); + + int documentLength = 0; + int cursorLength = 0; + int changeBegin = 0; + int changeRemoved = 0; + int changeAdded = 0; + connect(&doc, &QTextDocument::contentsChange, this, [&](int pos, int removed, int added){ + documentLength = doc.characterCount(); + + QTextCursor cursor(&doc); + cursor.movePosition(QTextCursor::End); + // includes end-of-paragraph character + cursorLength = cursor.position() + 1; + + changeBegin = pos; + changeRemoved = removed; + changeAdded = added; + }); + + QTextCursor cursor(&doc); + cursor.movePosition(QTextCursor::End); + if (expectedBegin < 0) + expectedBegin = cursor.position(); + cursor.insertBlock(); + + const int changeEnd = changeBegin + changeAdded; + + QVERIFY(documentLength > 0); + QCOMPARE(documentLength, cursorLength); + QVERIFY(documentLength >= changeEnd); + QCOMPARE(changeBegin, expectedBegin); + QCOMPARE(changeAdded - changeRemoved, 1); +} + +void tst_QTextDocument::insertHtmlWithComments_data() +{ + QTest::addColumn<QString>("html"); + QTest::addColumn<QStringList>("expectedBlocks"); + + QTest::newRow("commentless") << "<p>first</p><p>second</p><p>third</p>" + << QStringList { "first", "second", "third" }; + QTest::newRow("normal") << "<p>first</p><!--<p>second</p>--><p>third</p>" + << QStringList { "first", "third" }; + QTest::newRow("nonClosing") << "<p>first</p><!--<p>second</p><p>third</p>" + << QStringList { "first" }; + QTest::newRow("immediatelyClosing") << "<p>first</p><!----><p>second</p><p>third</p>" + << QStringList { "first", "second", "third" }; + QTest::newRow("fake") << "<p>first</p><!-<p>second</p><p>third</p>" + << QStringList { "first", "second", "third" }; + QTest::newRow("endingNonExistant") << "<p>first</p>--><p>second</p><p>third</p>" + << QStringList { "first", "-->", "second", "third" }; +} + +void tst_QTextDocument::insertHtmlWithComments() +{ + QFETCH(QString, html); + QFETCH(QStringList, expectedBlocks); + + QTextDocument doc; + doc.setHtml(html); + + QCOMPARE(doc.blockCount(), expectedBlocks.size()); + + QStringList blockContent; + auto currentBlock = doc.begin(); + while (currentBlock != doc.end()) { + blockContent.append(currentBlock.text()); + currentBlock = currentBlock.next(); } - QUrl resourseUrl; -}; + QCOMPARE(blockContent, expectedBlocks); +} -void tst_QTextDocument::resourceProvider() +void tst_QTextDocument::delayedLayout() +{ + QTextDocument doc; + doc.setHtml("<html>Foobar</html>"); + QCOMPARE(doc.blockCount(), 1); + + doc.setLayoutEnabled(false); + + // Force creation of a layout + QVERIFY(doc.documentLayout()); + + QTextBlock block = doc.begin(); + QTextLayout *layout = block.layout(); + QCOMPARE(layout->lineCount(), 0); // layout didn't happen yet + + doc.setLayoutEnabled(true); + QCOMPARE(layout->lineCount(), 1); // layout happened +} + +void tst_QTextDocument::undoContentChangeIndices() // QTBUG-113865 { QTextDocument doc; - UrlResourceProvider resourceProvider; - doc.setResourceProvider(&resourceProvider); - QUrl url("test://img"); - doc.setHtml(QStringLiteral("<img src='%1'/>").arg(url.toString())); - doc.resource(QTextDocument::UserResource, url); - QCOMPARE(url, resourceProvider.resourseUrl); + QTestDocumentLayout *layout = new QTestDocumentLayout(&doc); + QString content = QString("<html><body>" + "<ul><li>Undo</li></ul>" + "<ul><li>operation</li></ul>" + "<ul><li>of</li></ul>" + "<ul><li>unnumbered</li></ul>" + "<ul><li>lists</li></ul>" + "<ul><li>shows</li></ul>" + "<ul><li>invalid</li></ul>" + "<ul><li>content</li></ul>" + "<ul><li>indices</li></ul>" + "</body></html>"); + doc.setDocumentLayout(layout); + doc.setHtml(content); + + // Select the entire document content + QTextCursor cursor(&doc); + cursor.select(QTextCursor::Document); + cursor.removeSelectedText(); + + // Undo above operation + doc.undo(); + + // Move the cursor to the end + cursor.movePosition(QTextCursor::End); + cursor.insertHtml(content); + + // Select the whole document and remove the content + cursor.select(QTextCursor::Document); + cursor.removeSelectedText(); + + int documentLength = 0; + int changeRemoved = 0; + int changeAdded = 0; + int changePos = 0; + connect(&doc, &QTextDocument::contentsChange, this, [&](int pos, int removed, int added){ + documentLength = doc.characterCount(); + changeRemoved = removed; + changeAdded = added; + changePos = pos; + }); + + // Undo above operation + doc.undo(); + + const int changeEnd = changeAdded + changeRemoved; + + QVERIFY(documentLength > 0); + QCOMPARE(changePos, 0); + QVERIFY(changeRemoved >= 0); + QVERIFY(documentLength >= changeEnd); +} + +void tst_QTextDocument::restoreStrokeFromHtml() +{ + QTextDocument document; + QTextCursor textCursor(&document); + QTextCharFormat textOutline; + textOutline.setTextOutline(QPen(Qt::red, 2.3)); + textCursor.insertText("Outlined text", textOutline); + { + QTextDocument otherDocument; + otherDocument.setHtml(document.toHtml()); + QCOMPARE(otherDocument.blockCount(), 1); + QTextBlock block = otherDocument.firstBlock(); + QTextFragment fragment = block.begin().fragment(); + QCOMPARE(fragment.text(), QStringLiteral("Outlined text")); + QTextCharFormat fmt = fragment.charFormat(); + QVERIFY(fmt.hasProperty(QTextCharFormat::TextOutline)); + QPen pen = fmt.textOutline(); + QCOMPARE(pen.color(), QColor(Qt::red)); + QCOMPARE(pen.widthF(), 2.3); + } +} + +void tst_QTextDocument::restoreForegroundGradientFromHtml() +{ + QTextDocument document; + + QTextCursor textCursor(&document); + + QTextCharFormat foregroundGradient; + QLinearGradient lg; + lg.setColorAt(0.0, Qt::green); + lg.setColorAt(1.0, Qt::blue); + lg.setStart(QPointF(0,0)); + lg.setFinalStop(QPointF(800, 1000)); + foregroundGradient.setForeground(QBrush(lg)); + textCursor.insertText("Linear gradient text\n", foregroundGradient); + + QRadialGradient rg; + rg.setCoordinateMode(QGradient::ObjectBoundingMode); + rg.setSpread(QGradient::ReflectSpread); + rg.setColorAt(0.0, Qt::green); + rg.setColorAt(1.0, Qt::blue); + QPointF center(0.5, 0.5); + rg.setCenter(center); + rg.setFocalPoint(center); + rg.setRadius(0.5); + foregroundGradient.setForeground(QBrush(rg)); + textCursor.insertText("Radial gradient text\n", foregroundGradient); + + QConicalGradient cg; + cg.setCoordinateMode(QGradient::ObjectMode); + cg.setSpread(QGradient::RepeatSpread); + cg.setColorAt(0.0, Qt::green); + cg.setColorAt(1.0, Qt::blue); + cg.setCenter(QPointF(0.5, 0.5)); + cg.setAngle(0.0); + foregroundGradient.setForeground(QBrush(cg)); + textCursor.insertText("Conical gradient text\n", foregroundGradient); + + { + QTextDocument otherDocument; + otherDocument.setHtml(document.toHtml()); + + QCOMPARE(otherDocument.blockCount(), document.blockCount()); + + QTextBlock block = otherDocument.firstBlock(); + QTextFragment fragment = block.begin().fragment(); + + QCOMPARE(fragment.text(), QStringLiteral("Linear gradient text")); + + QTextCharFormat fmt = fragment.charFormat(); + QVERIFY(fmt.hasProperty(QTextCharFormat::ForegroundBrush)); + + QBrush brush = fmt.foreground(); + QCOMPARE(brush.style(), Qt::LinearGradientPattern); + QCOMPARE(brush.gradient()->coordinateMode(), lg.coordinateMode()); + QCOMPARE(brush.gradient()->spread(), lg.spread()); + QCOMPARE(brush.gradient()->stops().size(), lg.stops().size()); + QCOMPARE(static_cast<const QLinearGradient *>(brush.gradient())->start(), lg.start()); + QCOMPARE(static_cast<const QLinearGradient *>(brush.gradient())->finalStop(), lg.finalStop()); + + block = block.next(); + fragment = block.begin().fragment(); + + fmt = fragment.charFormat(); + QVERIFY(fmt.hasProperty(QTextCharFormat::ForegroundBrush)); + + brush = fmt.foreground(); + QCOMPARE(brush.style(), Qt::RadialGradientPattern); + QCOMPARE(brush.gradient()->coordinateMode(), rg.coordinateMode()); + QCOMPARE(brush.gradient()->spread(), rg.spread()); + QCOMPARE(static_cast<const QRadialGradient *>(brush.gradient())->center(), rg.center()); + QCOMPARE(static_cast<const QRadialGradient *>(brush.gradient())->focalPoint(), rg.focalPoint()); + QCOMPARE(static_cast<const QRadialGradient *>(brush.gradient())->radius(), rg.radius()); + + block = block.next(); + fragment = block.begin().fragment(); + + fmt = fragment.charFormat(); + QVERIFY(fmt.hasProperty(QTextCharFormat::ForegroundBrush)); + + brush = fmt.foreground(); + QCOMPARE(brush.style(), Qt::ConicalGradientPattern); + QCOMPARE(brush.gradient()->coordinateMode(), cg.coordinateMode()); + QCOMPARE(brush.gradient()->spread(), cg.spread()); + QCOMPARE(static_cast<const QConicalGradient *>(brush.gradient())->center(), cg.center()); + QCOMPARE(static_cast<const QConicalGradient *>(brush.gradient())->angle(), cg.angle()); + } } QTEST_MAIN(tst_QTextDocument) diff --git a/tests/auto/gui/text/qtextdocumentfragment/CMakeLists.txt b/tests/auto/gui/text/qtextdocumentfragment/CMakeLists.txt index 6f1207c49a..4a4075106e 100644 --- a/tests/auto/gui/text/qtextdocumentfragment/CMakeLists.txt +++ b/tests/auto/gui/text/qtextdocumentfragment/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qtextdocumentfragment.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtextdocumentfragment Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextdocumentfragment LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qtextdocumentfragment SOURCES tst_qtextdocumentfragment.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp index a7408fcc8e..f2c3b36dcd 100644 --- a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp +++ b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.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 <QTest> @@ -41,6 +16,8 @@ #include <qtextcursor.h> +using namespace Qt::StringLiterals; + QT_FORWARD_DECLARE_CLASS(QTextDocument) class tst_QTextDocumentFragment : public QObject @@ -100,6 +77,7 @@ private slots: void inheritAlignment(); void dontEmitEmptyNodeWhenEmptyTagIsFollowedByCloseTag(); void toPlainText(); + void toRawText(); void copyTableRow(); void copyTableColumn(); void copySubTable(); @@ -120,6 +98,7 @@ private slots: void html_thCentered(); void orderedListNumbering(); void html_blockAfterList(); + void html_listStartAttribute(); void html_subAndSuperScript(); void html_cssColors(); void obeyFragmentMarkersInImport(); @@ -142,6 +121,7 @@ private slots: void html_doNotInheritBackground(); void html_inheritBackgroundToInlineElements(); void html_doNotInheritBackgroundFromBlockElements(); + void html_inheritBackgroundFromBlockElements(); void html_nobr(); void fromPlainText(); void fromPlainText2(); @@ -267,6 +247,7 @@ private slots: void html_fromFirefox(); void html_emptyInlineInsideBlock(); void css_fontAndWordSpacing(); + void html_brWithWhitespaceAfterList(); private: inline void setHtml(const QString &html) @@ -1093,6 +1074,14 @@ void tst_QTextDocumentFragment::toPlainText() QCOMPARE(doc->blockCount(), 3); } +void tst_QTextDocumentFragment::toRawText() +{ + // Make sure nbsp, line separator, paragraph separator is preserved + doc->setPlainText("Hello\u0A00\u2028\u2029World"); + + QCOMPARE(QTextDocumentFragment(doc).toRawText(), "Hello\u0A00\u2028\u2029World"); +} + void tst_QTextDocumentFragment::copyTableRow() { QTextDocumentFragment frag; @@ -1190,7 +1179,7 @@ void tst_QTextDocumentFragment::copySubTable() table->cellAt(row, col).firstCursorPosition().insertText(rowS + QString::number(col)); } - QCOMPARE(table->format().columnWidthConstraints().count(), table->columns()); + QCOMPARE(table->format().columnWidthConstraints().size(), table->columns()); // select 2x2 subtable cursor = table->cellAt(1, 1).firstCursorPosition(); @@ -1486,6 +1475,22 @@ void tst_QTextDocumentFragment::html_blockAfterList() QCOMPARE(cursor.blockFormat().indent(), 0); } +void tst_QTextDocumentFragment::html_listStartAttribute() +{ + const char html[] = "<ol start=-1><li>Foo</ol><ol><li>Bar</ol>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + + cursor.movePosition(QTextCursor::Start); + + QVERIFY(cursor.currentList()); + QCOMPARE(cursor.currentList()->format().start(), -1); + + QVERIFY(cursor.movePosition(QTextCursor::NextBlock)); + + QVERIFY(cursor.currentList()); + QCOMPARE(cursor.currentList()->format().start(), 1); +} + void tst_QTextDocumentFragment::html_subAndSuperScript() { const char subHtml[] = "<sub>Subby</sub>"; @@ -2070,7 +2075,7 @@ void tst_QTextDocumentFragment::html_inheritBackgroundToInlineElements() void tst_QTextDocumentFragment::html_doNotInheritBackgroundFromBlockElements() { - const char html[] = "<p style=\"background: blue\"><span>Foo</span></span>"; + const char html[] = "<p style=\"background: blue\"><span>Foo</span></p>"; doc->setHtml(html); int fragmentCount = 0; @@ -2088,6 +2093,31 @@ void tst_QTextDocumentFragment::html_doNotInheritBackgroundFromBlockElements() QCOMPARE(fragmentCount, 1); } + +void tst_QTextDocumentFragment::html_inheritBackgroundFromBlockElements() +{ + const char html[] = "<div style=\"background: blue\"><p>Foo</p><p>Bar</p></div>"; + doc->setHtml(html); + + int fragmentCount = 0; + + QTextBlock block = doc->begin(); + for (QTextBlock::Iterator it = block.begin(); + !it.atEnd(); ++it, ++fragmentCount) { + + const QTextFragment fragment = it.fragment(); + if (fragmentCount == 0) { + QCOMPARE(fragment.text(), QString("Foo")); + QVERIFY(fragment.charFormat().hasProperty(QTextFormat::BackgroundBrush)); + } else { + QCOMPARE(fragment.text(), QString("Bar")); + QVERIFY(fragment.charFormat().hasProperty(QTextFormat::BackgroundBrush)); + } + } + + QCOMPARE(fragmentCount, 1); +} + void tst_QTextDocumentFragment::html_nobr() { const QString input = "Blah Foo Bar"; @@ -2225,7 +2255,7 @@ void tst_QTextDocumentFragment::html_frameImport() cursor.insertFragment(frag); QList<QTextFrame *> childFrames = doc->rootFrame()->childFrames(); - QCOMPARE(childFrames.count(), 1); + QCOMPARE(childFrames.size(), 1); QTextFrame *frame = childFrames.first(); QCOMPARE(frame->frameFormat().margin(), ffmt.margin()); QCOMPARE(frame->frameFormat().border(), ffmt.border()); @@ -2253,7 +2283,7 @@ void tst_QTextDocumentFragment::html_frameImport2() cursor.insertFragment(frag); QList<QTextFrame *> childFrames = doc->rootFrame()->childFrames(); - QCOMPARE(childFrames.count(), 1); + QCOMPARE(childFrames.size(), 1); QTextFrame *frame = childFrames.first(); QCOMPARE(frame->frameFormat().topMargin(), ffmt.topMargin()); QCOMPARE(frame->frameFormat().bottomMargin(), ffmt.bottomMargin()); @@ -2268,7 +2298,7 @@ void tst_QTextDocumentFragment::html_dontAddMarginsAcrossTableCells() cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html))); QList<QTextFrame *> childFrames = doc->rootFrame()->childFrames(); - QCOMPARE(childFrames.count(), 1); + QCOMPARE(childFrames.size(), 1); QTextFrame *frame = childFrames.first(); cursor = frame->firstCursorPosition(); QCOMPARE(cursor.blockFormat().leftMargin(), qreal(50.0)); @@ -2426,12 +2456,12 @@ void tst_QTextDocumentFragment::defaultFont() f.setFamily("Courier New"); f.setBold(true); f.setItalic(true); - f.setStrikeOut(true); // set here but deliberately ignored for the html export + f.setStrikeOut(true); f.setPointSize(100); doc->setDefaultFont(f); doc->setPlainText("Hello World"); const QString html = doc->toHtml(); - QLatin1String str("<body style=\" font-family:'Courier New'; font-size:100pt; font-weight:700; font-style:italic;\">"); + QLatin1String str("<body style=\" font-family:'Courier New'; font-size:100pt; font-weight:700; font-style:italic; text-decoration: line-through;\">"); QVERIFY(html.contains(str)); } @@ -2750,7 +2780,7 @@ void tst_QTextDocumentFragment::html_columnWidths() QTextTableFormat fmt = table->format(); const QList<QTextLength> columnWidths = fmt.columnWidthConstraints(); - QCOMPARE(columnWidths.count(), 2); + QCOMPARE(columnWidths.size(), 2); QCOMPARE(columnWidths.at(0).type(), QTextLength::VariableLength); QCOMPARE(columnWidths.at(1).type(), QTextLength::PercentageLength); QCOMPARE(columnWidths.at(1).rawValue(), qreal(1)); @@ -3473,6 +3503,12 @@ void tst_QTextDocumentFragment::html_hr() doc->setHtml("<hr />"); QCOMPARE(doc->blockCount(), 1); QVERIFY(doc->begin().blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)); + doc->setHtml("<hr style=\"background-color:green;\"/>"); + QCOMPARE(doc->blockCount(), 1); + QVERIFY(doc->begin().blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)); + QVERIFY(doc->begin().blockFormat().hasProperty(QTextFormat::BackgroundBrush)); + const auto brush = qvariant_cast<QBrush>(doc->begin().blockFormat().property(QTextFormat::BackgroundBrush)); + QCOMPARE(brush.color(), QColor("green")); } void tst_QTextDocumentFragment::html_hrMargins() @@ -4152,7 +4188,7 @@ void tst_QTextDocumentFragment::html_entities() setHtml(html); QCOMPARE(doc->blockCount(), 1); QString txt = doc->begin().text(); - QCOMPARE(txt.length(), 1); + QCOMPARE(txt.size(), 1); QCOMPARE(txt.at(0).unicode(), code); } @@ -4287,5 +4323,24 @@ void tst_QTextDocumentFragment::css_fontAndWordSpacing() } } +void tst_QTextDocumentFragment::html_brWithWhitespaceAfterList() // QTBUG-81662 +{ + setHtml(QString::fromLatin1("<ul><li>one</li><li>two</li></ul>\n <br/>\nhello")); + + QCOMPARE(doc->blockCount(), 3); + + QTextBlock block = doc->begin(); + QVERIFY(block.textList()); + + block = block.next(); + QVERIFY(block.textList()); + + block = block.next(); + QCOMPARE(block.text(), u"\u2028hello"_s); + + block = block.next(); + QVERIFY(block.text().isEmpty()); +} + QTEST_MAIN(tst_QTextDocumentFragment) #include "tst_qtextdocumentfragment.moc" diff --git a/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST b/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST index 5a2f81c448..ed85376c92 100644 --- a/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST +++ b/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST @@ -1,6 +1,3 @@ [imageAtRightAlignedTab] -rhel-6.6 -rhel-7.4 -rhel-7.6 sles centos diff --git a/tests/auto/gui/text/qtextdocumentlayout/CMakeLists.txt b/tests/auto/gui/text/qtextdocumentlayout/CMakeLists.txt index da41073962..07386d4e24 100644 --- a/tests/auto/gui/text/qtextdocumentlayout/CMakeLists.txt +++ b/tests/auto/gui/text/qtextdocumentlayout/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qtextdocumentlayout.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtextdocumentlayout Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextdocumentlayout LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qtextdocumentlayout SOURCES tst_qtextdocumentlayout.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui ) @@ -15,6 +22,6 @@ qt_internal_add_test(tst_qtextdocumentlayout ##################################################################### qt_internal_extend_target(tst_qtextdocumentlayout CONDITION TARGET Qt::Widgets - PUBLIC_LIBRARIES + LIBRARIES Qt::Widgets ) diff --git a/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp b/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp index 0075203c97..2a279682ca 100644 --- a/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp +++ b/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.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 <QTest> @@ -58,6 +33,7 @@ private slots: void floatingTablePageBreak(); void imageAtRightAlignedTab(); void blockVisibility(); + void testHitTest(); void largeImage(); @@ -405,5 +381,41 @@ void tst_QTextDocumentLayout::largeImage() } } +void tst_QTextDocumentLayout::testHitTest() +{ + QTextDocument document; + QTextCursor cur(&document); + int topMargin = 20; + + //insert 500 blocks into textedit + for (int i = 0; i < 500; i++) { + cur.insertBlock(); + cur.insertHtml(QString("block %1").arg(i)); + } + + //randomly set half the blocks invisible + QTextBlock blk=document.begin(); + for (int i = 0; i < 500; i++) { + if (i % 7) + blk.setVisible(0); + blk = blk.next(); + } + + //set margin for all blocks (not strictly necessary, but makes easier to click in between blocks) + QTextBlockFormat blkfmt; + blkfmt.setTopMargin(topMargin); + cur.movePosition(QTextCursor::Start); + cur.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + cur.mergeBlockFormat(blkfmt); + + for (int y = cur.selectionStart(); y < cur.selectionEnd(); y += 10) { + QPoint mousePoint(1, y); + int cursorPos = document.documentLayout()->hitTest(mousePoint, Qt::FuzzyHit); + int positionY = document.findBlock(cursorPos).layout()->position().toPoint().y(); + //mousePoint is in the rect of the current Block + QVERIFY(positionY - topMargin <= y); + } +} + QTEST_MAIN(tst_QTextDocumentLayout) #include "tst_qtextdocumentlayout.moc" diff --git a/tests/auto/gui/text/qtextformat/CMakeLists.txt b/tests/auto/gui/text/qtextformat/CMakeLists.txt index cacd7fbd18..4dea90900e 100644 --- a/tests/auto/gui/text/qtextformat/CMakeLists.txt +++ b/tests/auto/gui/text/qtextformat/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qtextformat.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtextformat Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextformat LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qtextformat SOURCES tst_qtextformat.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp b/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp index cf87cd41aa..d20a2f1ea5 100644 --- a/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp +++ b/tests/auto/gui/text/qtextformat/tst_qtextformat.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 <QTest> @@ -212,7 +187,7 @@ void tst_QTextFormat::resolveFont() QTextCursor(&doc).insertText("Test", fmt); QList<QTextFormat> formats = doc.allFormats(); - QCOMPARE(formats.count(), 3); + QCOMPARE(formats.size(), 3); QCOMPARE(formats.at(2).type(), int(QTextFormat::CharFormat)); fmt = formats.at(2).toCharFormat(); @@ -337,8 +312,8 @@ void tst_QTextFormat::getSetTabs() public: Comparator(const QList<QTextOption::Tab> &tabs, const QList<QTextOption::Tab> &tabs2) { - QCOMPARE(tabs.count(), tabs2.count()); - for(int i=0; i < tabs.count(); i++) { + QCOMPARE(tabs.size(), tabs2.size()); + for(int i=0; i < tabs.size(); i++) { QTextOption::Tab t1 = tabs[i]; QTextOption::Tab t2 = tabs2[i]; QCOMPARE(t1.position, t2.position); @@ -389,7 +364,7 @@ void tst_QTextFormat::testTabsUsed() QCOMPARE(line.cursorToX(4), 100.); QTextOption option = layout->textOption(); - QCOMPARE(option.tabs().count(), tabs.count()); + QCOMPARE(option.tabs().size(), tabs.size()); } @@ -673,16 +648,16 @@ void tst_QTextFormat::clearCollection() charFormat2.setUnderlineStyle(QTextCharFormat::SingleUnderline); int formatIndex2 = collection.indexForFormat(charFormat2); QCOMPARE(formatIndex2, 1); - QCOMPARE(collection.formats.count(), 2); - QCOMPARE(collection.hashes.count(), 2); + QCOMPARE(collection.formats.size(), 2); + QCOMPARE(collection.hashes.size(), 2); QCOMPARE(collection.defaultFont(), f); collection.clear(); - QCOMPARE(collection.formats.count(), 0); - QCOMPARE(collection.hashes.count(), 0); + QCOMPARE(collection.formats.size(), 0); + QCOMPARE(collection.hashes.size(), 0); QCOMPARE(collection.indexForFormat(charFormat2), 0); - QCOMPARE(collection.formats.count(), 1); - QCOMPARE(collection.hashes.count(), 1); + QCOMPARE(collection.formats.size(), 1); + QCOMPARE(collection.hashes.size(), 1); QCOMPARE(collection.defaultFont(), f); // kept, QTextDocument::clear or setPlainText should not reset the font set by setDefaultFont } @@ -704,7 +679,7 @@ void tst_QTextFormat::dataStreamCompatibility() QVERIFY(properties.contains(QTextFormat::FontFamilies)); QVERIFY(!properties.contains(QTextFormat::OldFontLetterSpacingType)); QVERIFY(!properties.contains(QTextFormat::OldFontStretch)); - QVERIFY(!properties.contains(QTextFormat::FontFamily)); + QVERIFY(!properties.contains(QTextFormat::OldFontFamily)); } QByteArray memory; @@ -735,7 +710,7 @@ void tst_QTextFormat::dataStreamCompatibility() QVERIFY(properties.contains(QTextFormat::FontFamilies)); QVERIFY(!properties.contains(QTextFormat::OldFontLetterSpacingType)); QVERIFY(!properties.contains(QTextFormat::OldFontStretch)); - QVERIFY(!properties.contains(QTextFormat::FontFamily)); + QVERIFY(!properties.contains(QTextFormat::OldFontFamily)); } } @@ -755,7 +730,7 @@ void tst_QTextFormat::dataStreamCompatibility() QVERIFY(properties.contains(QTextFormat::FontFamilies)); QVERIFY(!properties.contains(QTextFormat::OldFontLetterSpacingType)); QVERIFY(!properties.contains(QTextFormat::OldFontStretch)); - QVERIFY(!properties.contains(QTextFormat::FontFamily)); + QVERIFY(!properties.contains(QTextFormat::OldFontFamily)); } } @@ -788,7 +763,7 @@ void tst_QTextFormat::dataStreamCompatibility() QVERIFY(properties.contains(QTextFormat::FontFamilies)); QVERIFY(!properties.contains(QTextFormat::OldFontLetterSpacingType)); QVERIFY(!properties.contains(QTextFormat::OldFontStretch)); - QVERIFY(!properties.contains(QTextFormat::FontFamily)); + QVERIFY(!properties.contains(QTextFormat::OldFontFamily)); } } @@ -810,7 +785,7 @@ void tst_QTextFormat::dataStreamCompatibility() QVERIFY(!properties.contains(QTextFormat::FontFamilies)); QVERIFY(properties.contains(QTextFormat::OldFontLetterSpacingType)); QVERIFY(properties.contains(QTextFormat::OldFontStretch)); - QVERIFY(properties.contains(QTextFormat::FontFamily)); + QVERIFY(properties.contains(QTextFormat::OldFontFamily)); } } diff --git a/tests/auto/gui/text/qtextimagehandler/CMakeLists.txt b/tests/auto/gui/text/qtextimagehandler/CMakeLists.txt new file mode 100644 index 0000000000..8d282b8f2c --- /dev/null +++ b/tests/auto/gui/text/qtextimagehandler/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextimagehandler LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +list(APPEND test_data "data/image.png") +list(APPEND test_data "data/image@2x.png") + +qt_internal_add_test(tst_qtextimagehandler + SOURCES + tst_qtextimagehandler.cpp + LIBRARIES + Qt::CorePrivate + Qt::Gui + Qt::GuiPrivate + TESTDATA + ${test_data} +) + +qt_internal_add_resource(tst_qtextimagehandler "qtextimagehandler" + PREFIX + "/" + FILES + ${test_data} +) diff --git a/tests/auto/gui/text/qtextimagehandler/tst_qtextimagehandler.cpp b/tests/auto/gui/text/qtextimagehandler/tst_qtextimagehandler.cpp index d5dde13770..5311aa6f2b 100644 --- a/tests/auto/gui/text/qtextimagehandler/tst_qtextimagehandler.cpp +++ b/tests/auto/gui/text/qtextimagehandler/tst_qtextimagehandler.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** - ** - ** Copyright (C) 2020 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) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -42,6 +17,7 @@ private slots: void init(); void cleanup(); void cleanupTestCase(); + void loadAtNImages_data(); void loadAtNImages(); }; @@ -61,24 +37,40 @@ void tst_QTextImageHandler::cleanupTestCase() { } +void tst_QTextImageHandler::loadAtNImages_data() +{ + QTest::addColumn<QString>("imageFile"); + + QTest::addRow("file") << QFINDTESTDATA("data/image.png"); + QTest::addRow("file_url") << QUrl::fromLocalFile(QFINDTESTDATA("data/image.png")).toString(); + QTest::addRow("resource") << ":/data/image.png"; + QTest::addRow("qrc_url") << "qrc:/data/image.png"; +} + void tst_QTextImageHandler::loadAtNImages() { + QFETCH(QString, imageFile); + QTextDocument doc; QTextCursor c(&doc); - c.insertHtml("<img src=\"data/image.png\">"); + c.insertHtml("<img src=\"" + imageFile + "\">"); + const auto formats = doc.allFormats(); + const auto it = std::find_if(formats.begin(), formats.end(), [](const auto &format){ + return format.objectType() == QTextFormat::ImageObject; + }); + QVERIFY(it != formats.end()); + const QTextImageFormat format = (*it).toImageFormat(); QTextImageHandler handler; - QTextImageFormat fmt; - fmt.setName("data/image.png"); - for (int i = 1; i < 3; ++i) { + for (const auto &dpr : {1, 2}) { QImage img(20, 20, QImage::Format_ARGB32_Premultiplied); img.fill(Qt::white); - img.setDevicePixelRatio(i); + img.setDevicePixelRatio(dpr); QPainter p(&img); - handler.drawObject(&p, QRect(0, 0, 20, 20), &doc, 0, fmt); + handler.drawObject(&p, QRect(0, 0, 20, 20), &doc, 0, format); p.end(); QVERIFY(!img.isNull()); - const auto expectedColor = i == 1 ? Qt::red : Qt::green; + const auto expectedColor = dpr == 1 ? Qt::red : Qt::green; QCOMPARE(img.pixelColor(0, 0), expectedColor); } } diff --git a/tests/auto/gui/text/qtextlayout/CMakeLists.txt b/tests/auto/gui/text/qtextlayout/CMakeLists.txt index 3fb5dea8b9..655c0985a0 100644 --- a/tests/auto/gui/text/qtextlayout/CMakeLists.txt +++ b/tests/auto/gui/text/qtextlayout/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qtextlayout.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtextlayout Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextlayout LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qtextlayout SOURCES tst_qtextlayout.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp index 099ccab51c..209f5a56e2 100644 --- a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp +++ b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp @@ -1,31 +1,7 @@ -/**************************************************************************** -** -** 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 +#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses /* !!!!!! Warning !!!!! @@ -68,11 +44,15 @@ private slots: void forcedBreaks(); void breakAny(); void noWrap(); + void cursorToXForInlineObjects(); void cursorToXForSetColumns(); void cursorToXForTrailingSpaces_data(); void cursorToXForTrailingSpaces(); void cursorToXInvalidInput(); + void cursorToXForBidiBoundaries_data(); + void cursorToXForBidiBoundaries(); + void horizontalAlignment_data(); void horizontalAlignment(); void horizontalAlignmentMultiline_data(); @@ -86,6 +66,8 @@ private slots: #ifdef QT_BUILD_INTERNAL void xToCursorAtEndOfLine(); #endif + void xToCursorForBidiEnds_data(); + void xToCursorForBidiEnds(); void boundingRectTopLeft(); void graphemeBoundaryForSurrogatePairs(); void tabStops(); @@ -143,7 +125,9 @@ private slots: void tooManyDirectionalCharctersCrash_qtbug77819(); void softHyphens_data(); void softHyphens(); + void min_maximumWidth_data(); void min_maximumWidth(); + void negativeLineWidth(); private: QFont testFont; @@ -308,14 +292,14 @@ void tst_QTextLayout::simpleBoundingRect() QString hello("hello world"); - const int width = hello.length() * testFont.pixelSize(); + const int width = hello.size() * testFont.pixelSize(); QTextLayout layout(hello, testFont); layout.beginLayout(); QTextLine line = layout.createLine(); line.setLineWidth(width); - QCOMPARE(line.textLength(), hello.length()); + QCOMPARE(line.textLength(), hello.size()); QCOMPARE(layout.boundingRect(), QRectF(0, 0, width, QFontMetrics(testFont).height())); } @@ -350,18 +334,18 @@ void tst_QTextLayout::threeLineBoundingRect() QString thirdWord("world"); QString text(firstWord + wordBoundary1 + secondWord + wordBoundary2 + thirdWord); - int firstLineWidth = firstWord.length() * testFont.pixelSize(); - int secondLineWidth = secondWord.length() * testFont.pixelSize(); - int thirdLineWidth = thirdWord.length() * testFont.pixelSize(); + int firstLineWidth = firstWord.size() * testFont.pixelSize(); + int secondLineWidth = secondWord.size() * testFont.pixelSize(); + int thirdLineWidth = thirdWord.size() * testFont.pixelSize(); // Trailing spaces do not count to line width: if (!wordBoundary1.isSpace()) firstLineWidth += testFont.pixelSize(); if (!wordBoundary2.isSpace()) secondLineWidth += testFont.pixelSize(); // But trailing spaces do count to line length: - const int firstLineLength = firstWord.length() + 1; - const int secondLineLength = secondWord.length() + 1; - const int thirdLineLength = thirdWord.length(); + const int firstLineLength = firstWord.size() + 1; + const int secondLineLength = secondWord.size() + 1; + const int thirdLineLength = thirdWord.size(); const int longestLine = qMax(firstLineWidth, qMax(secondLineWidth, thirdLineWidth)); @@ -405,7 +389,7 @@ void tst_QTextLayout::boundingRectWithLongLineAndNoWrap() { QString longString("thisisaverylongstringthatcannotbewrappedatallitjustgoesonandonlikeonebigword"); - const int width = longString.length() * testFont.pixelSize() / 20; // very small widthx + const int width = longString.size() * testFont.pixelSize() / 20; // very small widthx QTextLayout layout(longString, testFont); layout.beginLayout(); @@ -530,18 +514,24 @@ void tst_QTextLayout::noWrap() void tst_QTextLayout::cursorToXForInlineObjects() { - QChar ch(QChar::ObjectReplacementCharacter); - QString text(ch); - QTextLayout layout(text, testFont); - layout.beginLayout(); + QString text = QStringLiteral("<html><body><img src=\"\" width=\"32\" height=\"32\" /></body></html>"); - QTextEngine *engine = layout.engine(); - const int item = engine->findItem(0); - engine->layoutData->items[item].width = 32; + QTextDocument document; + document.setHtml(text); + QCOMPARE(document.blockCount(), 1); - QTextLine line = layout.createLine(); - line.setLineWidth(0x10000); + // Trigger layout + { + QImage img(1, 1, QImage::Format_ARGB32_Premultiplied); + QPainter p(&img); + document.drawContents(&p); + } + + QTextLayout *layout = document.firstBlock().layout(); + QVERIFY(layout != nullptr); + QCOMPARE(layout->lineCount(), 1); + QTextLine line = layout->lineAt(0); QCOMPARE(line.cursorToX(0), qreal(0)); QCOMPARE(line.cursorToX(1), qreal(32)); } @@ -734,6 +724,76 @@ void tst_QTextLayout::cursorToXInvalidInput() QCOMPARE(cursorPos, 3); } +void tst_QTextLayout::cursorToXForBidiBoundaries_data() +{ + QTest::addColumn<Qt::LayoutDirection>("textDirection"); + QTest::addColumn<QString>("text"); + QTest::addColumn<int>("cursorPosition"); + QTest::addColumn<int>("runsToInclude"); + + QTest::addRow("LTR, abcشزذabc, 0") << Qt::LeftToRight << "abcشزذabc" + << 0 << 0; + QTest::addRow("RTL, abcشزذabc, 9") << Qt::RightToLeft << "abcشزذabc" + << 9 << 1; + QTest::addRow("LTR, abcشزذabc, 3") << Qt::LeftToRight << "abcشزذabc" + << 0 << 0; + QTest::addRow("RTL, abcشزذabc, 6") << Qt::RightToLeft << "abcشزذabc" + << 9 << 1; + + QTest::addRow("LTR, شزذabcشزذ, 0") << Qt::LeftToRight << "شزذabcشزذ" + << 0 << 1; + QTest::addRow("RTL, شزذabcشزذ, 9") << Qt::RightToLeft << "شزذabcشزذ" + << 9 << 0; + QTest::addRow("LTR, شزذabcشزذ, 3") << Qt::LeftToRight << "شزذabcشزذ" + << 3 << 1; + QTest::addRow("RTL, شزذabcشزذ, 3") << Qt::RightToLeft << "شزذabcشزذ" + << 3 << 2; + QTest::addRow("LTR, شزذabcشزذ, 6") << Qt::LeftToRight << "شزذabcشزذ" + << 6 << 2; + QTest::addRow("RTL, شزذabcشزذ, 6") << Qt::RightToLeft << "شزذabcشزذ" + << 6 << 1; +} + +void tst_QTextLayout::cursorToXForBidiBoundaries() +{ + QFETCH(Qt::LayoutDirection, textDirection); + QFETCH(QString, text); + QFETCH(int, cursorPosition); + QFETCH(int, runsToInclude); + + QTextOption option; + option.setTextDirection(textDirection); + + QTextLayout layout(text, testFont); + layout.setTextOption(option); + layout.beginLayout(); + + { + QTextLine line = layout.createLine(); + line.setLineWidth(0x10000); + } + layout.endLayout(); + + QTextLine line = layout.lineAt(0); + QList<QGlyphRun> glyphRuns = line.glyphRuns(-1, + -1, + QTextLayout::RetrieveStringIndexes + | QTextLayout::RetrieveGlyphIndexes); + QVERIFY(runsToInclude <= glyphRuns.size()); + + std::sort(glyphRuns.begin(), glyphRuns.end(), + [](const QGlyphRun &first, const QGlyphRun &second) { + return first.stringIndexes().first() < second.stringIndexes().first(); + }); + + qreal expectedX = 0.0; + for (int i = 0; i < runsToInclude; ++i) { + expectedX += glyphRuns.at(i).boundingRect().width(); + } + + QCOMPARE(line.cursorToX(cursorPosition), expectedX); +} + void tst_QTextLayout::horizontalAlignment_data() { qreal width = TESTFONT_SIZE * 4; @@ -1026,7 +1086,7 @@ void tst_QTextLayout::defaultWordSeparators_data() QString separators(".,:;-<>[](){}=/+%&^*"); separators += QLatin1String("!?"); - for (int i = 0; i < separators.count(); ++i) { + for (int i = 0; i < separators.size(); ++i) { QTest::newRow(QString::number(i).toLatin1().data()) << QString::fromLatin1("abcd") + separators.at(i) + QString::fromLatin1("efgh") << 0 << 4; @@ -1106,7 +1166,7 @@ void tst_QTextLayout::xToCursorAtEndOfLine() QString text = "FirstLine SecondLine"; text.replace('\n', QChar::LineSeparator); - const qreal firstLineWidth = QString("FirstLine").length() * testFont.pixelSize(); + const qreal firstLineWidth = QString("FirstLine").size() * testFont.pixelSize(); QTextLayout layout(text, testFont); layout.setCacheEnabled(true); @@ -1126,6 +1186,60 @@ void tst_QTextLayout::xToCursorAtEndOfLine() } #endif + +void tst_QTextLayout::xToCursorForBidiEnds_data() +{ + QTest::addColumn<Qt::LayoutDirection>("textDirection"); + QTest::addColumn<QString>("text"); + QTest::addColumn<int>("leftPosition"); + QTest::addColumn<int>("rightPosition"); + + QTest::addRow("LTR, abcشزذ") << Qt::LeftToRight << "abcشزذ" + << 0 << 6; + QTest::addRow("RTL, abcشزذ") << Qt::RightToLeft << "abcشزذ" + << 6 << 0; + QTest::addRow("LTR, شزذabc") << Qt::LeftToRight << "شزذabc" + << 0 << 6; + QTest::addRow("RTL, شزذabc") << Qt::RightToLeft << "شزذabc" + << 6 << 0; + QTest::addRow("LTR, شزذ123") << Qt::LeftToRight << "شزذ123" + << 0 << 6; + QTest::addRow("RTL, شزذ123") << Qt::RightToLeft << "شزذ123" + << 6 << 0; + + QTest::addRow("LTR, abcشزذabc") << Qt::LeftToRight << "abcشزذabc" + << 0 << 9; + QTest::addRow("RTL, abcشزذabc") << Qt::RightToLeft << "abcشزذabc" + << 9 << 0; + QTest::addRow("LTR, شزذabcشزذ") << Qt::LeftToRight << "شزذabcشزذ" + << 0 << 9; + QTest::addRow("RTL, شزذabcشزذ") << Qt::RightToLeft << "شزذabcشزذ" + << 9 << 0; +} + +void tst_QTextLayout::xToCursorForBidiEnds() +{ + QFETCH(Qt::LayoutDirection, textDirection); + QFETCH(QString, text); + QFETCH(int, leftPosition); + QFETCH(int, rightPosition); + + QTextOption option; + option.setTextDirection(textDirection); + + QTextLayout layout(text, testFont); + layout.setTextOption(option); + layout.beginLayout(); + + QTextLine line = layout.createLine(); + line.setLineWidth(0x10000); + + QCOMPARE(line.xToCursor(0), leftPosition); + QCOMPARE(line.xToCursor(line.width()), rightPosition); + + layout.endLayout(); +} + void tst_QTextLayout::boundingRectTopLeft() { QString text = "FirstLine\nSecondLine"; @@ -1195,7 +1309,7 @@ void tst_QTextLayout::integerOverflow() QVERIFY(line.isValid()); line.setLineWidth(INT_MAX); - QCOMPARE(line.textLength(), txt.length()); + QCOMPARE(line.textLength(), txt.size()); QVERIFY(!layout.createLine().isValid()); @@ -1770,7 +1884,7 @@ void tst_QTextLayout::capitalization_allUpperCase() QTextEngine *engine = layout.engine(); engine->itemize(); - QCOMPARE(engine->layoutData->items.count(), 1); + QCOMPARE(engine->layoutData->items.size(), 1); QCOMPARE(engine->layoutData->items.at(0).analysis.flags, ushort(QScriptAnalysis::Uppercase)); } @@ -1790,7 +1904,7 @@ void tst_QTextLayout::capitalization_allUpperCase_newline() QTextEngine *engine = layout.engine(); engine->itemize(); - QCOMPARE(engine->layoutData->items.count(), 3); + QCOMPARE(engine->layoutData->items.size(), 3); QCOMPARE(engine->layoutData->items.at(0).analysis.flags, ushort(QScriptAnalysis::Uppercase)); QCOMPARE(engine->layoutData->items.at(1).analysis.flags, ushort(QScriptAnalysis::LineOrParagraphSeparator)); QCOMPARE(engine->layoutData->items.at(2).analysis.flags, ushort(QScriptAnalysis::Uppercase)); @@ -1808,7 +1922,7 @@ void tst_QTextLayout::capitalization_allLowerCase() QTextEngine *engine = layout.engine(); engine->itemize(); - QCOMPARE(engine->layoutData->items.count(), 1); + QCOMPARE(engine->layoutData->items.size(), 1); QCOMPARE(engine->layoutData->items.at(0).analysis.flags, ushort(QScriptAnalysis::Lowercase)); } @@ -1824,7 +1938,7 @@ void tst_QTextLayout::capitalization_smallCaps() QTextEngine *engine = layout.engine(); engine->itemize(); - QCOMPARE(engine->layoutData->items.count(), 2); + QCOMPARE(engine->layoutData->items.size(), 2); QCOMPARE(engine->layoutData->items.at(0).analysis.flags, ushort(QScriptAnalysis::None)); QCOMPARE(engine->layoutData->items.at(1).analysis.flags, ushort(QScriptAnalysis::SmallCaps)); } @@ -1841,7 +1955,7 @@ void tst_QTextLayout::capitalization_capitalize() QTextEngine *engine = layout.engine(); engine->itemize(); - QCOMPARE(engine->layoutData->items.count(), 5); + QCOMPARE(engine->layoutData->items.size(), 5); QCOMPARE(engine->layoutData->items.at(0).analysis.flags, ushort(QScriptAnalysis::Uppercase)); QCOMPARE(engine->layoutData->items.at(1).analysis.flags, ushort(QScriptAnalysis::None)); QCOMPARE(engine->layoutData->items.at(2).analysis.flags, ushort(QScriptAnalysis::Tab)); @@ -1910,6 +2024,20 @@ void tst_QTextLayout::longText() QFontMetricsF fm(layout.font()); QVERIFY(layout.maximumWidth() - fm.horizontalAdvance(' ') <= QFIXED_MAX); } + + { + QTextLayout layout(QString("AAAAAAAA").repeated(200000)); + layout.setCacheEnabled(true); + layout.beginLayout(); + forever { + QTextLine line = layout.createLine(); + if (!line.isValid()) + break; + } + layout.endLayout(); + QFontMetricsF fm(layout.font()); + QVERIFY(layout.maximumWidth() - fm.horizontalAdvance('A') <= QFIXED_MAX); + } } void tst_QTextLayout::widthOfTabs() @@ -1938,7 +2066,7 @@ void tst_QTextLayout::columnWrapWithTabs() textLayout.beginLayout(); QTextLine line = textLayout.createLine(); line.setNumColumns(30); - QCOMPARE(line.textLength(), text.length()); + QCOMPARE(line.textLength(), text.size()); textLayout.endLayout(); } @@ -1949,7 +2077,7 @@ void tst_QTextLayout::columnWrapWithTabs() textLayout.beginLayout(); QTextLine line = textLayout.createLine(); line.setNumColumns(30); - QVERIFY(line.textLength() < text.length()); + QVERIFY(line.textLength() < text.size()); textLayout.endLayout(); } @@ -2353,7 +2481,7 @@ void tst_QTextLayout::nbspWithFormat() layout.setText(s1 + s2 + nbsp + s3); QTextLayout::FormatRange formatRange; - formatRange.start = s1.length() + s2.length(); + formatRange.start = s1.size() + s2.size(); formatRange.length = 1; formatRange.format.setFontUnderline(true); @@ -2370,9 +2498,9 @@ void tst_QTextLayout::nbspWithFormat() QCOMPARE(layout.lineCount(), 2); QCOMPARE(layout.lineAt(0).textStart(), 0); - QCOMPARE(layout.lineAt(0).textLength(), s1.length()); - QCOMPARE(layout.lineAt(1).textStart(), s1.length()); - QCOMPARE(layout.lineAt(1).textLength(), s2.length() + 1 + s3.length()); + QCOMPARE(layout.lineAt(0).textLength(), s1.size()); + QCOMPARE(layout.lineAt(1).textStart(), s1.size()); + QCOMPARE(layout.lineAt(1).textLength(), s2.size() + 1 + s3.size()); } void tst_QTextLayout::koreanWordWrap() @@ -2546,13 +2674,35 @@ void tst_QTextLayout::softHyphens() } } +void tst_QTextLayout::min_maximumWidth_data() +{ + QTest::addColumn<QString>("text"); + + QTest::newRow("long string") << QStringLiteral("lmong_long_crazy_87235982735_23857239682376923876923876-fuwhfhfw-names-AAAA-deeaois2019-03-03.and.more"); + QTest::newRow("QTBUG-106947") << QStringLiteral("text text"); + QTest::newRow("spaces") << QStringLiteral(" text text "); + QTest::newRow("QTBUG-104986") << QStringLiteral("text\ntext\ntext"); + QTest::newRow("spaces + line breaks") << QStringLiteral(" \n text\n \ntext \n "); +} + void tst_QTextLayout::min_maximumWidth() { - QString longString("lmong_long_crazy_87235982735_23857239682376923876923876-fuwhfhfw-names-AAAA-deeaois2019-03-03.and.more"); - QTextLayout layout(longString, testFont); + QFETCH(QString, text); + text.replace('\n', QChar::LineSeparator); + + QTextLayout layout(text, testFont); + layout.setCacheEnabled(true); + + QTextOption opt; + opt.setWrapMode(QTextOption::NoWrap); + layout.setTextOption(opt); + layout.beginLayout(); + while (layout.createLine().isValid()) { } + layout.endLayout(); + + const qreal nonWrappedMaxWidth = layout.maximumWidth(); for (int wrapMode = QTextOption::NoWrap; wrapMode <= QTextOption::WrapAtWordBoundaryOrAnywhere; ++wrapMode) { - QTextOption opt; opt.setWrapMode((QTextOption::WrapMode)wrapMode); layout.setTextOption(opt); layout.beginLayout(); @@ -2561,6 +2711,9 @@ void tst_QTextLayout::min_maximumWidth() const qreal minWidth = layout.minimumWidth(); const qreal maxWidth = layout.maximumWidth(); + QCOMPARE_LE(minWidth, maxWidth); + QCOMPARE_LE(maxWidth, nonWrappedMaxWidth); // maxWidth for wrapped text shouldn't exceed maxWidth for the text without wrapping. + // Try the layout from slightly wider than the widest (maxWidth) // and narrow it down to slighly narrower than minWidth // layout.maximumWidth() should return the same regardless @@ -2582,5 +2735,28 @@ void tst_QTextLayout::min_maximumWidth() } } +void tst_QTextLayout::negativeLineWidth() +{ + { + QTextLayout layout; + layout.setText("Foo bar"); + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(-1); + QVERIFY(line.textLength() > 0); + layout.endLayout(); + } + + { + QTextLayout layout; + layout.setText("Foo bar"); + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setNumColumns(2, -1); + QVERIFY(line.textLength() > 0); + layout.endLayout(); + } +} + QTEST_MAIN(tst_QTextLayout) #include "tst_qtextlayout.moc" diff --git a/tests/auto/gui/text/qtextlist/CMakeLists.txt b/tests/auto/gui/text/qtextlist/CMakeLists.txt index 2f325d5e17..5764df3e99 100644 --- a/tests/auto/gui/text/qtextlist/CMakeLists.txt +++ b/tests/auto/gui/text/qtextlist/CMakeLists.txt @@ -1,14 +1,21 @@ -# Generated from qtextlist.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtextlist Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextlist LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qtextlist SOURCES ../qtextdocument/common.h tst_qtextlist.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp b/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp index b160d41a05..28eae93f6a 100644 --- a/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp +++ b/tests/auto/gui/text/qtextlist/tst_qtextlist.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 <QTest> @@ -61,6 +36,8 @@ private slots: void blockUpdate(); void numbering_data(); void numbering(); + void start_data(); + void start(); private: QTextDocument *doc; @@ -425,5 +402,61 @@ void tst_QTextList::numbering() QCOMPARE(cursor.currentList()->itemText(cursor.block()), result); } +void tst_QTextList::start_data() +{ + QTest::addColumn<int>("format"); + QTest::addColumn<int>("start"); + QTest::addColumn<QStringList>("expectedItemTexts"); + + QTest::newRow("-1.") << int(QTextListFormat::ListDecimal) << -1 + << QStringList{ "-1.", "0.", "1." }; + QTest::newRow("0.") << int(QTextListFormat::ListDecimal) << 0 + << QStringList{ "0.", "1.", "2." }; + QTest::newRow("1.") << int(QTextListFormat::ListDecimal) << 1 + << QStringList{ "1.", "2.", "3." }; + + QTest::newRow("A. -1") << int(QTextListFormat::ListUpperAlpha) << -1 + << QStringList{ "-1.", "0.", "A." }; + QTest::newRow("A. 0.") << int(QTextListFormat::ListUpperAlpha) << 0 + << QStringList{ "0.", "A.", "B." }; + QTest::newRow("a. -1") << int(QTextListFormat::ListLowerAlpha) << -1 + << QStringList{ "-1.", "0.", "a." }; + QTest::newRow("a. 0.") << int(QTextListFormat::ListLowerAlpha) << 0 + << QStringList{ "0.", "a.", "b." }; + QTest::newRow("d. 4.") << int(QTextListFormat::ListLowerAlpha) << 4 + << QStringList{ "d.", "e.", "f." }; + + QTest::newRow("I. -1") << int(QTextListFormat::ListUpperRoman) << -1 + << QStringList{ "-1.", "0.", "I." }; + QTest::newRow("I. 0.") << int(QTextListFormat::ListUpperRoman) << 0 + << QStringList{ "0.", "I.", "II." }; + QTest::newRow("i. -1") << int(QTextListFormat::ListLowerRoman) << -1 + << QStringList{ "-1.", "0.", "i." }; + QTest::newRow("i. 0.") << int(QTextListFormat::ListLowerRoman) << 0 + << QStringList{ "0.", "i.", "ii." }; +} + +void tst_QTextList::start() +{ + QFETCH(int, format); + QFETCH(int, start); + QFETCH(QStringList, expectedItemTexts); + + QTextListFormat fmt; + fmt.setStyle(QTextListFormat::Style(format)); + fmt.setStart(start); + QTextList *list = cursor.createList(fmt); + QVERIFY(list); + + while (list->count() < int(expectedItemTexts.size())) + cursor.insertBlock(); + + QCOMPARE(list->count(), expectedItemTexts.size()); + + for (int i = 0; i < list->count(); ++i) + QCOMPARE(cursor.currentList()->itemText(cursor.currentList()->item(i)), + expectedItemTexts[i]); +} + QTEST_MAIN(tst_QTextList) #include "tst_qtextlist.moc" diff --git a/tests/auto/gui/text/qtextmarkdownimporter/BLACKLIST b/tests/auto/gui/text/qtextmarkdownimporter/BLACKLIST deleted file mode 100644 index ee09d02090..0000000000 --- a/tests/auto/gui/text/qtextmarkdownimporter/BLACKLIST +++ /dev/null @@ -1,3 +0,0 @@ -# QTBUG-89819 -[lists] -ci b2qt 32bit diff --git a/tests/auto/gui/text/qtextmarkdownimporter/CMakeLists.txt b/tests/auto/gui/text/qtextmarkdownimporter/CMakeLists.txt index cf14f38b5f..937dd5bd80 100644 --- a/tests/auto/gui/text/qtextmarkdownimporter/CMakeLists.txt +++ b/tests/auto/gui/text/qtextmarkdownimporter/CMakeLists.txt @@ -1,21 +1,26 @@ -# Generated from qtextmarkdownimporter.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtextmarkdownimporter Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextmarkdownimporter LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + # Collect test data -list(APPEND test_data "data/thematicBreaks.md") -list(APPEND test_data "data/headingBulletsContinuations.md") -list(APPEND test_data "data/fuzz20450.md") -list(APPEND test_data "data/fuzz20580.md") +file(GLOB_RECURSE test_data + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + data/* +) qt_internal_add_test(tst_qtextmarkdownimporter SOURCES tst_qtextmarkdownimporter.cpp - DEFINES - SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\" - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/paragraphs.md b/tests/auto/gui/text/qtextmarkdownimporter/data/paragraphs.md new file mode 100644 index 0000000000..3d89536376 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/data/paragraphs.md @@ -0,0 +1,9 @@ +This paragraph has enough text to auto-wrap when QTextMarkdownWriter writes it +to a markdown file. The wrapping should be around 80 columns. + +This paragrah has been broken up into shorter lines. +Each line break is created +by hitting shift-enter in QTextEdit. +But it's treated as one QTextBlock. + +This paragraph also has short lines.
Each ends with a Unicode LineSeparator.
 diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md b/tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md index 7a0d5388ad..e784879326 100644 --- a/tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md +++ b/tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md @@ -11,6 +11,7 @@ stars stars with tabs between *** stars with whitespace after + --- hyphens with whitespace after _____ diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/yaml-only.md b/tests/auto/gui/text/qtextmarkdownimporter/data/yaml-only.md new file mode 100644 index 0000000000..1eff4db37f --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/data/yaml-only.md @@ -0,0 +1,6 @@ +--- +name: "Space" +title: "Outer space" +keywords: + - astronomy +--- diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/yaml.md b/tests/auto/gui/text/qtextmarkdownimporter/data/yaml.md new file mode 100644 index 0000000000..41303a0187 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/data/yaml.md @@ -0,0 +1,11 @@ +--- +name: "Venus" +discoverer: "Galileo Galilei" +title: "A description of the planet Venus" +keywords: + - planets + - solar system + - astronomy +--- +*Venus* is the second planet from the Sun, orbiting it every 224.7 Earth days. + diff --git a/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp b/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp index 5a8df45d99..d9fe000253 100644 --- a/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp +++ b/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> #include <QBuffer> @@ -54,6 +29,7 @@ class tst_QTextMarkdownImporter : public QObject Q_OBJECT private slots: + void paragraphs(); void headingBulletsContinuations(); void thematicBreaks(); void lists_data(); @@ -62,8 +38,19 @@ private slots: void nestedSpans(); void avoidBlankLineAtBeginning_data(); void avoidBlankLineAtBeginning(); + void fragmentsAndProperties_data(); + void fragmentsAndProperties(); void pathological_data(); void pathological(); + void fencedCodeBlocks_data(); + void fencedCodeBlocks(); + void frontMatter_data(); + void frontMatter(); + void toRawText_data(); + void toRawText(); + +private: + bool isMainFontFixed(); public: enum CharFormat { @@ -75,12 +62,62 @@ public: Mono = 0x10, Link = 0x20 }; + Q_ENUM(CharFormat) Q_DECLARE_FLAGS(CharFormats, CharFormat) }; Q_DECLARE_METATYPE(tst_QTextMarkdownImporter::CharFormats) Q_DECLARE_OPERATORS_FOR_FLAGS(tst_QTextMarkdownImporter::CharFormats) +bool tst_QTextMarkdownImporter::isMainFontFixed() +{ + bool ret = QFontInfo(QGuiApplication::font()).fixedPitch(); + if (ret) { + qCWarning(lcTests) << "QFontDatabase::GeneralFont is monospaced: markdown writing is likely to use too many backticks"; + qCWarning(lcTests) << "system fonts: fixed" << QFontDatabase::systemFont(QFontDatabase::FixedFont) + << "fixed?" << QFontInfo(QFontDatabase::systemFont(QFontDatabase::FixedFont)).fixedPitch() + << "general" << QFontDatabase::systemFont(QFontDatabase::GeneralFont); + } + return ret; +} + +void tst_QTextMarkdownImporter::paragraphs() +{ + QFile f(QFINDTESTDATA("data/paragraphs.md")); + QVERIFY(f.open(QFile::ReadOnly | QIODevice::Text)); + QString md = QString::fromUtf8(f.readAll()); + f.close(); + + int lineSeparatorCount = 0; + QTextDocument doc; + QTextMarkdownImporter(&doc, QTextMarkdownImporter::DialectGitHub).import(md); + QTextFrame::iterator iterator = doc.rootFrame()->begin(); + int i = 0; + while (!iterator.atEnd()) { + QTextBlock block = iterator.currentBlock(); + int lineSeparatorPos = block.text().indexOf(QChar::LineSeparator); + qCDebug(lcTests) << i << block.text(); + while (lineSeparatorPos > 0) { + ++lineSeparatorCount; + qCDebug(lcTests) << " LineSeparator @" << lineSeparatorPos; + lineSeparatorPos = block.text().indexOf(QChar::LineSeparator, lineSeparatorPos + 1); + } + ++iterator; + ++i; + } + QCOMPARE(doc.blockCount(), 3); + QCOMPARE(lineSeparatorCount, 2); + +#ifdef DEBUG_WRITE_HTML + { + QFile out("/tmp/paragraphs.html"); + out.open(QFile::WriteOnly); + out.write(doc.toHtml().toLatin1()); + out.close(); + } +#endif +} + void tst_QTextMarkdownImporter::headingBulletsContinuations() { const QStringList expectedBlocks = QStringList() << @@ -106,7 +143,7 @@ void tst_QTextMarkdownImporter::headingBulletsContinuations() f.close(); QTextDocument doc; - QTextMarkdownImporter(QTextMarkdownImporter::DialectGitHub).import(&doc, md); + QTextMarkdownImporter(&doc, QTextMarkdownImporter::DialectGitHub).import(md); QTextFrame::iterator iterator = doc.rootFrame()->begin(); QTextFrame *currentFrame = iterator.currentFrame(); QStringList::const_iterator expectedIt = expectedBlocks.constBegin(); @@ -154,7 +191,7 @@ void tst_QTextMarkdownImporter::thematicBreaks() f.close(); QTextDocument doc; - QTextMarkdownImporter(QTextMarkdownImporter::DialectGitHub).import(&doc, md); + QTextMarkdownImporter(&doc, QTextMarkdownImporter::DialectGitHub).import(md); QTextFrame::iterator iterator = doc.rootFrame()->begin(); QTextFrame *currentFrame = iterator.currentFrame(); int i = 0; @@ -187,61 +224,123 @@ void tst_QTextMarkdownImporter::thematicBreaks() void tst_QTextMarkdownImporter::lists_data() { QTest::addColumn<QString>("input"); + QTest::addColumn<int>("skipToCheckStart"); + QTest::addColumn<int>("expectedListStart"); QTest::addColumn<int>("expectedItemCount"); QTest::addColumn<bool>("expectedEmptyItems"); QTest::addColumn<QString>("rewrite"); // Some of these cases show odd behavior, which is subject to change // as the importer and the writer are tweaked to fix bugs over time. - QTest::newRow("dot newline") << ".\n" << 0 << true << ".\n\n"; - QTest::newRow("number dot newline") << "1.\n" << 1 << true << "1. \n"; - QTest::newRow("star newline") << "*\n" << 1 << true << "* \n"; - QTest::newRow("hyphen newline") << "-\n" << 1 << true << "- \n"; - QTest::newRow("hyphen space newline") << "- \n" << 1 << true << "- \n"; - QTest::newRow("hyphen space letter newline") << "- a\n" << 1 << false << "- a\n"; + QTest::newRow("dot newline") << ".\n" << 0 << 1 << 0 << true << ".\n\n"; + QTest::newRow("number dot newline") << "1.\n" << 0 << 1 << 1 << true << "1. \n"; + QTest::newRow("number offset start") << "2. text\n" << 0 << 2 << 1 << false << "2. text\n"; + QTest::newRow("second list offset start") + << "1. text\n\nintervening paragraph\n\n4. second list item" + << 2 << 4 << 2 << false + << "1. text\n\nintervening paragraph\n\n4. second list item\n"; + QTest::newRow("list continuation offset start") + << "3. text\n\n next paragraph in item 1\n10. second list item" + << 2 << 3 << 2 << false + << "3. text\n\n next paragraph in item 1\n\n4. second list item\n"; + QTest::newRow("nested list offset start") + << "1. text\n\n 0. indented list item\n\n4. second item in first list" + << 1 << 0 << 3 << false + << "1. text\n 0. indented list item\n2. second item in first list\n"; + QTest::newRow("offset start after nested list") + << "1. text\n\n 0. indented list item\n\n4. second item in first list" + << 2 << 1 << 3 << false + << "1. text\n 0. indented list item\n2. second item in first list\n"; + QTest::newRow("star newline") << "*\n" << 0 << 1 << 1 << true << "* \n"; + QTest::newRow("hyphen newline") << "-\n" << 0 << 1 << 1 << true << "- \n"; + QTest::newRow("hyphen space newline") << "- \n" << 0 << 1 << 1 << true << "- \n"; + QTest::newRow("hyphen space letter newline") << "- a\n" << 0 << 1 << 1 << false << "- a\n"; QTest::newRow("hyphen nbsp newline") << - QString::fromUtf8("-\u00A0\n") << 0 << true << "-\u00A0\n\n"; - QTest::newRow("nested empty lists") << "*\n *\n *\n" << 1 << true << " * \n"; - QTest::newRow("list nested in empty list") << "-\n * a\n" << 2 << false << "- \n * a\n"; + QString::fromUtf8("-\u00A0\n") << 0 << 1 << 0 << true << "\\-\u00A0\n\n"; + QTest::newRow("nested empty lists") << "*\n *\n *\n" << 0 << 1 << 1 << true << " * \n"; + QTest::newRow("list nested in empty list") << "-\n * a\n" << 0 << 1 << 2 << false << "- \n * a\n"; QTest::newRow("lists nested in empty lists") - << "-\n * a\n * b\n- c\n *\n + d\n" << 5 << false + << "-\n * a\n * b\n- c\n *\n + d\n" << 0 << 1 << 5 << false << "- \n * a\n * b\n- c *\n + d\n"; QTest::newRow("numeric lists nested in empty lists") - << "- \n 1. a\n 2. b\n- c\n 1.\n + d\n" << 4 << false + << "- \n 1. a\n 2. b\n- c\n 1.\n + d\n" << 0 << 1 << 4 << false << "- \n 1. a\n 2. b\n- c 1. + d\n"; + QTest::newRow("styled spans in list items") + << "1. normal text\n2. **bold** text\n3. `code` in the item\n4. *italic* text\n5. _underlined_ text\n" + << 0 << 1 << 5 << false + << "1. normal text\n2. **bold** text\n3. `code` in the item\n4. *italic* text\n5. _underlined_ text\n"; } void tst_QTextMarkdownImporter::lists() { QFETCH(QString, input); + QFETCH(int, skipToCheckStart); + QFETCH(int, expectedListStart); QFETCH(int, expectedItemCount); QFETCH(bool, expectedEmptyItems); QFETCH(QString, rewrite); QTextDocument doc; doc.setMarkdown(input); // QTBUG-78870 : don't crash + +#ifdef DEBUG_WRITE_HTML + { + QFile out("/tmp/" + QLatin1String(QTest::currentDataTag()) + ".html"); + out.open(QFile::WriteOnly); + out.write(doc.toHtml().toLatin1()); + out.close(); + } +#endif + qCDebug(lcTests) << " original:" << input; + qCDebug(lcTests) << "rewritten:" << doc.toMarkdown(); + QTextFrame::iterator iterator = doc.rootFrame()->begin(); QTextFrame *currentFrame = iterator.currentFrame(); int i = 0; int itemCount = 0; bool emptyItems = true; + QString firstItemFontFamily; while (!iterator.atEnd()) { // There are no child frames QCOMPARE(iterator.currentFrame(), currentFrame); // Check whether the block is text or a horizontal rule QTextBlock block = iterator.currentBlock(); + QTextListFormat listFmt; if (block.textList()) { ++itemCount; if (!block.text().isEmpty()) emptyItems = false; + listFmt = block.textList()->format(); } qCDebug(lcTests, "%d %s%s", i, (block.textList() ? "<li>" : "<p>"), qPrintable(block.text())); + QTextCharFormat listItemFmt = block.charFormat(); + QFont listItemFont = listItemFmt.font(); + // QTextDocumentLayoutPrivate::drawListItem() uses listItemFont to render numbers in an ordered list. + // We want that to be consistent, regardless whether the list item's text begins with a styled span. + if (firstItemFontFamily.isEmpty()) + firstItemFontFamily = listItemFont.family(); + else + QCOMPARE(listItemFont.family(), firstItemFontFamily); + QCOMPARE(listItemFont.bold(), false); + QCOMPARE(listItemFont.italic(), false); + QCOMPARE(listItemFont.underline(), false); + QCOMPARE(listItemFont.fixedPitch(), false); + QCOMPARE(listItemFmt.fontItalic(), false); + QCOMPARE(listItemFmt.fontUnderline(), false); + QCOMPARE(listItemFmt.fontFixedPitch(), false); + if (i == skipToCheckStart) { + qCDebug(lcTests) << "skipped to list item" << i << block.text() + << "start" << listFmt.start() << "expected" << expectedListStart; + QCOMPARE(listFmt.start(), expectedListStart); + } ++iterator; ++i; } QCOMPARE(itemCount, expectedItemCount); QCOMPARE(emptyItems, expectedEmptyItems); + if (doc.toMarkdown() != rewrite && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); QCOMPARE(doc.toMarkdown(), rewrite); } @@ -333,13 +432,15 @@ void tst_QTextMarkdownImporter::nestedSpans() << "underlined" << fmt.fontUnderline() << "strikeout" << fmt.fontStrikeOut() << "anchor" << fmt.isAnchor() << "monospace" << QFontInfo(fmt.font()).fixedPitch() // depends on installed fonts (QTBUG-75649) - << fmt.fontFixedPitch() // returns false even when font family is "monospace" - << fmt.hasProperty(QTextFormat::FontFixedPitch); // works + << fmt.fontFixedPitch() + << fmt.hasProperty(QTextFormat::FontFixedPitch) + << "expected" << expectedFormat; QCOMPARE(fmt.fontWeight() > QFont::Normal, expectedFormat.testFlag(Bold)); QCOMPARE(fmt.fontItalic(), expectedFormat.testFlag(Italic)); QCOMPARE(fmt.fontUnderline(), expectedFormat.testFlag(Underlined)); QCOMPARE(fmt.fontStrikeOut(), expectedFormat.testFlag(Strikeout)); QCOMPARE(fmt.isAnchor(), expectedFormat.testFlag(Link)); + QCOMPARE(fmt.fontFixedPitch(), expectedFormat.testFlag(Mono)); QCOMPARE(fmt.hasProperty(QTextFormat::FontFixedPitch), expectedFormat.testFlag(Mono)); ++iterator; } @@ -352,7 +453,7 @@ void tst_QTextMarkdownImporter::avoidBlankLineAtBeginning_data() QTest::newRow("Text block") << QString("Markdown text") << 1; QTest::newRow("Headline") << QString("Markdown text\n============") << 1; - QTest::newRow("Code block") << QString(" Markdown text") << 2; + QTest::newRow("Code block") << QString(" Markdown text") << 1; QTest::newRow("Unordered list") << QString("* Markdown text") << 1; QTest::newRow("Ordered list") << QString("1. Markdown text") << 1; QTest::newRow("Blockquote") << QString("> Markdown text") << 1; @@ -364,7 +465,7 @@ void tst_QTextMarkdownImporter::avoidBlankLineAtBeginning() // QTBUG-81060 QFETCH(int, expectedNumberOfParagraphs); QTextDocument doc; - QTextMarkdownImporter(QTextMarkdownImporter::DialectGitHub).import(&doc, input); + QTextMarkdownImporter(&doc, QTextMarkdownImporter::DialectGitHub).import(input); QTextFrame::iterator iterator = doc.rootFrame()->begin(); int i = 0; while (!iterator.atEnd()) { @@ -378,6 +479,70 @@ void tst_QTextMarkdownImporter::avoidBlankLineAtBeginning() // QTBUG-81060 QCOMPARE(i, expectedNumberOfParagraphs); } +void tst_QTextMarkdownImporter::fragmentsAndProperties_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<int>("fragmentToCheck"); + QTest::addColumn<QString>("expectedText"); + QTest::addColumn<QTextFormat::Property>("propertyToCheck"); + QTest::addColumn<QVariant>("expectedPropertyValue"); + QTest::addColumn<int>("expectedNumberOfBlocks"); + QTest::addColumn<int>("expectedNumberOfFragments"); + + QTest::newRow("entitiesInHtmlFontBlock") // QTBUG-94245 + << QString("<font color='red'><123 test></font> test") + << 0 << "<123 test>" << QTextFormat::ForegroundBrush << QVariant(QBrush(QColor("red"))) + << 1 << 2; + QTest::newRow("entitiesInHtmlBoldBlock") // QTBUG-91222 + << QString("<b>x&lt;</b>") + << 0 << "x<" << QTextFormat::FontWeight << QVariant(700) + << 1 << 1; +} + +void tst_QTextMarkdownImporter::fragmentsAndProperties() +{ + QFETCH(QString, input); + QFETCH(int, fragmentToCheck); + QFETCH(QString, expectedText); + QFETCH(QTextFormat::Property, propertyToCheck); + QFETCH(QVariant, expectedPropertyValue); + QFETCH(int, expectedNumberOfBlocks); + QFETCH(int, expectedNumberOfFragments); + + QTextDocument doc; + QTextMarkdownImporter(&doc, QTextMarkdownImporter::DialectGitHub).import(input); +#ifdef DEBUG_WRITE_HTML + { + QFile out("/tmp/" + QLatin1String(QTest::currentDataTag()) + ".html"); + out.open(QFile::WriteOnly); + out.write(doc.toHtml().toLatin1()); + out.close(); + } +#endif + QTextFrame::iterator blockIter = doc.rootFrame()->begin(); + int blockCount = 0; + int fragCount = 0; + while (!blockIter.atEnd()) { + QTextBlock block = blockIter.currentBlock(); + auto fragIter = block.begin(); + while (!fragIter.atEnd()) { + auto frag = fragIter.fragment(); + qCDebug(lcTests) << "fragment" << fragCount << ':' << frag.text() << Qt::hex << frag.charFormat().properties(); + if (fragCount == fragmentToCheck) { + QVariant prop = frag.charFormat().property(propertyToCheck); + QCOMPARE(prop, expectedPropertyValue); + QCOMPARE(frag.text(), expectedText); + } + ++fragIter; + ++fragCount; + } + ++blockIter; + ++blockCount; + } + QCOMPARE(blockCount, expectedNumberOfBlocks); + QCOMPARE(fragCount, expectedNumberOfFragments); +} + void tst_QTextMarkdownImporter::pathological_data() { QTest::addColumn<QString>("warning"); @@ -400,5 +565,211 @@ void tst_QTextMarkdownImporter::pathological() // avoid crashing on crazy input QTextDocument().setMarkdown(f.readAll()); } +void tst_QTextMarkdownImporter::fencedCodeBlocks_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<int>("expectedCodeBlockCount"); + QTest::addColumn<int>("expectedPlainBlockCount"); + QTest::addColumn<QString>("expectedLanguage"); + QTest::addColumn<QString>("expectedFenceChar"); + QTest::addColumn<QString>("rewrite"); + + QTest::newRow("backtick fence with language") + << "```pseudocode\nprint('hello world\\n')\n```\n" + << 1 << 0 << "pseudocode" << "`" + << "```pseudocode\nprint('hello world\\n')\n```\n\n"; + QTest::newRow("backtick fence with punctuated language") + << "```html+js\n<html><head><script>function hi() { console.log('\\\"hello world') }</script></head>blah</html>\n```\n" + << 1 << 0 << "html+js" << "`" + << "```html+js\n<html><head><script>function hi() { console.log('\\\"hello world') }</script></head>blah</html>\n```\n\n"; + QTest::newRow("tilde fence with language") + << "~~~pseudocode\nprint('hello world\\n')\n~~~\n" + << 1 << 0 << "pseudocode" << "~" + << "~~~pseudocode\nprint('hello world\\n')\n~~~\n\n"; + QTest::newRow("embedded backticks") + << "```\nnone `one` ``two``\n```\nplain\n```\n```three``` ````four````\n```\nplain\n" + << 2 << 2 << QString() << "`" + << "```\nnone `one` ``two``\n```\nplain\n\n```\n```three``` ````four````\n```\nplain\n\n"; +} + +void tst_QTextMarkdownImporter::fencedCodeBlocks() +{ + QFETCH(QString, input); + QFETCH(int, expectedCodeBlockCount); + QFETCH(int, expectedPlainBlockCount); + QFETCH(QString, expectedLanguage); + QFETCH(QString, expectedFenceChar); + QFETCH(QString, rewrite); + + QTextDocument doc; + doc.setMarkdown(input); + +#ifdef DEBUG_WRITE_HTML + { + QFile out("/tmp/" + QLatin1String(QTest::currentDataTag()) + ".html"); + out.open(QFile::WriteOnly); + out.write(doc.toHtml().toLatin1()); + out.close(); + } +#endif + + QTextFrame::iterator iterator = doc.rootFrame()->begin(); + QTextFrame *currentFrame = iterator.currentFrame(); + int codeBlockCount = 0; + int plainBlockCount = 0; + while (!iterator.atEnd()) { + // There are no child frames + QCOMPARE(iterator.currentFrame(), currentFrame); + // Check whether the block is code or plain + QTextBlock block = iterator.currentBlock(); + const bool codeBlock = block.blockFormat().hasProperty(QTextFormat::BlockCodeFence); + QCOMPARE(block.blockFormat().nonBreakableLines(), codeBlock); + QCOMPARE(block.blockFormat().stringProperty(QTextFormat::BlockCodeLanguage), codeBlock ? expectedLanguage : QString()); + if (codeBlock) { + QCOMPARE(block.blockFormat().stringProperty(QTextFormat::BlockCodeFence), expectedFenceChar); + ++codeBlockCount; + } else { + ++plainBlockCount; + } + qCDebug(lcTests) << (codeBlock ? "code" : "text") << block.text() << block.charFormat().fontFamilies(); + ++iterator; + } + QCOMPARE(codeBlockCount, expectedCodeBlockCount); + QCOMPARE(plainBlockCount, expectedPlainBlockCount); + if (doc.toMarkdown() != rewrite && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(doc.toMarkdown(), rewrite); +} + +void tst_QTextMarkdownImporter::frontMatter_data() +{ + QTest::addColumn<QString>("inputFile"); + QTest::addColumn<int>("expectedBlockCount"); + + QTest::newRow("yaml + markdown") << QFINDTESTDATA("data/yaml.md") << 1; + QTest::newRow("yaml only") << QFINDTESTDATA("data/yaml-only.md") << 0; +} + +void tst_QTextMarkdownImporter::frontMatter() +{ + QFETCH(QString, inputFile); + QFETCH(int, expectedBlockCount); + + QFile f(inputFile); + QVERIFY(f.open(QFile::ReadOnly | QIODevice::Text)); + QString md = QString::fromUtf8(f.readAll()); + f.close(); + const int yamlBegin = md.indexOf("name:"); + const int yamlEnd = md.indexOf("---", yamlBegin); + const QString yaml = md.sliced(yamlBegin, yamlEnd - yamlBegin); + + QTextDocument doc; + QTextMarkdownImporter(&doc, QTextMarkdownImporter::DialectGitHub).import(md); + int blockCount = 0; + for (QTextFrame::iterator iterator = doc.rootFrame()->begin(); !iterator.atEnd(); ++iterator) { + // Check whether the block is text or a horizontal rule + if (!iterator.currentBlock().text().isEmpty()) + ++blockCount; + } + QCOMPARE(blockCount, expectedBlockCount); // yaml is not part of the markdown text + QCOMPARE(doc.metaInformation(QTextDocument::FrontMatter), yaml); // without fences +} + +void tst_QTextMarkdownImporter::toRawText_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("expectedRawText"); + + // tests to verify that fixing QTBUG-122083 is safe + // https://spec.commonmark.org/0.31.2/#example-12 + QTest::newRow("punctuation backslash escapes") << + R"(\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~)" << + R"(!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~)"; + // https://spec.commonmark.org/0.31.2/#example-13 + QTest::newRow("literal backslashes") << + QString(uR"(\→\A\a\ \3\φ\«)") << + QString(uR"(\→\A\a\ \3\φ\«)"); + // https://spec.commonmark.org/0.31.2/#example-14 + QTest::newRow("escape to avoid em") << + R"(\*not emphasized*)" << + R"(*not emphasized*)"; + QTest::newRow("escape to avoid html") << + R"(\<br/> not a tag)" << + R"(<br/> not a tag)"; + QTest::newRow("escape to avoid link") << + R"(\[not a link](/foo))" << + R"([not a link](/foo))"; + QTest::newRow("escape to avoid mono") << + R"(\`not code`)" << + R"(`not code`)"; + QTest::newRow("escape to avoid num list") << + R"(1\. not a list)" << + R"(1. not a list)"; + QTest::newRow("escape to avoid list") << + R"(\* not a list)" << + R"(* not a list)"; + QTest::newRow("escape to avoid heading") << + R"(\# not a heading)" << + R"(# not a heading)"; + QTest::newRow("escape to avoid reflink") << + R"(\[foo]: /url "not a reference")" << + R"([foo]: /url "not a reference")"; + QTest::newRow("escape to avoid entity") << + R"(\ö not a character entity)" << + R"(ö not a character entity)"; + // https://spec.commonmark.org/0.31.2/#example-15 + QTest::newRow("escape backslash only") << + R"(\\*emphasis*)" << + R"(\emphasis)"; + // https://spec.commonmark.org/0.31.2/#example-16 + QTest::newRow("backslash line break") << + "foo\\\nbar" << + "foo\u2029bar"; + // https://spec.commonmark.org/0.31.2/#example-17 + QTest::newRow("backslash in mono span") << + R"(`` \[\` ``)" << + R"(\[\`)"; + // https://spec.commonmark.org/0.31.2/#example-18 + QTest::newRow("backslash in indented code") << + R"( \[\])" << + R"(\[\])"; + // https://spec.commonmark.org/0.31.2/#example-19 + QTest::newRow("backslash in fenced code") << + "~~~\n\\[\\]\n~~~" << + R"(\[\])"; + // https://spec.commonmark.org/0.31.2/#example-20 + QTest::newRow("backslash in autolink") << + R"(<https://example.com?find=\*>)" << + R"(https://example.com?find=\*)"; + // https://spec.commonmark.org/0.31.2/#example-21 + QTest::newRow("backslash in autolink") << + "<a href=\"/bar\\/)\"" << + "<a href=\"/bar/)\""; + // https://spec.commonmark.org/0.31.2/#example-22 + QTest::newRow("escapes in link") << + R"([foo](/bar\* "ti\*tle"))" << + R"(foo)"; + // https://spec.commonmark.org/0.31.2/#example-24 + QTest::newRow("backslash in code lang") << + "```\nfoo\\+bar\nfoo\n```" << + "foo\\+bar\u2029foo"; + // end of tests to verify that fixing QTBUG-122083 is safe + // (it's ok to add unrelated markdown-to-rawtext cases later) +} + +void tst_QTextMarkdownImporter::toRawText() +{ + QFETCH(QString, input); + QFETCH(QString, expectedRawText); + + QTextDocument doc; + doc.setMarkdown(input); + + // These are testing md4c more than Qt, so any change may be an md4c bug, or a fix + QCOMPARE(doc.toRawText(), expectedRawText); + if (doc.blockCount() == 1) + QCOMPARE(doc.firstBlock().text(), expectedRawText); +} + QTEST_MAIN(tst_QTextMarkdownImporter) #include "tst_qtextmarkdownimporter.moc" diff --git a/tests/auto/gui/text/qtextmarkdownwriter/BLACKLIST b/tests/auto/gui/text/qtextmarkdownwriter/BLACKLIST deleted file mode 100644 index 12cb21f40a..0000000000 --- a/tests/auto/gui/text/qtextmarkdownwriter/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -# QTBUG-89819 -ci b2qt 32bit diff --git a/tests/auto/gui/text/qtextmarkdownwriter/CMakeLists.txt b/tests/auto/gui/text/qtextmarkdownwriter/CMakeLists.txt index d8815c64f6..0cdf1d9225 100644 --- a/tests/auto/gui/text/qtextmarkdownwriter/CMakeLists.txt +++ b/tests/auto/gui/text/qtextmarkdownwriter/CMakeLists.txt @@ -1,19 +1,26 @@ -# Generated from qtextmarkdownwriter.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtextmarkdownwriter Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextmarkdownwriter LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + # Collect test data -list(APPEND test_data "data/example.md") -list(APPEND test_data "data/blockquotes.md") +file(GLOB_RECURSE test_data + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + data/* +) qt_internal_add_test(tst_qtextmarkdownwriter SOURCES tst_qtextmarkdownwriter.cpp - DEFINES - SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\" - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md index 702ccef134..8e605ef7e6 100644 --- a/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md @@ -8,18 +8,17 @@ MacFarlane writes: > What distinguishes Markdown from many other lightweight markup syntaxes, > which are often easier to write, is its readability. As Gruber writes: - +> > > The overriding design goal for Markdown's formatting syntax is to make it > > as readable as possible. The idea is that a Markdown-formatted document should > > be publishable as-is, as plain text, without looking like it's been marked up > > with tags or formatting instructions. ( -> > [http://daringfireball.net/projects/markdown/](http://daringfireball.net/projects/markdown/) -> > ) - +> > <http://daringfireball.net/projects/markdown/> ) +> > The point can be illustrated by comparing a sample of AsciiDoc with an > equivalent sample of Markdown. Here is a sample of AsciiDoc from the AsciiDoc > manual: - +> > ```AsciiDoc > 1. List item one. > + @@ -50,6 +49,7 @@ Now let's have an indented code block: } and end with a fenced code block: + ~~~pseudocode #include <something.h> #include <else.h> diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotesWithLists.md b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotesWithLists.md new file mode 100644 index 0000000000..1728889adc --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotesWithLists.md @@ -0,0 +1,14 @@ +What if we have a quotation containing a list? + +> First some quoted text, and then a list: +> +> - one +> - two is longer and has enough words to form a paragraph with text continuing +> onto the next line +> +> enough of that, let's try a numbered list +> +> 1. List item one +> 2. List item two is longer and has enough words to form a paragraph with +> text continuing onto the next line. +>
\ No newline at end of file diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/example.md b/tests/auto/gui/text/qtextmarkdownwriter/data/example.md index a9a157f25a..15b30598e6 100644 --- a/tests/auto/gui/text/qtextmarkdownwriter/data/example.md +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/example.md @@ -83,7 +83,7 @@ is used extensively in [Qt Assistant](http://doc.qt.io/qt-5/qtassistant-index.html). Hyperlinks are automatically created when an HTML file is imported into an editor. Since the rich text framework supports hyperlinks natively, they can also be created -programatically. +programmatically. ## Undo and Redo diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/links.md b/tests/auto/gui/text/qtextmarkdownwriter/data/links.md index 33cdb2b3ab..c9aae80c67 100644 --- a/tests/auto/gui/text/qtextmarkdownwriter/data/links.md +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/links.md @@ -23,3 +23,6 @@ title") * [link](/url "title title title") * nonlink + +Qt has the <https://qt.io> site + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/listItemWithBlockquote.md b/tests/auto/gui/text/qtextmarkdownwriter/data/listItemWithBlockquote.md new file mode 100644 index 0000000000..c417125fea --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/listItemWithBlockquote.md @@ -0,0 +1,6 @@ +What if we have a list item containing a block quote? + +- one +- > two is longer and has enough words to form a paragraph with text continuing + > onto the next line + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/listsAndCodeBlocks.md b/tests/auto/gui/text/qtextmarkdownwriter/data/listsAndCodeBlocks.md index 54e3f25afa..b3539167ab 100644 --- a/tests/auto/gui/text/qtextmarkdownwriter/data/listsAndCodeBlocks.md +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/listsAndCodeBlocks.md @@ -22,3 +22,10 @@ - still didn't fix it, expecting a breakthrough any day now - some sort of miracle - profit! +- Alternatively we can have a non-indented fenced code block under a list item: + +```qml +import QtQuick +Text { text: "hello world" } +``` +- but that means the code block is not part of the list item. diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/longHeadings.md b/tests/auto/gui/text/qtextmarkdownwriter/data/longHeadings.md new file mode 100644 index 0000000000..72692b4845 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/longHeadings.md @@ -0,0 +1,9 @@ +# The quick brown fox jumped over the lazy dog while the cat played the fiddle and the cow jumped over the moon + +Hey diddle diddle + +## This document has a verbose subheading too, which we do not expect to wrap in the output + +Qt can write it right. Long text here in this paragraph will actually wrap, +even though its heading doesn't. + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/yaml.md b/tests/auto/gui/text/qtextmarkdownwriter/data/yaml.md new file mode 100644 index 0000000000..41303a0187 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/yaml.md @@ -0,0 +1,11 @@ +--- +name: "Venus" +discoverer: "Galileo Galilei" +title: "A description of the planet Venus" +keywords: + - planets + - solar system + - astronomy +--- +*Venus* is the second planet from the Sun, orbiting it every 224.7 Earth days. + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp index bc6ee81ad4..0d261bc27e 100644 --- a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp +++ b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> #include <QTextDocument> @@ -34,9 +9,13 @@ #include <QTextTable> #include <QBuffer> #include <QDebug> +#include <QFontInfo> +#include <QLoggingCategory> #include <private/qtextmarkdownwriter_p.h> +Q_LOGGING_CATEGORY(lcTests, "qt.text.tests") + // #define DEBUG_WRITE_OUTPUT class tst_QTextMarkdownWriter : public QObject @@ -51,20 +30,35 @@ private slots: void testWriteParagraph(); void testWriteList(); void testWriteEmptyList(); + void testWriteCheckboxListItemEndingWithCode(); void testWriteNestedBulletLists_data(); void testWriteNestedBulletLists(); void testWriteNestedNumericLists(); + void testWriteNumericListWithStart(); void testWriteTable(); + void frontMatter(); + void charFormatWrapping_data(); + void charFormatWrapping(); + void charFormat_data(); + void charFormat(); void rewriteDocument_data(); void rewriteDocument(); void fromHtml_data(); void fromHtml(); + void fromPlainTextAndBack_data(); + void fromPlainTextAndBack(); + void escapeSpecialCharacters_data(); + void escapeSpecialCharacters(); private: + bool isMainFontFixed(); + bool isFixedFontProportional(); QString documentToUnixMarkdown(); private: QTextDocument *document; + QFont m_monoFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); + QFont m_defaultFont; }; void tst_QTextMarkdownWriter::init() @@ -77,10 +71,39 @@ void tst_QTextMarkdownWriter::cleanup() delete document; } +bool tst_QTextMarkdownWriter::isMainFontFixed() +{ + bool ret = QFontInfo(QGuiApplication::font()).fixedPitch(); + if (ret) { + qCWarning(lcTests) << "QFontDatabase::GeneralFont is monospaced: markdown writing is likely to use too many backticks" + << QFontDatabase::systemFont(QFontDatabase::GeneralFont); + } + return ret; +} + +bool tst_QTextMarkdownWriter::isFixedFontProportional() +{ + bool ret = !QFontInfo(QFontDatabase::systemFont(QFontDatabase::FixedFont)).fixedPitch(); + if (ret) { + qCWarning(lcTests) << "QFontDatabase::FixedFont is NOT monospaced: markdown writing is likely to use too few backticks" + << QFontDatabase::systemFont(QFontDatabase::FixedFont); + } + return ret; +} + +QString tst_QTextMarkdownWriter::documentToUnixMarkdown() +{ + QString ret; + QTextStream ts(&ret, QIODevice::WriteOnly); + QTextMarkdownWriter writer(ts, QTextDocument::MarkdownDialectGitHub); + writer.writeAll(document); + return ret; +} + void tst_QTextMarkdownWriter::testWriteParagraph_data() { QTest::addColumn<QString>("input"); - QTest::addColumn<QString>("output"); + QTest::addColumn<QString>("expectedOutput"); QTest::newRow("empty") << "" << ""; @@ -103,12 +126,15 @@ void tst_QTextMarkdownWriter::testWriteParagraph_data() void tst_QTextMarkdownWriter::testWriteParagraph() { QFETCH(QString, input); - QFETCH(QString, output); + QFETCH(QString, expectedOutput); QTextCursor cursor(document); cursor.insertText(input); - QCOMPARE(documentToUnixMarkdown(), output); + const QString output = documentToUnixMarkdown(); + if (output != expectedOutput && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(output, expectedOutput); } void tst_QTextMarkdownWriter::testWriteList() @@ -121,8 +147,11 @@ void tst_QTextMarkdownWriter::testWriteList() cursor.insertText("ListItem 2"); list->add(cursor.block()); - QCOMPARE(documentToUnixMarkdown(), QString::fromLatin1( - "- ListItem 1\n- ListItem 2\n")); + const QString output = documentToUnixMarkdown(); + const QString expected = QString::fromLatin1("- ListItem 1\n- ListItem 2\n"); + if (output != expected && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(output, expected); } void tst_QTextMarkdownWriter::testWriteEmptyList() @@ -133,6 +162,38 @@ void tst_QTextMarkdownWriter::testWriteEmptyList() QCOMPARE(documentToUnixMarkdown(), QString::fromLatin1("- \n")); } +void tst_QTextMarkdownWriter::testWriteCheckboxListItemEndingWithCode() +{ + QTextCursor cursor(document); + QTextList *list = cursor.createList(QTextListFormat::ListDisc); + cursor.insertText("Image.originalSize property (not necessary; PdfDocument.pagePointSize() substitutes)"); + list->add(cursor.block()); + { + auto fmt = cursor.block().blockFormat(); + fmt.setMarker(QTextBlockFormat::MarkerType::Unchecked); + cursor.setBlockFormat(fmt); + } + cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 2); + cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor, 4); + QCOMPARE(cursor.selectedText(), QString::fromLatin1("PdfDocument.pagePointSize()")); + auto fmt = cursor.charFormat(); + fmt.setFontFixedPitch(true); + cursor.setCharFormat(fmt); + cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 5); + cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor); + cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor, 4); + QCOMPARE(cursor.selectedText(), QString::fromLatin1("Image.originalSize")); + cursor.setCharFormat(fmt); + + const QString output = documentToUnixMarkdown(); + const QString expected = QString::fromLatin1( + "- [ ] `Image.originalSize` property (not necessary; `PdfDocument.pagePointSize()`\n substitutes)\n"); + if (output != expected && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(output, expected); +} + void tst_QTextMarkdownWriter::testWriteNestedBulletLists_data() { QTest::addColumn<bool>("checkbox"); @@ -212,7 +273,7 @@ void tst_QTextMarkdownWriter::testWriteNestedBulletLists() cursor.insertText("continuation"); } - QString output = documentToUnixMarkdown(); + const QString output = documentToUnixMarkdown(); #ifdef DEBUG_WRITE_OUTPUT { QFile out("/tmp/" + QLatin1String(QTest::currentDataTag()) + ".md"); @@ -221,7 +282,9 @@ void tst_QTextMarkdownWriter::testWriteNestedBulletLists() out.close(); } #endif - QCOMPARE(documentToUnixMarkdown(), expectedOutput); + if (output != expectedOutput && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(output, expectedOutput); } void tst_QTextMarkdownWriter::testWriteNestedNumericLists() @@ -233,6 +296,7 @@ void tst_QTextMarkdownWriter::testWriteNestedNumericLists() list1->add(cursor.block()); QTextListFormat fmt2; + // Alpha "numbering" is not supported in markdown, so we'll actually get decimal. fmt2.setStyle(QTextListFormat::ListLowerAlpha); fmt2.setNumberSuffix(QLatin1String(")")); fmt2.setIndent(2); @@ -253,9 +317,116 @@ void tst_QTextMarkdownWriter::testWriteNestedNumericLists() cursor.insertText("ListItem 5"); list2->add(cursor.block()); - // There's no QTextList API to set the starting number so we hard-coded all lists to start at 1 (QTBUG-65384) - QCOMPARE(documentToUnixMarkdown(), QString::fromLatin1( - "1. ListItem 1\n 1) ListItem 2\n 1. ListItem 3\n2. ListItem 4\n 2) ListItem 5\n")); + const QString output = documentToUnixMarkdown(); + + #ifdef DEBUG_WRITE_OUTPUT + { + QFile out(QDir::temp().filePath(QLatin1String(QTest::currentTestFunction()) + ".md")); + out.open(QFile::WriteOnly); + out.write(output.toUtf8()); + out.close(); + } + { + QFile out(QDir::temp().filePath(QLatin1String(QTest::currentTestFunction()) + ".html")); + out.open(QFile::WriteOnly); + out.write(document->toHtml().toUtf8()); + out.close(); + } +#endif + + // While we can set the start index for a block, if list items intersect each other, they will + // still use the list numbering. + const QString expected = QString::fromLatin1( + "1. ListItem 1\n 1) ListItem 2\n 1. ListItem 3\n2. ListItem 4\n 2) ListItem 5\n"); + if (output != expected && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(output, expected); +} + +void tst_QTextMarkdownWriter::testWriteNumericListWithStart() +{ + QTextCursor cursor(document); + + // The first list will start at 2. + QTextListFormat fmt1; + fmt1.setStyle(QTextListFormat::ListDecimal); + fmt1.setStart(2); + QTextList *list1 = cursor.createList(fmt1); + cursor.insertText("ListItem 1"); + list1->add(cursor.block()); + + // This list uses the default start (1) again. + QTextListFormat fmt2; + // Alpha "numbering" is not supported in markdown, so we'll actually get decimal. + fmt2.setStyle(QTextListFormat::ListLowerAlpha); + fmt2.setNumberSuffix(QLatin1String(")")); + fmt2.setIndent(2); + QTextList *list2 = cursor.insertList(fmt2); + cursor.insertText("ListItem 2"); + + // Negative list numbers are disallowed by most Markdown implementations. This list will start + // at 1 for that reason. + QTextListFormat fmt3; + fmt3.setStyle(QTextListFormat::ListDecimal); + fmt3.setIndent(3); + fmt3.setStart(-1); + cursor.insertList(fmt3); + cursor.insertText("ListItem 3"); + + // Continuing list1, so the second item will have the number 3. + cursor.insertBlock(); + cursor.insertText("ListItem 4"); + list1->add(cursor.block()); + + // This will look out of place: it's in a different position than its list would suggest. + // Generates invalid markdown numbering (OK for humans, but md4c will parse it differently than we "meant"). + // TODO QTBUG-111707: the writer needs to add newlines, otherwise ListItem 5 becomes part of the text for ListItem 4. + cursor.insertBlock(); + cursor.insertText("ListItem 5"); + list2->add(cursor.block()); + + // 0 indexed lists are fine. + QTextListFormat fmt4; + fmt4.setStyle(QTextListFormat::ListDecimal); + fmt4.setStart(0); + QTextList *list4 = cursor.insertList(fmt4); + cursor.insertText("SecondList Item 0"); + list4->add(cursor.block()); + + // Ensure list numbers are incremented properly. + cursor.insertBlock(); + cursor.insertText("SecondList Item 1"); + list4->add(cursor.block()); + + const QString output = documentToUnixMarkdown(); + const QString expected = QString::fromLatin1( + R"(2. ListItem 1 + 1) ListItem 2 + 1. ListItem 3 +3. ListItem 4 + 2) ListItem 5 +0. SecondList Item 0 +1. SecondList Item 1 +)"); + +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out(QDir::temp().filePath(QLatin1String(QTest::currentTestFunction()) + ".md")); + out.open(QFile::WriteOnly); + out.write(output.toUtf8()); + out.close(); + } + { + QFile out(QDir::temp().filePath(QLatin1String(QTest::currentTestFunction()) + ".html")); + out.open(QFile::WriteOnly); + out.write(document->toHtml().toUtf8()); + out.close(); + } +#endif + + if (output != expected && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(output, expected); } void tst_QTextMarkdownWriter::testWriteTable() @@ -308,6 +479,8 @@ void tst_QTextMarkdownWriter::testWriteTable() QString expected = QString::fromLatin1( "\n|one |two |three|\n|------|----|-----|\n|alice |bob |carl |\n|dennis|eric|fiona|\n|gina | | |\n\n"); + if (md != expected && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); QCOMPARE(md, expected); // create table with merged cells @@ -357,7 +530,221 @@ void tst_QTextMarkdownWriter::testWriteTable() } #endif - QCOMPARE(md, QString::fromLatin1("\n|a ||b|\n|-|-|-|\n|c|d ||\n|e|f| |\n\n")); + expected = QString::fromLatin1("\n|a ||b|\n|-|-|-|\n|c|d ||\n|e|f| |\n\n"); + if (md != expected && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(md, expected); +} + +void tst_QTextMarkdownWriter::frontMatter() +{ + QTextCursor cursor(document); + cursor.insertText("bar"); + document->setMetaInformation(QTextDocument::FrontMatter, "foo"); + + const QString output = documentToUnixMarkdown(); + const QString expectedOutput("---\nfoo\n---\nbar\n\n"); + if (output != expectedOutput && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); + QCOMPARE(output, expectedOutput); +} + +void tst_QTextMarkdownWriter::charFormatWrapping_data() +{ + QTest::addColumn<QTextFormat::Property>("property"); + QTest::addColumn<QVariant>("propertyValue"); + QTest::addColumn<QString>("followingText"); + QTest::addColumn<QString>("expectedIndicator"); + + const QString spaced = " after"; + const QString unspaced = ", and some more after"; + + QTest::newRow("FontFixedPitch-spaced") + << QTextFormat::FontFixedPitch << QVariant(true) << spaced << "`"; + QTest::newRow("FontFixedPitch-unspaced") + << QTextFormat::FontFixedPitch << QVariant(true) << unspaced << "`"; + QTest::newRow("FontItalic") + << QTextFormat::FontItalic << QVariant(true) << spaced << "*"; + QTest::newRow("FontUnderline") + << QTextFormat::FontUnderline << QVariant(true) << spaced << "_"; + QTest::newRow("FontStrikeOut") + << QTextFormat::FontStrikeOut << QVariant(true) << spaced << "~~"; + QTest::newRow("FontWeight-spaced") + << QTextFormat::FontWeight << QVariant(700) << spaced << "**"; + QTest::newRow("FontWeight-unspaced") + << QTextFormat::FontWeight << QVariant(700) << unspaced << "**"; +} + +void tst_QTextMarkdownWriter::charFormatWrapping() // QTBUG-116927 +{ + QFETCH(QTextFormat::Property, property); + QFETCH(QVariant, propertyValue); + QFETCH(QString, expectedIndicator); + QFETCH(QString, followingText); + + const QString newLine("\n"); + QTextCursor cursor(document); + cursor.insertText("around sixty-four characters to go before some formatted words "); + QTextCharFormat fmt; + fmt.setProperty(property, propertyValue); + cursor.setCharFormat(fmt); + cursor.insertText("formatted text"); + + cursor.setCharFormat({}); + cursor.insertText(followingText); + qsizetype lastNewLineIndex = 100; + + for (int push = 0; push < 10; ++push) { + if (push > 0) { + cursor.movePosition(QTextCursor::StartOfBlock); + cursor.insertText("a"); + } + + const QString output = documentToUnixMarkdown().trimmed(); // get rid of trailing newlines + const auto nlIdx = output.indexOf(newLine); + qCDebug(lcTests) << "push" << push << ":" << output << "newline @" << nlIdx; + // we're always wrapping in this test: expect to find a newline + QCOMPARE_GT(nlIdx, 70); + // don't expect the newline to be more than one character to the right of where we found it last time + // i.e. if we already started breaking in the middle: "`formatted\ntext`", + // then we would not expect that prepending one more character would make it go + // back to breaking afterwards: "`formatted text`\n" (because then the line becomes longer than necessary) + QCOMPARE_LE(nlIdx, lastNewLineIndex + 1); + lastNewLineIndex = nlIdx; + const QString nextChars = output.sliced(nlIdx + newLine.size(), expectedIndicator.size()); + const auto startingIndicatorIdx = output.indexOf(expectedIndicator); + // the starting indicator always exists, except in case of font problems on some CI platforms + if (startingIndicatorIdx <= 0) + QSKIP("starting indicator not found, probably due to platform font problems (QTBUG-103484 etc.)"); + const auto endingIndicatorIdx = output.indexOf(expectedIndicator, startingIndicatorIdx + 5); + qCDebug(lcTests) << "next chars past newline" << nextChars + << "indicators @" << startingIndicatorIdx << endingIndicatorIdx; + // the closing indicator must exist + QCOMPARE_GT(endingIndicatorIdx, startingIndicatorIdx); + // don't start a new line with an ending indicator: + // we can have "**formatted\ntext**" or "**formatted text**\n" or "\n**formatted text**" + // but not "**formatted text\n**" + if (startingIndicatorIdx < nlIdx) + QCOMPARE_NE(nextChars, expectedIndicator); + } +} + +void tst_QTextMarkdownWriter::charFormat_data() +{ + QTest::addColumn<QTextFormat::Property>("property"); + QTest::addColumn<QVariant>("propertyValue"); + QTest::addColumn<QFont>("explicitFont"); + QTest::addColumn<QString>("expectedOutput"); + + const QTextFormat::Property NoProperty = QTextFormat::ObjectIndex; + + QTest::newRow("FontFixedPitch") + << QTextFormat::FontFixedPitch << QVariant(true) << m_defaultFont + << "before `formatted` after"; + if (!isFixedFontProportional()) { + // QTBUG-54623 QTBUG-75649 QTBUG-79900 QTBUG-103484 etc. + QTest::newRow("mono font") << NoProperty << QVariant() << m_monoFont + << "before `formatted` after"; + } + + { + QFont font; + font.setItalic(true); + QTest::newRow("italic font") + << NoProperty << QVariant() << font + << "before *formatted* after"; + } + QTest::newRow("FontItalic") + << QTextFormat::FontItalic << QVariant(true) << m_defaultFont + << "before *formatted* after"; + + { + QFont font; + font.setUnderline(true); + QTest::newRow("underline font") + << NoProperty << QVariant() << font + << "before _formatted_ after"; + } + QTest::newRow("FontUnderline") + << QTextFormat::FontUnderline << QVariant(true) << m_defaultFont + << "before _formatted_ after"; + + { + QFont font; + font.setStrikeOut(true); + QTest::newRow("strikeout font") + << NoProperty << QVariant() << font + << "before ~~formatted~~ after"; + } + QTest::newRow("FontStrikeOut") + << QTextFormat::FontStrikeOut << QVariant(true) << m_defaultFont + << "before ~~formatted~~ after"; + + { + QFont font; + font.setBold(true); + QTest::newRow("bold font") + << NoProperty << QVariant() << font + << "before **formatted** after"; + } + { + QFont font; + font.setWeight(QFont::Black); + QTest::newRow("black font") + << NoProperty << QVariant() << font + << "before **formatted** after"; + } + QTest::newRow("FontWeight") + << QTextFormat::FontWeight << QVariant(700) << m_defaultFont + << "before **formatted** after"; + + QTest::newRow("AnchorHref") + << QTextFormat::AnchorHref << QVariant("linky linky") << m_defaultFont + << "before [formatted](linky linky) after"; + + QTest::newRow("TextToolTip") // no effect without AnchorHref + << QTextFormat::TextToolTip << QVariant("such a tool") << m_defaultFont + << "before formatted after"; +} + +void tst_QTextMarkdownWriter::charFormat() +{ + if (isMainFontFixed()) + QSKIP("QTextMarkdownWriter would generate bogus backticks"); + + QFETCH(QTextFormat::Property, property); + QFETCH(QVariant, propertyValue); + QFETCH(QFont, explicitFont); + QFETCH(QString, expectedOutput); + + QTextCursor cursor(document); + cursor.insertText("before "); + + QTextCharFormat fmt; + if (explicitFont != m_defaultFont) + fmt.setFont(explicitFont); + if (property != QTextFormat::ObjectIndex) // != 0 + fmt.setProperty(property, propertyValue); + if (explicitFont == m_monoFont) { + QFontInfo fontInfo(fmt.font()); + qCDebug(lcTests) << "mono font" << explicitFont << "fontInfo fixedPitch" << fontInfo.fixedPitch() << "fmt fixedPitch" << fmt.fontFixedPitch(); + } + cursor.setCharFormat(fmt); + cursor.insertText("formatted"); + + cursor.setCharFormat({}); + cursor.insertText(" after"); + + const QString output = documentToUnixMarkdown(); +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out(QDir::temp().filePath(QLatin1String(QTest::currentDataTag()) + ".md")); + out.open(QFile::WriteOnly); + out.write(output.toUtf8()); + out.close(); + } +#endif + QCOMPARE(output.trimmed(), expectedOutput); } void tst_QTextMarkdownWriter::rewriteDocument_data() @@ -365,11 +752,15 @@ void tst_QTextMarkdownWriter::rewriteDocument_data() QTest::addColumn<QString>("inputFile"); QTest::newRow("block quotes") << "blockquotes.md"; + QTest::newRow("block quotes with lists") << "blockquotesWithLists.md"; + // QTest::newRow("list item with block quote") << "listItemWithBlockquote.md"; // not supported for now QTest::newRow("example") << "example.md"; QTest::newRow("list items after headings") << "headingsAndLists.md"; QTest::newRow("word wrap") << "wordWrap.md"; QTest::newRow("links") << "links.md"; QTest::newRow("lists and code blocks") << "listsAndCodeBlocks.md"; + QTest::newRow("front matter") << "yaml.md"; + QTest::newRow("long headings") << "longHeadings.md"; } void tst_QTextMarkdownWriter::rewriteDocument() @@ -390,17 +781,19 @@ void tst_QTextMarkdownWriter::rewriteDocument() out.close(); #endif + if (md != orig && isMainFontFixed()) + QEXPECT_FAIL("", "fixed-pitch main font (QTBUG-103484)", Continue); QCOMPARE(md, orig); } void tst_QTextMarkdownWriter::fromHtml_data() { - QTest::addColumn<QString>("expectedInput"); + QTest::addColumn<QString>("input"); QTest::addColumn<QString>("expectedOutput"); QTest::newRow("long URL") << "<span style=\"font-style:italic;\">https://www.example.com/dir/subdir/subsubdir/subsubsubdir/subsubsubsubdir/subsubsubsubsubdir/</span>" << - "*https://www.example.com/dir/subdir/subsubdir/subsubsubdir/subsubsubsubdir/subsubsubsubsubdir/*\n\n"; + "\n*https://www.example.com/dir/subdir/subsubdir/subsubsubdir/subsubsubsubdir/subsubsubsubsubdir/*\n\n"; QTest::newRow("non-emphasis inline asterisk") << "3 * 4" << "3 * 4\n\n"; QTest::newRow("arithmetic") << "(2 * a * x + b)^2 = b^2 - 4 * a * c" << "(2 * a * x + b)^2 = b^2 - 4 * a * c\n\n"; QTest::newRow("escaped asterisk after newline") << @@ -432,22 +825,51 @@ void tst_QTextMarkdownWriter::fromHtml_data() "![foo](/url \"title\")\n\n"; QTest::newRow("code") << "<pre class=\"language-pseudocode\">\n#include \"foo.h\"\n\nblock {\n statement();\n}\n\n</pre>" << - "```pseudocode\n#include \"foo.h\"\n\nblock {\n statement();\n}\n```\n\n"; - // TODO -// QTest::newRow("escaped number and paren after double newline") << -// "<p>(The first sentence of this paragraph is a line, the next paragraph has a number</p>13) but that's not part of an ordered list" << -// "(The first sentence of this paragraph is a line, the next paragraph has a number\n\n13\\) but that's not part of an ordered list\n\n"; -// QTest::newRow("preformats with embedded backticks") << -// "<pre>none `one` ``two``</pre><pre>```three``` ````four````</pre>plain" << -// "``` none `one` ``two`` ```\n\n````` ```three``` ````four```` `````\n\nplain\n\n"; + "```pseudocode\n#include \"foo.h\"\n\nblock {\n statement();\n}\n\n```\n\n"; + QTest::newRow("escaped number and paren after single newline") << + "<p>(The first sentence of this paragraph is a line, next paragraph has a number 13) but that's not part of an ordered list</p>" << + "(The first sentence of this paragraph is a line, next paragraph has a number\n13\\) but that's not part of an ordered list\n\n"; + QTest::newRow("escaped number and paren after double newline") << + "<p>(The first sentence of this paragraph is a line, the next paragraph has a number</p>13) but that's not part of an ordered list" << + "(The first sentence of this paragraph is a line, the next paragraph has a number\n\n13\\) but that's not part of an ordered list\n\n"; + QTest::newRow("preformats with embedded backticks") << + "<pre>none `one` ``two``</pre>plain<pre>```three``` ````four````</pre>plain" << + "```\nnone `one` ``two``\n\n```\nplain\n\n```\n```three``` ````four````\n\n```\nplain\n\n"; + QTest::newRow("list items with and without checkboxes") << + "<ul><li>bullet</li><li class=\"unchecked\">unchecked item</li><li class=\"checked\">checked item</li></ul>" << + "- bullet\n- [ ] unchecked item\n- [x] checked item\n"; + QTest::newRow("table with backslash in cell") << // QTBUG-96051 + "<table><tr><td>1011011 [</td><td>1011100 backslash \\</td></tr></table>" << + "|1011011 [|1011100 backslash \\\\|"; + // https://spec.commonmark.org/0.31.2/#example-12 + // escaping punctuation is ok, but QTextMarkdownWriter currently doesn't do that (which is also ok) + QTest::newRow("punctuation") << + R"(<p>!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~</p>)" << + R"(!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~)"; + // https://spec.commonmark.org/0.31.2/#example-14 + QTest::newRow("backslash asterisk no emphasis") << // QTBUG-122083 + R"(\*no emphasis*)" << + R"(\\\*no emphasis*)"; + // https://spec.commonmark.org/0.31.2/#example-15 + QTest::newRow("backslash before emphasis") << + R"(\<em>emphasis</em>)" << + R"(\\*emphasis*)"; + // https://spec.commonmark.org/0.31.2/#example-20 + QTest::newRow("backslash-asterisk in autolink") << + R"(<p><a href="https://example.com?find=\\*">https://example.com?find=\*</a></p>)" << + R"(<https://example.com?find=\\*>)"; + // https://spec.commonmark.org/0.31.2/#example-24 + QTest::newRow("plus in fenced code lang") << + "<pre class=\"language-foo+bar\">foo</pre>" << + "```foo+bar\nfoo\n```"; } void tst_QTextMarkdownWriter::fromHtml() { - QFETCH(QString, expectedInput); + QFETCH(QString, input); QFETCH(QString, expectedOutput); - document->setHtml(expectedInput); + document->setHtml(input); QString output = documentToUnixMarkdown(); #ifdef DEBUG_WRITE_OUTPUT @@ -459,16 +881,140 @@ void tst_QTextMarkdownWriter::fromHtml() } #endif + output = output.trimmed(); + expectedOutput = expectedOutput.trimmed(); + if (output != expectedOutput && (isMainFontFixed() || isFixedFontProportional())) + QEXPECT_FAIL("", "fixed main font or proportional fixed font (QTBUG-103484)", Continue); QCOMPARE(output, expectedOutput); } -QString tst_QTextMarkdownWriter::documentToUnixMarkdown() +void tst_QTextMarkdownWriter::fromPlainTextAndBack_data() { - QString ret; - QTextStream ts(&ret, QIODevice::WriteOnly); - QTextMarkdownWriter writer(ts, QTextDocument::MarkdownDialectGitHub); - writer.writeAll(document); - return ret; + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("expectedMarkdown"); + + // tests to verify that fixing QTBUG-122083 is safe + QTest::newRow("single backslashes") << + R"(\ again: \ not esc: \* \-\-\ \*abc*)" << + R"(\\ again: \\ not esc: \\* \\-\\-\\ \\\*abc*)"; + // https://spec.commonmark.org/0.31.2/#example-12 + QTest::newRow("punctuation") << + R"(!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~)" << + R"(!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~)"; + // https://spec.commonmark.org/0.31.2/#example-13 + QTest::newRow("literal backslashes") << + QString(uR"(\→\A\a\ \3\φ\«)") << + "\\\\\u2192\\\\A\\\\a\\\\ \\\\3\\\\\u03C6\\\\\u00AB"; + // https://spec.commonmark.org/0.31.2/#example-14 + QTest::newRow("escape to avoid em") << + R"(*not emphasized*)" << + R"(\*not emphasized*)"; + QTest::newRow("escape to avoid html") << + R"(<br/> not a tag)" << + R"(\<br/> not a tag)"; + QTest::newRow("escape to avoid link") << + R"([not a link](/foo))" << + R"(\[not a link](/foo))"; + QTest::newRow("escape to avoid mono") << + R"(`not code`)" << + R"(\`not code`)"; + QTest::newRow("escape to avoid num list") << + R"(1. not a list)" << + R"(1\. not a list)"; + QTest::newRow("escape to avoid list") << + R"(* not a list)" << + R"(\* not a list)"; + QTest::newRow("escape to avoid heading") << + R"(# not a heading)" << + R"(\# not a heading)"; + QTest::newRow("escape to avoid reflink") << + R"([foo]: /url "not a reference")" << + R"(\[foo]: /url "not a reference")"; + QTest::newRow("escape to avoid entity") << + R"(ö not a character entity)" << + R"(\ö not a character entity)"; + // end of tests to verify that fixing QTBUG-122083 is safe + // (it's ok to add unrelated plain-to-markdown-to-plaintext cases later) +} + +void tst_QTextMarkdownWriter::fromPlainTextAndBack() +{ + QFETCH(QString, input); + QFETCH(QString, expectedMarkdown); + + document->setPlainText(input); + QString output = documentToUnixMarkdown(); + +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out("/tmp/" + QLatin1String(QTest::currentDataTag()) + ".md"); + out.open(QFile::WriteOnly); + out.write(output.toUtf8()); + out.close(); + } +#endif + + output = output.trimmed(); + expectedMarkdown = expectedMarkdown.trimmed(); + if (output != expectedMarkdown && (isMainFontFixed() || isFixedFontProportional())) + QSKIP("", "fixed main font or proportional fixed font (QTBUG-103484)"); + QCOMPARE(output, expectedMarkdown); + QCOMPARE(document->toPlainText(), input); + document->setMarkdown(output); + QCOMPARE(document->toPlainText(), input); + if (document->blockCount() == 1) + QCOMPARE(document->firstBlock().text(), input); +} + +void tst_QTextMarkdownWriter::escapeSpecialCharacters_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("expectedOutput"); + + QTest::newRow("backslash") << "foo \\ bar \\\\ baz \\" << "foo \\\\ bar \\\\\\\\ baz \\\\"; + QTest::newRow("not emphasized") << "*normal* **normal too**" << "\\*normal* \\**normal too**"; + QTest::newRow("not code") << "`normal` `normal too`" << "\\`normal` \\`normal too`"; + QTest::newRow("code fence") << "```not a fence; ``` no risk here; ```not a fence" // TODO slightly inconsistent + << "\\```not a fence; ``` no risk here; \\```not a fence"; + QTest::newRow("not html") << "<p>not a tag: <br/> nope</p>" << "\\<p>not a tag: \\<br/> nope\\</p>"; + QTest::newRow("not a link") << "text [not a link](/foo)" << "text \\[not a link](/foo)"; + QTest::newRow("not a circle") << "* polaris" << "\\* polaris"; + QTest::newRow("not a square") << "+ groovy" << "\\+ groovy"; + QTest::newRow("not a bullet") << "- stayin alive" << "\\- stayin alive"; + QTest::newRow("arithmetic") << "1 + 2 - 3 * 4" << "1 + 2 - 3 * 4"; + QTest::newRow("not a list") << "1. not a list" << "1\\. not a list"; + QTest::newRow("not a list either") << "Jupiter and 10." << "Jupiter and 10."; + QTest::newRow("not a heading") << "# not a heading" << "\\# not a heading"; + QTest::newRow("a non-entity") << "ö not a character entity" << "\\ö not a character entity"; +} + +/*! \internal + If the user types into a Qt-based editor plain text that the + markdown parser would misinterpret, escape it when we save to markdown + to clarify that it's plain text. + https://spec.commonmark.org/0.31.2/#backslash-escapes +*/ +void tst_QTextMarkdownWriter::escapeSpecialCharacters() // QTBUG-96051, QTBUG-122083 +{ + QFETCH(QString, input); + QFETCH(QString, expectedOutput); + + document->setPlainText(input); + QString output = documentToUnixMarkdown(); + +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out("/tmp/" + QLatin1String(QTest::currentDataTag()) + ".md"); + out.open(QFile::WriteOnly); + out.write(output.toUtf8()); + out.close(); + } +#endif + + output = output.trimmed(); + if (output != expectedOutput && (isMainFontFixed() || isFixedFontProportional())) + QEXPECT_FAIL("", "fixed main font or proportional fixed font (QTBUG-103484)", Continue); + QCOMPARE(output, expectedOutput); } QTEST_MAIN(tst_QTextMarkdownWriter) diff --git a/tests/auto/gui/text/qtextobject/CMakeLists.txt b/tests/auto/gui/text/qtextobject/CMakeLists.txt index 07ea132de0..dd7aeae60e 100644 --- a/tests/auto/gui/text/qtextobject/CMakeLists.txt +++ b/tests/auto/gui/text/qtextobject/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qtextobject.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtextobject Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextobject LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qtextobject SOURCES tst_qtextobject.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui ) @@ -15,6 +22,6 @@ qt_internal_add_test(tst_qtextobject ##################################################################### qt_internal_extend_target(tst_qtextobject CONDITION TARGET Qt::Widgets - PUBLIC_LIBRARIES + LIBRARIES Qt::Widgets ) diff --git a/tests/auto/gui/text/qtextobject/tst_qtextobject.cpp b/tests/auto/gui/text/qtextobject/tst_qtextobject.cpp index 2afca43915..e75dfcb270 100644 --- a/tests/auto/gui/text/qtextobject/tst_qtextobject.cpp +++ b/tests/auto/gui/text/qtextobject/tst_qtextobject.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 <QTest> diff --git a/tests/auto/gui/text/qtextodfwriter/CMakeLists.txt b/tests/auto/gui/text/qtextodfwriter/CMakeLists.txt index 16c86c4977..d371fe2ee1 100644 --- a/tests/auto/gui/text/qtextodfwriter/CMakeLists.txt +++ b/tests/auto/gui/text/qtextodfwriter/CMakeLists.txt @@ -1,15 +1,20 @@ -# Generated from qtextodfwriter.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtextodfwriter Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextodfwriter LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qtextodfwriter SOURCES tst_qtextodfwriter.cpp - DEFINES - SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\" - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/gui/text/qtextodfwriter/tst_qtextodfwriter.cpp b/tests/auto/gui/text/qtextodfwriter/tst_qtextodfwriter.cpp index e9e2eac268..6b56e7c727 100644 --- a/tests/auto/gui/text/qtextodfwriter/tst_qtextodfwriter.cpp +++ b/tests/auto/gui/text/qtextodfwriter/tst_qtextodfwriter.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 <QTest> #include <QTextDocument> @@ -104,7 +79,7 @@ QString tst_QTextOdfWriter::getContentFromXml() if (index > 0) { index = stringContent.indexOf('>', index); if (index > 0) - ret = stringContent.mid(index+1, stringContent.length() - index - 10); + ret = stringContent.mid(index+1, stringContent.size() - index - 10); } return ret; } @@ -304,7 +279,7 @@ file.open(QIODevice::WriteOnly); file.write(buffer->data()); file.close(); */ - QVERIFY(buffer->data().length() > 80); + QVERIFY(buffer->data().size() > 80); QCOMPARE(buffer->data()[0], 'P'); // its a zip :) QCOMPARE(buffer->data()[1], 'K'); QString mimetype(buffer->data().mid(38, 39)); diff --git a/tests/auto/gui/text/qtextpiecetable/CMakeLists.txt b/tests/auto/gui/text/qtextpiecetable/CMakeLists.txt index 49cfcfab6a..8bdf17890c 100644 --- a/tests/auto/gui/text/qtextpiecetable/CMakeLists.txt +++ b/tests/auto/gui/text/qtextpiecetable/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qtextpiecetable.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextpiecetable LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() if(WIN32) return() @@ -15,11 +22,8 @@ qt_internal_add_test(tst_qtextpiecetable SOURCES ../qtextdocument/common.h tst_qtextpiecetable.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate ) - -#### Keys ignored in scope 1:.:.:qtextpiecetable.pro:<TRUE>: -# _REQUIREMENTS = "!win32" "qtConfig(private_tests)" diff --git a/tests/auto/gui/text/qtextpiecetable/tst_qtextpiecetable.cpp b/tests/auto/gui/text/qtextpiecetable/tst_qtextpiecetable.cpp index 32ab425ccf..f47d5dc0d6 100644 --- a/tests/auto/gui/text/qtextpiecetable/tst_qtextpiecetable.cpp +++ b/tests/auto/gui/text/qtextpiecetable/tst_qtextpiecetable.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 <QTest> @@ -124,21 +99,21 @@ void tst_QTextPieceTable::cleanup() void tst_QTextPieceTable::insertion1() { - table->insert(0, "aacc", charFormatIndex); + table->insert(0, u"aacc", charFormatIndex); QCOMPARE(table->plainText(), QString("aacc")); - table->insert(2, "bb", charFormatIndex); + table->insert(2, u"bb", charFormatIndex); QCOMPARE(table->plainText(), QString("aabbcc")); - table->insert(1, "1", charFormatIndex); + table->insert(1, u"1", charFormatIndex); QCOMPARE(table->plainText(), QString("a1abbcc")); - table->insert(6, "d", charFormatIndex); + table->insert(6, u"d", charFormatIndex); QCOMPARE(table->plainText(), QString("a1abbcdc")); - table->insert(8, "z", charFormatIndex); + table->insert(8, u"z", charFormatIndex); QCOMPARE(table->plainText(), QString("a1abbcdcz")); } void tst_QTextPieceTable::insertion2() { - table->insert(0, "bb", charFormatIndex); + table->insert(0, u"bb", charFormatIndex); QCOMPARE(table->plainText(), QString("bb")); } @@ -201,21 +176,21 @@ void tst_QTextPieceTable::insertion5() void tst_QTextPieceTable::removal1() { - table->insert(0, "abbccc", charFormatIndex); + table->insert(0, u"abbccc", charFormatIndex); QCOMPARE(table->plainText(), QString("abbccc")); table->remove(1, 2); QCOMPARE(table->plainText(), QString("accc")); - table->insert(1, "1", charFormatIndex); + table->insert(1, u"1", charFormatIndex); QCOMPARE(table->plainText(), QString("a1ccc")); table->remove(4, 1); QCOMPARE(table->plainText(), QString("a1cc")); - table->insert(4, "z", charFormatIndex); + table->insert(4, u"z", charFormatIndex); QCOMPARE(table->plainText(), QString("a1ccz")); } void tst_QTextPieceTable::removal2() { - table->insert(0, "bb", charFormatIndex); + table->insert(0, u"bb", charFormatIndex); QCOMPARE(table->plainText(), QString("bb")); table->remove(0, 2); QCOMPARE(table->plainText(), QString("")); @@ -224,7 +199,7 @@ void tst_QTextPieceTable::removal2() table->remove(0, 1); QCOMPARE(table->plainText(), QString("")); - table->insert(0, "bb", charFormatIndex); + table->insert(0, u"bb", charFormatIndex); QCOMPARE(table->plainText(), QString("bb")); table->insertBlock(1, blockFormatIndex, charFormatIndex); QCOMPARE(table->plainText(), QString("b") + QString(QChar(QChar::ParagraphSeparator)) + QString("b")); @@ -295,16 +270,16 @@ void tst_QTextPieceTable::removal4() void tst_QTextPieceTable::undoRedo1() { - table->insert(0, "01234567", charFormatIndex); - table->insert(0, "a", charFormatIndex); - table->insert(1, "b", charFormatIndex); + table->insert(0, u"01234567", charFormatIndex); + table->insert(0, u"a", charFormatIndex); + table->insert(1, u"b", charFormatIndex); QCOMPARE(table->plainText(), QString("ab01234567")); table->undo(); QCOMPARE(table->plainText(), QString("01234567")); table->redo(); QCOMPARE(table->plainText(), QString("ab01234567")); table->undo(); - table->insert(1, "c", charFormatIndex); + table->insert(1, u"c", charFormatIndex); QCOMPARE(table->plainText(), QString("0c1234567")); table->undo(); QCOMPARE(table->plainText(), QString("01234567")); @@ -314,8 +289,8 @@ void tst_QTextPieceTable::undoRedo1() void tst_QTextPieceTable::undoRedo2() { - table->insert(0, "01", charFormatIndex); - table->insert(1, "a", charFormatIndex); + table->insert(0, u"01", charFormatIndex); + table->insert(1, u"a", charFormatIndex); QCOMPARE(table->plainText(), QString("0a1")); table->undo(); QCOMPARE(table->plainText(), QString("01")); @@ -329,8 +304,8 @@ void tst_QTextPieceTable::undoRedo2() void tst_QTextPieceTable::undoRedo3() { - table->insert(0, "01", charFormatIndex); - table->insert(2, "ab", charFormatIndex); + table->insert(0, u"01", charFormatIndex); + table->insert(2, u"ab", charFormatIndex); table->remove(2, 1); QCOMPARE(table->plainText(), QString("01b")); table->undo(); @@ -345,8 +320,8 @@ void tst_QTextPieceTable::undoRedo3() void tst_QTextPieceTable::undoRedo4() { - table->insert(0, "01", charFormatIndex); - table->insert(0, "ab", charFormatIndex); + table->insert(0, u"01", charFormatIndex); + table->insert(0, u"ab", charFormatIndex); table->remove(0, 1); QCOMPARE(table->plainText(), QString("b01")); table->undo(); @@ -366,7 +341,7 @@ void tst_QTextPieceTable::undoRedo4() void tst_QTextPieceTable::undoRedo5() { table->beginEditBlock(); - table->insert(0, "01", charFormatIndex); + table->insert(0, u"01", charFormatIndex); table->remove(1, 1); table->endEditBlock(); QCOMPARE(table->plainText(), QString("0")); @@ -409,8 +384,8 @@ void tst_QTextPieceTable::undoRedo6() void tst_QTextPieceTable::undoRedo7() { - table->insert(0, "a", charFormatIndex); - table->insert(1, "b", charFormatIndex); + table->insert(0, u"a", charFormatIndex); + table->insert(1, u"b", charFormatIndex); QCOMPARE(table->plainText(), QString("ab")); table->undo(); @@ -419,8 +394,8 @@ void tst_QTextPieceTable::undoRedo7() void tst_QTextPieceTable::undoRedo8() { - table->insert(0, "a", charFormatIndex); - table->insert(1, "b", charFormatIndex); + table->insert(0, u"a", charFormatIndex); + table->insert(1, u"b", charFormatIndex); QCOMPARE(table->plainText(), QString("ab")); table->remove(0, 1); @@ -433,8 +408,8 @@ void tst_QTextPieceTable::undoRedo8() void tst_QTextPieceTable::undoRedo9() { - table->insert(0, "a", charFormatIndex); - table->insert(1, "b", charFormatIndex); + table->insert(0, u"a", charFormatIndex); + table->insert(1, u"b", charFormatIndex); QCOMPARE(table->plainText(), QString("ab")); table->remove(1, 1); @@ -455,9 +430,9 @@ void tst_QTextPieceTable::undoRedo10() QTextBlockFormat f; int idx = table->formatCollection()->indexForFormat(f); - table->insert(0, "a", cfIdx); + table->insert(0, u"a", cfIdx); table->insertBlock(1, idx, cfIdx); - table->insert(1, "b", cfIdx); + table->insert(1, u"b", cfIdx); cf.setForeground(Qt::red); int newCfIdx = table->formatCollection()->indexForFormat(cf); @@ -510,7 +485,7 @@ void tst_QTextPieceTable::checkDocumentChanged() // single insert layout->expect(0, 0, 15); - table->insert(0, "012345678901234", charFormatIndex); + table->insert(0, u"012345678901234", charFormatIndex); QVERIFY(!layout->error); // single remove @@ -521,7 +496,7 @@ void tst_QTextPieceTable::checkDocumentChanged() // symmetric insert/remove layout->expect(0, 0, 0); table->beginEditBlock(); - table->insert(0, "01234", charFormatIndex); + table->insert(0, u"01234", charFormatIndex); table->remove(0, 5); table->endEditBlock(); QVERIFY(!layout->error); @@ -529,7 +504,7 @@ void tst_QTextPieceTable::checkDocumentChanged() layout->expect(0, 5, 5); table->beginEditBlock(); table->remove(0, 5); - table->insert(0, "01234", charFormatIndex); + table->insert(0, u"01234", charFormatIndex); table->endEditBlock(); QVERIFY(!layout->error); @@ -537,13 +512,13 @@ void tst_QTextPieceTable::checkDocumentChanged() layout->expect(0, 3, 5); table->beginEditBlock(); table->remove(0, 3); - table->insert(0, "01234", charFormatIndex); + table->insert(0, u"01234", charFormatIndex); table->endEditBlock(); QVERIFY(!layout->error); layout->expect(0, 0, 2); table->beginEditBlock(); - table->insert(0, "01234", charFormatIndex); + table->insert(0, u"01234", charFormatIndex); table->remove(0, 3); table->endEditBlock(); QVERIFY(!layout->error); @@ -551,14 +526,14 @@ void tst_QTextPieceTable::checkDocumentChanged() // insert + remove inside insert block layout->expect(0, 0, 2); table->beginEditBlock(); - table->insert(0, "01234", charFormatIndex); + table->insert(0, u"01234", charFormatIndex); table->remove(1, 3); table->endEditBlock(); QVERIFY(!layout->error); layout->expect(0, 0, 2); table->beginEditBlock(); - table->insert(0, "01234", charFormatIndex); + table->insert(0, u"01234", charFormatIndex); table->remove(2, 3); table->endEditBlock(); QVERIFY(!layout->error); @@ -566,42 +541,42 @@ void tst_QTextPieceTable::checkDocumentChanged() // insert + remove partly outside layout->expect(0, 1, 0); table->beginEditBlock(); - table->insert(1, "0", charFormatIndex); + table->insert(1, u"0", charFormatIndex); table->remove(0, 2); table->endEditBlock(); QVERIFY(!layout->error); layout->expect(0, 1, 1); table->beginEditBlock(); - table->insert(1, "01", charFormatIndex); + table->insert(1, u"01", charFormatIndex); table->remove(0, 2); table->endEditBlock(); QVERIFY(!layout->error); layout->expect(0, 1, 2); table->beginEditBlock(); - table->insert(1, "012", charFormatIndex); + table->insert(1, u"012", charFormatIndex); table->remove(0, 2); table->endEditBlock(); QVERIFY(!layout->error); layout->expect(1, 1, 0); table->beginEditBlock(); - table->insert(1, "0", charFormatIndex); + table->insert(1, u"0", charFormatIndex); table->remove(1, 2); table->endEditBlock(); QVERIFY(!layout->error); layout->expect(1, 1, 1); table->beginEditBlock(); - table->insert(1, "01", charFormatIndex); + table->insert(1, u"01", charFormatIndex); table->remove(2, 2); table->endEditBlock(); QVERIFY(!layout->error); layout->expect(1, 1, 2); table->beginEditBlock(); - table->insert(1, "012", charFormatIndex); + table->insert(1, u"012", charFormatIndex); table->remove(3, 2); table->endEditBlock(); QVERIFY(!layout->error); @@ -609,14 +584,14 @@ void tst_QTextPieceTable::checkDocumentChanged() // insert + remove non overlapping layout->expect(0, 1, 1); table->beginEditBlock(); - table->insert(1, "0", charFormatIndex); + table->insert(1, u"0", charFormatIndex); table->remove(0, 1); table->endEditBlock(); QVERIFY(!layout->error); layout->expect(0, 2, 2); table->beginEditBlock(); - table->insert(2, "1", charFormatIndex); + table->insert(2, u"1", charFormatIndex); table->remove(0, 1); table->endEditBlock(); QVERIFY(!layout->error); @@ -624,14 +599,14 @@ void tst_QTextPieceTable::checkDocumentChanged() layout->expect(0, 2, 2); table->beginEditBlock(); table->remove(0, 1); - table->insert(1, "0", charFormatIndex); + table->insert(1, u"0", charFormatIndex); table->endEditBlock(); QVERIFY(!layout->error); layout->expect(0, 3, 3); table->beginEditBlock(); table->remove(0, 1); - table->insert(2, "1", charFormatIndex); + table->insert(2, u"1", charFormatIndex); table->endEditBlock(); @@ -656,9 +631,9 @@ void tst_QTextPieceTable::checkDocumentChanged2() layout->expect(0, 0, 12); table->beginEditBlock(); - table->insert(0, "0123", charFormatIndex); - table->insert(4, "4567", anotherCharFormatIndex); - table->insert(8, "8901", charFormatIndex); + table->insert(0, u"0123", charFormatIndex); + table->insert(4, u"4567", anotherCharFormatIndex); + table->insert(8, u"8901", charFormatIndex); table->endEditBlock(); QVERIFY(!layout->error); @@ -721,7 +696,7 @@ void tst_QTextPieceTable::blockInsertion2() int pos = 0; table->insertBlock(pos, blockFormatIndex, charFormatIndex); pos += 1; - table->insert(pos, "a", charFormatIndex); + table->insert(pos, u"a", charFormatIndex); pos += 1; pos -= 1; @@ -744,11 +719,11 @@ void tst_QTextPieceTable::blockRemoval1() int idx1 = table->formatCollection()->indexForFormat(fmt1); int idx2 = table->formatCollection()->indexForFormat(fmt2); - table->insert(0, "0123", charFormatIndex); + table->insert(0, u"0123", charFormatIndex); table->insertBlock(4, idx1, charFormatIndex); - table->insert(5, "5678", charFormatIndex); + table->insert(5, u"5678", charFormatIndex); table->insertBlock(9, idx2, charFormatIndex); - table->insert(10, "0123", charFormatIndex); + table->insert(10, u"0123", charFormatIndex); QCOMPARE(table->blocksFind(0).blockFormat(), QTextBlockFormat()); QCOMPARE(table->blocksFind(4).blockFormat(), QTextBlockFormat()); @@ -792,11 +767,11 @@ void tst_QTextPieceTable::blockRemoval2() int idx1 = table->formatCollection()->indexForFormat(fmt1); int idx2 = table->formatCollection()->indexForFormat(fmt2); - table->insert(0, "0123", charFormatIndex); + table->insert(0, u"0123", charFormatIndex); table->insertBlock(4, idx1, charFormatIndex); - table->insert(5, "5678", charFormatIndex); + table->insert(5, u"5678", charFormatIndex); table->insertBlock(9, idx2, charFormatIndex); - table->insert(10, "0123", charFormatIndex); + table->insert(10, u"0123", charFormatIndex); QCOMPARE(table->blocksFind(0).blockFormat(), QTextBlockFormat()); QCOMPARE(table->blocksFind(4).blockFormat(), QTextBlockFormat()); @@ -838,11 +813,11 @@ void tst_QTextPieceTable::blockRemoval3() int idx1 = table->formatCollection()->indexForFormat(fmt1); int idx2 = table->formatCollection()->indexForFormat(fmt2); - table->insert(0, "0123", charFormatIndex); + table->insert(0, u"0123", charFormatIndex); table->insertBlock(4, idx1, charFormatIndex); - table->insert(5, "5678", charFormatIndex); + table->insert(5, u"5678", charFormatIndex); table->insertBlock(9, idx2, charFormatIndex); - table->insert(10, "0123", charFormatIndex); + table->insert(10, u"0123", charFormatIndex); QCOMPARE(table->blocksFind(0).blockFormat(), QTextBlockFormat()); QCOMPARE(table->blocksFind(4).blockFormat(), QTextBlockFormat()); @@ -935,11 +910,11 @@ void tst_QTextPieceTable::blockRemoval5() int idx1 = table->formatCollection()->indexForFormat(fmt1); int idx2 = table->formatCollection()->indexForFormat(fmt2); - table->insert(0, "0123", charFormatIndex); + table->insert(0, u"0123", charFormatIndex); table->insertBlock(4, idx1, charFormatIndex); - table->insert(5, "5678", charFormatIndex); + table->insert(5, u"5678", charFormatIndex); table->insertBlock(9, idx2, charFormatIndex); - table->insert(10, "0123", charFormatIndex); + table->insert(10, u"0123", charFormatIndex); QCOMPARE(table->blocksFind(0).blockFormat(), QTextBlockFormat()); QCOMPARE(table->blocksFind(4).blockFormat(), QTextBlockFormat()); @@ -987,7 +962,7 @@ void tst_QTextPieceTable::checkBlockSeparation() void tst_QTextPieceTable::checkFrames1() { QTextFrameFormat ffmt; - table->insert(0, "Hello", charFormatIndex); + table->insert(0, u"Hello", charFormatIndex); QPointer<QTextFrame> frame = table->insertFrame(1, 3, ffmt); QTextFrame *root = table->rootFrame(); @@ -996,7 +971,7 @@ void tst_QTextPieceTable::checkFrames1() QVERIFY(root); QVERIFY(!root->parentFrame()); - QCOMPARE(root->childFrames().count(), 1); + QCOMPARE(root->childFrames().size(), 1); QVERIFY(frame->format() == ffmt); QCOMPARE(frame->firstPosition(), 2); QCOMPARE(frame->lastPosition(), 4); @@ -1004,10 +979,10 @@ void tst_QTextPieceTable::checkFrames1() QPointer<QTextFrame> frame2 = table->insertFrame(2, 3, ffmt); - QCOMPARE(root->childFrames().count(), 1); + QCOMPARE(root->childFrames().size(), 1); QCOMPARE(root->childFrames().at(0), frame.data()); - QCOMPARE(frame->childFrames().count(), 1); - QCOMPARE(frame2->childFrames().count(), 0); + QCOMPARE(frame->childFrames().size(), 1); + QCOMPARE(frame2->childFrames().size(), 0); QCOMPARE(frame2->parentFrame(), frame.data()); QCOMPARE(frame2->firstPosition(), 3); QCOMPARE(frame2->lastPosition(), 4); @@ -1018,10 +993,10 @@ void tst_QTextPieceTable::checkFrames1() table->removeFrame(frame); - QCOMPARE(root->childFrames().count(), 1); + QCOMPARE(root->childFrames().size(), 1); QCOMPARE(root->childFrames().at(0), frame2.data()); QVERIFY(!frame); - QCOMPARE(frame2->childFrames().count(), 0); + QCOMPARE(frame2->childFrames().size(), 0); QCOMPARE(frame2->parentFrame(), root); QCOMPARE(frame2->firstPosition(), 2); QCOMPARE(frame2->lastPosition(), 3); @@ -1030,11 +1005,11 @@ void tst_QTextPieceTable::checkFrames1() frame = table->frameAt(2); - QCOMPARE(root->childFrames().count(), 1); + QCOMPARE(root->childFrames().size(), 1); QCOMPARE(root->childFrames().at(0), frame.data()); - QCOMPARE(frame->childFrames().count(), 1); + QCOMPARE(frame->childFrames().size(), 1); QCOMPARE(frame->childFrames().at(0), frame2.data()); - QCOMPARE(frame2->childFrames().count(), 0); + QCOMPARE(frame2->childFrames().size(), 0); QCOMPARE(frame2->parentFrame(), frame.data()); QCOMPARE(frame2->firstPosition(), 3); QCOMPARE(frame2->lastPosition(), 4); @@ -1044,9 +1019,9 @@ void tst_QTextPieceTable::checkFrames1() table->undo(); - QCOMPARE(root->childFrames().count(), 1); + QCOMPARE(root->childFrames().size(), 1); QCOMPARE(root->childFrames().at(0), frame.data()); - QCOMPARE(frame->childFrames().count(), 0); + QCOMPARE(frame->childFrames().size(), 0); QVERIFY(!frame2); QCOMPARE(frame->firstPosition(), 2); @@ -1056,7 +1031,7 @@ void tst_QTextPieceTable::checkFrames1() void tst_QTextPieceTable::removeFrameDirect() { QTextFrameFormat ffmt; - table->insert(0, "Hello", charFormatIndex); + table->insert(0, u"Hello", charFormatIndex); QTextFrame *frame = table->insertFrame(1, 5, ffmt); @@ -1090,7 +1065,7 @@ void tst_QTextPieceTable::removeWithChildFrame() In this case frameAt(2) != frameAt(6), so the assertion in remove() needed an adjustement. */ QTextFrameFormat ffmt; - table->insert(0, "Hello World", charFormatIndex); + table->insert(0, u"Hello World", charFormatIndex); QTextFrame *frame = table->insertFrame(1, 6, ffmt); QTextFrame *childFrame = table->insertFrame(3, 5, ffmt); @@ -1120,7 +1095,7 @@ void tst_QTextPieceTable::clearWithFrames() The idea is to remove from [1] until [7]. */ QTextFrameFormat ffmt; - table->insert(0, "Hello World", charFormatIndex); + table->insert(0, u"Hello World", charFormatIndex); QTextFrame *firstFrame = table->insertFrame(1, 2, ffmt); QTextFrame *secondFrame = table->insertFrame(4, 6, ffmt); diff --git a/tests/auto/gui/text/qtextscriptengine/CMakeLists.txt b/tests/auto/gui/text/qtextscriptengine/CMakeLists.txt index 01d418ebd4..9bb9e4c13b 100644 --- a/tests/auto/gui/text/qtextscriptengine/CMakeLists.txt +++ b/tests/auto/gui/text/qtextscriptengine/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qtextscriptengine.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtextscriptengine Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtextscriptengine LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qtextscriptengine SOURCES tst_qtextscriptengine.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate diff --git a/tests/auto/gui/text/qtextscriptengine/generate/CMakeLists.txt b/tests/auto/gui/text/qtextscriptengine/generate/CMakeLists.txt index d3b6b1dc6d..db284b2e1c 100644 --- a/tests/auto/gui/text/qtextscriptengine/generate/CMakeLists.txt +++ b/tests/auto/gui/text/qtextscriptengine/generate/CMakeLists.txt @@ -1,4 +1,5 @@ -# Generated from generate.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## generate Binary: @@ -9,9 +10,8 @@ qt_internal_add_executable(generate SOURCES main.cpp INCLUDE_DIRECTORIES - . /usr/include/freetype2 - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Gui ) diff --git a/tests/auto/gui/text/qtextscriptengine/generate/main.cpp b/tests/auto/gui/text/qtextscriptengine/generate/main.cpp index 708864521a..5082c2b406 100644 --- a/tests/auto/gui/text/qtextscriptengine/generate/main.cpp +++ b/tests/auto/gui/text/qtextscriptengine/generate/main.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 <QApplication> diff --git a/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp b/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp index b3a33c2d92..975658005e 100644 --- a/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp +++ b/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.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 <QTest> #include <private/qfontengine_p.h> @@ -1119,11 +1094,12 @@ void tst_QTextScriptEngine::combiningMarks_qtbug15675_data() bool hasTests = false; - QStringList families; - families << QStringLiteral("Monaco"); - families << QStringLiteral("DejaVu Sans Mono"); + const QString families[] = { + QStringLiteral("Monaco"), + QStringLiteral("DejaVu Sans Mono"), + }; - foreach (const QString &family, families) { + for (const QString &family : families) { QFont font(family); font.setStyleStrategy(QFont::NoFontMerging); if (QFontInfo(font).family() != family) diff --git a/tests/auto/gui/text/qtexttable/CMakeLists.txt b/tests/auto/gui/text/qtexttable/CMakeLists.txt index 94d33d3530..e83a38f087 100644 --- a/tests/auto/gui/text/qtexttable/CMakeLists.txt +++ b/tests/auto/gui/text/qtexttable/CMakeLists.txt @@ -1,13 +1,20 @@ -# Generated from qtexttable.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtexttable Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtexttable LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + qt_internal_add_test(tst_qtexttable SOURCES tst_qtexttable.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui Qt::GuiPrivate ) @@ -16,6 +23,6 @@ qt_internal_add_test(tst_qtexttable ##################################################################### qt_internal_extend_target(tst_qtexttable CONDITION TARGET Qt::Widgets - PUBLIC_LIBRARIES + LIBRARIES Qt::Widgets ) diff --git a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp index dabe51f833..d0e1e1cd74 100644 --- a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp +++ b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp @@ -1,35 +1,10 @@ -/**************************************************************************** -** -** 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 <QTest> - +#include <qbuffer.h> #include <qtextdocument.h> #include <qtextdocumentfragment.h> #include <qtexttable.h> @@ -44,6 +19,7 @@ #include <QPainter> #include <QPaintEngine> #endif +#include <private/qtextdocumentlayout_p.h> #include <private/qpagedpaintdevice_p.h> typedef QList<int> IntList; @@ -99,6 +75,15 @@ private slots: #endif void checkBorderAttributes_data(); void checkBorderAttributes(); + void checkTableBorderAttributes_data(); + void checkTableBorderAttributes(); + +#ifndef QT_NO_WIDGETS + void columnWidthWithSpans(); + + void columnWidthWithImage_data(); + void columnWidthWithImage(); +#endif private: QTextTable *create2x2Table(); @@ -138,7 +123,7 @@ void tst_QTextTable::variousTableModifications() QTextTableFormat tableFmt; QTextTable *tab = cursor.insertTable(2, 2, tableFmt); - QCOMPARE(doc->toPlainText().length(), 5); + QCOMPARE(doc->toPlainText().size(), 5); QCOMPARE(tab, cursor.currentTable()); QCOMPARE(tab->columns(), 2); QCOMPARE(tab->rows(), 2); @@ -193,14 +178,14 @@ void tst_QTextTable::variousTableModifications() cursor.movePosition(QTextCursor::NextBlock); QCOMPARE(cursor.position(), 1); cursor.deleteChar(); - QCOMPARE(doc->toPlainText().length(), 5); + QCOMPARE(doc->toPlainText().size(), 5); cursor.movePosition(QTextCursor::NextBlock); QCOMPARE(cursor.position(), 2); cursor.deleteChar(); - QCOMPARE(doc->toPlainText().length(), 5); + QCOMPARE(doc->toPlainText().size(), 5); cursor.deletePreviousChar(); QCOMPARE(cursor.position(), 2); - QCOMPARE(doc->toPlainText().length(), 5); + QCOMPARE(doc->toPlainText().size(), 5); QTextTable *table = cursor.currentTable(); QCOMPARE(table->rows(), 2); @@ -209,16 +194,16 @@ void tst_QTextTable::variousTableModifications() table->insertRows(2, 1); QCOMPARE(table->rows(), 3); QCOMPARE(table->columns(), 2); - QCOMPARE(doc->toPlainText().length(), 7); + QCOMPARE(doc->toPlainText().size(), 7); table->insertColumns(2, 2); QCOMPARE(table->rows(), 3); QCOMPARE(table->columns(), 4); - QCOMPARE(doc->toPlainText().length(), 13); + QCOMPARE(doc->toPlainText().size(), 13); table->resize(4, 5); QCOMPARE(table->rows(), 4); QCOMPARE(table->columns(), 5); - QCOMPARE(doc->toPlainText().length(), 21); + QCOMPARE(doc->toPlainText().size(), 21); } void tst_QTextTable::tableShrinking() @@ -226,7 +211,7 @@ void tst_QTextTable::tableShrinking() QTextTableFormat tableFmt; cursor.insertTable(3, 4, tableFmt); - QCOMPARE(doc->toPlainText().length(), 13); + QCOMPARE(doc->toPlainText().size(), 13); QTextTable *table = cursor.currentTable(); QCOMPARE(table->rows(), 3); @@ -235,16 +220,16 @@ void tst_QTextTable::tableShrinking() table->removeRows(1, 1); QCOMPARE(table->rows(), 2); QCOMPARE(table->columns(), 4); - QCOMPARE(doc->toPlainText().length(), 9); + QCOMPARE(doc->toPlainText().size(), 9); table->removeColumns(1, 2); QCOMPARE(table->rows(), 2); QCOMPARE(table->columns(), 2); - QCOMPARE(doc->toPlainText().length(), 5); + QCOMPARE(doc->toPlainText().size(), 5); table->resize(1, 1); QCOMPARE(table->rows(), 1); QCOMPARE(table->columns(), 1); - QCOMPARE(doc->toPlainText().length(), 2); + QCOMPARE(doc->toPlainText().size(), 2); } void tst_QTextTable::spans() @@ -269,7 +254,7 @@ void tst_QTextTable::variousModifications2() QTextTableFormat tableFmt; cursor.insertTable(2, 5, tableFmt); - QCOMPARE(doc->toPlainText().length(), 11); + QCOMPARE(doc->toPlainText().size(), 11); QTextTable *table = cursor.currentTable(); QCOMPARE(cursor.position(), 1); QCOMPARE(table->rows(), 2); @@ -1165,8 +1150,8 @@ void tst_QTextTable::QTBUG31330_renderBackground() doc.print(&paintDevice); QVERIFY(paintDevice.pages >= 2); - QCOMPARE(engine.rects.count(), paintDevice.pages); - for (int i = 0; i < engine.rects.count(); ++i) { + QCOMPARE(engine.rects.size(), paintDevice.pages); + for (int i = 0; i < engine.rects.size(); ++i) { QRectF rect = engine.rects[i]; QVERIFY(rect.top() > 0); QVERIFY(rect.bottom() < 1000); @@ -1278,5 +1263,150 @@ void tst_QTextTable::checkBorderAttributes() } } +void tst_QTextTable::checkTableBorderAttributes_data() +{ + QTest::addColumn<QString>("html"); + QTest::addColumn<qreal>("tableBorderWidth"); + QTest::addColumn<QTextFrameFormat::BorderStyle>("tableBorderStyle"); + QTest::addColumn<QBrush>("tableBorderBrush"); + + const QString tableHtmlStart = QStringLiteral("<html><head><style>"); + const QString tableHtmlEnd1 = QStringLiteral("</style></head><body>" + "<table><tr><td>One</td><td>Two</td></tr></table>" + "</body></html>"); + const QString tableHtmlEnd2 = QStringLiteral("</style></head><body>" + "<table border=10><tr><td>One</td><td>Two</td></tr></table>" + "</body></html>"); + + QTest::newRow("table-border-attributes-shorthand") + << QString("%1" + "table {" + "border: 2px solid red;" + "}" + "%2").arg(tableHtmlStart).arg(tableHtmlEnd1) + << 2.0 << QTextFrameFormat::BorderStyle_Solid << QBrush(Qt::red); + + QTest::newRow("table-border-attributes-explicit") + << QString("%1" + "table {" + "border-width: 2px;" + "border-color: red;" + "border-style: dashed;" + "}" + "%2").arg(tableHtmlStart).arg(tableHtmlEnd1) + << 2.0 << QTextFrameFormat::BorderStyle_Dashed << QBrush(Qt::red); + + QTest::newRow("table-border-override") + << QString("%1" + "table {" + "border: 2px solid red;" + "}" + "%2").arg(tableHtmlStart).arg(tableHtmlEnd2) + << 2.0 << QTextFrameFormat::BorderStyle_Solid << QBrush(Qt::red); + + QTest::newRow("table-border-default") + << QString("%1" + "%2").arg(tableHtmlStart).arg(tableHtmlEnd2) + << 10.0 << QTextFrameFormat::BorderStyle_Outset << QBrush(Qt::darkGray); +} + +void tst_QTextTable::checkTableBorderAttributes() +{ + QFETCH(QString, html); + QFETCH(qreal, tableBorderWidth); + QFETCH(QTextFrameFormat::BorderStyle, tableBorderStyle); + QFETCH(QBrush, tableBorderBrush); + + QTextDocument doc; + doc.setHtml(html); + QTextCursor cursor(doc.firstBlock()); + cursor.movePosition(QTextCursor::Right); + + QTextTable *currentTable = cursor.currentTable(); + QVERIFY(currentTable); + QCOMPARE(currentTable->format().border(), tableBorderWidth); + QCOMPARE(currentTable->format().borderStyle(), tableBorderStyle); + QCOMPARE(currentTable->format().borderBrush(), tableBorderBrush); +} + +#ifndef QT_NO_WIDGETS +void tst_QTextTable::columnWidthWithSpans() +{ + cleanup(); + init(); + QTextTable *table = cursor.insertTable(4, 4); + QTextEdit textEdit; + textEdit.setDocument(doc); + textEdit.show(); + QVERIFY(QTest::qWaitForWindowExposed(&textEdit)); + + for (int i = 0; i < table->columns(); ++i) + table->cellAt(0, i).firstCursorPosition().insertText(QString("Header %1").arg(i)); + + QTextBlock block = table->cellAt(0, 0).firstCursorPosition().block(); + const QRectF beforeRect = table->document()->documentLayout()->blockBoundingRect(block); + table->mergeCells(1, 0, 1, table->columns()); + block = table->cellAt(0, 0).firstCursorPosition().block(); + const QRectF afterRect = table->document()->documentLayout()->blockBoundingRect(block); + QCOMPARE(afterRect, beforeRect); +} + +void tst_QTextTable::columnWidthWithImage_data() +{ + const auto imageHtml = [](int width, int height) { + QImage image(width, height, QImage::Format_RGB32); + image.fill(Qt::red); + QByteArray imageBytes; + QBuffer buffer(&imageBytes); + buffer.open(QIODevice::WriteOnly); + image.save(&buffer, "png"); + return QString("<td><img src='data:image/png;base64,%1'/></td>").arg(imageBytes.toBase64()); + }; + + QTest::addColumn<QString>("leftHtml"); + QTest::addColumn<QString>("rightHtml"); + QTest::addColumn<QSize>("imageSize"); + QTest::addRow("image") + << imageHtml(500, 32) << "<td></td>" << QSize(500, 32); + QTest::addRow("image, text") + << imageHtml(32, 32) << "<td>abc</td>" << QSize(32, 32); + QTest::addRow("image, 100%% text") + << imageHtml(32, 32) << "<td style='background-color: grey' width='100%'>abc</td>" + << QSize(32, 32); + QTest::addRow("image, image") + << imageHtml(256, 32) << imageHtml(256, 32) << QSize(256, 32); +} + +void tst_QTextTable::columnWidthWithImage() +{ + const QString tableTemplate = "<table><tr>%1 %2</tr></table>"; + + QFETCH(QString, leftHtml); + QFETCH(QString, rightHtml); + QFETCH(QSize, imageSize); + + QTextDocument doc; + doc.setHtml(tableTemplate.arg(leftHtml).arg(rightHtml)); + QTextEdit textEdit; + textEdit.setDocument(&doc); + textEdit.show(); + QVERIFY(QTest::qWaitForWindowExposed(&textEdit)); + + QTextCursor cursor(doc.firstBlock()); + cursor.movePosition(QTextCursor::Right); + + QTextTable *currentTable = cursor.currentTable(); + QVERIFY(currentTable); + + QTextBlock block = currentTable->cellAt(0, 0).firstCursorPosition().block(); + const QRectF leftRect = currentTable->document()->documentLayout()->blockBoundingRect(block); + block = currentTable->cellAt(0, 1).firstCursorPosition().block(); + const QRectF rightRect = currentTable->document()->documentLayout()->blockBoundingRect(block); + QCOMPARE(leftRect.size().toSize(), imageSize); + QVERIFY(rightRect.left() > leftRect.right()); +} +#endif + + QTEST_MAIN(tst_QTextTable) #include "tst_qtexttable.moc" diff --git a/tests/auto/gui/text/qzip/.gitignore b/tests/auto/gui/text/qzip/.gitignore deleted file mode 100644 index 2d7dfbe70c..0000000000 --- a/tests/auto/gui/text/qzip/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qzip diff --git a/tests/auto/gui/text/qzip/CMakeLists.txt b/tests/auto/gui/text/qzip/CMakeLists.txt deleted file mode 100644 index 7240a611d2..0000000000 --- a/tests/auto/gui/text/qzip/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -# Generated from qzip.pro. - -##################################################################### -## tst_qzip Test: -##################################################################### - -# Collect test data -list(APPEND test_data "testdata") - -qt_internal_add_test(tst_qzip - SOURCES - tst_qzip.cpp - PUBLIC_LIBRARIES - Qt::Gui - Qt::GuiPrivate - TESTDATA ${test_data} -) - -## Scopes: -##################################################################### - -if(ANDROID) - # Resources: - set(testdata_resource_files - "testdata/symlink.zip" - "testdata/test.zip" - ) - - qt_internal_add_resource(tst_qzip "testdata" - PREFIX - "/" - FILES - ${testdata_resource_files} - ) -endif() diff --git a/tests/auto/gui/text/qzip/testdata.qrc b/tests/auto/gui/text/qzip/testdata.qrc deleted file mode 100644 index c7e3a6b14e..0000000000 --- a/tests/auto/gui/text/qzip/testdata.qrc +++ /dev/null @@ -1,6 +0,0 @@ -<RCC> - <qresource prefix="/"> - <file>testdata/symlink.zip</file> - <file>testdata/test.zip</file> - </qresource> -</RCC> diff --git a/tests/auto/gui/text/qzip/testdata/symlink.zip b/tests/auto/gui/text/qzip/testdata/symlink.zip Binary files differdeleted file mode 100644 index 027f96477a..0000000000 --- a/tests/auto/gui/text/qzip/testdata/symlink.zip +++ /dev/null diff --git a/tests/auto/gui/text/qzip/testdata/test.zip b/tests/auto/gui/text/qzip/testdata/test.zip Binary files differdeleted file mode 100644 index a57ba4e2a9..0000000000 --- a/tests/auto/gui/text/qzip/testdata/test.zip +++ /dev/null diff --git a/tests/auto/gui/text/qzip/tst_qzip.cpp b/tests/auto/gui/text/qzip/tst_qzip.cpp deleted file mode 100644 index 6be7c7b833..0000000000 --- a/tests/auto/gui/text/qzip/tst_qzip.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#include <QTest> -#include <QDebug> -#include <QBuffer> - -#include <private/qzipwriter_p.h> -#include <private/qzipreader_p.h> - -class tst_QZip : public QObject -{ - Q_OBJECT - -private slots: - void basicUnpack(); - void symlinks(); - void readTest(); - void createArchive(); -}; - -void tst_QZip::basicUnpack() -{ - QZipReader zip(QFINDTESTDATA("/testdata/test.zip"), QIODevice::ReadOnly); - QList<QZipReader::FileInfo> files = zip.fileInfoList(); - QCOMPARE(files.count(), 2); - - QZipReader::FileInfo fi = files.at(0); - QVERIFY(fi.isValid()); - QCOMPARE(fi.filePath, QString("test")); - QCOMPARE(uint(fi.isDir), (uint) 1); - QCOMPARE(uint(fi.isFile), (uint) 0); - QCOMPARE(uint(fi.isSymLink), (uint) 0); - - QCOMPARE(fi.permissions,QFile::Permissions( QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner - | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser )); - - QCOMPARE(fi.lastModified, QDateTime::fromString("2005.11.11 13:08:02", "yyyy.MM.dd HH:mm:ss")); - - fi = files.at(1); - QVERIFY(fi.isValid()); - QCOMPARE(fi.filePath, QString("test/test.txt")); - QCOMPARE(uint(fi.isDir), (uint) 0); - QCOMPARE(uint(fi.isFile), (uint) 1); - QCOMPARE(uint(fi.isSymLink), (uint) 0); - - QVERIFY(fi.permissions == QFile::Permissions( QFile::ReadOwner | QFile::WriteOwner - | QFile::ReadUser | QFile::WriteUser )); - - QCOMPARE(fi.lastModified, QDateTime::fromString("2005.11.11 13:08:02", "yyyy.MM.dd HH:mm:ss")); - - QCOMPARE(zip.fileData("test/test.txt"), QByteArray("content\n")); - - fi = zip.entryInfoAt(-1); - QVERIFY(!fi.isValid()); -} - -void tst_QZip::symlinks() -{ - QZipReader zip(QFINDTESTDATA("/testdata/symlink.zip"), QIODevice::ReadOnly); - QList<QZipReader::FileInfo> files = zip.fileInfoList(); - QCOMPARE(files.count(), 2); - - QZipReader::FileInfo fi = files.at(0); - QVERIFY(fi.isValid()); - QCOMPARE(fi.filePath, QString("symlink")); - QVERIFY(!fi.isDir); - QVERIFY(!fi.isFile); - QVERIFY(fi.isSymLink); - - QCOMPARE(zip.fileData("symlink"), QByteArray("destination")); - - fi = files.at(1); - QVERIFY(fi.isValid()); - QCOMPARE(fi.filePath, QString("destination")); - QVERIFY(!fi.isDir); - QVERIFY(fi.isFile); - QVERIFY(!fi.isSymLink); -} - -void tst_QZip::readTest() -{ - QZipReader zip("foobar.zip", QIODevice::ReadOnly); // non existing file. - QList<QZipReader::FileInfo> files = zip.fileInfoList(); - QCOMPARE(files.count(), 0); - QByteArray b = zip.fileData("foobar"); - QCOMPARE(b.size(), 0); -} - -void tst_QZip::createArchive() -{ - QBuffer buffer; - QZipWriter zip(&buffer); - QByteArray fileContents("simple file contents\nline2\n"); - zip.addFile("My Filename", fileContents); - zip.close(); - QByteArray zipFile = buffer.buffer(); - - // QFile f("createArchiveTest.zip"); f.open(QIODevice::WriteOnly); f.write(zipFile); f.close(); - - QBuffer buffer2(&zipFile); - QZipReader zip2(&buffer2); - QList<QZipReader::FileInfo> files = zip2.fileInfoList(); - QCOMPARE(files.count(), 1); - QZipReader::FileInfo file = files.at(0); - QCOMPARE(file.filePath, QString("My Filename")); - QCOMPARE(uint(file.isDir), (uint) 0); - QCOMPARE(uint(file.isFile), (uint) 1); - QCOMPARE(uint(file.isSymLink), (uint) 0); - QCOMPARE(file.permissions, QFile::Permissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::WriteUser) ); - QCOMPARE(file.size, (long long) 27); - QCOMPARE(zip2.fileData("My Filename"), fileContents); -} - -QTEST_MAIN(tst_QZip) -#include "tst_qzip.moc" |