/**************************************************************************** ** ** 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 #include #include #include #include class tst_qquickstyledtext : public QObject { Q_OBJECT public: tst_qquickstyledtext() { } struct Format { enum Type { Bold = 0x01, Underline = 0x02, Italic = 0x04, Anchor = 0x08, StrikeOut = 0x10 }; Format(int t, int s, int l) : type(t), start(s), length(l) {} int type; int start; int length; }; typedef QList FormatList; static const QChar bullet; static const QChar disc; static const QChar square; private slots: void textOutput(); void textOutput_data(); void anchors(); void anchors_data(); void longString(); }; Q_DECLARE_METATYPE(tst_qquickstyledtext::FormatList); const QChar tst_qquickstyledtext::bullet(0x2022); const QChar tst_qquickstyledtext::disc(0x25e6); const QChar tst_qquickstyledtext::square(0x25a1); // For malformed input all we test is that we get the expected text and format out. // void tst_qquickstyledtext::textOutput_data() { QTest::addColumn("input"); QTest::addColumn("output"); QTest::addColumn("formats"); QTest::addColumn("modifiesFontSize"); QTest::newRow("empty") << "" << "" << FormatList() << false; QTest::newRow("empty tag") << "<>test" << "test" << FormatList() << false; QTest::newRow("nest opening") << ">test" << ">test" << FormatList() << false; QTest::newRow("nest closing") << "test</b>" << "test/b>" << (FormatList() << Format(Format::Bold, 0, 7)) << false; QTest::newRow("bold") << "bold" << "bold" << (FormatList() << Format(Format::Bold, 0, 4)) << false; QTest::newRow("bold 2") << ">>>>bold" << ">>>>bold" << (FormatList() << Format(Format::Bold, 0, 8)) << false; QTest::newRow("bold 3") << "bold<>/b>" << "bold/b>" << (FormatList() << Format(Format::Bold, 0, 7)) << false; QTest::newRow("italic") << "italic" << "italic" << (FormatList() << Format(Format::Italic, 0, 6)) << false; QTest::newRow("underline") << "underline" << "underline" << (FormatList() << Format(Format::Underline, 0, 9)) << false; QTest::newRow("strong") << "strong" << "strong" << (FormatList() << Format(Format::Bold, 0, 6)) << false; QTest::newRow("underline") << "underline" << "underline" << (FormatList() << Format(Format::Underline, 0, 9)) << false; QTest::newRow("strike out s") << "strike out" << "strike out" << (FormatList() << Format(Format::StrikeOut, 0, 10)) << false; QTest::newRow("strike out del") << "strike out" << "strike out" << (FormatList() << Format(Format::StrikeOut, 0, 10)) << false; QTest::newRow("strike out not s") << "this is not a test" << "this is not a test" << (FormatList() << Format(Format::StrikeOut, 8, 3)) << false; QTest::newRow("strike out not del") << "this is not a test" << "this is not a test" << (FormatList() << Format(Format::StrikeOut, 8, 3)) << false; QTest::newRow("missing >") << "text") << "text") << "text<" << "text" << (FormatList() << Format(Format::Bold, 0, 4)) << false; QTest::newRow("missing ") << "text" << "text" << (FormatList() << Format(Format::Bold, 0, 4)) << false; QTest::newRow("nested") << "text italic bold" << "text italic bold" << (FormatList() << Format(Format::Bold, 0, 5) << Format(Format::Bold | Format::Italic, 5, 6) << Format(Format::Bold, 11, 5)) << false; QTest::newRow("bad nest") << "text italic" << "text italic" << (FormatList() << Format(Format::Bold, 0, 5) << Format(Format::Bold | Format::Italic, 5, 6)) << false; QTest::newRow("font color") << "red text" << "red text" << (FormatList() << Format(0, 0, 8)) << false; QTest::newRow("font color: single quote") << "red text" << "red text" << (FormatList() << Format(0, 0, 8)) << false; QTest::newRow("font size") << "text" << "text" << (FormatList() << Format(0, 0, 4)) << true; QTest::newRow("font empty") << "text" << "text" << FormatList() << false; QTest::newRow("font bad 1") << "text" << "text" << FormatList() << false; QTest::newRow("font bad 2") << "text" << "" << FormatList() << false; QTest::newRow("extra close") << "text" << "text" << (FormatList() << Format(Format::Bold, 0, 4)) << false; QTest::newRow("extra space") << "text" << "text" << (FormatList() << Format(Format::Bold, 0, 4)) << false; QTest::newRow("entities") << "<b>"this" & that</b>" << "\"this\" & that" << FormatList() << false; QTest::newRow("newline") << "text
more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false; QTest::newRow("self-closing newline") << "text
more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false; QTest::newRow("paragraph") << "text

more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false; QTest::newRow("paragraph closed") << "text

more text

more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false; QTest::newRow("paragraph closed bold") << "text

more text

more text
" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << (FormatList() << Format(Format::Bold, 0, 24)) << false; QTest::newRow("unknown tag") << "underline not" << "underline not" << (FormatList() << Format(Format::Underline, 0, 9)) << false; QTest::newRow("ordered list") << "
  1. one
  2. two" << QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") << FormatList() << false; QTest::newRow("ordered list closed") << "
    1. one
    2. two
    " << QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false; QTest::newRow("ordered list alpha") << "
    1. one
    2. two
    " << QString(6, QChar::Nbsp) + QLatin1String("a.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("b.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false; QTest::newRow("ordered list upper alpha") << "
    1. one
    2. two
    " << QString(6, QChar::Nbsp) + QLatin1String("A.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("B.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false; QTest::newRow("ordered list roman") << "
    1. one
    2. two
    " << QString(6, QChar::Nbsp) + QLatin1String("i.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("ii.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false; QTest::newRow("ordered list upper roman") << "
    1. one
    2. two
    " << QString(6, QChar::Nbsp) + QLatin1String("I.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("II.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false; QTest::newRow("ordered list bad") << "
    1. one
    2. two
    " << QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false; QTest::newRow("unordered list") << "
    • one
    • two" << QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") << FormatList() << false; QTest::newRow("unordered list closed") << "
      • one
      • two
      " << QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false; QTest::newRow("unordered list disc") << "
      • one
      • two
      " << QString(6, QChar::Nbsp) + disc + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + disc + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false; QTest::newRow("unordered list square") << "
      • one
      • two
      " << QString(6, QChar::Nbsp) + square + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + square + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false; QTest::newRow("unordered list bad") << "
      • one
      • two
      " << QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false; QTest::newRow("header close") << "

      head

      more" << QLatin1String("head") + QChar(QChar::LineSeparator) + QLatin1String("more") << (FormatList() << Format(Format::Bold, 0, 4)) << true; QTest::newRow("h0") << "head" << "head" << FormatList() << false; QTest::newRow("h1") << "

      head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true; QTest::newRow("h2") << "

      head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true; QTest::newRow("h3") << "

      head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true; QTest::newRow("h4") << "

      head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true; QTest::newRow("h5") << "

      head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true; QTest::newRow("h6") << "
      head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true; QTest::newRow("h7") << "head" << "head" << FormatList() << false; QTest::newRow("pre") << "normal
      pre text
      normal" << QLatin1String("normal") + QChar(QChar::LineSeparator) + QLatin1String("pre") + QChar(QChar::Nbsp) + QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("normal") << (FormatList() << Format(0, 6, 9)) << false; QTest::newRow("pre lb") << "normal
      pre\n text
      normal" << QLatin1String("normal") + QChar(QChar::LineSeparator) + QLatin1String("pre") + QChar(QChar::LineSeparator) + QChar(QChar::Nbsp) + QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("normal") << (FormatList() << Format(0, 6, 10)) << false; QTest::newRow("line feed") << "line\nfeed" << "line feed" << FormatList() << false; QTest::newRow("leading whitespace") << " leading whitespace" << "leading whitespace" << FormatList() << false; QTest::newRow("trailing whitespace") << "trailing whitespace " << "trailing whitespace" << FormatList() << false; QTest::newRow("consecutive whitespace") << " consecutive \t \n whitespace" << "consecutive whitespace" << FormatList() << false; QTest::newRow("space after newline") << "text
      more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false; QTest::newRow("space after paragraph") << "text

      more text

      more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false; QTest::newRow("space in header") << "

      head

      " << QLatin1String("head") + QChar(QChar::LineSeparator) << (FormatList() << Format(Format::Bold, 0, 4)) << true; QTest::newRow("space before bold") << "this is bold" << "this is bold" << (FormatList() << Format(Format::Bold, 8, 4)) << false; QTest::newRow("space leading bold") << "this is bold" << "this is bold" << (FormatList() << Format(Format::Bold, 7, 5)) << false; QTest::newRow("space trailing bold") << "this is bold " << "this is bold " << (FormatList() << Format(Format::Bold, 8, 5)) << false; QTest::newRow("img") << "ab" << "a b" << FormatList() << false; QTest::newRow("tag mix") << "dsgfhghjdfgdfg
      ewrqjklhj" << "dsgfhghjdfgdfgewrqjklhj" << (FormatList() << Format(Format::Bold, 2, 3)) << false; QTest::newRow("named html entities") << "> < & "  " << QLatin1String("> < & \" ") + QChar(QChar::Nbsp) << FormatList() << false; QTest::newRow("invalid html entities") << "a &hello & a &goodbye;" << "a &hello & a " << FormatList() << false; } void tst_qquickstyledtext::textOutput() { QFETCH(QString, input); QFETCH(QString, output); QFETCH(FormatList, formats); QFETCH(bool, modifiesFontSize); QTextLayout layout; QList imgTags; bool fontSizeModified = false; QQuickStyledText::parse(input, layout, imgTags, QUrl(), nullptr, false, &fontSizeModified); QCOMPARE(layout.text(), output); const QVector layoutFormats = layout.formats(); QCOMPARE(layoutFormats.count(), formats.count()); for (int i = 0; i < formats.count(); ++i) { QCOMPARE(layoutFormats.at(i).start, formats.at(i).start); QCOMPARE(layoutFormats.at(i).length, formats.at(i).length); if (formats.at(i).type & Format::Bold) QCOMPARE(layoutFormats.at(i).format.fontWeight(), int(QFont::Bold)); else QCOMPARE(layoutFormats.at(i).format.fontWeight(), int(QFont::Normal)); QVERIFY(layoutFormats.at(i).format.fontItalic() == bool(formats.at(i).type & Format::Italic)); QVERIFY(layoutFormats.at(i).format.fontUnderline() == bool(formats.at(i).type & Format::Underline)); QVERIFY(layoutFormats.at(i).format.fontStrikeOut() == bool(formats.at(i).type & Format::StrikeOut)); } QCOMPARE(fontSizeModified, modifiesFontSize); } void tst_qquickstyledtext::anchors() { QFETCH(QString, input); QFETCH(QString, output); QFETCH(FormatList, formats); QTextLayout layout; QList imgTags; bool fontSizeModified = false; QQuickStyledText::parse(input, layout, imgTags, QUrl(), nullptr, false, &fontSizeModified); QCOMPARE(layout.text(), output); const QVector layoutFormats = layout.formats(); QCOMPARE(layoutFormats.count(), formats.count()); for (int i = 0; i < formats.count(); ++i) { QCOMPARE(layoutFormats.at(i).start, formats.at(i).start); QCOMPARE(layoutFormats.at(i).length, formats.at(i).length); QVERIFY(layoutFormats.at(i).format.isAnchor() == bool(formats.at(i).type & Format::Anchor)); } } void tst_qquickstyledtext::anchors_data() { QTest::addColumn("input"); QTest::addColumn("output"); QTest::addColumn("formats"); QTest::newRow("empty 1") << "Test string with url." << "Test string with url." << FormatList(); QTest::newRow("empty 2") << "Test string with url." << "Test string with url." << FormatList(); QTest::newRow("unknown attr") << "Test string with @ok-hostname\">url." << "Test string with url." << FormatList(); QTest::newRow("close") << "Test string with @ok-hostname\"/>url." << "Test string with url." << (FormatList() << Format(Format::Anchor, 17, 4)); QTest::newRow("username") << "Test string with @ok-hostname\">url." << "Test string with url." << (FormatList() << Format(Format::Anchor, 17, 3)); QTest::newRow("query") << "Test string with url." << "Test string with url." << (FormatList() << Format(Format::Anchor, 17, 3)); QTest::newRow("ipv6") << "Test string with url." << "Test string with url." << (FormatList() << Format(Format::Anchor, 17, 3)); QTest::newRow("uni") << "Test string with url." << "Test string with url." << (FormatList() << Format(Format::Anchor, 17, 3)); QTest::newRow("utf8") << "Test string with url." << "Test string with url." << (FormatList() << Format(Format::Anchor, 17, 3)); } void tst_qquickstyledtext::longString() { QTextLayout layout; QList imgTags; bool fontSizeModified = false; QString input(9999999, QChar('.')); QQuickStyledText::parse(input, layout, imgTags, QUrl(), nullptr, false, &fontSizeModified); QCOMPARE(layout.text(), input); input = QString(9999999, QChar('\t')); // whitespace QQuickStyledText::parse(input, layout, imgTags, QUrl(), nullptr, false, &fontSizeModified); QCOMPARE(layout.text(), QString("")); } QTEST_MAIN(tst_qquickstyledtext) #include "tst_qquickstyledtext.moc"