File indexing completed on 2024-04-28 04:59:30
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 <QSignalSpy> 0006 #include <QTest> 0007 0008 #include <Quotient/connection.h> 0009 #include <Quotient/quotient_common.h> 0010 #include <Quotient/syncdata.h> 0011 0012 #include "enums/delegatetype.h" 0013 #include "models/messageeventmodel.h" 0014 #include "neochatroom.h" 0015 0016 #include "testutils.h" 0017 0018 using namespace Quotient; 0019 0020 class MessageEventModelTest : public QObject 0021 { 0022 Q_OBJECT 0023 0024 private: 0025 Connection *connection = nullptr; 0026 MessageEventModel *model = nullptr; 0027 0028 private Q_SLOTS: 0029 void initTestCase(); 0030 void init(); 0031 0032 void switchEmptyRoom(); 0033 void switchSyncedRoom(); 0034 void simpleTimeline(); 0035 void syncNewEvents(); 0036 void pendingEvent(); 0037 void disconnect(); 0038 void idToRow(); 0039 0040 void cleanup(); 0041 }; 0042 0043 void MessageEventModelTest::initTestCase() 0044 { 0045 connection = Connection::makeMockConnection(QStringLiteral("@bob:kde.org")); 0046 } 0047 0048 void MessageEventModelTest::init() 0049 { 0050 QCOMPARE(model, nullptr); 0051 model = new MessageEventModel; 0052 } 0053 0054 // Make sure that basic empty rooms can be switched without crashing. 0055 void MessageEventModelTest::switchEmptyRoom() 0056 { 0057 auto firstRoom = new TestUtils::TestRoom(connection, QStringLiteral("#firstRoom:kde.org")); 0058 auto secondRoom = new TestUtils::TestRoom(connection, QStringLiteral("#secondRoom:kde.org")); 0059 0060 QSignalSpy spy(model, SIGNAL(roomChanged())); 0061 0062 QCOMPARE(model->room(), nullptr); 0063 model->setRoom(firstRoom); 0064 QCOMPARE(spy.count(), 1); 0065 QCOMPARE(model->room()->id(), QStringLiteral("#firstRoom:kde.org")); 0066 model->setRoom(secondRoom); 0067 QCOMPARE(spy.count(), 2); 0068 QCOMPARE(model->room()->id(), QStringLiteral("#secondRoom:kde.org")); 0069 model->setRoom(nullptr); 0070 QCOMPARE(spy.count(), 3); 0071 QCOMPARE(model->room(), nullptr); 0072 } 0073 0074 // Make sure that rooms with some events can be switched without crashing 0075 void MessageEventModelTest::switchSyncedRoom() 0076 { 0077 auto firstRoom = new TestUtils::TestRoom(connection, QStringLiteral("#firstRoom:kde.org"), QLatin1String("test-messageventmodel-sync.json")); 0078 auto secondRoom = new TestUtils::TestRoom(connection, QStringLiteral("#secondRoom:kde.org"), QLatin1String("test-messageventmodel-sync.json")); 0079 0080 QSignalSpy spy(model, SIGNAL(roomChanged())); 0081 0082 QCOMPARE(model->room(), nullptr); 0083 model->setRoom(firstRoom); 0084 QCOMPARE(spy.count(), 1); 0085 QCOMPARE(model->room()->id(), QStringLiteral("#firstRoom:kde.org")); 0086 model->setRoom(secondRoom); 0087 QCOMPARE(spy.count(), 2); 0088 QCOMPARE(model->room()->id(), QStringLiteral("#secondRoom:kde.org")); 0089 model->setRoom(nullptr); 0090 QCOMPARE(spy.count(), 3); 0091 QCOMPARE(model->room(), nullptr); 0092 } 0093 0094 void MessageEventModelTest::simpleTimeline() 0095 { 0096 auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-messageventmodel-sync.json")); 0097 0098 model->setRoom(room); 0099 QCOMPARE(model->rowCount(), 2); 0100 0101 QCOMPARE(model->data(model->index(0), MessageEventModel::DelegateTypeRole), DelegateType::State); 0102 QCOMPARE(model->data(model->index(0)), QStringLiteral("changed their display name to Example Changed")); 0103 0104 QCOMPARE(model->data(model->index(1)), QStringLiteral("<b>This is an example<br>text message</b>")); 0105 QCOMPARE(model->data(model->index(1), MessageEventModel::DelegateTypeRole), DelegateType::Message); 0106 QCOMPARE(model->data(model->index(1), MessageEventModel::PlainText), QStringLiteral("This is an example\ntext message")); 0107 QCOMPARE(model->data(model->index(1), MessageEventModel::EventIdRole), QStringLiteral("$153456789:example.org")); 0108 0109 QTest::ignoreMessage(QtWarningMsg, "Index QModelIndex(-1,-1,0x0,QObject(0x0)) is not valid (expected valid)"); 0110 QCOMPARE(model->data(model->index(-1)), QVariant()); 0111 QTest::ignoreMessage(QtWarningMsg, "Index QModelIndex(-1,-1,0x0,QObject(0x0)) is not valid (expected valid)"); 0112 QCOMPARE(model->data(model->index(model->rowCount())), QVariant()); 0113 } 0114 0115 // Sync some events into the MessageEventModel's current room and don't crash. 0116 void MessageEventModelTest::syncNewEvents() 0117 { 0118 auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org")); 0119 QSignalSpy spy(room, SIGNAL(aboutToAddNewMessages(Quotient::RoomEventsRange))); 0120 0121 model->setRoom(room); 0122 QCOMPARE(model->rowCount(), 0); 0123 0124 room->syncNewEvents(QLatin1String("test-messageventmodel-sync.json")); 0125 0126 QCOMPARE(model->rowCount(), 2); 0127 QCOMPARE(spy.count(), 1); 0128 } 0129 0130 // Check the adding of pending events to the room doesn't cause any issues in the model. 0131 void MessageEventModelTest::pendingEvent() 0132 { 0133 QSignalSpy spyInsert(model, SIGNAL(rowsInserted(const QModelIndex &, int, int))); 0134 QSignalSpy spyRemove(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int))); 0135 QSignalSpy spyChanged(model, SIGNAL(dataChanged(const QModelIndex, const QModelIndex, const QList<int> &))); 0136 0137 auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org")); 0138 model->setRoom(room); 0139 QCOMPARE(model->rowCount(), 0); 0140 0141 auto txnId = room->postPlainText("New plain message"_ls); 0142 QCOMPARE(model->rowCount(), 1); 0143 QCOMPARE(spyInsert.count(), 1); 0144 0145 room->discardMessage(txnId); 0146 QCOMPARE(model->rowCount(), 0); 0147 QCOMPARE(spyRemove.count(), 1); 0148 0149 txnId = room->postPlainText("New plain message"_ls); 0150 QCOMPARE(model->rowCount(), 1); 0151 QCOMPARE(spyInsert.count(), 2); 0152 0153 // We need to manually set the transaction ID of the new message as it will be 0154 // different every time. 0155 QFile testSyncFile; 0156 testSyncFile.setFileName(QLatin1String(DATA_DIR) + u'/' + QLatin1String("test-pending-sync.json")); 0157 testSyncFile.open(QIODevice::ReadOnly); 0158 auto testSyncJson = QJsonDocument::fromJson(testSyncFile.readAll()); 0159 auto root = testSyncJson.object(); 0160 auto timeline = root["timeline"_ls].toObject(); 0161 auto events = timeline["events"_ls].toArray(); 0162 auto firstEvent = events[0].toObject(); 0163 firstEvent.insert(QLatin1String("unsigned"), QJsonObject{{QLatin1String("transaction_id"), txnId}}); 0164 events[0] = firstEvent; 0165 timeline.insert("events"_ls, events); 0166 root.insert("timeline"_ls, timeline); 0167 testSyncJson.setObject(root); 0168 SyncRoomData roomData(QStringLiteral("@bob:kde.org"), JoinState::Join, testSyncJson.object()); 0169 room->update(std::move(roomData)); 0170 0171 QCOMPARE(model->rowCount(), 1); 0172 // The model will throw multiple data changed signals we need the one that refreshes 0173 // the IsPendingRole. 0174 QCOMPARE(spyChanged.count() > 0, true); 0175 auto isPendingChanged = false; 0176 for (auto signal : spyChanged) { 0177 auto roles = signal.at(2).toList(); 0178 if (roles.contains(MessageEventModel::IsPendingRole)) { 0179 isPendingChanged = true; 0180 } 0181 } 0182 QCOMPARE(isPendingChanged, true); 0183 } 0184 0185 // Make sure that the signals are disconnecting correctly when a room is switched. 0186 void MessageEventModelTest::disconnect() 0187 { 0188 auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org")); 0189 model->setRoom(room); 0190 0191 QSignalSpy spy(model, SIGNAL(rowsInserted(const QModelIndex &, int, int))); 0192 0193 model->setRoom(nullptr); 0194 room->syncNewEvents(QLatin1String("test-messageventmodel-sync.json")); 0195 0196 QCOMPARE(spy.count(), 0); 0197 } 0198 0199 void MessageEventModelTest::idToRow() 0200 { 0201 auto room = new TestUtils::TestRoom(connection, QStringLiteral("#myroom:kde.org"), QLatin1String("test-min-sync.json")); 0202 model->setRoom(room); 0203 0204 QCOMPARE(model->eventIdToRow(QStringLiteral("$153456789:example.org")), 0); 0205 } 0206 0207 void MessageEventModelTest::cleanup() 0208 { 0209 delete model; 0210 model = nullptr; 0211 QCOMPARE(model, nullptr); 0212 } 0213 0214 QTEST_MAIN(MessageEventModelTest) 0215 #include "messageeventmodeltest.moc"