File indexing completed on 2024-05-26 05:28:45
0001 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net> 0002 0003 This file is part of the Trojita Qt IMAP e-mail client, 0004 http://trojita.flaska.net/ 0005 0006 This program is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU General Public License as 0008 published by the Free Software Foundation; either version 2 of 0009 the License or (at your option) version 3 or any later version 0010 accepted by the membership of KDE e.V. (or its successor approved 0011 by the membership of KDE e.V.), which shall act as a proxy 0012 defined in Section 14 of version 3 of the license. 0013 0014 This program is distributed in the hope that it will be useful, 0015 but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0017 GNU General Public License for more details. 0018 0019 You should have received a copy of the GNU General Public License 0020 along with this program. If not, see <http://www.gnu.org/licenses/>. 0021 */ 0022 0023 #include <QtTest> 0024 #include <QAction> 0025 #include <QTextDocument> 0026 #include <QWebFrame> 0027 #include <QWebView> 0028 #include "test_Html_formatting.h" 0029 #include "Composer/Recipients.h" 0030 #include "Composer/ReplaceSignature.h" 0031 #include "Composer/SenderIdentitiesModel.h" 0032 #include "Composer/SubjectMangling.h" 0033 0034 #if defined(__has_feature) 0035 # if __has_feature(address_sanitizer) 0036 # define SKIP_WEBKIT_TESTS 0037 # endif 0038 #endif 0039 0040 0041 Q_DECLARE_METATYPE(QList<QUrl>) 0042 0043 static QString visualizeWhitespace(QString s) 0044 { 0045 return s.replace(QLatin1Char(' '), 0046 // U+00B7, a middle dot 0047 QChar(0x00b7)); 0048 } 0049 0050 /** @short Test that conversion of plaintext mail to HTML works reasonably well */ 0051 void HtmlFormattingTest::testPlainTextFormattingFlowed() 0052 { 0053 QFETCH(QString, plaintext); 0054 QFETCH(QString, htmlFlowed); 0055 QFETCH(QString, htmlNotFlowed); 0056 0057 QCOMPARE(visualizeWhitespace(UiUtils::plainTextToHtml(plaintext, UiUtils::FlowedFormat::FLOWED)), 0058 visualizeWhitespace(htmlFlowed)); 0059 QCOMPARE(visualizeWhitespace(UiUtils::plainTextToHtml(plaintext, UiUtils::FlowedFormat::PLAIN)), 0060 visualizeWhitespace(htmlNotFlowed)); 0061 } 0062 0063 /** @short Data for testPlainTextFormattingFlowed */ 0064 void HtmlFormattingTest::testPlainTextFormattingFlowed_data() 0065 { 0066 QTest::addColumn<QString>("plaintext"); 0067 QTest::addColumn<QString>("htmlFlowed"); 0068 QTest::addColumn<QString>("htmlNotFlowed"); 0069 0070 QTest::newRow("empty-1") << QString() << QString() << QString(); 0071 QTest::newRow("empty-2") << QStringLiteral("") << QStringLiteral("") << QStringLiteral(""); 0072 QTest::newRow("empty-3") << QStringLiteral("\n") << QStringLiteral("\n") << QStringLiteral("\n"); 0073 QTest::newRow("empty-4") << QStringLiteral("\n\n") << QStringLiteral("\n\n") << QStringLiteral("\n\n"); 0074 0075 QTest::newRow("minimal") << QStringLiteral("ahoj") << QStringLiteral("ahoj") << QStringLiteral("ahoj"); 0076 0077 QTest::newRow("multiline-trivial-LF") << QStringLiteral("Sample \ntext") << QStringLiteral("Sample text") << QStringLiteral("Sample \ntext"); 0078 QTest::newRow("multiline-trivial-CR") << QStringLiteral("Sample \rtext") << QStringLiteral("Sample \rtext") << QStringLiteral("Sample \rtext"); 0079 QTest::newRow("multiline-trivial-CRLF") << QStringLiteral("Sample \r\ntext") << QStringLiteral("Sample text") << QStringLiteral("Sample \ntext"); 0080 QTest::newRow("multiline-with-empty-lines") 0081 << QStringLiteral("Sample \ntext.\n\nYay!") 0082 << QStringLiteral("Sample text.\n\nYay!") 0083 << QStringLiteral("Sample \ntext.\n\nYay!"); 0084 0085 QTest::newRow("signature-LF") 0086 << QStringLiteral("Yay.\n-- \nMeh.\n") 0087 << QStringLiteral("Yay.\n<span class=\"signature\">-- \nMeh.\n</span>") 0088 << QStringLiteral("Yay.\n<span class=\"signature\">-- \nMeh.\n</span>"); 0089 QTest::newRow("signature-CRLF") 0090 << QStringLiteral("Yay.\r\n-- \r\nMeh.\r\n") 0091 << QStringLiteral("Yay.\n<span class=\"signature\">-- \nMeh.\n</span>") 0092 << QStringLiteral("Yay.\n<span class=\"signature\">-- \nMeh.\n</span>"); 0093 0094 QTest::newRow("gerrit-extra-leading-space") 0095 << QStringLiteral("Patch Set 2: Code-Review+2\r\n" 0096 "\r\n" 0097 "> There is no limit on the number of flags which could be present for\r\n" 0098 " > a message\r\n" 0099 "\r\n" 0100 "Ok, checked ::normalizedFlags() - indeed *everything* is implicitly shared =)") 0101 << QStringLiteral("Patch Set 2: Code-Review+2\n" 0102 "\n" 0103 "<span class=\"level\"><input type=\"checkbox\" id=\"q1\"/><span class=\"shortquote\"><blockquote><span class=\"quotemarks\">> </span>There is no limit on the number of flags which could be present for\n" 0104 "<label for=\"q1\"></label></blockquote></span></span>> a message\n" 0105 "\n" 0106 "Ok, checked ::normalizedFlags() - indeed <b><span class=\"markup\">*</span>everything<span class=\"markup\">*</span></b> is implicitly shared =)") 0107 << QStringLiteral("Patch Set 2: Code-Review+2\n" 0108 "\n" 0109 "<span class=\"level\"><input type=\"checkbox\" id=\"q1\"/><span class=\"shortquote\"><blockquote><span class=\"quotemarks\">> </span>There is no limit on the number of flags which could be present for\n" 0110 "<span class=\"quotemarks\">> </span>a message\n" 0111 "<label for=\"q1\"></label></blockquote></span></span>\n" 0112 "Ok, checked ::normalizedFlags() - indeed <b><span class=\"markup\">*</span>everything<span class=\"markup\">*</span></b> is implicitly shared =)"); 0113 } 0114 0115 /** @short Corner cases of the DelSp formatting */ 0116 void HtmlFormattingTest::testPlainTextFormattingFlowedDelSp() 0117 { 0118 QFETCH(QString, plaintext); 0119 QFETCH(QString, htmlFlowedDelSp); 0120 0121 QCOMPARE(visualizeWhitespace(UiUtils::plainTextToHtml(plaintext, UiUtils::FlowedFormat::FLOWED_DELSP)), 0122 visualizeWhitespace(htmlFlowedDelSp)); 0123 } 0124 0125 /** @short Data for testPlainTextFormattingFlowedDelSp */ 0126 void HtmlFormattingTest::testPlainTextFormattingFlowedDelSp_data() 0127 { 0128 QTest::addColumn<QString>("plaintext"); 0129 QTest::addColumn<QString>("htmlFlowedDelSp"); 0130 0131 QTest::newRow("delsp-canonical") << QStringLiteral("abc \r\ndef") << QStringLiteral("abc def"); 0132 QTest::newRow("delsp-just-lf") << QStringLiteral("abc \ndef") << QStringLiteral("abc def"); 0133 QTest::newRow("delsp-borked-crlf") << QStringLiteral("abc\r\ndef") << QStringLiteral("abc\ndef"); 0134 QTest::newRow("delsp-borked-lf") << QStringLiteral("abc\ndef") << QStringLiteral("abc\ndef"); 0135 QTest::newRow("delsp-single-line-no-crlf") << QStringLiteral("abc ") << QStringLiteral("abc"); 0136 QTest::newRow("delsp-single-line-crlf") << QStringLiteral("abc \r\n") << QStringLiteral("abc\n"); 0137 QTest::newRow("delsp-single-line-lf") << QStringLiteral("abc \n") << QStringLiteral("abc\n"); 0138 QTest::newRow("delsp-single-line-cr") << QStringLiteral("abc \r") << QStringLiteral("abc"); 0139 } 0140 0141 void HtmlFormattingTest::testPlainTextFormattingViaHtml() 0142 { 0143 QFETCH(QString, plaintext); 0144 QFETCH(QString, html); 0145 0146 QCOMPARE(UiUtils::plainTextToHtml(plaintext, UiUtils::FlowedFormat::FLOWED), html); 0147 } 0148 0149 void HtmlFormattingTest::testPlainTextFormattingViaHtml_data() 0150 { 0151 QTest::addColumn<QString>("plaintext"); 0152 QTest::addColumn<QString>("html"); 0153 0154 QTest::newRow("containing-html") 0155 << QStringLiteral("<p>ahoj & blesmrt</p>") 0156 << QStringLiteral("<p>ahoj &amp; blesmrt</p>"); 0157 QTest::newRow("basic-formatting-1") << QStringLiteral("foo bar") << QStringLiteral("foo bar"); 0158 QTest::newRow("basic-formatting-2") 0159 << QStringLiteral("ahoj *cau* nazdar") 0160 << QStringLiteral("ahoj <b><span class=\"markup\">*</span>cau<span class=\"markup\">*</span></b> nazdar"); 0161 QTest::newRow("basic-formatting-3") 0162 << QStringLiteral("/ahoj/ *cau*") 0163 << QStringLiteral("<i><span class=\"markup\">/</span>ahoj<span class=\"markup\">/</span></i> <b><span class=\"markup\">*</span>cau<span class=\"markup\">*</span></b>"); 0164 QTest::newRow("basic-formatting-4") 0165 << QStringLiteral("ahoj *_cau_* nazdar") 0166 << QStringLiteral("ahoj <b><span class=\"markup\">*</span><u><span class=\"markup\">_</span>cau" 0167 "<span class=\"markup\">_</span></u><span class=\"markup\">*</span></b> nazdar"); 0168 QTest::newRow("basic-formatting-666") 0169 << QStringLiteral("foo *bar* _baz_ /pwn/ yay foo@ @bar @ blesmrt") 0170 << QStringLiteral("foo <b><span class=\"markup\">*</span>bar<span class=\"markup\">*</span></b> " 0171 "<u><span class=\"markup\">_</span>baz<span class=\"markup\">_</span></u> " 0172 "<i><span class=\"markup\">/</span>pwn<span class=\"markup\">/</span></i> yay foo@ @bar @ blesmrt"); 0173 QTest::newRow("formatting-and-newlines") 0174 << QStringLiteral("*blesmrt*\ntrojita") 0175 << QStringLiteral("<b><span class=\"markup\">*</span>blesmrt<span class=\"markup\">*</span></b>\ntrojita"); 0176 QTest::newRow("links") 0177 << QStringLiteral("ahoj http://pwn:123/foo?bar&baz#nope") 0178 << QStringLiteral("ahoj <a href=\"http://pwn:123/foo?bar&baz#nope\">http://pwn:123/foo?bar&baz#nope</a>"); 0179 // Test our escaping 0180 QTest::newRow("escaping-1") 0181 << QStringLiteral("<>&> § §gt; §para;\n") 0182 << QStringLiteral("<>&&gt; § §gt; §para;\n"); 0183 // A plaintext actually containing some HTML code -- bug 323390 0184 QTest::newRow("escaping-html-url-bug-323390") 0185 << QStringLiteral("<a href=\"http://trojita.flaska.net\">Trojita</a>") 0186 << QStringLiteral("<a href="<a href=\"http://trojita.flaska.net\">http://trojita.flaska.net</a>">Trojita</a>"); 0187 QTest::newRow("escaping-html-mail-bug-323390") 0188 << QStringLiteral("some-mail&ad'dr@foo") 0189 << QStringLiteral("<a href=\"mailto:some-mail&ad'dr@foo\">some-mail&ad'dr@foo</a>"); 0190 0191 QTest::newRow("mailto-1") 0192 << QStringLiteral("ble.smrt-1_2+3@example.org") 0193 << QStringLiteral("<a href=\"mailto:ble.smrt-1_2+3@example.org\">ble.smrt-1_2+3@example.org</a>"); 0194 0195 QTest::newRow("multiple-links-on-line") 0196 << QStringLiteral("Hi,\n" 0197 "http://meh/ http://pwn/now foo@bar http://wtf\n" 0198 "nothing x@y.org\n" 0199 "foo@example.org else\n" 0200 "test@domain" 0201 ) 0202 << QStringLiteral("Hi,\n" 0203 "<a href=\"http://meh/\">http://meh/</a> <a href=\"http://pwn/now\">http://pwn/now</a> " 0204 "<a href=\"mailto:foo@bar\">foo@bar</a> <a href=\"http://wtf\">http://wtf</a>\n" 0205 "nothing <a href=\"mailto:x@y.org\">x@y.org</a>\n" 0206 "<a href=\"mailto:foo@example.org\">foo@example.org</a> else\n" 0207 "<a href=\"mailto:test@domain\">test@domain</a>"); 0208 0209 QTest::newRow("http-link-with-nested-mail-and-formatting-chars") 0210 << QStringLiteral("http://example.org/meh/yay/?foo=test@example.org\n" 0211 "http://example.org/(*checkout*)/pwn\n" 0212 "*https://domain.org/yay*") 0213 << QStringLiteral("<a href=\"http://example.org/meh/yay/?foo=test@example.org\">http://example.org/meh/yay/?foo=test@example.org</a>\n" 0214 "<a href=\"http://example.org/(*checkout*)/pwn\">http://example.org/(*checkout*)/pwn</a>\n" 0215 "<b><span class=\"markup\">*</span><a href=\"https://domain.org/yay\">https://domain.org/yay</a><span class=\"markup\">*</span></b>"); 0216 0217 QTest::newRow("just-underscores") 0218 << QStringLiteral("___________") 0219 << QStringLiteral("___________"); 0220 0221 QTest::newRow("duplicated-formatters") 0222 << QStringLiteral("__meh__ **blah** //boo//") 0223 << QStringLiteral("__meh__ **blah** //boo//"); 0224 0225 QTest::newRow("two-but-different") 0226 << QStringLiteral("_/meh/_ *_blah_* /*boo*/") 0227 << QStringLiteral("<u><span class=\"markup\">_</span><i><span class=\"markup\">/</span>meh" 0228 "<span class=\"markup\">/</span></i><span class=\"markup\">_</span></u> " 0229 "<b><span class=\"markup\">*</span><u><span class=\"markup\">_</span>blah" 0230 "<span class=\"markup\">_</span></u><span class=\"markup\">*</span></b> " 0231 "<i><span class=\"markup\">/</span><b><span class=\"markup\">*</span>boo" 0232 "<span class=\"markup\">*</span></b><span class=\"markup\">/</span></i>"); 0233 } 0234 0235 WebRenderingTester::WebRenderingTester() 0236 { 0237 m_web = new QWebView(0); 0238 m_loop = new QEventLoop(this); 0239 connect(m_web, &QWebView::loadFinished, m_loop, &QEventLoop::quit); 0240 } 0241 0242 WebRenderingTester::~WebRenderingTester() 0243 { 0244 delete m_web; 0245 } 0246 0247 QString WebRenderingTester::asPlainText(const QString &input, const UiUtils::FlowedFormat format, 0248 const CollapsingFlags collapsing) 0249 { 0250 // FIXME: bad pasted thing! 0251 static const QString stylesheet = QStringLiteral( 0252 "pre{word-wrap: break-word; white-space: pre-wrap;}" 0253 ".quotemarks{color:transparent;font-size:0px;}" 0254 "blockquote{font-size:90%; margin: 4pt 0 4pt 0; padding: 0 0 0 1em; border-left: 2px solid blue;}" 0255 "blockquote blockquote blockquote {font-size: 100%}" 0256 ".signature{opacity: 0.6;}" 0257 "input {display: none}" 0258 "input ~ span.full {display: block}" 0259 "input ~ span.short {display: none}" 0260 "input:checked ~ span.full {display: none}" 0261 "input:checked ~ span.short {display: block}" 0262 "label {border: 1px solid #333333; border-radius: 5px; padding: 0px 4px 0px 4px; margin-left: 8px; white-space: nowrap}" 0263 "span.full > blockquote > label:before {content: \"\u25b4\"}" 0264 "span.short > blockquote > label:after {content: \" \u25be\"}" 0265 "span.shortquote > blockquote > label {display: none}" 0266 ); 0267 static const QString htmlHeader(QStringLiteral("<html><head><style type=\"text/css\"><!--") + stylesheet + QLatin1String("--></style></head><body><pre>")); 0268 static const QString htmlFooter(QStringLiteral("\n</pre></body></html>")); 0269 0270 sourceData = htmlHeader + UiUtils::plainTextToHtml(input, format) + htmlFooter; 0271 if (collapsing == RenderExpandEverythingCollapsed) 0272 sourceData = sourceData.replace(QStringLiteral(" checked=\"checked\""), QString()); 0273 QTimer::singleShot(0, this, SLOT(doDelayedLoad())); 0274 m_loop->exec(); 0275 m_web->page()->action(QWebPage::SelectAll)->trigger(); 0276 return m_web->page()->selectedText(); 0277 } 0278 0279 void WebRenderingTester::doDelayedLoad() 0280 { 0281 m_web->page()->mainFrame()->setHtml(sourceData); 0282 } 0283 0284 // ...because QCOMPARE uses a fixed buffer for 1024 bytes for the debug printing... 0285 #define LONG_STR_QCOMPARE(WHAT, EXPECTED) \ 0286 { \ 0287 if (EXPECTED.size() < 350) { \ 0288 QCOMPARE(WHAT, EXPECTED); \ 0289 } else { \ 0290 QString actual = WHAT; \ 0291 if (actual != EXPECTED) {\ 0292 qDebug() << actual; \ 0293 qDebug() << EXPECTED; \ 0294 qDebug() << #WHAT; \ 0295 }; \ 0296 QVERIFY(actual == EXPECTED); \ 0297 } \ 0298 } 0299 0300 void HtmlFormattingTest::testPlainTextFormattingViaPaste() 0301 { 0302 QFETCH(QString, source); 0303 QFETCH(QString, formattedFlowed); 0304 QFETCH(QString, formattedPlain); 0305 QFETCH(QString, expandedFlowed); 0306 0307 // Allow specifying "the same" by just passing null QStrings along 0308 if (formattedPlain.isEmpty()) 0309 formattedPlain = formattedFlowed; 0310 if (expandedFlowed.isEmpty()) 0311 expandedFlowed = formattedFlowed; 0312 0313 #ifdef SKIP_WEBKIT_TESTS 0314 QSKIP("ASAN build -- QtWebKit is known to be broken, skipping"); 0315 #else 0316 { 0317 WebRenderingTester tester; 0318 LONG_STR_QCOMPARE(visualizeWhitespace(tester.asPlainText(source, UiUtils::FlowedFormat::FLOWED)), 0319 visualizeWhitespace(formattedFlowed)); 0320 } 0321 0322 { 0323 WebRenderingTester tester; 0324 LONG_STR_QCOMPARE(visualizeWhitespace(tester.asPlainText(source, UiUtils::FlowedFormat::PLAIN)), 0325 visualizeWhitespace(formattedPlain)); 0326 } 0327 0328 { 0329 WebRenderingTester tester; 0330 LONG_STR_QCOMPARE(visualizeWhitespace(tester.asPlainText(source, UiUtils::FlowedFormat::FLOWED, WebRenderingTester::RenderExpandEverythingCollapsed)), 0331 visualizeWhitespace(expandedFlowed)); 0332 } 0333 #endif 0334 } 0335 0336 void HtmlFormattingTest::testPlainTextFormattingViaPaste_data() 0337 { 0338 QTest::addColumn<QString>("source"); 0339 QTest::addColumn<QString>("formattedFlowed"); 0340 QTest::addColumn<QString>("formattedPlain"); 0341 QTest::addColumn<QString>("expandedFlowed"); 0342 0343 QTest::newRow("no-quotes") 0344 << QStringLiteral("Sample mail message.\n") 0345 << QStringLiteral("Sample mail message.\n") 0346 << QStringLiteral() << QStringLiteral(); 0347 0348 QTest::newRow("no-quotes-flowed") 0349 << QStringLiteral("This is something which is split \namong a few lines \n like \n this. ") 0350 << QStringLiteral("This is something which is split among a few lines like this.") 0351 << QStringLiteral("This is something which is split \namong a few lines \n like \n this. ") 0352 << QStringLiteral(); 0353 0354 QTest::newRow("quote-1") 0355 << QStringLiteral("Foo bar.\n> blesmrt\n>>trojita\nomacka") 0356 << QStringLiteral("Foo bar.\n> blesmrt\n>> trojita\nomacka") 0357 << QStringLiteral() << QStringLiteral(); 0358 0359 QTest::newRow("quote-levels") 0360 << QStringLiteral("Zero.\n>One\n>> Two\n>>>> Four-0\n>>>> Four-1\n>>>> Four-2\n>>>> Four-3\n>>>Three\nZeroB") 0361 << QStringLiteral("Zero.\n> One\n>> Two ...\nZeroB") 0362 << QStringLiteral() 0363 << QStringLiteral("Zero.\n> One\n>> Two\n>>>> Four-0\n>>>> Four-1\n>>>> Four-2\n>>>> Four-3\n>>> Three\nZeroB"); 0364 0365 QTest::newRow("quoted-no-spacing") 0366 << QStringLiteral("> foo\nbar\n> baz") 0367 << QStringLiteral("> foo\nbar\n> baz") 0368 << QStringLiteral() << QStringLiteral(); 0369 0370 QTest::newRow("bottom-quoting") 0371 << QStringLiteral("Foo bar.\n> blesmrt\n>> 333") 0372 << QStringLiteral("Foo bar.\n> blesmrt\n>> 333") 0373 << QStringLiteral() 0374 << QStringLiteral(); 0375 0376 QTest::newRow("bottom-quoting-toobig") 0377 << QStringLiteral("Foo bar.\n> blesmrt\n>> 333\n>> 666\n>> 666-2\n>> 666-3\n>> 666-4") 0378 << QStringLiteral("Foo bar.\n> blesmrt ...\n") 0379 << QStringLiteral() 0380 << QStringLiteral("Foo bar.\n> blesmrt\n>> 333\n>> 666\n>> 666-2\n>> 666-3\n>> 666-4\n"); 0381 0382 QTest::newRow("different-quote-levels-not-flowed-together") 0383 << QStringLiteral("Foo bar. \n> blesmrt \n>> 333") 0384 << QStringLiteral("Foo bar.\n> blesmrt\n>> 333") 0385 << QStringLiteral("Foo bar. \n> blesmrt \n>> 333") 0386 << QStringLiteral("Foo bar.\n> blesmrt\n>> 333"); 0387 0388 QTest::newRow("different-quote-levels-not-flowed-together-toobig") 0389 << QStringLiteral("Foo bar. \n> blesmrt \n>> 333\n>> 666\n>> 666-2\n>> 666-3\n>> 666-4") 0390 // The space right in front of "..." is a separator for copy-paste. The original space from the input 0391 // is interpretted as a line mistakenly marked as flowed, but since the line of a paragraph cannot be 0392 // flowed, it's a bug which we detect and throw it away. 0393 << QStringLiteral("Foo bar.\n> blesmrt ...\n") 0394 // On the other hand, we *do* expect two spaces here -- one for the non-flowed space, 0395 // and the other one for our separator. 0396 << QStringLiteral("Foo bar. \n> blesmrt ...\n") 0397 << QStringLiteral("Foo bar.\n> blesmrt\n>> 333\n>> 666\n>> 666-2\n>> 666-3\n>> 666-4\n"); 0398 0399 QTest::newRow("nested-quotes-correct-indicator") 0400 << QStringLiteral(">>> Three levels down.\n>> Two levels down.\n> One level down.\nReal mail.") 0401 << QStringLiteral(">>> ...\n>> Two levels down. ...\n> One level down.\nReal mail.") 0402 << QStringLiteral() 0403 << QStringLiteral(">>> Three levels down.\n>> Two levels down.\n> One level down.\nReal mail."); 0404 0405 QString lipsum = QStringLiteral("Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut " 0406 "labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco " 0407 "laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in " 0408 "voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat " 0409 "cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."); 0410 QString shortLipsum = QString(lipsum + QLatin1Char(' ') + lipsum).left(5*160); 0411 0412 QTest::newRow("collapsed-last-quote") 0413 << QStringLiteral("Some real text.\n> ") + lipsum + QLatin1Char(' ') + lipsum 0414 << QStringLiteral("Some real text.\n> ") + shortLipsum + " ...\n" 0415 << QString() 0416 << QStringLiteral("Some real text.\n> ") + lipsum + QLatin1Char(' ') + lipsum + "\n"; 0417 0418 QTest::newRow("quoted-common") 0419 << QStringLiteral("On quinta-feira, 4 de outubro de 2012 15.46.57, André Somers wrote:\n" 0420 "> If you think that running 21 threads on an 8 core system will run make \n" 0421 "> your task go faster, then Thiago is right: you don't understand your \n" 0422 "> problem.\n" 0423 "If you run 8 threads on an 8-core system and they use the CPU fully, then \n" 0424 "you're running as fast as you can.\n" 0425 "\n" 0426 "If you have more threads than the number of processors and if all threads are \n" 0427 "ready to be executed, then the OS will schedule timeslices to each thread. \n" 0428 "That means threads get executed and suspended all the time, sometimes \n" 0429 "migrating between processors. That adds overhead.\n" 0430 // yes, some parts have been removed here. 0431 "\n" 0432 "-- \n" 0433 "Thiago's name goes here.\n") 0434 << QStringLiteral("On quinta-feira, 4 de outubro de 2012 15.46.57, André Somers wrote:\n" 0435 "> If you think that running 21 threads on an 8 core system will run make " 0436 "your task go faster, then Thiago is right: you don't understand your " 0437 "problem.\n" 0438 "If you run 8 threads on an 8-core system and they use the CPU fully, then " 0439 "you're running as fast as you can.\n" 0440 "\n" 0441 "If you have more threads than the number of processors and if all threads are " 0442 "ready to be executed, then the OS will schedule timeslices to each thread. " 0443 "That means threads get executed and suspended all the time, sometimes " 0444 "migrating between processors. That adds overhead.\n" 0445 "\n" 0446 "-- \n" 0447 "Thiago's name goes here.\n") 0448 << QStringLiteral("On quinta-feira, 4 de outubro de 2012 15.46.57, André Somers wrote:\n" 0449 "> If you think that running 21 threads on an 8 core system will run make \n" 0450 "> your task go faster, then Thiago is right: you don't understand your \n" 0451 "> problem.\n" 0452 "If you run 8 threads on an 8-core system and they use the CPU fully, then \n" 0453 "you're running as fast as you can.\n" 0454 "\n" 0455 "If you have more threads than the number of processors and if all threads are \n" 0456 "ready to be executed, then the OS will schedule timeslices to each thread. \n" 0457 "That means threads get executed and suspended all the time, sometimes \n" 0458 "migrating between processors. That adds overhead.\n" 0459 "\n" 0460 "-- \n" 0461 "Thiago's name goes here.\n") 0462 << QString(); 0463 0464 QTest::newRow("small-quotes-arent-collapsible") 0465 << QStringLiteral("On Wednesday 09 January 2013 08:56:25 Jekyll Wu wrote:\n" 0466 "> If you plan to \n" 0467 "> use bugs.kde.org as the tracker, then you don't need to call \n" 0468 "> setBugAddress() at all. The default value just works.\n" 0469 "\n" 0470 "Fixed.\n" 0471 "\n" 0472 "\n" 0473 "> And don't forget to ask sysadmins to create a \"mangonel\" product on \n" 0474 "> bugs.kde.org :)\n" 0475 "\n" 0476 "Done.\n" 0477 "\n" 0478 "Thanks for the review! :D\n" 0479 "\n" 0480 "-- \n" 0481 "Martin Sandsmark\n" 0482 "KDE\n") 0483 << QStringLiteral("On Wednesday 09 January 2013 08:56:25 Jekyll Wu wrote:\n" 0484 "> If you plan to use bugs.kde.org as the tracker, then you don't need to call setBugAddress() " 0485 "at all. The default value just works.\n" 0486 "\n" 0487 "Fixed.\n" 0488 "\n" 0489 "\n" 0490 "> And don't forget to ask sysadmins to create a \"mangonel\" product on bugs.kde.org :)\n" 0491 "\n" 0492 "Done.\n" 0493 "\n" 0494 "Thanks for the review! :D\n" 0495 "\n" 0496 "-- \n" 0497 "Martin Sandsmark\n" 0498 "KDE\n") 0499 << QStringLiteral("On Wednesday 09 January 2013 08:56:25 Jekyll Wu wrote:\n" 0500 "> If you plan to \n" 0501 "> use bugs.kde.org as the tracker, then you don't need to call \n" 0502 "> setBugAddress() at all. The default value just works.\n" 0503 "\n" 0504 "Fixed.\n" 0505 "\n" 0506 "\n" 0507 "> And don't forget to ask sysadmins to create a \"mangonel\" product on \n" 0508 "> bugs.kde.org :)\n" 0509 "\n" 0510 "Done.\n" 0511 "\n" 0512 "Thanks for the review! :D\n" 0513 "\n" 0514 "-- \n" 0515 "Martin Sandsmark\n" 0516 "KDE\n") 0517 << QString(); 0518 0519 // https://bugs.kde.org/show_bug.cgi?id=337919 0520 QTest::newRow("blank-line-separator") 0521 << QStringLiteral("First para. \n\nSecond para.\n\n\nThird para.") 0522 << QStringLiteral("First para. \n\nSecond para.\n\n\nThird para.") 0523 << QStringLiteral("First para. \n\nSecond para.\n\n\nThird para.") 0524 << QStringLiteral("First para. \n\nSecond para.\n\n\nThird para."); 0525 0526 QTest::newRow("blank-line-separator-of-quoted") 0527 << QStringLiteral("> First para. \n>\n> Second para.\n>\n>\n>Third para.") 0528 << QStringLiteral("> First para. \n> \n> Second para.\n> \n> \n> Third para. ...\n") 0529 << QStringLiteral("> First para. \n> \n> Second para.\n> \n> \n> Third para. ...\n") 0530 << QStringLiteral("> First para. \n> \n> Second para.\n> \n> \n> Third para.\n"); 0531 0532 QTest::newRow("blanks-in-different-levels") 0533 << QStringLiteral("Yesterday: \n>> Test2A. \n>>\n>> Test2B \n>>\nTest0. \n> Test1A. \n> \n>Test 1B. ") 0534 << QStringLiteral("Yesterday:\n>> Test2A. \n>> \n>> Test2B \n>> \nTest0.\n> Test1A. \n> \n> Test 1B.") 0535 << QStringLiteral("Yesterday: \n>> Test2A. \n>> \n>> Test2B \n>> \nTest0. \n> Test1A. \n> \n> Test 1B. ") 0536 << QStringLiteral("Yesterday:\n>> Test2A. \n>> \n>> Test2B \n>> \nTest0.\n> Test1A. \n> \n> Test 1B."); 0537 0538 QTest::newRow("kmail-spaces-in-quotes") 0539 << QStringLiteral("On Wednesday 12 of November 2014 06:54:53 John Layt wrote:\r\n" 0540 "> On 8 November 2014 08:45, John Layt <jlayt@kde.org> wrote:\r\n" 0541 "> > Hi,\r\n" 0542 "> > \r\n" 0543 "> > Just checking, has the sponsorship budget been approved (so I can book\r\n" 0544 "> > flights before they cost silly amounts), and has accommodation been\r\n" 0545 "> > sorted yet or do we need to do it ourselves?\r\n" 0546 "> \r\n" 0547 "> Ping?\r\n" 0548 "\r\n" 0549 "CC'd Michael directly in case he missed the emails between all the jenkins \r\n" 0550 "spam. I'd like to have this sorted out soon too :)\r\n") 0551 << QStringLiteral("On Wednesday 12 of November 2014 06:54:53 John Layt wrote:\n" 0552 "> On 8 November 2014 08:45, John Layt <jlayt@kde.org> wrote:\n" 0553 "> > Hi,\n" 0554 // This might be surprising at first, but "> > > " is actually correct here. 0555 // The first ">" is the quote level, second ">" is the second ">" from the first line, 0556 // and because that line ends with a space, it's a flowed line, and therefore the next 0557 // line should be joined in there. The next line has a quote depth of one (the matching 0558 // stops at first space), and then again actually starts with another ">". 0559 // Therefore ">" for a quote prefix, " " as a spearator, and "> > Just..." as actual content. 0560 "> > > Just checking, has the sponsorship budget been approved (so I can book\n" 0561 "> > flights before they cost silly amounts), and has accommodation been\n" 0562 "> > sorted yet or do we need to do it ourselves?\n" 0563 "> \n" 0564 "> Ping?\n" 0565 "\n" 0566 "CC'd Michael directly in case he missed the emails between all the jenkins spam. I'd like to have this sorted out soon too :)\n") 0567 << QStringLiteral("On Wednesday 12 of November 2014 06:54:53 John Layt wrote:\n" 0568 "> On 8 November 2014 08:45, John Layt <jlayt@kde.org> wrote:\n" 0569 ">> Hi,\n" 0570 ">> \n" 0571 ">> Just checking, has the sponsorship budget been approved (so I can book\n" 0572 ">> flights before they cost silly amounts), and has accommodation been\n" 0573 ">> sorted yet or do we need to do it ourselves?\n" 0574 "> \n" 0575 "> Ping?\n" 0576 "\n" 0577 "CC'd Michael directly in case he missed the emails between all the jenkins \n" 0578 "spam. I'd like to have this sorted out soon too :)\n") 0579 << QStringLiteral("On Wednesday 12 of November 2014 06:54:53 John Layt wrote:\n" 0580 "> On 8 November 2014 08:45, John Layt <jlayt@kde.org> wrote:\n" 0581 "> > Hi,\n" 0582 // See above for that "weird" "> > > ". 0583 "> > > Just checking, has the sponsorship budget been approved (so I can book\n" 0584 "> > flights before they cost silly amounts), and has accommodation been\n" 0585 "> > sorted yet or do we need to do it ourselves?\n" 0586 "> \n" 0587 "> Ping?\n" 0588 "\n" 0589 "CC'd Michael directly in case he missed the emails between all the jenkins spam. I'd like to have this sorted out soon too :)\n"); 0590 } 0591 0592 void HtmlFormattingTest::testPlainTextFormattingViaPasteDelSp() 0593 { 0594 QFETCH(QString, source); 0595 QFETCH(QString, expandedFlowed); 0596 QFETCH(QString, expandedFlowedDelSp); 0597 0598 #ifdef SKIP_WEBKIT_TESTS 0599 QSKIP("ASAN build -- QtWebKit is known to be broken, skipping"); 0600 #else 0601 { 0602 WebRenderingTester tester; 0603 LONG_STR_QCOMPARE(visualizeWhitespace(tester.asPlainText(source, UiUtils::FlowedFormat::FLOWED, WebRenderingTester::RenderExpandEverythingCollapsed)), 0604 visualizeWhitespace(expandedFlowed)); 0605 } 0606 { 0607 WebRenderingTester tester; 0608 LONG_STR_QCOMPARE(visualizeWhitespace(tester.asPlainText(source, UiUtils::FlowedFormat::FLOWED_DELSP, WebRenderingTester::RenderExpandEverythingCollapsed)), 0609 visualizeWhitespace(expandedFlowedDelSp)); 0610 } 0611 #endif 0612 } 0613 0614 0615 void HtmlFormattingTest::testPlainTextFormattingViaPasteDelSp_data() 0616 { 0617 QTest::addColumn<QString>("source"); 0618 QTest::addColumn<QString>("expandedFlowed"); 0619 QTest::addColumn<QString>("expandedFlowedDelSp"); 0620 0621 QTest::newRow("no-quotes") 0622 << QStringLiteral("Sample mail message.\n") 0623 << QStringLiteral("Sample mail message.\n") 0624 << QStringLiteral("Sample mail message.\n"); 0625 0626 QTest::newRow("no-quotes-flowed") 0627 << QStringLiteral("This is something which is split \namong a \n few lines \n like \n this. ") 0628 << QStringLiteral("This is something which is split among a few lines like this.") 0629 // yes, "afew" -- that's because of space stuffing. 0630 << QStringLiteral("This is something which is splitamong afew lines like this."); 0631 0632 QTest::newRow("quote-1") 0633 << QStringLiteral("Foo bar. \n> blesmrt\n>> trojita \n omacka") 0634 << QStringLiteral("Foo bar.\n> blesmrt\n>> trojita\nomacka") 0635 << QStringLiteral("Foo bar.\n> blesmrt\n>> trojita\nomacka"); 0636 0637 // https://bugs.kde.org/show_bug.cgi?id=337919 0638 QTest::newRow("blank-line-separator") 0639 << QStringLiteral("First para. \n\nSecond para.\n\n\nThird para.") 0640 << QStringLiteral("First para. \n\nSecond para.\n\n\nThird para.") 0641 << QStringLiteral("First para.\n\nSecond para.\n\n\nThird para."); 0642 0643 QTest::newRow("blank-line-separator-of-quoted") 0644 << QStringLiteral("> First para. \n>\n> Second para.\n>\n>\n>Third para.") 0645 << QStringLiteral("> First para. \n> \n> Second para.\n> \n> \n> Third para.\n") 0646 << QStringLiteral("> First para.\n> \n> Second para.\n> \n> \n> Third para.\n"); 0647 0648 QTest::newRow("blanks-in-different-levels") 0649 << QStringLiteral("Yesterday: \n>> Test2A. \n>>\n>> Test2B \n>>\nTest0. \n> Test1A. \n> \n>Test 1B. ") 0650 << QStringLiteral("Yesterday:\n>> Test2A. \n>> \n>> Test2B \n>> \nTest0.\n> Test1A. \n> \n> Test 1B.") 0651 << QStringLiteral("Yesterday:\n>> Test2A.\n>> \n>> Test2B\n>> \nTest0.\n> Test1A.\n> \n> Test 1B."); 0652 } 0653 0654 /** @short Test that the link recognition in plaintext -> HTML formatting recognizes the interesting links */ 0655 void HtmlFormattingTest::testLinkRecognition() 0656 { 0657 QFETCH(QString, prefix); 0658 QFETCH(QString, link); 0659 QFETCH(QString, suffix); 0660 0661 QString input = prefix + link + suffix; 0662 QString expected = prefix + QStringLiteral("<a href=\"%1\">%1</a>").arg(link) + suffix; 0663 0664 QCOMPARE(UiUtils::plainTextToHtml(input, UiUtils::FlowedFormat::PLAIN), expected); 0665 } 0666 0667 /** @short Test data for testLinkRecognition */ 0668 void HtmlFormattingTest::testLinkRecognition_data() 0669 { 0670 QTest::addColumn<QString>("prefix"); 0671 QTest::addColumn<QString>("link"); 0672 QTest::addColumn<QString>("suffix"); 0673 0674 QString empty; 0675 QString space(QStringLiteral(" ")); 0676 0677 QTest::newRow("basic-http") << empty << QStringLiteral("http://blesmrt") << empty; 0678 QTest::newRow("basic-https") << empty << QStringLiteral("https://blesmrt") << empty; 0679 QTest::newRow("parentheses") << QStringLiteral("(") << QStringLiteral("https://blesmrt") << QStringLiteral(")"); 0680 QTest::newRow("url-query") << empty << QStringLiteral("https://blesmrt.trojita/?foo=bar") << empty; 0681 QTest::newRow("url-fragment") << empty << QStringLiteral("https://blesmrt.trojita/#pwn") << empty; 0682 0683 QTest::newRow("trailing-dot") << empty << QStringLiteral("http://blesmrt") << QStringLiteral("."); 0684 QTest::newRow("trailing-dot-2") << empty << QStringLiteral("http://blesmrt") << QStringLiteral(". Foo"); 0685 QTest::newRow("trailing-comma") << empty << QStringLiteral("http://blesmrt") << QStringLiteral(","); 0686 QTest::newRow("trailing-comma-2") << empty << QStringLiteral("http://blesmrt") << QStringLiteral(", foo"); 0687 QTest::newRow("trailing-semicolon") << empty << QStringLiteral("http://blesmrt") << QStringLiteral(";"); 0688 QTest::newRow("trailing-semicolon-2") << empty << QStringLiteral("http://blesmrt") << QStringLiteral("; foo"); 0689 QTest::newRow("trailing-colon") << empty << QStringLiteral("http://blesmrt") << QStringLiteral(":"); 0690 QTest::newRow("trailing-colon-2") << empty << QStringLiteral("http://blesmrt") << QStringLiteral(": blah"); 0691 0692 QTest::newRow("trailing-sentence-1") << QStringLiteral("meh ") << QStringLiteral("http://blesmrt") << QStringLiteral("?"); 0693 QTest::newRow("trailing-sentence-2") << QStringLiteral("meh ") << QStringLiteral("http://blesmrt") << QStringLiteral("!"); 0694 QTest::newRow("trailing-sentence-3") << QStringLiteral("meh ") << QStringLiteral("http://blesmrt") << QStringLiteral("."); 0695 } 0696 0697 /** @short Test data which should not be recognized as links */ 0698 void HtmlFormattingTest::testUnrecognizedLinks() 0699 { 0700 QFETCH(QString, input); 0701 0702 QCOMPARE(UiUtils::plainTextToHtml(input, UiUtils::FlowedFormat::PLAIN), input); 0703 } 0704 0705 /** @short Test data for testUnrecognizedLinks */ 0706 void HtmlFormattingTest::testUnrecognizedLinks_data() 0707 { 0708 QTest::addColumn<QString>("input"); 0709 0710 QTest::newRow("basic-ftp") << QStringLiteral("ftp://blesmrt"); 0711 QTest::newRow("at-sign-start") << QStringLiteral("@foo"); 0712 QTest::newRow("at-sign-end") << QStringLiteral("foo@"); 0713 QTest::newRow("at-sign-standalone-1") << QStringLiteral("@"); 0714 QTest::newRow("at-sign-standalone-2") << QStringLiteral(" @ "); 0715 QTest::newRow("http-standalone") << QStringLiteral("http://"); 0716 QTest::newRow("http-standalone-stuff") << QStringLiteral("http:// foo"); 0717 } 0718 0719 void HtmlFormattingTest::testSignatures() 0720 { 0721 QFETCH(QString, original); 0722 QFETCH(QString, signature); 0723 QFETCH(QString, result); 0724 0725 QTextDocument doc; 0726 doc.setPlainText(original); 0727 Composer::Util::replaceSignature(&doc, signature); 0728 QCOMPARE(doc.toPlainText(), result); 0729 } 0730 0731 void HtmlFormattingTest::testSignatures_data() 0732 { 0733 QTest::addColumn<QString>("original"); 0734 QTest::addColumn<QString>("signature"); 0735 QTest::addColumn<QString>("result"); 0736 0737 QTest::newRow("empty-all") << QString() << QString() << QString(); 0738 QTest::newRow("empty-signature-1") << QStringLiteral("foo") << QString() << QStringLiteral("foo"); 0739 QTest::newRow("empty-signature-2") << QStringLiteral("foo\n") << QString() << QStringLiteral("foo\n"); 0740 QTest::newRow("empty-signature-3") << QStringLiteral("foo\n-- ") << QString() << QStringLiteral("foo"); 0741 QTest::newRow("empty-signature-4") << QStringLiteral("foo\n-- \n") << QString() << QStringLiteral("foo"); 0742 QTest::newRow("empty-signature-5") << QStringLiteral("foo\n\n-- \n") << QString() << QStringLiteral("foo\n"); 0743 0744 QTest::newRow("no-signature-1") << QStringLiteral("foo") << QStringLiteral("meh") << QStringLiteral("foo\n-- \nmeh"); 0745 QTest::newRow("no-signature-2") << QStringLiteral("foo\n") << QStringLiteral("meh") << QStringLiteral("foo\n\n-- \nmeh"); 0746 QTest::newRow("no-signature-3") << QStringLiteral("foo\n\n") << QStringLiteral("meh") << QStringLiteral("foo\n\n\n-- \nmeh"); 0747 QTest::newRow("no-signature-4") << QStringLiteral("foo\nbar\nbaz") << QStringLiteral("meh") << QStringLiteral("foo\nbar\nbaz\n-- \nmeh"); 0748 QTest::newRow("no-signature-5") << QStringLiteral("foo\n--") << QStringLiteral("meh") << QStringLiteral("foo\n--\n-- \nmeh"); 0749 0750 QTest::newRow("replacement") << QStringLiteral("foo\n-- \njohoho") << QStringLiteral("sig") << QStringLiteral("foo\n-- \nsig"); 0751 QTest::newRow("replacement-of-multiline") << QStringLiteral("foo\n-- \njohoho\nwtf\nbar") << QStringLiteral("sig") << QStringLiteral("foo\n-- \nsig"); 0752 } 0753 0754 QTEST_MAIN(HtmlFormattingTest)