Refactor LinkPreviewer

Refactor `LinkPreviewer` to take an event and put the functions for getting the link in the class itself. This means the functions in `EventHandler` are no longer required.

This mr also sets up `LinkPreviewer` so that it is automatically updated when an event is edited. This includes changing the link if edited, and it can handle a message having a previous link removed or a one added when one didn't exist before.

Also adds test suite.
This commit is contained in:
James Graham
2024-01-07 18:07:13 +00:00
parent f361f4e2d8
commit 51f7de117d
22 changed files with 401 additions and 194 deletions

View File

@@ -76,3 +76,9 @@ ecm_add_test(
LINK_LIBRARIES neochat Qt::Test
TEST_NAME reactionmodeltest
)
ecm_add_test(
linkpreviewertest.cpp
LINK_LIBRARIES neochat Qt::Test
TEST_NAME linkpreviewertest
)

View File

@@ -0,0 +1,14 @@
{
"content": {
"body": "https://matrix.to/#/@alice:example.org",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -0,0 +1,14 @@
{
"content": {
"body": "mxc://example.org/SEsfnsuifSDFSSEF",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -0,0 +1,14 @@
{
"content": {
"body": "testhttps://kde.org",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -0,0 +1,24 @@
{
"timeline": {
"events": [
{
"content": {
"body": "https://kde.org",
"format": "org.matrix.custom.html",
"formatted_body": "https://kde.org",
"msgtype": "m.text"
},
"origin_server_ts": 1704648567967,
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 112
},
"event_id": "$validlink:example.org",
"room_id": "!test:example.org"
}
],
"limited": true,
"prev_batch": "t34-23535_0_0"
}
}

View File

@@ -0,0 +1,35 @@
{
"timeline": {
"events": [
{
"content": {
"body": "* ",
"format": "org.matrix.custom.html",
"formatted_body": "no link",
"m.new_content": {
"body": "",
"format": "org.matrix.custom.html",
"formatted_body": "no link",
"msgtype": "m.text"
},
"m.relates_to": {
"event_id": "$validlink:example.org",
"rel_type": "m.replace"
},
"msgtype": "m.text",
"type": "m.room.message"
},
"origin_server_ts": 1704648614969,
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 65
},
"event_id": "$nolink:example.org",
"room_id": "!test:example.org"
}
],
"limited": true,
"prev_batch": "t34-23535_0_0"
}
}

View File

@@ -0,0 +1,14 @@
{
"content": {
"body": "www.example.org https://kde.org",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -0,0 +1,14 @@
{
"content": {
"body": "https://kde.org",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -0,0 +1,14 @@
{
"content": {
"body": "www.example.org",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -0,0 +1,16 @@
{
"content": {
"body": "[Rich Link](https://kde.org)",
"format": "org.matrix.custom.html",
"formatted_body": "<a href=\"https://kde.org\">Rich Link</a>",
"msgtype": "m.text"
},
"event_id": "$validlink1:example.org",
"origin_server_ts": 1432735824654,
"room_id": "!test:example.org",
"sender": "@example:example.org",
"type": "m.room.message",
"unsigned": {
"age": 1234
}
}

View File

@@ -65,8 +65,6 @@ private Q_SLOTS:
void nullSubtitle();
void mediaInfo();
void nullMediaInfo();
void linkPreviewer();
void nullLinkPreviewer();
void hasReply();
void nullHasReply();
void replyId();
@@ -399,28 +397,6 @@ void EventHandlerTest::nullMediaInfo()
QCOMPARE(noEventHandler.getMediaInfo(), QVariantMap());
}
void EventHandlerTest::linkPreviewer()
{
auto event = room->messageEvents().at(2).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.getLinkPreviewer()->url(), QUrl("https://kde.org"_ls));
event = room->messageEvents().at(0).get();
eventHandler.setEvent(event);
QCOMPARE(eventHandler.getLinkPreviewer(), nullptr);
}
void EventHandlerTest::nullLinkPreviewer()
{
QTest::ignoreMessage(QtWarningMsg, "getLinkPreviewer called with m_room set to nullptr.");
QCOMPARE(emptyHandler.getLinkPreviewer(), nullptr);
QTest::ignoreMessage(QtWarningMsg, "getLinkPreviewer called with m_event set to nullptr.");
QCOMPARE(noEventHandler.getLinkPreviewer(), nullptr);
}
void EventHandlerTest::hasReply()
{
auto event = room->messageEvents().at(5).get();

View File

@@ -0,0 +1,104 @@
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include <QObject>
#include <QTest>
#include "linkpreviewer.h"
#include <Quotient/events/roommessageevent.h>
#include <Quotient/quotient_common.h>
#include <Quotient/syncdata.h>
#include "utils.h"
#include "testutils.h"
using namespace Quotient;
class LinkPreviewerTest : public QObject
{
Q_OBJECT
private:
Connection *connection = nullptr;
TestUtils::TestRoom *room = nullptr;
private Q_SLOTS:
void initTestCase();
void linkPreviewsMatch_data();
void linkPreviewsMatch();
void linkPreviewsReject_data();
void linkPreviewsReject();
void editedLink();
};
void LinkPreviewerTest::initTestCase()
{
connection = Connection::makeMockConnection(QStringLiteral("@bob:example.org"));
room = new TestUtils::TestRoom(connection, QStringLiteral("!test:example.org"));
}
void LinkPreviewerTest::linkPreviewsMatch_data()
{
QTest::addColumn<QString>("eventSource");
QTest::addColumn<QUrl>("testOutputLink");
QTest::newRow("plainHttps") << QStringLiteral("test-validplainlink-event.json") << QUrl("https://kde.org"_ls);
QTest::newRow("richHttps") << QStringLiteral("test-validrichlink-event.json") << QUrl("https://kde.org"_ls);
QTest::newRow("plainWww") << QStringLiteral("test-validplainwwwlink-event.json") << QUrl("www.example.org"_ls);
QTest::newRow("multipleHttps") << QStringLiteral("test-multiplelink-event.json") << QUrl("www.example.org"_ls);
}
void LinkPreviewerTest::linkPreviewsMatch()
{
QFETCH(QString, eventSource);
QFETCH(QUrl, testOutputLink);
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
auto linkPreviewer = LinkPreviewer(room, event.get());
QCOMPARE(linkPreviewer.empty(), false);
QCOMPARE(linkPreviewer.url(), testOutputLink);
}
void LinkPreviewerTest::linkPreviewsReject_data()
{
QTest::addColumn<QString>("eventSource");
QTest::newRow("mxc") << QStringLiteral("test-invalidmxclink-event.json");
QTest::newRow("matrixTo") << QStringLiteral("test-invalidmatrixtolink-event.json");
QTest::newRow("noSpace") << QStringLiteral("test-invalidnospacelink-event.json");
}
void LinkPreviewerTest::linkPreviewsReject()
{
QFETCH(QString, eventSource);
auto event = TestUtils::loadEventFromFile<RoomMessageEvent>(eventSource);
auto linkPreviewer = LinkPreviewer(room, event.get());
QCOMPARE(linkPreviewer.empty(), true);
QCOMPARE(linkPreviewer.url(), QUrl());
}
void LinkPreviewerTest::editedLink()
{
room->syncNewEvents(QStringLiteral("test-linkpreviewerintial-sync.json"));
auto event = eventCast<const RoomMessageEvent>(room->messageEvents().at(0).get());
auto linkPreviewer = LinkPreviewer(room, event);
QCOMPARE(linkPreviewer.empty(), false);
QCOMPARE(linkPreviewer.url(), QUrl("https://kde.org"_ls));
room->syncNewEvents(QStringLiteral("test-linkpreviewerreplace-sync.json"));
QCOMPARE(linkPreviewer.empty(), true);
QCOMPARE(linkPreviewer.url(), QUrl());
}
QTEST_MAIN(LinkPreviewerTest)
#include "linkpreviewertest.moc"

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include <Quotient/events/event.h>
#include <Quotient/syncdata.h>
#include "neochatroom.h"
@@ -38,4 +39,17 @@ public:
}
}
};
template<Quotient::EventClass EventT>
inline Quotient::event_ptr_tt<EventT> loadEventFromFile(const QString &eventFileName)
{
if (!eventFileName.isEmpty()) {
QFile testEventFile;
testEventFile.setFileName(QLatin1String(DATA_DIR) + u'/' + eventFileName);
testEventFile.open(QIODevice::ReadOnly);
auto testSyncJson = QJsonDocument::fromJson(testEventFile.readAll()).object();
return Quotient::loadEvent<EventT>(testSyncJson);
}
return nullptr;
}
}

View File

@@ -64,11 +64,6 @@ private Q_SLOTS:
void receiveRichEdited();
void receiveLineSeparator();
void receiveRichCodeUrl();
void linkPreviewsMatch_data();
void linkPreviewsMatch();
void linkPreviewsReject_data();
void linkPreviewsReject();
};
void TextHandlerTest::initTestCase()
@@ -523,53 +518,6 @@ void TextHandlerTest::receiveLineSeparator()
QCOMPARE(textHandler.handleRecievePlainText(Qt::PlainText, true), QStringLiteral("foo bar"));
}
void TextHandlerTest::linkPreviewsMatch_data()
{
QTest::addColumn<QString>("testInputString");
QTest::addColumn<QList<QUrl>>("testOutputLinks");
QTest::newRow("plainHttps") << QStringLiteral("https://kde.org") << QList<QUrl>({QUrl("https://kde.org"_ls)});
QTest::newRow("richHttps") << QStringLiteral("<a href=\"https://kde.org\">Rich Link</a>") << QList<QUrl>({QUrl("https://kde.org"_ls)});
QTest::newRow("plainWww") << QStringLiteral("www.example.org") << QList<QUrl>({QUrl("www.example.org"_ls)});
QTest::newRow("multipleHttps") << QStringLiteral("https://kde.org www.example.org")
<< QList<QUrl>({
QUrl("https://kde.org"_ls),
QUrl("www.example.org"_ls),
});
}
void TextHandlerTest::linkPreviewsMatch()
{
QFETCH(QString, testInputString);
QFETCH(QList<QUrl>, testOutputLinks);
TextHandler testTextHandler;
testTextHandler.setData(testInputString);
QCOMPARE(testTextHandler.getLinkPreviews(), testOutputLinks);
}
void TextHandlerTest::linkPreviewsReject_data()
{
QTest::addColumn<QString>("testInputString");
QTest::addColumn<QList<QUrl>>("testOutputLinks");
QTest::newRow("mxc") << QStringLiteral("mxc://example.org/SEsfnsuifSDFSSEF") << QList<QUrl>();
QTest::newRow("matrixTo") << QStringLiteral("https://matrix.to/#/@alice:example.org") << QList<QUrl>();
QTest::newRow("noSpace") << QStringLiteral("testhttps://kde.org") << QList<QUrl>();
}
void TextHandlerTest::linkPreviewsReject()
{
QFETCH(QString, testInputString);
QFETCH(QList<QUrl>, testOutputLinks);
TextHandler testTextHandler;
testTextHandler.setData(testInputString);
QCOMPARE(testTextHandler.getLinkPreviews(), testOutputLinks);
}
void TextHandlerTest::receiveRichCodeUrl()
{
auto input = QStringLiteral("<code>https://kde.org</code>");