summaryrefslogtreecommitdiffstats
path: root/tests/auto/gui/text
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/gui/text')
-rw-r--r--tests/auto/gui/text/qcssparser/tst_qcssparser.cpp29
-rw-r--r--tests/auto/gui/text/qfont/BLACKLIST2
-rw-r--r--tests/auto/gui/text/qfont/tst_qfont.cpp26
-rw-r--r--tests/auto/gui/text/qfontcache/tst_qfontcache.cpp2
-rw-r--r--tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp4
-rw-r--r--tests/auto/gui/text/qglyphrun/BLACKLIST1
-rw-r--r--tests/auto/gui/text/qstatictext/tst_qstatictext.cpp2
-rw-r--r--tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp29
-rw-r--r--tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp153
-rw-r--r--tests/auto/gui/text/qtextdocumentlayout/BLACKLIST4
-rw-r--r--tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp40
-rw-r--r--tests/auto/gui/text/qtextlist/tst_qtextlist.cpp2
-rw-r--r--tests/auto/gui/text/qtextmarkdownimporter/data/headingBulletsContinuations.md28
-rw-r--r--tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md17
-rw-r--r--tests/auto/gui/text/qtextmarkdownimporter/qtextmarkdownimporter.pro9
-rw-r--r--tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp226
-rw-r--r--tests/auto/gui/text/qtextmarkdownwriter/BLACKLIST2
-rw-r--r--tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md62
-rw-r--r--tests/auto/gui/text/qtextmarkdownwriter/data/example.md95
-rw-r--r--tests/auto/gui/text/qtextmarkdownwriter/data/headingsAndLists.md12
-rw-r--r--tests/auto/gui/text/qtextmarkdownwriter/data/wordWrap.md13
-rw-r--r--tests/auto/gui/text/qtextmarkdownwriter/qtextmarkdownwriter.pro9
-rw-r--r--tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp473
-rw-r--r--tests/auto/gui/text/qtexttable/qtexttable.pro2
-rw-r--r--tests/auto/gui/text/qtexttable/tst_qtexttable.cpp150
-rw-r--r--tests/auto/gui/text/text.pro4
26 files changed, 1359 insertions, 37 deletions
diff --git a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp
index 7dbeb13aa7..7764a716ca 100644
--- a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp
+++ b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp
@@ -78,6 +78,8 @@ private slots:
void extractBorder();
void noTextDecoration();
void quotedAndUnquotedIdentifiers();
+ void whitespaceValues_data();
+ void whitespaceValues();
};
void tst_QCssParser::scanner_data()
@@ -1746,6 +1748,33 @@ void tst_QCssParser::quotedAndUnquotedIdentifiers()
QCOMPARE(decls.at(1).d->values.first().toString(), QLatin1String("bold"));
}
+void tst_QCssParser::whitespaceValues_data()
+{
+ QTest::addColumn<QString>("value");
+
+ QTest::newRow("normal") << "normal";
+ QTest::newRow("inherit") << "inherit";
+ QTest::newRow("nowrap") << "nowrap";
+ QTest::newRow("pre") << "pre";
+ QTest::newRow("pre-wrap") << "pre-wrap";
+ QTest::newRow("pre-line") << "pre-line";
+}
+
+void tst_QCssParser::whitespaceValues()
+{
+ QFETCH(QString, value);
+ QCss::Parser parser(QString("foo { white-space: %1 }").arg(value));
+ QCss::StyleSheet sheet;
+ QVERIFY(parser.parse(&sheet));
+
+ QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ?
+ sheet.styleRules.at(0) : *sheet.nameIndex.begin();
+ QCOMPARE(rule.declarations.size(), 1);
+
+ QCOMPARE(rule.declarations.at(0).d->property, QLatin1String("white-space"));
+ QCOMPARE(rule.declarations.at(0).d->values.first().toString(), value);
+}
+
QTEST_MAIN(tst_QCssParser)
#include "tst_qcssparser.moc"
diff --git a/tests/auto/gui/text/qfont/BLACKLIST b/tests/auto/gui/text/qfont/BLACKLIST
deleted file mode 100644
index 42cb8408f4..0000000000
--- a/tests/auto/gui/text/qfont/BLACKLIST
+++ /dev/null
@@ -1,2 +0,0 @@
-[defaultFamily]
-b2qt
diff --git a/tests/auto/gui/text/qfont/tst_qfont.cpp b/tests/auto/gui/text/qfont/tst_qfont.cpp
index bb047d5461..9487436336 100644
--- a/tests/auto/gui/text/qfont/tst_qfont.cpp
+++ b/tests/auto/gui/text/qfont/tst_qfont.cpp
@@ -58,7 +58,9 @@ private slots:
void insertAndRemoveSubstitutions();
void serialize_data();
void serialize();
+#if QT_DEPRECATED_SINCE(5, 13)
void lastResortFont();
+#endif
void styleName();
void defaultFamily_data();
void defaultFamily();
@@ -493,6 +495,7 @@ void tst_QFont::serialize()
}
}
+#if QT_DEPRECATED_SINCE(5, 13)
// QFont::lastResortFont() may abort with qFatal() on QWS/QPA
// if absolutely no font is found. Just as ducumented for QFont::lastResortFont().
// This happens on our CI machines which run QWS autotests.
@@ -503,6 +506,7 @@ void tst_QFont::lastResortFont()
QFont font;
QVERIFY(!font.lastResortFont().isEmpty());
}
+#endif
void tst_QFont::styleName()
{
@@ -544,10 +548,10 @@ void tst_QFont::defaultFamily_data()
QTest::addColumn<QStringList>("acceptableFamilies");
QTest::newRow("serif") << QFont::Serif << (QStringList() << "Times New Roman" << "Times" << "Droid Serif" << getPlatformGenericFont("serif").split(","));
- QTest::newRow("monospace") << QFont::Monospace << (QStringList() << "Courier New" << "Monaco" << "Droid Sans Mono" << getPlatformGenericFont("monospace").split(","));
+ QTest::newRow("monospace") << QFont::Monospace << (QStringList() << "Courier New" << "Monaco" << "Menlo" << "Droid Sans Mono" << getPlatformGenericFont("monospace").split(","));
QTest::newRow("cursive") << QFont::Cursive << (QStringList() << "Comic Sans MS" << "Apple Chancery" << "Roboto" << "Droid Sans" << getPlatformGenericFont("cursive").split(","));
QTest::newRow("fantasy") << QFont::Fantasy << (QStringList() << "Impact" << "Zapfino" << "Roboto" << "Droid Sans" << getPlatformGenericFont("fantasy").split(","));
- QTest::newRow("sans-serif") << QFont::SansSerif << (QStringList() << "Arial" << "Lucida Grande" << "Roboto" << "Droid Sans" << "Segoe UI" << getPlatformGenericFont("sans-serif").split(","));
+ QTest::newRow("sans-serif") << QFont::SansSerif << (QStringList() << "Arial" << "Lucida Grande" << "Helvetica" << "Roboto" << "Droid Sans" << "Segoe UI" << getPlatformGenericFont("sans-serif").split(","));
}
void tst_QFont::defaultFamily()
@@ -637,37 +641,37 @@ void tst_QFont::sharing()
QFont f;
f.setStyleHint(QFont::Serif);
f.exactMatch(); // loads engine
- QCOMPARE(QFontPrivate::get(f)->ref.load(), 1);
+ QCOMPARE(QFontPrivate::get(f)->ref.loadRelaxed(), 1);
QVERIFY(QFontPrivate::get(f)->engineData);
- QCOMPARE(QFontPrivate::get(f)->engineData->ref.load(), 1 + refs_by_cache);
+ QCOMPARE(QFontPrivate::get(f)->engineData->ref.loadRelaxed(), 1 + refs_by_cache);
QFont f2(f);
QCOMPARE(QFontPrivate::get(f2), QFontPrivate::get(f));
- QCOMPARE(QFontPrivate::get(f2)->ref.load(), 2);
+ QCOMPARE(QFontPrivate::get(f2)->ref.loadRelaxed(), 2);
QVERIFY(QFontPrivate::get(f2)->engineData);
QCOMPARE(QFontPrivate::get(f2)->engineData, QFontPrivate::get(f)->engineData);
- QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 1 + refs_by_cache);
+ QCOMPARE(QFontPrivate::get(f2)->engineData->ref.loadRelaxed(), 1 + refs_by_cache);
f2.setKerning(!f.kerning());
QVERIFY(QFontPrivate::get(f2) != QFontPrivate::get(f));
- QCOMPARE(QFontPrivate::get(f2)->ref.load(), 1);
+ QCOMPARE(QFontPrivate::get(f2)->ref.loadRelaxed(), 1);
QVERIFY(QFontPrivate::get(f2)->engineData);
QCOMPARE(QFontPrivate::get(f2)->engineData, QFontPrivate::get(f)->engineData);
- QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 2 + refs_by_cache);
+ QCOMPARE(QFontPrivate::get(f2)->engineData->ref.loadRelaxed(), 2 + refs_by_cache);
f2 = f;
QCOMPARE(QFontPrivate::get(f2), QFontPrivate::get(f));
- QCOMPARE(QFontPrivate::get(f2)->ref.load(), 2);
+ QCOMPARE(QFontPrivate::get(f2)->ref.loadRelaxed(), 2);
QVERIFY(QFontPrivate::get(f2)->engineData);
QCOMPARE(QFontPrivate::get(f2)->engineData, QFontPrivate::get(f)->engineData);
- QCOMPARE(QFontPrivate::get(f2)->engineData->ref.load(), 1 + refs_by_cache);
+ QCOMPARE(QFontPrivate::get(f2)->engineData->ref.loadRelaxed(), 1 + refs_by_cache);
if (f.pointSize() > 0)
f2.setPointSize(f.pointSize() * 2 / 3);
else
f2.setPixelSize(f.pixelSize() * 2 / 3);
QVERIFY(QFontPrivate::get(f2) != QFontPrivate::get(f));
- QCOMPARE(QFontPrivate::get(f2)->ref.load(), 1);
+ QCOMPARE(QFontPrivate::get(f2)->ref.loadRelaxed(), 1);
QVERIFY(!QFontPrivate::get(f2)->engineData);
QVERIFY(QFontPrivate::get(f2)->engineData != QFontPrivate::get(f)->engineData);
}
diff --git a/tests/auto/gui/text/qfontcache/tst_qfontcache.cpp b/tests/auto/gui/text/qfontcache/tst_qfontcache.cpp
index 785cc3fef2..3d3211c7a2 100644
--- a/tests/auto/gui/text/qfontcache/tst_qfontcache.cpp
+++ b/tests/auto/gui/text/qfontcache/tst_qfontcache.cpp
@@ -217,7 +217,7 @@ void tst_QFontCache::clear()
#ifdef QT_BUILD_INTERNAL
QList<QFontEngine *> leakedEngines = QFontEngine_stopCollectingEngines();
-for (int i = 0; i < leakedEngines.size(); ++i) qWarning() << i << leakedEngines.at(i) << leakedEngines.at(i)->ref.load();
+for (int i = 0; i < leakedEngines.size(); ++i) qWarning() << i << leakedEngines.at(i) << leakedEngines.at(i)->ref.loadRelaxed();
// and we are not leaking!
QCOMPARE(leakedEngines.size(), 0);
#endif
diff --git a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp
index 064e37f73c..2b69801b59 100644
--- a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp
+++ b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp
@@ -211,8 +211,8 @@ void tst_QFontDatabase::widthTwoTimes()
f.setPixelSize(pixelSize);
QFontMetrics fm(f);
- int w1 = fm.charWidth(text, 0);
- int w2 = fm.charWidth(text, 0);
+ int w1 = fm.horizontalAdvance(text, 0);
+ int w2 = fm.horizontalAdvance(text, 0);
QCOMPARE(w1, w2);
}
diff --git a/tests/auto/gui/text/qglyphrun/BLACKLIST b/tests/auto/gui/text/qglyphrun/BLACKLIST
index d8dbdabb4b..57f32c683d 100644
--- a/tests/auto/gui/text/qglyphrun/BLACKLIST
+++ b/tests/auto/gui/text/qglyphrun/BLACKLIST
@@ -1,4 +1,3 @@
[mixedScripts]
ubuntu-18.04
b2qt
-windows
diff --git a/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp b/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp
index d00dc251d8..b091edb64d 100644
--- a/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp
+++ b/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp
@@ -681,7 +681,7 @@ static bool checkPixels(const QImage &image,
if (pixel != expectedRgb1 && pixel != expectedRgb2) {
QString message;
QDebug(&message) << "Color mismatch in image" << image
- << "at" << x << ',' << y << ':' << showbase << hex << pixel
+ << "at" << x << ',' << y << ':' << Qt::showbase << Qt::hex << pixel
<< "(expected: " << expectedRgb1 << ',' << expectedRgb2 << ')';
*errorMessage = message.toLocal8Bit();
return false;
diff --git a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
index 58810f73c1..52e56feb5a 100644
--- a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
+++ b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
@@ -50,6 +50,7 @@
#include <QDomDocument>
#include "common.h"
+// #define DEBUG_WRITE_OUTPUT
QT_FORWARD_DECLARE_CLASS(QTextDocument)
@@ -196,6 +197,7 @@ private:
void backgroundImage_checkExpectedHtml(const QTextDocument &doc);
void buildRegExpData();
static QString cssFontSizeString(const QFont &font);
+ void writeActualAndExpected(const char* testTag, const QString &actual, const QString &expected);
QTextDocument *doc;
QTextCursor cursor;
@@ -224,6 +226,27 @@ QString tst_QTextDocument::cssFontSizeString(const QFont &font)
: QString::number(font.pixelSize()) + QStringLiteral("px");
}
+void tst_QTextDocument::writeActualAndExpected(const char *testTag, const QString &actual, const QString &expected)
+{
+#ifdef DEBUG_WRITE_OUTPUT
+ {
+ QFile out(QDir::temp().absoluteFilePath(QLatin1String(testTag) + QLatin1String("-actual.html")));
+ out.open(QFile::WriteOnly);
+ out.write(actual.toUtf8());
+ out.close();
+ } {
+ QFile out(QDir::temp().absoluteFilePath(QLatin1String(testTag) + QLatin1String("-expected.html")));
+ out.open(QFile::WriteOnly);
+ out.write(expected.toUtf8());
+ out.close();
+ }
+#else
+ Q_UNUSED(testTag)
+ Q_UNUSED(actual)
+ Q_UNUSED(expected)
+#endif
+}
+
// Testing get/set functions
void tst_QTextDocument::getSetCheck()
{
@@ -1765,6 +1788,8 @@ void tst_QTextDocument::toHtml()
QString output = doc->toHtml();
+ writeActualAndExpected(QTest::currentDataTag(), output, expectedOutput);
+
QCOMPARE(output, expectedOutput);
QDomDocument document;
@@ -1962,6 +1987,8 @@ void tst_QTextDocument::toHtmlRootFrameProperties()
expectedOutput.replace("DEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"");
expectedOutput.append(htmlTail);
+ writeActualAndExpected(QTest::currentTestFunction(), doc.toHtml(), expectedOutput);
+
QCOMPARE(doc.toHtml(), expectedOutput);
}
@@ -2734,6 +2761,8 @@ void tst_QTextDocument::backgroundImage_checkExpectedHtml(const QTextDocument &d
.arg(defaultFont.weight() * 8)
.arg((defaultFont.italic() ? "italic" : "normal"));
+ writeActualAndExpected(QTest::currentTestFunction(), doc.toHtml(), expectedHtml);
+
QCOMPARE(doc.toHtml(), expectedHtml);
}
diff --git a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp
index fe0b6dae49..b6917f1208 100644
--- a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp
+++ b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp
@@ -34,6 +34,7 @@
#include <qtextdocumentfragment.h>
#include <qtexttable.h>
#include <qtextlist.h>
+#include <qregularexpression.h>
#include <qdebug.h>
#include <private/qtextdocument_p.h>
@@ -180,6 +181,11 @@ private slots:
void html_tableCellBackground();
void css_bodyBackground();
void css_tableCellBackground();
+ void css_tableCellBorder();
+ void css_tableCellBorderShorthand();
+ void css_tableCellAllBordersShorthand();
+ void css_tableCellOverrideOneBorder();
+ void css_tableBorderCollapse();
void css_fontWeight();
void css_float();
void css_textIndent();
@@ -944,7 +950,7 @@ void tst_QTextDocumentFragment::namedAnchorFragments3()
QCOMPARE(it.fragment().text(), QString::fromLatin1("T"));
QVERIFY(it.fragment().charFormat().isAnchor());
- QCOMPARE(it.fragment().charFormat().anchorName(), QString("target"));
+ QCOMPARE(it.fragment().charFormat().anchorNames().constFirst(), QLatin1String("target"));
QStringList targets; targets << "target" << "target2";
QCOMPARE(it.fragment().charFormat().anchorNames(), targets);
@@ -1271,11 +1277,11 @@ void tst_QTextDocumentFragment::html_whitespace_data()
QTest::newRow("2") << QString("<span> </span><span>nowhitespacehereplease</span>")
<< QString::fromLatin1("nowhitespacehereplease");
- QTest::newRow("3") << QString("<span style=\"white-space: pre;\"> white space here </span>")
- << QString::fromLatin1(" white space here ");
+ QTest::newRow("3") << QString("<span style=\"white-space: pre;\"> white space \n\n here </span>")
+ << QString::fromLatin1(" white space \n\n here ");
- QTest::newRow("4") << QString("<span style=\"white-space: pre-wrap;\"> white space here </span>")
- << QString::fromLatin1(" white space here ");
+ QTest::newRow("4") << QString("<span style=\"white-space: pre-wrap;\"> white space \n\n here </span>")
+ << QString::fromLatin1(" white space \n\n here ");
QTest::newRow("5") << QString("<a href=\"One.html\">One</a> <a href=\"Two.html\">Two</a> <b>Three</b>\n"
"<b>Four</b>")
@@ -1290,6 +1296,12 @@ void tst_QTextDocumentFragment::html_whitespace_data()
QTest::newRow("8") << QString("<table><tr><td><i>Blah</i></td></tr></table> <i>Blub</i>")
<< QString("\nBlah\nBlub");
+ QTest::newRow("9") << QString("<span style=\"white-space: nowrap;\"> white space \n\n here </span>")
+ << QString::fromLatin1("white space here ");
+
+ QTest::newRow("10") << QString("<span style=\"white-space: pre-line;\"> white space \n\n here </span>")
+ << QString::fromLatin1("white space\n\nhere ");
+
QTest::newRow("task116492") << QString("<p>a<font=\"Times\"> b </font>c</p>")
<< QString("a b c");
@@ -1746,6 +1758,135 @@ void tst_QTextDocumentFragment::css_tableCellBackground()
QCOMPARE(cell.format().background().style(), Qt::TexturePattern);
}
+void tst_QTextDocumentFragment::css_tableCellBorder()
+{
+ const char html[] = "<body><table><tr><td style=\"border-width:8px;border-color:green;border-style:groove;border-left-style:dashed;border-left-color:red;border-left-width:4px\">Foo</td></tr></table></body>";
+ doc->setHtml(html);
+
+ cursor.movePosition(QTextCursor::Start);
+ cursor.movePosition(QTextCursor::NextBlock);
+ QTextTable *table = cursor.currentTable();
+ QVERIFY(table);
+
+ QTextTableCell cell = table->cellAt(0, 0);
+ QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
+ QCOMPARE(cellFormat.leftBorder(), qreal(4));
+ QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("red")));
+ QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
+
+ QCOMPARE(cellFormat.rightBorder(), qreal(8));
+ QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green")));
+ QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Groove);
+
+ QCOMPARE(cellFormat.bottomBorder(), qreal(8));
+ QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green")));
+ QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Groove);
+
+ QCOMPARE(cellFormat.topBorder(), qreal(8));
+ QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green")));
+ QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Groove);
+}
+
+void tst_QTextDocumentFragment::css_tableCellBorderShorthand()
+{
+ const char html[] = "<body><table><tr><td style=\"border-left:1px solid green;border-right:2px dashed red;border-bottom:3px dotted yellow;border-top:4px dot-dash blue\">Foo</td></tr></table></body>";
+ doc->setHtml(html);
+
+ cursor.movePosition(QTextCursor::Start);
+ cursor.movePosition(QTextCursor::NextBlock);
+ QTextTable *table = cursor.currentTable();
+ QVERIFY(table);
+
+ QTextTableCell cell = table->cellAt(0, 0);
+ QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
+ QCOMPARE(cellFormat.leftBorder(), qreal(1));
+ QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("green")));
+ QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Solid);
+
+ QCOMPARE(cellFormat.rightBorder(), qreal(2));
+ QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("red")));
+ QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
+
+ QCOMPARE(cellFormat.bottomBorder(), qreal(3));
+ QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("yellow")));
+ QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dotted);
+
+ QCOMPARE(cellFormat.topBorder(), qreal(4));
+ QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("blue")));
+ QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_DotDash);
+}
+
+void tst_QTextDocumentFragment::css_tableCellAllBordersShorthand()
+{
+ const char html[] = "<body><table><tr><td style=\"border:2px dashed green\">Foo</td></tr></table></body>";
+ doc->setHtml(html);
+
+ cursor.movePosition(QTextCursor::Start);
+ cursor.movePosition(QTextCursor::NextBlock);
+ QTextTable *table = cursor.currentTable();
+ QVERIFY(table);
+
+ QTextTableCell cell = table->cellAt(0, 0);
+ QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
+ QCOMPARE(cellFormat.leftBorder(), qreal(2));
+ QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("green")));
+ QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
+
+ QCOMPARE(cellFormat.rightBorder(), qreal(2));
+ QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green")));
+ QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
+
+ QCOMPARE(cellFormat.bottomBorder(), qreal(2));
+ QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green")));
+ QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
+
+ QCOMPARE(cellFormat.topBorder(), qreal(2));
+ QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green")));
+ QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
+}
+
+void tst_QTextDocumentFragment::css_tableCellOverrideOneBorder()
+{
+ const char html[] = "<body><table><tr><td style=\"border:2px dashed green;border-left:4px solid red\">Foo</td></tr></table></body>";
+ doc->setHtml(html);
+
+ cursor.movePosition(QTextCursor::Start);
+ cursor.movePosition(QTextCursor::NextBlock);
+ QTextTable *table = cursor.currentTable();
+ QVERIFY(table);
+
+ QTextTableCell cell = table->cellAt(0, 0);
+ QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
+ QCOMPARE(cellFormat.leftBorder(), qreal(4));
+ QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("red")));
+ QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Solid);
+
+ QCOMPARE(cellFormat.rightBorder(), qreal(2));
+ QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green")));
+ QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
+
+ QCOMPARE(cellFormat.bottomBorder(), qreal(2));
+ QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green")));
+ QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
+
+ QCOMPARE(cellFormat.topBorder(), qreal(2));
+ QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green")));
+ QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Dashed);
+}
+
+void tst_QTextDocumentFragment::css_tableBorderCollapse()
+{
+ const char html[] = "<body><table style=\"border-collapse:collapse\"><tr><td>Foo</td></tr></table></body>";
+ doc->setHtml(html);
+
+ cursor.movePosition(QTextCursor::Start);
+ cursor.movePosition(QTextCursor::NextBlock);
+ QTextTable *table = cursor.currentTable();
+ QVERIFY(table);
+
+ QCOMPARE(table->format().borderCollapse(), true);
+}
+
void tst_QTextDocumentFragment::css_cellPaddings()
{
const char html[] = "<body><table><tr><td style=\"padding-left:1\">Foo</td>"
@@ -1925,7 +2066,7 @@ void tst_QTextDocumentFragment::html_nobr()
QString text = doc->begin().begin().fragment().text();
QString expectedText = input;
- expectedText.replace(QRegExp("\\s+"), QString(QChar::Nbsp));
+ expectedText.replace(QRegularExpression("\\s+"), QString(QChar::Nbsp));
QCOMPARE(text, expectedText);
}
diff --git a/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST b/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST
index b13b2497d3..5c81e74aa0 100644
--- a/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST
+++ b/tests/auto/gui/text/qtextdocumentlayout/BLACKLIST
@@ -1,2 +1,4 @@
[imageAtRightAlignedTab]
-linux
+rhel-6.6
+rhel-7.4
+rhel-7.6
diff --git a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
index f0a32c2ed4..2dcca0209e 100644
--- a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
+++ b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
@@ -138,6 +138,7 @@ private slots:
void noModificationOfInputString();
void superscriptCrash_qtbug53911();
void showLineAndParagraphSeparatorsCrash();
+ void koreanWordWrap();
void tooManyDirectionalCharctersCrash_qtbug77819();
private:
@@ -2067,7 +2068,12 @@ void tst_QTextLayout::cursorInLigatureWithMultipleLines()
void tst_QTextLayout::xToCursorForLigatures()
{
+#if defined(Q_OS_WIN32)
+ QTextLayout layout("fi", QFont("Calibri", 20));
+#else
QTextLayout layout("fi", QFont("Times", 20));
+#endif
+
layout.setCacheEnabled(true);
layout.beginLayout();
QTextLine line = layout.createLine();
@@ -2228,7 +2234,6 @@ void tst_QTextLayout::superscriptCrash_qtbug53911()
for (int j = 0; j < 4; ++j) {
QTextLayout* newTextLayout = new QTextLayout();
newTextLayout->setText(layoutText);
- QList<QTextLayout::FormatRange> formatRanges;
QTextLayout::FormatRange formatRange;
formatRange.format.setFont(QFont());
@@ -2257,8 +2262,7 @@ void tst_QTextLayout::superscriptCrash_qtbug53911()
formatRange.start = 0;
formatRange.length = layoutText.size();
- formatRanges << formatRange;
- newTextLayout->setAdditionalFormats(formatRanges);
+ newTextLayout->setFormats({formatRange});
textLayouts.push_front(newTextLayout);
}
@@ -2289,10 +2293,7 @@ void tst_QTextLayout::nbspWithFormat()
formatRange.length = 1;
formatRange.format.setFontUnderline(true);
- QList<QTextLayout::FormatRange> overrides;
- overrides.append(formatRange);
-
- layout.setAdditionalFormats(overrides);
+ layout.setFormats({formatRange});
layout.beginLayout();
forever {
@@ -2310,6 +2311,31 @@ void tst_QTextLayout::nbspWithFormat()
QCOMPARE(layout.lineAt(1).textLength(), s2.length() + 1 + s3.length());
}
+void tst_QTextLayout::koreanWordWrap()
+{
+ QString s = QString::fromUtf8("안녕하세요 여러분!");
+ QTextLayout layout;
+ QTextOption option = layout.textOption();
+ option.setWrapMode(QTextOption::WordWrap);
+ option.setFlags(QTextOption::Flag(QTextOption::IncludeTrailingSpaces));
+ layout.setTextOption(option);
+ layout.setText(s);
+
+ QFontMetrics metrics(layout.font());
+
+ layout.beginLayout();
+ forever {
+ QTextLine line = layout.createLine();
+ if (!line.isValid())
+ break;
+ line.setLineWidth(metrics.horizontalAdvance(s) * 0.8);
+ }
+ layout.endLayout();
+ QCOMPARE(layout.lineCount(), 2);
+ QCOMPARE(layout.lineAt(0).textLength(), 6);
+ QCOMPARE(layout.lineAt(1).textLength(), 4);
+}
+
void tst_QTextLayout::tooManyDirectionalCharctersCrash_qtbug77819()
{
QString data;
diff --git a/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp b/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp
index d623ce4044..93e40e7f23 100644
--- a/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp
+++ b/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp
@@ -314,7 +314,7 @@ void tst_QTextList::partialRemoval()
selection.deleteChar(); // deletes the second list
QVERIFY(!secondList);
- QVERIFY(!firstList->isEmpty());
+ QVERIFY(firstList->count() > 0);
doc->undo();
}
diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/headingBulletsContinuations.md b/tests/auto/gui/text/qtextmarkdownimporter/data/headingBulletsContinuations.md
new file mode 100644
index 0000000000..99eb633d17
--- /dev/null
+++ b/tests/auto/gui/text/qtextmarkdownimporter/data/headingBulletsContinuations.md
@@ -0,0 +1,28 @@
+# heading
+- bullet 1
+ continuation line 1, indented via tab
+- bullet 2
+ continuation line 2, indented via 4 spaces
+- bullet 3
+
+ continuation paragraph 3, indented via tab
+
+ - bullet 3.1
+
+ continuation paragraph 3.1, indented via 4 spaces
+
+ - bullet 3.2
+ continuation line, indented via 2 tabs
+- bullet 4
+
+ continuation paragraph 4, indented via 4 spaces
+ and continuing onto another line too
+
+- bullet 5
+
+ continuation paragraph 5, indented via 2 spaces and continuing onto another
+ line too
+
+- bullet 6
+
+plain old paragraph at the end
diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md b/tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md
new file mode 100644
index 0000000000..7a0d5388ad
--- /dev/null
+++ b/tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md
@@ -0,0 +1,17 @@
+Heading
+-------
+***
+stars
+- bullet
+ ** not a bullet or a rule, just two stars
+- [ ] unchecked
+
+ --- indented too far, so not a rule
+* * *
+stars with tabs between
+***
+stars with whitespace after
+---
+hyphens with whitespace after
+_____
+underscores with whitespace after
diff --git a/tests/auto/gui/text/qtextmarkdownimporter/qtextmarkdownimporter.pro b/tests/auto/gui/text/qtextmarkdownimporter/qtextmarkdownimporter.pro
new file mode 100644
index 0000000000..7b7fb61244
--- /dev/null
+++ b/tests/auto/gui/text/qtextmarkdownimporter/qtextmarkdownimporter.pro
@@ -0,0 +1,9 @@
+CONFIG += testcase
+TARGET = tst_qtextmarkdownimporter
+QT += core-private gui-private testlib
+SOURCES += tst_qtextmarkdownimporter.cpp
+TESTDATA += \
+ data/thematicBreaks.md \
+ data/headingBulletsContinuations.md \
+
+DEFINES += SRCDIR=\\\"$$PWD\\\"
diff --git a/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp b/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp
new file mode 100644
index 0000000000..2f0b877799
--- /dev/null
+++ b/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QTextDocument>
+#include <QTextCursor>
+#include <QTextBlock>
+#include <QTextList>
+#include <QTextTable>
+#include <QBuffer>
+#include <QDebug>
+
+#include <private/qtextmarkdownimporter_p.h>
+
+// #define DEBUG_WRITE_HTML
+
+Q_LOGGING_CATEGORY(lcTests, "qt.text.tests")
+
+static const QChar LineBreak = QChar(0x2028);
+static const QChar Tab = QLatin1Char('\t');
+static const QChar Space = QLatin1Char(' ');
+static const QChar Period = QLatin1Char('.');
+
+class tst_QTextMarkdownImporter : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void headingBulletsContinuations();
+ void thematicBreaks();
+ void lists_data();
+ void lists();
+};
+
+void tst_QTextMarkdownImporter::headingBulletsContinuations()
+{
+ const QStringList expectedBlocks = QStringList() <<
+ "" << // we could do without this blank line before the heading, but currently it happens
+ "heading" <<
+ "bullet 1 continuation line 1, indented via tab" <<
+ "bullet 2 continuation line 2, indented via 4 spaces" <<
+ "bullet 3" <<
+ "continuation paragraph 3, indented via tab" <<
+ "bullet 3.1" <<
+ "continuation paragraph 3.1, indented via 4 spaces" <<
+ "bullet 3.2 continuation line, indented via 2 tabs" <<
+ "bullet 4" <<
+ "continuation paragraph 4, indented via 4 spaces and continuing onto another line too" <<
+ "bullet 5" <<
+ // indenting by only 2 spaces is perhaps non-standard but currently is OK
+ "continuation paragraph 5, indented via 2 spaces and continuing onto another line too" <<
+ "bullet 6" <<
+ "plain old paragraph at the end";
+
+ QFile f(QFINDTESTDATA("data/headingBulletsContinuations.md"));
+ QVERIFY(f.open(QFile::ReadOnly | QIODevice::Text));
+ QString md = QString::fromUtf8(f.readAll());
+ f.close();
+
+ QTextDocument doc;
+ QTextMarkdownImporter(QTextMarkdownImporter::DialectGitHub).import(&doc, md);
+ QTextFrame::iterator iterator = doc.rootFrame()->begin();
+ QTextFrame *currentFrame = iterator.currentFrame();
+ QStringList::const_iterator expectedIt = expectedBlocks.constBegin();
+ int i = 0;
+ while (!iterator.atEnd()) {
+ // There are no child frames
+ QCOMPARE(iterator.currentFrame(), currentFrame);
+ // Check whether we got the right child block
+ QTextBlock block = iterator.currentBlock();
+ QCOMPARE(block.text().contains(LineBreak), false);
+ QCOMPARE(block.text().contains(Tab), false);
+ QVERIFY(!block.text().startsWith(Space));
+ int expectedIndentation = 0;
+ if (block.text().contains(QLatin1String("continuation paragraph")))
+ expectedIndentation = (block.text().contains(Period) ? 2 : 1);
+ qCDebug(lcTests) << i << "child block" << block.text() << "indentation" << block.blockFormat().indent();
+ QVERIFY(expectedIt != expectedBlocks.constEnd());
+ QCOMPARE(block.text(), *expectedIt);
+ if (i > 2)
+ QCOMPARE(block.blockFormat().indent(), expectedIndentation);
+ ++iterator;
+ ++expectedIt;
+ ++i;
+ }
+ QCOMPARE(expectedIt, expectedBlocks.constEnd());
+
+#ifdef DEBUG_WRITE_HTML
+ {
+ QFile out("/tmp/headingBulletsContinuations.html");
+ out.open(QFile::WriteOnly);
+ out.write(doc.toHtml().toLatin1());
+ out.close();
+ }
+#endif
+}
+
+void tst_QTextMarkdownImporter::thematicBreaks()
+{
+ int horizontalRuleCount = 0;
+ int textLinesCount = 0;
+
+ QFile f(QFINDTESTDATA("data/thematicBreaks.md"));
+ QVERIFY(f.open(QFile::ReadOnly | QIODevice::Text));
+ QString md = QString::fromUtf8(f.readAll());
+ f.close();
+
+ QTextDocument doc;
+ QTextMarkdownImporter(QTextMarkdownImporter::DialectGitHub).import(&doc, md);
+ QTextFrame::iterator iterator = doc.rootFrame()->begin();
+ QTextFrame *currentFrame = iterator.currentFrame();
+ int i = 0;
+ 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();
+ if (block.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth))
+ ++horizontalRuleCount;
+ else if (!block.text().isEmpty())
+ ++textLinesCount;
+ qCDebug(lcTests) << i << (block.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth) ? QLatin1String("- - -") : block.text());
+ ++iterator;
+ ++i;
+ }
+ QCOMPARE(horizontalRuleCount, 5);
+ QCOMPARE(textLinesCount, 9);
+
+#ifdef DEBUG_WRITE_HTML
+ {
+ QFile out("/tmp/thematicBreaks.html");
+ out.open(QFile::WriteOnly);
+ out.write(doc.toHtml().toLatin1());
+ out.close();
+ }
+#endif
+}
+
+void tst_QTextMarkdownImporter::lists_data()
+{
+ QTest::addColumn<QString>("input");
+ 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("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";
+ 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 + 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 1. + d\n";
+}
+
+void tst_QTextMarkdownImporter::lists()
+{
+ QFETCH(QString, input);
+ QFETCH(int, expectedItemCount);
+ QFETCH(bool, expectedEmptyItems);
+ QFETCH(QString, rewrite);
+
+ QTextDocument doc;
+ doc.setMarkdown(input); // QTBUG-78870 : don't crash
+ QTextFrame::iterator iterator = doc.rootFrame()->begin();
+ QTextFrame *currentFrame = iterator.currentFrame();
+ int i = 0;
+ int itemCount = 0;
+ bool emptyItems = true;
+ 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();
+ if (block.textList()) {
+ ++itemCount;
+ if (!block.text().isEmpty())
+ emptyItems = false;
+ }
+ qCDebug(lcTests, "%d %s%s", i,
+ (block.textList() ? "<li>" : "<p>"), qPrintable(block.text()));
+ ++iterator;
+ ++i;
+ }
+ QCOMPARE(itemCount, expectedItemCount);
+ QCOMPARE(emptyItems, expectedEmptyItems);
+ QCOMPARE(doc.toMarkdown(), rewrite);
+}
+
+QTEST_MAIN(tst_QTextMarkdownImporter)
+#include "tst_qtextmarkdownimporter.moc"
diff --git a/tests/auto/gui/text/qtextmarkdownwriter/BLACKLIST b/tests/auto/gui/text/qtextmarkdownwriter/BLACKLIST
new file mode 100644
index 0000000000..0ce46130ce
--- /dev/null
+++ b/tests/auto/gui/text/qtextmarkdownwriter/BLACKLIST
@@ -0,0 +1,2 @@
+[rewriteDocument]
+winrt
diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md
new file mode 100644
index 0000000000..6336d0219f
--- /dev/null
+++ b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md
@@ -0,0 +1,62 @@
+In 1958, Mahatma Gandhi was quoted as follows:
+
+> The Earth provides enough to satisfy every man's need but not for every man's
+> greed.
+
+In [The CommonMark Specification](https://spec.commonmark.org/0.29/) John
+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/)
+> > )
+
+> 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.
+> +
+> List item one continued with a second paragraph followed by an
+> Indented block.
+> +
+> .................
+> $ ls *.sh
+> $ mv *.sh ~/tmp
+> .................
+> +
+> List item continued with a third paragraph.
+>
+> 2. List item two continued with an open block.
+> ...
+> ```
+The quotation includes an embedded quotation and a code quotation and ends with
+an ellipsis due to being incomplete.
+
+Now let's have an indented code block:
+
+ #include <stdio.h>
+
+ int main(void)
+ {
+ printf("# hello markdown\n");
+ return 0;
+ }
+
+and end with a fenced code block:
+~~~ pseudocode
+#include <something.h>
+#include <else.h>
+
+a block {
+ a statement;
+ another statement;
+}
+~~~
+
diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/example.md b/tests/auto/gui/text/qtextmarkdownwriter/data/example.md
new file mode 100644
index 0000000000..0c3f34e09d
--- /dev/null
+++ b/tests/auto/gui/text/qtextmarkdownwriter/data/example.md
@@ -0,0 +1,95 @@
+# QTextEdit
+
+The QTextEdit widget is an advanced editor that supports formatted rich text.
+It can be used to display HTML and other rich document formats. Internally,
+QTextEdit uses the QTextDocument class to describe both the high-level
+structure of each document and the low-level formatting of paragraphs.
+
+If you are viewing this document in the textedit example, you can edit this
+document to explore Qt's rich text editing features. We have included some
+comments in each of the following sections to encourage you to experiment.
+
+## Font and Paragraph Styles
+
+QTextEdit supports **bold**, *italic*, and ~~strikethrough~~ font styles, and can
+display multicolored text. Font families such as Times New Roman and `Courier`
+can also be used directly. *If you place the cursor in a region of styled text,
+the controls in the tool bars will change to reflect the current style.*
+
+Paragraphs can be formatted so that the text is left-aligned, right-aligned,
+centered, or fully justified.
+
+*Try changing the alignment of some text and resize the editor to see how the
+text layout changes.*
+
+## Lists
+
+Different kinds of lists can be included in rich text documents. Standard
+bullet lists can be nested, using different symbols for each level of the list:
+
+- Disc symbols are typically used for top-level list items.
+ * Circle symbols can be used to distinguish between items in lower-level
+ lists.
+ + Square symbols provide a reasonable alternative to discs and circles.
+
+Ordered lists can be created that can be used for tables of contents. Different
+characters can be used to enumerate items, and we can use both Roman and Arabic
+numerals in the same list structure:
+
+1. Introduction
+2. Qt Tools
+ 1) Qt Assistant
+ 2) Qt Designer
+ 1. Form Editor
+ 2. Component Architecture
+ 3) Qt Linguist
+
+The list will automatically be renumbered if you add or remove items. *Try
+adding new sections to the above list or removing existing item to see the
+numbers change.*
+
+## Images
+
+Inline images are treated like ordinary ranges of characters in the text
+editor, so they flow with the surrounding text. Images can also be selected in
+the same way as text, making it easy to cut, copy, and paste them.
+
+![image](images/logo32.png) *Try to select this image by clicking and dragging
+over it with the mouse, or use the text cursor to select it by holding down
+Shift and using the arrow keys. You can then cut or copy it, and paste it into
+different parts of this document.*
+
+## Tables
+
+QTextEdit can arrange and format tables, supporting features such as row and
+column spans, text formatting within cells, and size constraints for columns.
+
+
+| |Development Tools |Programming Techniques |Graphical User Interfaces|
+|-------------|------------------------------------|---------------------------|-------------------------|
+|9:00 - 11:00 |Introduction to Qt |||
+|11:00 - 13:00|Using qmake |Object-oriented Programming|Layouts in Qt |
+|13:00 - 15:00|Qt Designer Tutorial |Extreme Programming |Writing Custom Styles |
+|15:00 - 17:00|Qt Linguist and Internationalization|  |  |
+
+*Try adding text to the cells in the table and experiment with the alignment of
+the paragraphs.*
+
+## Hyperlinks
+
+QTextEdit is designed to support hyperlinks between documents, and this feature
+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.
+
+## Undo and Redo
+
+Full support for undo and redo operations is built into QTextEdit and the
+underlying rich text framework. Operations on a document can be packaged
+together to make editing a more comfortable experience for the user.
+
+*Try making changes to this document and press `Ctrl+Z` to undo them. You can
+always recover the original contents of the document.*
+
diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/headingsAndLists.md b/tests/auto/gui/text/qtextmarkdownwriter/data/headingsAndLists.md
new file mode 100644
index 0000000000..d5d14fb168
--- /dev/null
+++ b/tests/auto/gui/text/qtextmarkdownwriter/data/headingsAndLists.md
@@ -0,0 +1,12 @@
+# heading 1
+
+- list item 1
+- list item 2
+
+## heading 2
+
+1) list item 1
+2) list item 2
+
+the end paragraph
+
diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/wordWrap.md b/tests/auto/gui/text/qtextmarkdownwriter/data/wordWrap.md
new file mode 100644
index 0000000000..dacb0acf77
--- /dev/null
+++ b/tests/auto/gui/text/qtextmarkdownwriter/data/wordWrap.md
@@ -0,0 +1,13 @@
+[The CommonMark Specification](https://spec.commonmark.org/0.29/) is the
+conservative formal specification of the Markdown format, while
+[GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown)
+adds extra features such as task lists and tables.
+
+Qt owes thanks to the authors of the [MD4C parser](https://github.com/mity/md4c)
+for making markdown import possible. The QTextMarkdownWriter class does not
+have such dependencies, and also has not yet been tested as extensively, so we
+do not yet guarantee that we are able to rewrite every Markdown document that
+you are able to read and display with Text or QTextEdit. But you are free to
+write [bugs](https://bugreports.qt.io) about any troublesome cases that you
+encounter.
+
diff --git a/tests/auto/gui/text/qtextmarkdownwriter/qtextmarkdownwriter.pro b/tests/auto/gui/text/qtextmarkdownwriter/qtextmarkdownwriter.pro
new file mode 100644
index 0000000000..6144710b99
--- /dev/null
+++ b/tests/auto/gui/text/qtextmarkdownwriter/qtextmarkdownwriter.pro
@@ -0,0 +1,9 @@
+CONFIG += testcase
+TARGET = tst_qtextmarkdownwriter
+QT += core-private gui-private testlib
+SOURCES += tst_qtextmarkdownwriter.cpp
+TESTDATA += \
+ data/example.md \
+ data/blockquotes.md \
+
+DEFINES += SRCDIR=\\\"$$PWD\\\"
diff --git a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp
new file mode 100644
index 0000000000..d15e856a20
--- /dev/null
+++ b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp
@@ -0,0 +1,473 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QTextDocument>
+#include <QTextCursor>
+#include <QTextBlock>
+#include <QTextList>
+#include <QTextTable>
+#include <QBuffer>
+#include <QDebug>
+
+#include <private/qtextmarkdownwriter_p.h>
+
+// #define DEBUG_WRITE_OUTPUT
+
+class tst_QTextMarkdownWriter : public QObject
+{
+ Q_OBJECT
+public slots:
+ void init();
+ void cleanup();
+
+private slots:
+ void testWriteParagraph_data();
+ void testWriteParagraph();
+ void testWriteList();
+ void testWriteEmptyList();
+ void testWriteNestedBulletLists_data();
+ void testWriteNestedBulletLists();
+ void testWriteNestedNumericLists();
+ void testWriteTable();
+ void rewriteDocument_data();
+ void rewriteDocument();
+ void fromHtml_data();
+ void fromHtml();
+
+private:
+ QString documentToUnixMarkdown();
+
+private:
+ QTextDocument *document;
+};
+
+void tst_QTextMarkdownWriter::init()
+{
+ document = new QTextDocument();
+}
+
+void tst_QTextMarkdownWriter::cleanup()
+{
+ delete document;
+}
+
+void tst_QTextMarkdownWriter::testWriteParagraph_data()
+{
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<QString>("output");
+
+ QTest::newRow("empty") << "" <<
+ "";
+ QTest::newRow("spaces") << "foobar word" <<
+ "foobar word\n\n";
+ QTest::newRow("starting spaces") << " starting spaces" <<
+ " starting spaces\n\n";
+ QTest::newRow("trailing spaces") << "trailing spaces " <<
+ "trailing spaces \n\n";
+ QTest::newRow("tab") << "word\ttab x" <<
+ "word\ttab x\n\n";
+ QTest::newRow("tab2") << "word\t\ttab\tx" <<
+ "word\t\ttab\tx\n\n";
+ QTest::newRow("misc") << "foobar word\ttab x" <<
+ "foobar word\ttab x\n\n";
+ QTest::newRow("misc2") << "\t \tFoo" <<
+ "\t \tFoo\n\n";
+}
+
+void tst_QTextMarkdownWriter::testWriteParagraph()
+{
+ QFETCH(QString, input);
+ QFETCH(QString, output);
+
+ QTextCursor cursor(document);
+ cursor.insertText(input);
+
+ QCOMPARE(documentToUnixMarkdown(), output);
+}
+
+void tst_QTextMarkdownWriter::testWriteList()
+{
+ QTextCursor cursor(document);
+ QTextList *list = cursor.createList(QTextListFormat::ListDisc);
+ cursor.insertText("ListItem 1");
+ list->add(cursor.block());
+ cursor.insertBlock();
+ cursor.insertText("ListItem 2");
+ list->add(cursor.block());
+
+ QCOMPARE(documentToUnixMarkdown(), QString::fromLatin1(
+ "- ListItem 1\n- ListItem 2\n"));
+}
+
+void tst_QTextMarkdownWriter::testWriteEmptyList()
+{
+ QTextCursor cursor(document);
+ cursor.createList(QTextListFormat::ListDisc);
+
+ QCOMPARE(documentToUnixMarkdown(), QString::fromLatin1("- \n"));
+}
+
+void tst_QTextMarkdownWriter::testWriteNestedBulletLists_data()
+{
+ QTest::addColumn<bool>("checkbox");
+ QTest::addColumn<bool>("checked");
+ QTest::addColumn<bool>("continuationLine");
+ QTest::addColumn<bool>("continuationParagraph");
+ QTest::addColumn<QString>("expectedOutput");
+
+ QTest::newRow("plain bullets") << false << false << false << false <<
+ "- ListItem 1\n * ListItem 2\n + ListItem 3\n- ListItem 4\n * ListItem 5\n";
+ QTest::newRow("bullets with continuation lines") << false << false << true << false <<
+ "- ListItem 1\n * ListItem 2\n + ListItem 3 with text that won't fit on one line and thus needs a\n continuation\n- ListItem 4\n * ListItem 5 with text that won't fit on one line and thus needs a\n continuation\n";
+ QTest::newRow("bullets with continuation paragraphs") << false << false << false << true <<
+ "- ListItem 1\n\n * ListItem 2\n + ListItem 3\n\n continuation\n\n- ListItem 4\n\n * ListItem 5\n\n continuation\n\n";
+ QTest::newRow("unchecked") << true << false << false << false <<
+ "- [ ] ListItem 1\n * [ ] ListItem 2\n + [ ] ListItem 3\n- [ ] ListItem 4\n * [ ] ListItem 5\n";
+ QTest::newRow("checked") << true << true << false << false <<
+ "- [x] ListItem 1\n * [x] ListItem 2\n + [x] ListItem 3\n- [x] ListItem 4\n * [x] ListItem 5\n";
+ QTest::newRow("checked with continuation lines") << true << true << true << false <<
+ "- [x] ListItem 1\n * [x] ListItem 2\n + [x] ListItem 3 with text that won't fit on one line and thus needs a\n continuation\n- [x] ListItem 4\n * [x] ListItem 5 with text that won't fit on one line and thus needs a\n continuation\n";
+ QTest::newRow("checked with continuation paragraphs") << true << true << false << true <<
+ "- [x] ListItem 1\n\n * [x] ListItem 2\n + [x] ListItem 3\n\n continuation\n\n- [x] ListItem 4\n\n * [x] ListItem 5\n\n continuation\n\n";
+}
+
+void tst_QTextMarkdownWriter::testWriteNestedBulletLists()
+{
+ QFETCH(bool, checkbox);
+ QFETCH(bool, checked);
+ QFETCH(bool, continuationParagraph);
+ QFETCH(bool, continuationLine);
+ QFETCH(QString, expectedOutput);
+
+ QTextCursor cursor(document);
+ QTextBlockFormat blockFmt = cursor.blockFormat();
+ if (checkbox) {
+ blockFmt.setMarker(checked ? QTextBlockFormat::MarkerType::Checked : QTextBlockFormat::MarkerType::Unchecked);
+ cursor.setBlockFormat(blockFmt);
+ }
+
+ QTextList *list1 = cursor.createList(QTextListFormat::ListDisc);
+ cursor.insertText("ListItem 1");
+ list1->add(cursor.block());
+
+ QTextListFormat fmt2;
+ fmt2.setStyle(QTextListFormat::ListCircle);
+ fmt2.setIndent(2);
+ QTextList *list2 = cursor.insertList(fmt2);
+ cursor.insertText("ListItem 2");
+
+ QTextListFormat fmt3;
+ fmt3.setStyle(QTextListFormat::ListSquare);
+ fmt3.setIndent(3);
+ cursor.insertList(fmt3);
+ cursor.insertText(continuationLine ?
+ "ListItem 3 with text that won't fit on one line and thus needs a continuation" :
+ "ListItem 3");
+ if (continuationParagraph) {
+ QTextBlockFormat blockFmt;
+ blockFmt.setIndent(2);
+ cursor.insertBlock(blockFmt);
+ cursor.insertText("continuation");
+ }
+
+ cursor.insertBlock(blockFmt);
+ cursor.insertText("ListItem 4");
+ list1->add(cursor.block());
+
+ cursor.insertBlock();
+ cursor.insertText(continuationLine ?
+ "ListItem 5 with text that won't fit on one line and thus needs a continuation" :
+ "ListItem 5");
+ list2->add(cursor.block());
+ if (continuationParagraph) {
+ QTextBlockFormat blockFmt;
+ blockFmt.setIndent(2);
+ cursor.insertBlock(blockFmt);
+ cursor.insertText("continuation");
+ }
+
+ 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
+ QCOMPARE(documentToUnixMarkdown(), expectedOutput);
+}
+
+void tst_QTextMarkdownWriter::testWriteNestedNumericLists()
+{
+ QTextCursor cursor(document);
+
+ QTextList *list1 = cursor.createList(QTextListFormat::ListDecimal);
+ cursor.insertText("ListItem 1");
+ list1->add(cursor.block());
+
+ QTextListFormat fmt2;
+ fmt2.setStyle(QTextListFormat::ListLowerAlpha);
+ fmt2.setNumberSuffix(QLatin1String(")"));
+ fmt2.setIndent(2);
+ QTextList *list2 = cursor.insertList(fmt2);
+ cursor.insertText("ListItem 2");
+
+ QTextListFormat fmt3;
+ fmt3.setStyle(QTextListFormat::ListDecimal);
+ fmt3.setIndent(3);
+ cursor.insertList(fmt3);
+ cursor.insertText("ListItem 3");
+
+ cursor.insertBlock();
+ cursor.insertText("ListItem 4");
+ list1->add(cursor.block());
+
+ cursor.insertBlock();
+ 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"));
+}
+
+void tst_QTextMarkdownWriter::testWriteTable()
+{
+ QTextCursor cursor(document);
+ QTextTable * table = cursor.insertTable(4, 3);
+ cursor = table->cellAt(0, 0).firstCursorPosition();
+ // valid Markdown tables need headers, but QTextTable doesn't make that distinction
+ // so QTextMarkdownWriter assumes the first row of any table is a header
+ cursor.insertText("one");
+ cursor.movePosition(QTextCursor::NextCell);
+ cursor.insertText("two");
+ cursor.movePosition(QTextCursor::NextCell);
+ cursor.insertText("three");
+ cursor.movePosition(QTextCursor::NextCell);
+
+ cursor.insertText("alice");
+ cursor.movePosition(QTextCursor::NextCell);
+ cursor.insertText("bob");
+ cursor.movePosition(QTextCursor::NextCell);
+ cursor.insertText("carl");
+ cursor.movePosition(QTextCursor::NextCell);
+
+ cursor.insertText("dennis");
+ cursor.movePosition(QTextCursor::NextCell);
+ cursor.insertText("eric");
+ cursor.movePosition(QTextCursor::NextCell);
+ cursor.insertText("fiona");
+ cursor.movePosition(QTextCursor::NextCell);
+
+ cursor.insertText("gina");
+ /*
+ |one |two |three|
+ |------|----|-----|
+ |alice |bob |carl |
+ |dennis|eric|fiona|
+ |gina | | |
+ */
+
+ QString md = documentToUnixMarkdown();
+
+#ifdef DEBUG_WRITE_OUTPUT
+ {
+ QFile out("/tmp/table.md");
+ out.open(QFile::WriteOnly);
+ out.write(md.toUtf8());
+ out.close();
+ }
+#endif
+
+ QString expected = QString::fromLatin1(
+ "\n|one |two |three|\n|------|----|-----|\n|alice |bob |carl |\n|dennis|eric|fiona|\n|gina | | |\n\n");
+ QCOMPARE(md, expected);
+
+ // create table with merged cells
+ document->clear();
+ cursor = QTextCursor(document);
+ table = cursor.insertTable(3, 3);
+ table->mergeCells(0, 0, 1, 2);
+ table->mergeCells(1, 1, 1, 2);
+ cursor = table->cellAt(0, 0).firstCursorPosition();
+ cursor.insertText("a");
+ cursor.movePosition(QTextCursor::NextCell);
+ cursor.insertText("b");
+ cursor.movePosition(QTextCursor::NextCell);
+ cursor.insertText("c");
+ cursor.movePosition(QTextCursor::NextCell);
+ cursor.insertText("d");
+ cursor.movePosition(QTextCursor::NextCell);
+ cursor.insertText("e");
+ cursor.movePosition(QTextCursor::NextCell);
+ cursor.insertText("f");
+ /*
+ +---+-+
+ |a |b|
+ +---+-+
+ |c| d|
+ +-+-+-+
+ |e|f| |
+ +-+-+-+
+
+ generates
+
+ |a ||b|
+ |-|-|-|
+ |c|d ||
+ |e|f| |
+
+ */
+
+ md = documentToUnixMarkdown();
+
+#ifdef DEBUG_WRITE_OUTPUT
+ {
+ QFile out("/tmp/table-merged-cells.md");
+ out.open(QFile::WriteOnly);
+ out.write(md.toUtf8());
+ out.close();
+ }
+#endif
+
+ QCOMPARE(md, QString::fromLatin1("\n|a ||b|\n|-|-|-|\n|c|d ||\n|e|f| |\n\n"));
+}
+
+void tst_QTextMarkdownWriter::rewriteDocument_data()
+{
+ QTest::addColumn<QString>("inputFile");
+
+ QTest::newRow("block quotes") << "blockquotes.md";
+ QTest::newRow("example") << "example.md";
+ QTest::newRow("list items after headings") << "headingsAndLists.md";
+ QTest::newRow("word wrap") << "wordWrap.md";
+}
+
+void tst_QTextMarkdownWriter::rewriteDocument()
+{
+ QFETCH(QString, inputFile);
+ QTextDocument doc;
+ QFile f(QFINDTESTDATA("data/" + inputFile));
+ QVERIFY(f.open(QFile::ReadOnly | QIODevice::Text));
+ QString orig = QString::fromUtf8(f.readAll());
+ f.close();
+ doc.setMarkdown(orig);
+ QString md = doc.toMarkdown();
+
+#ifdef DEBUG_WRITE_OUTPUT
+ QFile out("/tmp/rewrite-" + inputFile);
+ out.open(QFile::WriteOnly);
+ out.write(md.toUtf8());
+ out.close();
+#endif
+
+ QCOMPARE(md, orig);
+}
+
+void tst_QTextMarkdownWriter::fromHtml_data()
+{
+ QTest::addColumn<QString>("expectedInput");
+ 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";
+ 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") <<
+ "The first sentence of this paragraph holds 80 characters, then there's a star. * This is wrapped, but is <em>not</em> a bullet point." <<
+ "The first sentence of this paragraph holds 80 characters, then there's a star.\n\\* This is wrapped, but is *not* a bullet point.\n\n";
+ QTest::newRow("escaped plus after newline") <<
+ "The first sentence of this paragraph holds 80 characters, then there's a plus. + This is wrapped, but is <em>not</em> a bullet point." <<
+ "The first sentence of this paragraph holds 80 characters, then there's a plus.\n\\+ This is wrapped, but is *not* a bullet point.\n\n";
+ QTest::newRow("escaped hyphen after newline") <<
+ "The first sentence of this paragraph holds 80 characters, then there's a minus. - This is wrapped, but is <em>not</em> a bullet point." <<
+ "The first sentence of this paragraph holds 80 characters, then there's a minus.\n\\- This is wrapped, but is *not* a bullet point.\n\n";
+ QTest::newRow("list items with indented continuations") <<
+ "<ul><li>bullet<p>continuation paragraph</p></li><li>another bullet<br/>continuation line</li></ul>" <<
+ "- bullet\n\n continuation paragraph\n\n- another bullet\n continuation line\n";
+ QTest::newRow("nested list items with continuations") <<
+ "<ul><li>bullet<p>continuation paragraph</p></li><li>another bullet<br/>continuation line</li><ul><li>bullet<p>continuation paragraph</p></li><li>another bullet<br/>continuation line</li></ul></ul>" <<
+ "- bullet\n\n continuation paragraph\n\n- another bullet\n continuation line\n\n - bullet\n\n continuation paragraph\n\n - another bullet\n continuation line\n";
+ QTest::newRow("nested ordered list items with continuations") <<
+ "<ol><li>item<p>continuation paragraph</p></li><li>another item<br/>continuation line</li><ol><li>item<p>continuation paragraph</p></li><li>another item<br/>continuation line</li></ol><li>another</li><li>another</li></ol>" <<
+ "1. item\n\n continuation paragraph\n\n2. another item\n continuation line\n\n 1. item\n\n continuation paragraph\n\n 2. another item\n continuation line\n\n3. another\n4. another\n";
+ QTest::newRow("thematic break") <<
+ "something<hr/>something else" <<
+ "something\n\n- - -\nsomething else\n\n";
+ QTest::newRow("block quote") <<
+ "<p>In 1958, Mahatma Gandhi was quoted as follows:</p><blockquote>The Earth provides enough to satisfy every man's need but not for every man's greed.</blockquote>" <<
+ "In 1958, Mahatma Gandhi was quoted as follows:\n\n> The Earth provides enough to satisfy every man's need but not for every man's\n> greed.\n\n";
+ QTest::newRow("image") <<
+ "<img src=\"/url\" alt=\"foo\" title=\"title\"/>" <<
+ "![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";
+}
+
+void tst_QTextMarkdownWriter::fromHtml()
+{
+ QFETCH(QString, expectedInput);
+ QFETCH(QString, expectedOutput);
+
+ document->setHtml(expectedInput);
+ 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
+
+ QCOMPARE(output, expectedOutput);
+}
+
+QString tst_QTextMarkdownWriter::documentToUnixMarkdown()
+{
+ QString ret;
+ QTextStream ts(&ret, QIODevice::WriteOnly);
+ QTextMarkdownWriter writer(ts, QTextDocument::MarkdownDialectGitHub);
+ writer.writeAll(document);
+ return ret;
+}
+
+QTEST_MAIN(tst_QTextMarkdownWriter)
+#include "tst_qtextmarkdownwriter.moc"
diff --git a/tests/auto/gui/text/qtexttable/qtexttable.pro b/tests/auto/gui/text/qtexttable/qtexttable.pro
index 2faadfcb0d..73e94d5735 100644
--- a/tests/auto/gui/text/qtexttable/qtexttable.pro
+++ b/tests/auto/gui/text/qtexttable/qtexttable.pro
@@ -1,6 +1,6 @@
CONFIG += testcase
TARGET = tst_qtexttable
-QT += testlib
+QT += testlib gui-private
qtHaveModule(widgets): QT += widgets
SOURCES += tst_qtexttable.cpp
diff --git a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp
index 22f00c677d..7b2ff4cc10 100644
--- a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp
+++ b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp
@@ -44,11 +44,14 @@
#include <QPainter>
#include <QPaintEngine>
#endif
+#include <private/qpagedpaintdevice_p.h>
typedef QList<int> IntList;
QT_FORWARD_DECLARE_CLASS(QTextDocument)
+Q_DECLARE_METATYPE(QTextFrameFormat::BorderStyle);
+
class tst_QTextTable : public QObject
{
Q_OBJECT
@@ -91,9 +94,11 @@ private slots:
void QTBUG11282_insertBeforeMergedEnding();
#endif
void QTBUG22011_insertBeforeRowSpan();
-#ifndef QT_NO_PRINTER
+#if !defined(QT_NO_PRINTER) && defined(QT_BUILD_INTERNAL)
void QTBUG31330_renderBackground();
#endif
+ void checkBorderAttributes_data();
+ void checkBorderAttributes();
private:
QTextTable *create2x2Table();
@@ -1025,7 +1030,7 @@ void tst_QTextTable::QTBUG22011_insertBeforeRowSpan()
QCOMPARE(table->columns(), 6);
}
-#ifndef QT_NO_PRINTER
+#if !defined(QT_NO_PRINTER) && defined(QT_BUILD_INTERNAL)
namespace {
class QTBUG31330_PaintDevice : public QPagedPaintDevice
{
@@ -1065,11 +1070,46 @@ public:
{}
};
+ class QDummyPagedPaintDevicePrivate : public QPagedPaintDevicePrivate
+ {
+ bool setPageLayout(const QPageLayout &newPageLayout) override
+ {
+ m_pageLayout = newPageLayout;
+ return m_pageLayout.isEquivalentTo(newPageLayout);
+ }
+
+ bool setPageSize(const QPageSize &pageSize) override
+ {
+ m_pageLayout.setPageSize(pageSize);
+ return m_pageLayout.pageSize().isEquivalentTo(pageSize);
+ }
+
+ bool setPageOrientation(QPageLayout::Orientation orientation) override
+ {
+ m_pageLayout.setOrientation(orientation);
+ return m_pageLayout.orientation() == orientation;
+ }
+
+ bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units) override
+ {
+ m_pageLayout.setUnits(units);
+ m_pageLayout.setMargins(margins);
+ return m_pageLayout.margins() == margins && m_pageLayout.units() == units;
+ }
+
+ QPageLayout pageLayout() const override
+ {
+ return m_pageLayout;
+ }
+
+ QPageLayout m_pageLayout;
+ };
+
int pages;
QPaintEngine* engine;
QTBUG31330_PaintDevice(QPaintEngine* engine)
- : pages(1), engine(engine)
+ : QPagedPaintDevice(new QDummyPagedPaintDevicePrivate), pages(1), engine(engine)
{
QPageLayout layout = pageLayout();
layout.setUnits(QPageLayout::Point);
@@ -1134,5 +1174,109 @@ void tst_QTextTable::QTBUG31330_renderBackground()
}
#endif
+void tst_QTextTable::checkBorderAttributes_data()
+{
+ QTest::addColumn<QString>("html");
+ QTest::addColumn<qreal>("topBorderWidth");
+ QTest::addColumn<qreal>("bottomBorderWidth");
+ QTest::addColumn<qreal>("leftBorderWidth");
+ QTest::addColumn<qreal>("rightBorderWidth");
+ QTest::addColumn<QTextFrameFormat::BorderStyle>("topBorderStyle");
+ QTest::addColumn<QTextFrameFormat::BorderStyle>("bottomBorderStyle");
+ QTest::addColumn<QTextFrameFormat::BorderStyle>("leftBorderStyle");
+ QTest::addColumn<QTextFrameFormat::BorderStyle>("rightBorderStyle");
+ QTest::addColumn<QBrush>("topBorderBrush");
+ QTest::addColumn<QBrush>("bottomBorderBrush");
+ QTest::addColumn<QBrush>("leftBorderBrush");
+ QTest::addColumn<QBrush>("rightBorderBrush");
+
+ const QString tableHtmlStart = QStringLiteral("<html><head><style>");
+ const QString tableHtmlEnd = QStringLiteral("</style></head><body>"
+ "<table border=\"1\"><tr><td>One</td><td>Two</td></tr>"
+ "<tr><td>Three</td><td>Four</td></tr></table></body></html>");
+ QTest::newRow("1px-solid-colors")
+ << QString("%1"
+ "td {"
+ "border-top: 1px solid red;"
+ "border-bottom: 1px solid blue;"
+ "border-left: 1px solid green;"
+ "border-right: 1px solid yellow;"
+ "}"
+ "%2").arg(tableHtmlStart).arg(tableHtmlEnd)
+ << 1.0 << 1.0 << 1.0 << 1.0
+ << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid
+ << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid
+ << QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow);
+ QTest::newRow("MixedWidth-solid-colors")
+ << QString("%1"
+ "td {"
+ "border-top: 1px solid red;"
+ "border-bottom: 2px solid blue;"
+ "border-left: 3px solid green;"
+ "border-right: 4px solid yellow;"
+ "}"
+ "%2").arg(tableHtmlStart).arg(tableHtmlEnd)
+ << 1.0 << 2.0 << 3.0 << 4.0
+ << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid
+ << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Solid
+ << QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow);
+ QTest::newRow("MixedWidth-MixedStyle-colors")
+ << QString("%1"
+ "td {"
+ "border-top: 1px solid red;"
+ "border-bottom: 2px dotted blue;"
+ "border-left: 3px dashed green;"
+ "border-right: 4px inset yellow;"
+ "}"
+ "%2").arg(tableHtmlStart).arg(tableHtmlEnd)
+ << 1.0 << 2.0 << 3.0 << 4.0
+ << QTextFrameFormat::BorderStyle_Solid << QTextFrameFormat::BorderStyle_Dotted
+ << QTextFrameFormat::BorderStyle_Dashed << QTextFrameFormat::BorderStyle_Inset
+ << QBrush(Qt::red) << QBrush(Qt::blue) << QBrush(Qt::darkGreen) << QBrush(Qt::yellow);
+}
+
+void tst_QTextTable::checkBorderAttributes()
+{
+ QFETCH(QString, html);
+ QFETCH(qreal, topBorderWidth);
+ QFETCH(qreal, bottomBorderWidth);
+ QFETCH(qreal, leftBorderWidth);
+ QFETCH(qreal, rightBorderWidth);
+ QFETCH(QTextFrameFormat::BorderStyle, topBorderStyle);
+ QFETCH(QTextFrameFormat::BorderStyle, bottomBorderStyle);
+ QFETCH(QTextFrameFormat::BorderStyle, leftBorderStyle);
+ QFETCH(QTextFrameFormat::BorderStyle, rightBorderStyle);
+ QFETCH(QBrush, topBorderBrush);
+ QFETCH(QBrush, bottomBorderBrush);
+ QFETCH(QBrush, leftBorderBrush);
+ QFETCH(QBrush, rightBorderBrush);
+
+ QTextDocument doc;
+ doc.setHtml(html);
+ QTextCursor cursor(doc.firstBlock());
+ cursor.movePosition(QTextCursor::Right);
+
+ QTextTable *currentTable = cursor.currentTable();
+ QVERIFY(currentTable);
+ for (int row = 0; row < 2; row++) {
+ for (int column = 0; column < 2; column++) {
+ QTextTableCell cell = currentTable->cellAt(row, column);
+ QTextCharFormat cellFormat = cell.format();
+ QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellTopBorder), topBorderWidth);
+ QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellBottomBorder), bottomBorderWidth);
+ QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellLeftBorder), leftBorderWidth);
+ QCOMPARE(cellFormat.doubleProperty(QTextFormat::TableCellRightBorder), rightBorderWidth);
+ QCOMPARE(cellFormat.property(QTextFormat::TableCellTopBorderStyle), topBorderStyle);
+ QCOMPARE(cellFormat.property(QTextFormat::TableCellBottomBorderStyle), bottomBorderStyle);
+ QCOMPARE(cellFormat.property(QTextFormat::TableCellLeftBorderStyle), leftBorderStyle);
+ QCOMPARE(cellFormat.property(QTextFormat::TableCellRightBorderStyle), rightBorderStyle);
+ QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellTopBorderBrush), topBorderBrush);
+ QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellBottomBorderBrush), bottomBorderBrush);
+ QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellLeftBorderBrush), leftBorderBrush);
+ QCOMPARE(cellFormat.brushProperty(QTextFormat::TableCellRightBorderBrush), rightBorderBrush);
+ }
+ }
+}
+
QTEST_MAIN(tst_QTextTable)
#include "tst_qtexttable.moc"
diff --git a/tests/auto/gui/text/text.pro b/tests/auto/gui/text/text.pro
index 6b033fb506..794d9ea8d3 100644
--- a/tests/auto/gui/text/text.pro
+++ b/tests/auto/gui/text/text.pro
@@ -28,12 +28,16 @@ SUBDIRS=\
win32:SUBDIRS -= qtextpiecetable
+qtConfig(textmarkdownreader): SUBDIRS += qtextmarkdownimporter
+qtConfig(textmarkdownwriter): SUBDIRS += qtextmarkdownwriter
+
!qtConfig(private_tests): SUBDIRS -= \
qfontcache \
qcssparser \
qtextlayout \
qtextpiecetable \
qzip \
+ qtextmarkdownwriter \
qtextodfwriter
!qtHaveModule(xml): SUBDIRS -= \