File indexing completed on 2024-05-12 16:25:02
0001 // SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com> 0002 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0003 0004 #include <QObject> 0005 #include <QTest> 0006 0007 #include "texthandler.h" 0008 0009 #include <Quotient/quotient_common.h> 0010 #include <Quotient/syncdata.h> 0011 #include <qnamespace.h> 0012 0013 using namespace Quotient; 0014 0015 class TestRoom : public NeoChatRoom 0016 { 0017 public: 0018 using NeoChatRoom::NeoChatRoom; 0019 0020 void update(SyncRoomData &&data, bool fromCache = false) 0021 { 0022 Room::updateData(std::move(data), fromCache); 0023 } 0024 }; 0025 0026 class TextHandlerTest : public QObject 0027 { 0028 Q_OBJECT 0029 0030 private: 0031 Connection *connection = nullptr; 0032 TestRoom *room = nullptr; 0033 0034 private Q_SLOTS: 0035 void initTestCase(); 0036 0037 void allowedAttributes(); 0038 void stripDisallowedTags(); 0039 void stripDisallowedAttributes(); 0040 void emptyCodeTags(); 0041 0042 void sendSimpleStringCase(); 0043 void sendSingleParaMarkup(); 0044 void sendMultipleSectionMarkup(); 0045 void sendBadLinks(); 0046 void sendEscapeCode(); 0047 void sendCodeClass(); 0048 0049 void receiveStripReply(); 0050 void receivePlainTextIn(); 0051 0052 void receiveRichInPlainOut_data(); 0053 void receiveRichInPlainOut(); 0054 void receivePlainStripHtml(); 0055 void receivePlainStripMarkup(); 0056 void receiveStripNewlines(); 0057 0058 void receiveRichUserPill(); 0059 void receiveRichStrikethrough(); 0060 void receiveRichtextIn(); 0061 void receiveRichMxcUrl(); 0062 void receiveRichPlainUrl(); 0063 void receiveRichEmote(); 0064 void receiveRichEdited_data(); 0065 void receiveRichEdited(); 0066 void receiveLineSeparator(); 0067 0068 void linkPreviewsMatch_data(); 0069 void linkPreviewsMatch(); 0070 void linkPreviewsReject_data(); 0071 void linkPreviewsReject(); 0072 }; 0073 0074 void TextHandlerTest::initTestCase() 0075 { 0076 connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org")); 0077 room = new TestRoom(connection, QStringLiteral("#myroom:kde.org"), JoinState::Join); 0078 0079 const auto json = QJsonDocument::fromJson(R"EVENT({ 0080 "account_data": { 0081 "events": [ 0082 { 0083 "content": { 0084 "tags": { 0085 "u.work": { 0086 "order": 0.9 0087 } 0088 } 0089 }, 0090 "type": "m.tag" 0091 }, 0092 { 0093 "content": { 0094 "custom_config_key": "custom_config_value" 0095 }, 0096 "type": "org.example.custom.room.config" 0097 } 0098 ] 0099 }, 0100 "ephemeral": { 0101 "events": [ 0102 { 0103 "content": { 0104 "user_ids": [ 0105 "@alice:matrix.org", 0106 "@bob:example.com" 0107 ] 0108 }, 0109 "room_id": "!jEsUZKDJdhlrceRyVU:example.org", 0110 "type": "m.typing" 0111 } 0112 ] 0113 }, 0114 "state": { 0115 "events": [ 0116 { 0117 "content": { 0118 "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", 0119 "displayname": "Alice Margatroid", 0120 "membership": "join", 0121 "reason": "Looking for support" 0122 }, 0123 "event_id": "$143273582443PhrSn:example.org", 0124 "origin_server_ts": 1432735824653, 0125 "room_id": "!jEsUZKDJdhlrceRyVU:example.org", 0126 "sender": "@example:example.org", 0127 "state_key": "@alice:example.org", 0128 "type": "m.room.member", 0129 "unsigned": { 0130 "age": 1234 0131 } 0132 } 0133 ] 0134 }, 0135 "summary": { 0136 "m.heroes": [ 0137 "@alice:example.com", 0138 "@bob:example.com" 0139 ], 0140 "m.invited_member_count": 0, 0141 "m.joined_member_count": 2 0142 }, 0143 "timeline": { 0144 "events": [ 0145 { 0146 "content": { 0147 "body": "This is an **example** text message", 0148 "format": "org.matrix.custom.html", 0149 "formatted_body": "<b>This is an example text message</b>", 0150 "msgtype": "m.text" 0151 }, 0152 "event_id": "$143273582443PhrSn:example.org", 0153 "origin_server_ts": 1432735824654, 0154 "room_id": "!jEsUZKDJdhlrceRyVU:example.org", 0155 "sender": "@example:example.org", 0156 "type": "m.room.message", 0157 "unsigned": { 0158 "age": 1232 0159 } 0160 }, 0161 { 0162 "content": { 0163 "body": "/me This is an emote.", 0164 "format": "org.matrix.custom.html", 0165 "formatted_body": "This is an emote.", 0166 "msgtype": "m.emote" 0167 }, 0168 "event_id": "$153273582443PhrSn:example.org", 0169 "origin_server_ts": 1532735824654, 0170 "room_id": "!jEsUZKDJdhlrceRyVU:example.org", 0171 "sender": "@example:example.org", 0172 "type": "m.room.message", 0173 "unsigned": { 0174 "age": 1231 0175 } 0176 }, 0177 { 0178 "content": { 0179 "body": "tested", 0180 "msgtype": "m.text" 0181 }, 0182 "event_id": "$zrCiBxBnqqTn0Z5FY78qSZAszno_w8nJJXzfBULG-3E", 0183 "origin_server_ts": 1680948575928, 0184 "room_id": "!jEsUZKDJdhlrceRyVU:example.org", 0185 "sender": "@example:example.org", 0186 "type": "m.room.message", 0187 "unsigned": { 0188 "age": 1747776, 0189 "m.relations": { 0190 "m.replace": { 0191 "event_id": "$UX0PlpyI7vYO32iHMuuYEP7ECMh4sX3XLGiB2SwM4mQ", 0192 "origin_server_ts": 1680948580992, 0193 "sender": "@example:example.org" 0194 } 0195 } 0196 } 0197 } 0198 ], 0199 "limited": true, 0200 "prev_batch": "t34-23535_0_0" 0201 } 0202 })EVENT"); 0203 SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, json.object()); 0204 room->update(std::move(roomData)); 0205 } 0206 0207 void TextHandlerTest::allowedAttributes() 0208 { 0209 const QString testInputString1 = QStringLiteral("<p><span data-mx-spoiler><font color=#FFFFFF>Test</font><span></p>"); 0210 const QString testOutputString1 = QStringLiteral("<p><span data-mx-spoiler><font color=#FFFFFF>Test</font><span></p>"); 0211 // Handle urls where the href has either single (') or double (") quotes. 0212 const QString testInputString2 = QStringLiteral("<p><a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a></p>"); 0213 const QString testOutputString2 = QStringLiteral("<p><a href=\"https://kde.org\">link</a><a href='https://kde.org'>link</a></p>"); 0214 0215 TextHandler testTextHandler; 0216 testTextHandler.setData(testInputString1); 0217 0218 QCOMPARE(testTextHandler.handleSendText(), testOutputString1); 0219 QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString1); 0220 0221 testTextHandler.setData(testInputString2); 0222 QCOMPARE(testTextHandler.handleSendText(), testOutputString2); 0223 QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString2); 0224 } 0225 0226 void TextHandlerTest::stripDisallowedTags() 0227 { 0228 const QString testInputString = QStringLiteral("<p>Allowed</p> <span>Allowed</span> <body>Disallowed</body>"); 0229 const QString testOutputString = QStringLiteral("<p>Allowed</p> <span>Allowed</span> Disallowed"); 0230 0231 TextHandler testTextHandler; 0232 testTextHandler.setData(testInputString); 0233 0234 QCOMPARE(testTextHandler.handleSendText(), testOutputString); 0235 QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString); 0236 } 0237 0238 void TextHandlerTest::stripDisallowedAttributes() 0239 { 0240 const QString testInputString = QStringLiteral("<p style=\"font-size:50px;\" color=#FFFFFF>Test</p>"); 0241 const QString testOutputString = QStringLiteral("<p>Test</p>"); 0242 0243 TextHandler testTextHandler; 0244 testTextHandler.setData(testInputString); 0245 0246 QCOMPARE(testTextHandler.handleSendText(), testOutputString); 0247 QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString); 0248 } 0249 0250 /** 0251 * Make sure that empty code tags are handled. 0252 * (this was a bug during development hence the test) 0253 */ 0254 void TextHandlerTest::emptyCodeTags() 0255 { 0256 const QString testInputString = QStringLiteral("<pre><code></code></pre>"); 0257 const QString testOutputString = QStringLiteral("<pre><code></code></pre>"); 0258 0259 TextHandler testTextHandler; 0260 testTextHandler.setData(testInputString); 0261 0262 QCOMPARE(testTextHandler.handleSendText(), testOutputString); 0263 QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString); 0264 } 0265 0266 void TextHandlerTest::sendSimpleStringCase() 0267 { 0268 const QString testInputString = QStringLiteral("This data should just be put in a paragraph."); 0269 const QString testOutputString = QStringLiteral("<p>This data should just be put in a paragraph.</p>"); 0270 0271 TextHandler testTextHandler; 0272 testTextHandler.setData(testInputString); 0273 0274 QCOMPARE(testTextHandler.handleSendText(), testOutputString); 0275 } 0276 0277 void TextHandlerTest::sendSingleParaMarkup() 0278 { 0279 const QString testInputString = QStringLiteral( 0280 "Text para with **bold**, *italic*, [link](https://kde.org), ![image](mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e), `inline code`."); 0281 const QString testOutputString = QStringLiteral( 0282 "<p>Text para with <strong>bold</strong>, <em>italic</em>, <a href=\"https://kde.org\">link</a>, <img " 0283 "src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e\" alt=\"image\">, <code>inline code</code>.</p>"); 0284 0285 TextHandler testTextHandler; 0286 testTextHandler.setData(testInputString); 0287 0288 QCOMPARE(testTextHandler.handleSendText(), testOutputString); 0289 } 0290 0291 void TextHandlerTest::sendMultipleSectionMarkup() 0292 { 0293 const QString testInputString = 0294 QStringLiteral("Text para\n> blockquote\n* List 1\n* List 2\n1. one\n2. two\n# Heading 1\n## Heading 2\nhorizontal rule\n\n---\n```\ncodeblock\n```"); 0295 const QString testOutputString = QStringLiteral( 0296 "<p>Text para</p>\n<blockquote>\n<p>blockquote</p>\n</blockquote>\n<ul>\n<li>List 1</li>\n<li>List " 0297 "2</li>\n</ul>\n<ol>\n<li>one</li>\n<li>two</li>\n</ol>\n<h1>Heading 1</h1>\n<h2>Heading 2</h2>\n<p>horizontal " 0298 "rule</p>\n<hr>\n<pre><code>codeblock\n</code></pre>"); 0299 0300 TextHandler testTextHandler; 0301 testTextHandler.setData(testInputString); 0302 0303 QCOMPARE(testTextHandler.handleSendText(), testOutputString); 0304 } 0305 0306 void TextHandlerTest::sendBadLinks() 0307 { 0308 const QString testInputString = QStringLiteral("[link](kde.org), ![image](https://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e)"); 0309 const QString testOutputString = QStringLiteral("<p><a>link</a>, <img alt=\"image\"></p>"); 0310 0311 TextHandler testTextHandler; 0312 testTextHandler.setData(testInputString); 0313 0314 QCOMPARE(testTextHandler.handleSendText(), testOutputString); 0315 } 0316 0317 /** 0318 * All text between code tags is treated as plain so it should get escaped. 0319 */ 0320 void TextHandlerTest::sendEscapeCode() 0321 { 0322 const QString testInputString = QStringLiteral("```\n<p>Test <span style=\"font-size:50px;\">some</span> code</p>\n```"); 0323 const QString testOutputString = 0324 QStringLiteral("<pre><code><p>Test <span style="font-size:50px;">some</span> code</p>\n</code></pre>"); 0325 0326 TextHandler testTextHandler; 0327 testTextHandler.setData(testInputString); 0328 0329 QCOMPARE(testTextHandler.handleSendText(), testOutputString); 0330 } 0331 0332 void TextHandlerTest::sendCodeClass() 0333 { 0334 const QString testInputString = QStringLiteral("```html\nsome code\n```\n<pre><code class=\"code-underline\">some more code</code></pre>"); 0335 const QString testOutputString = QStringLiteral("<pre><code class=\"language-html\">some code\n</code></pre>\n<pre><code>some more code</code></pre>"); 0336 0337 TextHandler testTextHandler; 0338 testTextHandler.setData(testInputString); 0339 0340 QCOMPARE(testTextHandler.handleSendText(), testOutputString); 0341 } 0342 0343 void TextHandlerTest::receiveStripReply() 0344 { 0345 const QString testInputString = QStringLiteral( 0346 "<mx-reply><blockquote><a href=\"https://matrix.to/#/!somewhere:example.org/$event:example.org\">In reply to</a><a " 0347 "href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a><br />Message replied to.</blockquote></mx-reply>Reply message."); 0348 const QString testOutputString = QStringLiteral("Reply message."); 0349 0350 TextHandler testTextHandler; 0351 testTextHandler.setData(testInputString); 0352 0353 QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString); 0354 QCOMPARE(testTextHandler.handleRecievePlainText(), testOutputString); 0355 } 0356 0357 void TextHandlerTest::receiveRichInPlainOut_data() 0358 { 0359 QTest::addColumn<QString>("testInputString"); 0360 QTest::addColumn<QString>("testOutputString"); 0361 0362 QTest::newRow("ampersand") << QStringLiteral("a & b") << QStringLiteral("a & b"); 0363 QTest::newRow("quote") << QStringLiteral(""a and b"") << QStringLiteral("\"a and b\""); 0364 } 0365 0366 void TextHandlerTest::receiveRichInPlainOut() 0367 { 0368 QFETCH(QString, testInputString); 0369 QFETCH(QString, testOutputString); 0370 0371 TextHandler testTextHandler; 0372 testTextHandler.setData(testInputString); 0373 0374 QCOMPARE(testTextHandler.handleRecievePlainText(Qt::RichText), testOutputString); 0375 } 0376 0377 void TextHandlerTest::receivePlainTextIn() 0378 { 0379 const QString testInputString = QStringLiteral("<plain text in tag bracket>\nTest link https://kde.org."); 0380 const QString testOutputStringRich = QStringLiteral("<plain text in tag bracket><br>Test link <a href=\"https://kde.org\">https://kde.org</a>."); 0381 QString testOutputStringPlain = QStringLiteral("<plain text in tag bracket>\nTest link https://kde.org."); 0382 0383 // Make sure quotes are maintained in a plain string. 0384 const QString testInputString2 = QStringLiteral("last line is \"Time to switch to a new topic.\""); 0385 const QString testOutputString2 = QStringLiteral("last line is \"Time to switch to a new topic.\""); 0386 0387 TextHandler testTextHandler; 0388 testTextHandler.setData(testInputString); 0389 0390 QCOMPARE(testTextHandler.handleRecieveRichText(Qt::PlainText), testOutputStringRich); 0391 QCOMPARE(testTextHandler.handleRecievePlainText(), testOutputStringPlain); 0392 0393 testTextHandler.setData(testInputString2); 0394 QCOMPARE(testTextHandler.handleRecieveRichText(Qt::PlainText), testOutputString2); 0395 QCOMPARE(testTextHandler.handleRecievePlainText(), testOutputString2); 0396 } 0397 0398 void TextHandlerTest::receiveStripNewlines() 0399 { 0400 const QString testInputStringPlain = QStringLiteral("Test\nmany\nnew\nlines."); 0401 const QString testInputStringRich = QStringLiteral("Test<br>many<br />new<br>lines."); 0402 const QString testOutputString = QStringLiteral("Test many new lines."); 0403 0404 const QString testInputStringPlain2 = QStringLiteral("* List\n* Items"); 0405 const QString testOutputString2 = QStringLiteral("List Items"); 0406 0407 TextHandler testTextHandler; 0408 testTextHandler.setData(testInputStringPlain); 0409 0410 QCOMPARE(testTextHandler.handleRecievePlainText(Qt::PlainText, true), testOutputString); 0411 QCOMPARE(testTextHandler.handleRecieveRichText(Qt::PlainText, nullptr, nullptr, true), testOutputString); 0412 0413 testTextHandler.setData(testInputStringRich); 0414 QCOMPARE(testTextHandler.handleRecievePlainText(Qt::RichText, true), testOutputString); 0415 QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, nullptr, nullptr, true), testOutputString); 0416 0417 testTextHandler.setData(testInputStringPlain2); 0418 QCOMPARE(testTextHandler.handleRecievePlainText(Qt::RichText, true), testOutputString2); 0419 } 0420 0421 /** 0422 * For a plain text output of a received string all html is stripped except for 0423 * code which is unescaped if it's html. 0424 */ 0425 void TextHandlerTest::receivePlainStripHtml() 0426 { 0427 const QString testInputString = QStringLiteral("<p>Test</p> <pre><code>Some code <strong>with tags</strong></code></pre>"); 0428 const QString testOutputString = QStringLiteral("Test Some code <strong>with tags</strong>"); 0429 0430 TextHandler testTextHandler; 0431 testTextHandler.setData(testInputString); 0432 0433 QCOMPARE(testTextHandler.handleRecievePlainText(Qt::RichText), testOutputString); 0434 } 0435 0436 void TextHandlerTest::receivePlainStripMarkup() 0437 { 0438 const QString testInputString = QStringLiteral("**bold** `<p>inline code</p>` *italic*"); 0439 const QString testOutputString = QStringLiteral("bold <p>inline code</p> italic"); 0440 0441 TextHandler testTextHandler; 0442 testTextHandler.setData(testInputString); 0443 0444 QCOMPARE(testTextHandler.handleRecievePlainText(), testOutputString); 0445 } 0446 0447 void TextHandlerTest::receiveRichUserPill() 0448 { 0449 const QString testInputString = QStringLiteral("<p><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></p>"); 0450 const QString testOutputString = QStringLiteral("<p><b><a href=\"https://matrix.to/#/@alice:example.org\">@alice:example.org</a></b></p>"); 0451 0452 TextHandler testTextHandler; 0453 testTextHandler.setData(testInputString); 0454 0455 QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString); 0456 } 0457 0458 void TextHandlerTest::receiveRichStrikethrough() 0459 { 0460 const QString testInputString = QStringLiteral("<p><del>Test</del></p>"); 0461 const QString testOutputString = QStringLiteral("<p><s>Test</s></p>"); 0462 0463 TextHandler testTextHandler; 0464 testTextHandler.setData(testInputString); 0465 0466 QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString); 0467 } 0468 0469 void TextHandlerTest::receiveRichtextIn() 0470 { 0471 const QString testInputString = QStringLiteral("<p>Test</p> <pre><code>Some code <strong>with tags</strong></code></pre>"); 0472 const QString testOutputString = QStringLiteral("<p>Test</p> <pre><code>Some code <strong>with tags</strong></code></pre>"); 0473 0474 TextHandler testTextHandler; 0475 testTextHandler.setData(testInputString); 0476 0477 QCOMPARE(testTextHandler.handleRecieveRichText(), testOutputString); 0478 } 0479 0480 void TextHandlerTest::receiveRichMxcUrl() 0481 { 0482 const QString testInputString = QStringLiteral( 0483 "<img src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e\" alt=\"image\"><img src=\"mxc://kde.org/34c3464b3a1bd7f55af2d559e07d2c773c430e73\" " 0484 "alt=\"image\">"); 0485 const QString testOutputString = QStringLiteral( 0486 "<img " 0487 "src=\"mxc://kde.org/aebd3ffd40503e1ef0525bf8f0d60282fec6183e?user_id=@bob:kde.org&room_id=%23myroom:kde.org&event_id=$143273582443PhrSn:example.org\" " 0488 "alt=\"image\"><img " 0489 "src=\"mxc://kde.org/34c3464b3a1bd7f55af2d559e07d2c773c430e73?user_id=@bob:kde.org&room_id=%23myroom:kde.org&event_id=$143273582443PhrSn:example.org\" " 0490 "alt=\"image\">"); 0491 0492 TextHandler testTextHandler; 0493 testTextHandler.setData(testInputString); 0494 0495 QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, room->messageEvents().at(0).get()), testOutputString); 0496 } 0497 0498 /** 0499 * For when your rich input string has a plain text url left in. 0500 * 0501 * This test is to show that a url that is already rich will be left alone but a 0502 * plain one will be linkified. 0503 */ 0504 void TextHandlerTest::receiveRichPlainUrl() 0505 { 0506 // This is an actual link that caused trouble which is why it's so long. Keeping 0507 // so we can confirm consistent behaviour for complex urls. 0508 const QString testInputStringLink1 = QStringLiteral( 0509 "https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im " 0510 "<a " 0511 "href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/" 0512 "$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">Link already rich</a>"); 0513 const QString testOutputStringLink1 = QStringLiteral( 0514 "<a " 0515 "href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/" 0516 "$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">https://matrix.to/#/" 0517 "!RvzunyTWZGfNxJVQqv:matrix.org/$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im</a> <a " 0518 "href=\"https://matrix.to/#/!RvzunyTWZGfNxJVQqv:matrix.org/" 0519 "$-9TJVTh5PvW6MvIhFDwteiyLBVGriinueO5eeIazQS8?via=libera.chat&via=matrix.org&via=fedora.im\">Link already rich</a>"); 0520 0521 // Another real case. The linkification wasn't handling it when a single link 0522 // contains what looks like and email. It was been broken into 3 but needs to 0523 // be just single link. 0524 const QString testInputStringLink2 = QStringLiteral("https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/"); 0525 const QString testOutputStringLink2 = QStringLiteral( 0526 "<a " 0527 "href=\"https://lore.kernel.org/lkml/CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/\">https://lore.kernel.org/lkml/" 0528 "CAHk-=wio46vC4t6xXD-sFqjoPwFm_u515jm3suzmkGxQTeA1_A@mail.gmail.com/</a>"); 0529 0530 QString testInputStringEmail = QStringLiteral(R"(email@example.com <a href="mailto:email@example.com">Link already rich</a>)"); 0531 QString testOutputStringEmail = 0532 QStringLiteral(R"(<a href="mailto:email@example.com">email@example.com</a> <a href="mailto:email@example.com">Link already rich</a>)"); 0533 0534 QString testInputStringMxId = QStringLiteral("@user:kde.org <a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a>"); 0535 QString testOutputStringMxId = QStringLiteral( 0536 "<b><a href=\"https://matrix.to/#/@user:kde.org\">@user:kde.org</a></b> <b><a href=\"https://matrix.to/#/@user:kde.org\">Link already rich</a></b>"); 0537 0538 TextHandler testTextHandler; 0539 testTextHandler.setData(testInputStringLink1); 0540 0541 QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringLink1); 0542 0543 testTextHandler.setData(testInputStringLink2); 0544 QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringLink2); 0545 0546 testTextHandler.setData(testInputStringEmail); 0547 QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringEmail); 0548 0549 testTextHandler.setData(testInputStringMxId); 0550 QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText), testOutputStringMxId); 0551 } 0552 0553 // Test that user pill is add to an emote message. 0554 // N.B. The second message in the test timeline is marked as an emote. 0555 void TextHandlerTest::receiveRichEmote() 0556 { 0557 auto event = room->messageEvents().at(1).get(); 0558 auto author = static_cast<NeoChatUser *>(room->user(event->senderId())); 0559 const QString testInputString = QStringLiteral("This is an emote."); 0560 const QString testOutputString = QStringLiteral("* <a href=\"https://matrix.to/#/@example:example.org\" style=\"color:") + author->color().name() 0561 + QStringLiteral("\">@example:example.org</a> This is an emote."); 0562 0563 TextHandler testTextHandler; 0564 testTextHandler.setData(testInputString); 0565 0566 QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, event), testOutputString); 0567 } 0568 0569 void TextHandlerTest::receiveRichEdited_data() 0570 { 0571 QTest::addColumn<QString>("testInputString"); 0572 QTest::addColumn<QString>("testOutputString"); 0573 0574 QTest::newRow("basic") << QStringLiteral("Edited") << QStringLiteral("Edited <span style=\"color:#000000\">(edited)</span>"); 0575 QTest::newRow("multiple paragraphs") << QStringLiteral("<p>Edited</p>\n<p>Edited</p>") 0576 << QStringLiteral("<p>Edited</p>\n<p>Edited <span style=\"color:#000000\">(edited)</span></p>"); 0577 QTest::newRow("blockquote") << QStringLiteral("<blockquote>Edited</blockquote>") 0578 << QStringLiteral("<blockquote>Edited</blockquote><p> <span style=\"color:#000000\">(edited)</span></p>"); 0579 } 0580 0581 void TextHandlerTest::receiveRichEdited() 0582 { 0583 QFETCH(QString, testInputString); 0584 QFETCH(QString, testOutputString); 0585 0586 TextHandler testTextHandler; 0587 testTextHandler.setData(testInputString); 0588 0589 QCOMPARE(testTextHandler.handleRecieveRichText(Qt::RichText, room, room->messageEvents().at(2).get()), testOutputString); 0590 } 0591 0592 void TextHandlerTest::receiveLineSeparator() 0593 { 0594 auto text = QStringLiteral("foo\u2028bar"); 0595 TextHandler textHandler; 0596 textHandler.setData(text); 0597 QCOMPARE(textHandler.handleRecievePlainText(Qt::PlainText, true), QStringLiteral("foo bar")); 0598 } 0599 0600 void TextHandlerTest::linkPreviewsMatch_data() 0601 { 0602 QTest::addColumn<QString>("testInputString"); 0603 QTest::addColumn<QList<QUrl>>("testOutputLinks"); 0604 0605 QTest::newRow("plainHttps") << QStringLiteral("https://kde.org") << QList<QUrl>({QUrl("https://kde.org")}); 0606 QTest::newRow("richHttps") << QStringLiteral("<a href=\"https://kde.org\">Rich Link</a>") << QList<QUrl>({QUrl("https://kde.org")}); 0607 QTest::newRow("plainWww") << QStringLiteral("www.example.org") << QList<QUrl>({QUrl("www.example.org")}); 0608 QTest::newRow("multipleHttps") << QStringLiteral("https://kde.org www.example.org") 0609 << QList<QUrl>({ 0610 QUrl("https://kde.org"), 0611 QUrl("www.example.org"), 0612 }); 0613 } 0614 0615 void TextHandlerTest::linkPreviewsMatch() 0616 { 0617 QFETCH(QString, testInputString); 0618 QFETCH(QList<QUrl>, testOutputLinks); 0619 0620 TextHandler testTextHandler; 0621 testTextHandler.setData(testInputString); 0622 0623 QCOMPARE(testTextHandler.getLinkPreviews(), testOutputLinks); 0624 } 0625 0626 void TextHandlerTest::linkPreviewsReject_data() 0627 { 0628 QTest::addColumn<QString>("testInputString"); 0629 QTest::addColumn<QList<QUrl>>("testOutputLinks"); 0630 0631 QTest::newRow("mxc") << QStringLiteral("mxc://example.org/SEsfnsuifSDFSSEF") << QList<QUrl>(); 0632 QTest::newRow("matrixTo") << QStringLiteral("https://matrix.to/#/@alice:example.org") << QList<QUrl>(); 0633 QTest::newRow("noSpace") << QStringLiteral("testhttps://kde.org") << QList<QUrl>(); 0634 } 0635 0636 void TextHandlerTest::linkPreviewsReject() 0637 { 0638 QFETCH(QString, testInputString); 0639 QFETCH(QList<QUrl>, testOutputLinks); 0640 0641 TextHandler testTextHandler; 0642 testTextHandler.setData(testInputString); 0643 0644 QCOMPARE(testTextHandler.getLinkPreviews(), testOutputLinks); 0645 } 0646 0647 QTEST_GUILESS_MAIN(TextHandlerTest) 0648 #include "texthandlertest.moc"