diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index a5a8a0259..2a9114ab1 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -104,3 +104,9 @@ ecm_add_test( LINK_LIBRARIES neochat Qt::Test neochat_server TEST_NAME roommanagertest ) + +ecm_add_test( + modeltest.cpp + LINK_LIBRARIES neochat Qt::Test neochat_server Devtools + TEST_NAME modeltest +) diff --git a/autotests/modeltest.cpp b/autotests/modeltest.cpp new file mode 100644 index 000000000..06a493812 --- /dev/null +++ b/autotests/modeltest.cpp @@ -0,0 +1,604 @@ +// SPDX-FileCopyrightText: 2025 Tobias Fella +// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL + +#include +#include +#include +#include +#include + +#include + +#include "accountmanager.h" +#include "contentprovider.h" +#include "enums/powerlevel.h" +#include "enums/roomsortparameter.h" +#include "models/accountemoticonmodel.h" +#include "models/actionsmodel.h" +#include "models/commonroomsmodel.h" +#include "models/completionmodel.h" +#include "models/completionproxymodel.h" +#include "models/customemojimodel.h" +#include "models/devicesmodel.h" +#include "models/devicesproxymodel.h" +#include "models/emojimodel.h" +#include "models/emoticonfiltermodel.h" +#include "models/eventmessagecontentmodel.h" +#include "models/imagepacksmodel.h" +#include "models/linemodel.h" +#include "models/livelocationsmodel.h" +#include "models/locationsmodel.h" +#include "models/messagecontentfiltermodel.h" +#include "models/notificationsmodel.h" +#include "models/permissionsmodel.h" +#include "models/pinnedmessagemodel.h" +#include "models/pollanswermodel.h" +#include "models/publicroomlistmodel.h" +#include "models/pushrulemodel.h" +#include "models/readmarkermodel.h" +#include "models/roomsortparametermodel.h" +#include "models/searchmodel.h" +#include "models/serverlistmodel.h" +#include "models/spacechildrenmodel.h" +#include "models/spacechildsortfiltermodel.h" +#include "models/statefiltermodel.h" +#include "models/statekeysmodel.h" +#include "models/statemodel.h" +#include "models/stickermodel.h" +#include "models/threadmodel.h" +#include "models/threepidmodel.h" +#include "models/userdirectorylistmodel.h" +#include "models/userfiltermodel.h" +#include "models/webshortcutmodel.h" +#include "neochatroom.h" +#include "pollhandler.h" +#include "roommanager.h" +#include "server.h" + +using namespace Quotient; + +// Performs basic tests on all models in NeoChat +// When adding a new test, create the model first, then the tester, then initialize the model (e.g., setConnection and setRoom). +// That way, the models are also tested for whether they can handle having no connection etc. +class ModelTest : public QObject +{ + Q_OBJECT + +private: + NeoChatConnection *connection = nullptr; + NeoChatRoom *room = nullptr; + + Server server; + +private Q_SLOTS: + void initTestCase(); + void testRoomTreeModel(); + void testMessageContentModel(); + void testEventMessageContentModel(); + void testThreadModel(); + void testThreadFetchModel(); + void testThreadChatBarModel(); + void testReactionModel(); + void testPollAnswerModel(); + void testLineModel(); + void testSpaceChildrenModel(); + void testItineraryModel(); + void testPublicRoomListModel(); + void testMessageFilterModel(); + void testThreePIdModel(); + void testMediaMessageFilterModel(); + void testWebshortcutModel(); + void testTimelineMessageModel(); + void testReadMarkerModel(); + void testSearchModel(); + void testStateModel(); + void testTimelineModel(); + void testStateKeysModel(); + void testPinnedMessageModel(); + void testUserListModel(); + void testStickerModel(); + void testPowerLevelModel(); + void testImagePacksModel(); + void testCompletionModel(); + void testRoomListModel(); + void testCommonRoomsModel(); + void testNotificationsModel(); + void testLocationsModel(); + void testServerListModel(); + void testEmojiModel(); + void testCustomEmojiModel(); + void testPushRuleModel(); + void testActionsModel(); + void testDevicesModel(); + void testUserDirectoryListModel(); + void testAccountEmoticonModel(); + void testPermissionsModel(); + void testLiveLocationsModel(); + void testRoomSortParameterModel(); + void testSortFilterRoomTreeModel(); + void testSortFilterSpaceListModel(); + void testSortFilterRoomListModel(); + void testSpaceChildSortFilterModel(); + void testStateFilterModel(); + void testMessageContentFilterModel(); + void testUserFilterModel(); + void testEmoticonFilterModel(); + void testDevicesProxyModel(); + void testCompletionProxyModel(); +}; + +void ModelTest::initTestCase() +{ + Connection::setRoomType(); + server.start(); + KLocalizedString::setApplicationDomain(QByteArrayLiteral("neochat")); + auto accountManager = new AccountManager(true); + QSignalSpy spy(accountManager, &AccountManager::connectionAdded); + connection = dynamic_cast(accountManager->accounts()->front()); + const auto roomId = server.createRoom(u"@user:localhost:1234"_s); + + QSignalSpy syncSpy(connection, &Connection::syncDone); + // We need to wait for two syncs, as the next one won't have the changes yet + QVERIFY(syncSpy.wait()); + QVERIFY(syncSpy.wait()); + room = dynamic_cast(connection->room(roomId)); + QVERIFY(room); +} + +void ModelTest::testRoomTreeModel() +{ + auto roomTreeModel = new RoomTreeModel(); + auto tester = new QAbstractItemModelTester(roomTreeModel); + tester->setUseFetchMore(true); + roomTreeModel->setConnection(connection); + // TODO +} + +void ModelTest::testMessageContentModel() +{ + auto contentModel = new MessageContentModel(room, nullptr, QString(/* TODO: use a proper event id here*/)); + auto tester = new QAbstractItemModelTester(contentModel); + tester->setUseFetchMore(true); +} + +void ModelTest::testEventMessageContentModel() +{ + auto model = new EventMessageContentModel(room, QString(/* TODO */)); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); +} + +void ModelTest::testThreadModel() +{ + auto model = new ThreadModel(QString(/* TODO */), room); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); +} + +void ModelTest::testThreadFetchModel() +{ + auto model = new ThreadFetchModel(new ThreadModel(QString(/* TODO */), room)); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testThreadChatBarModel() +{ + auto model = new ThreadChatBarModel(new ThreadModel(QString(/* TODO */), room), room); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); +} + +void ModelTest::testReactionModel() +{ + auto model = new ReactionModel(new MessageContentModel(room), QString(/* TODO */), room); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO add data +} + +void ModelTest::testPollAnswerModel() +{ + auto handler = new PollHandler(); + auto model = new PollAnswerModel(handler); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO add data +} + +void ModelTest::testLineModel() +{ + auto model = new LineModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + auto quickDocument = new QQuickTextDocument(new QQuickItem()); + auto document = new QTextDocument(); + quickDocument->setTextDocument(document); + model->setDocument(quickDocument); + document->setPlainText(u"foo\nbar\n\nbaz"_s); +} + +void ModelTest::testSpaceChildrenModel() +{ + auto model = new SpaceChildrenModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testItineraryModel() +{ + auto model = new ItineraryModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testPublicRoomListModel() +{ + auto model = new PublicRoomListModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testMessageFilterModel() +{ + auto model = new MessageFilterModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testThreePIdModel() +{ + auto model = new ThreePIdModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + model->setConnection(connection); +} + +void ModelTest::testMediaMessageFilterModel() +{ + auto model = new MediaMessageFilterModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + auto messageFilterModel = new MessageFilterModel(); + model->setSourceModel(messageFilterModel); + auto timelineModel = new TimelineModel(); + messageFilterModel->setSourceModel(timelineModel); + timelineModel->setRoom(room); +} + +void ModelTest::testWebshortcutModel() +{ + auto model = new WebShortcutModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testTimelineMessageModel() +{ + auto model = new TimelineMessageModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testReadMarkerModel() +{ + auto model = new ReadMarkerModel(QString(), room); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testSearchModel() +{ + auto model = new SearchModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testStateModel() +{ + auto model = new StateModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testTimelineModel() +{ + auto model = new TimelineModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testStateKeysModel() +{ + auto model = new StateKeysModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testPinnedMessageModel() +{ + auto model = new PinnedMessageModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testUserListModel() +{ + auto model = new UserListModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testStickerModel() +{ + auto model = new StickerModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testPowerLevelModel() +{ + auto model = new PowerLevelModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testImagePacksModel() +{ + auto model = new ImagePacksModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testCompletionModel() +{ + auto model = new CompletionModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testRoomListModel() +{ + auto model = new RoomListModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + model->setConnection(connection); + // TODO test rooms +} + +void ModelTest::testCommonRoomsModel() +{ + auto model = new CommonRoomsModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + model->setConnection(connection); + model->setUserId(u"@user:example.com"_s); + // TODO create mock data +} + +void ModelTest::testNotificationsModel() +{ + auto model = new NotificationsModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO +} + +void ModelTest::testLocationsModel() +{ + auto model = new LocationsModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + model->setRoom(room); + // TODO add some locations to the room +} + +void ModelTest::testServerListModel() +{ + auto model = new ServerListModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + model->setConnection(connection); +} + +void ModelTest::testEmojiModel() +{ + auto tester = new QAbstractItemModelTester(&EmojiModel::instance()); + tester->setUseFetchMore(true); +} + +void ModelTest::testCustomEmojiModel() +{ + auto tester = new QAbstractItemModelTester(&CustomEmojiModel::instance()); + tester->setUseFetchMore(true); + CustomEmojiModel::instance().setConnection(connection); + // TODO: add some emojis +} + +void ModelTest::testPushRuleModel() +{ + auto model = new PushRuleModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + model->setConnection(connection); + // TODO: Add some push rules to the mock server +} + +void ModelTest::testActionsModel() +{ + auto tester = new QAbstractItemModelTester(&ActionsModel::instance()); + tester->setUseFetchMore(true); +} + +void ModelTest::testDevicesModel() +{ + // TODO: Make the server return some dummy devices + auto model = new DevicesModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + model->setConnection(connection); +} + +void ModelTest::testUserDirectoryListModel() +{ + auto model = new UserDirectoryListModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + model->setConnection(connection); + model->setSearchText(u"foo"_s); + // TODO implement user directory model in mock server +} + +void ModelTest::testAccountEmoticonModel() +{ + auto model = new AccountEmoticonModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + model->setConnection(connection); + // TODO add some emojis +} + +void ModelTest::testPermissionsModel() +{ + auto model = new PermissionsModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + model->setRoom(room); +} + +void ModelTest::testLiveLocationsModel() +{ + auto model = new LiveLocationsModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + model->setRoom(room); + // TODO add some data to the room +} + +void ModelTest::testRoomSortParameterModel() +{ + auto model = new RoomSortParameterModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); +} + +void ModelTest::testSortFilterRoomTreeModel() +{ + auto sourceModel = new RoomTreeModel(); + auto model = new SortFilterRoomTreeModel(sourceModel); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + sourceModel->setConnection(connection); +} + +void ModelTest::testSortFilterSpaceListModel() +{ + // TODO make sure we have some spaces + auto sourceModel = new RoomListModel(); + auto model = new SortFilterSpaceListModel(sourceModel); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + sourceModel->setConnection(connection); +} + +void ModelTest::testSortFilterRoomListModel() +{ + // TODO make sure we have some rooms + auto sourceModel = new RoomListModel(); + auto model = new SortFilterRoomListModel(sourceModel); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + sourceModel->setConnection(connection); +} + +void ModelTest::testSpaceChildSortFilterModel() +{ + auto model = new SpaceChildSortFilterModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + auto spaceChildrenModel = new SpaceChildrenModel(); + model->setSourceModel(spaceChildrenModel); + spaceChildrenModel->setSpace(nullptr); // TODO create a real space +} + +void ModelTest::testStateFilterModel() +{ + auto model = new StateFilterModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + auto stateModel = new StateModel(); + model->setSourceModel(stateModel); + stateModel->setRoom(room); + // TODO the dummy room probably already has some state? +} + +void ModelTest::testMessageContentFilterModel() +{ + auto model = new MessageContentFilterModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + model->setSourceModel(ContentProvider::self().contentModelForEvent(room, QString(/* TODO: use a proper event id here*/))); +} + +void ModelTest::testUserFilterModel() +{ + auto model = new UserFilterModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + auto userListModel = new UserListModel(); + model->setSourceModel(userListModel); + userListModel->setRoom(room); + // TODO open room with some )users +} + +void ModelTest::testEmoticonFilterModel() +{ + auto model = new EmoticonFilterModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + // TODO: Add some emoticons to the account; requires extending the server first + auto accountEmoticonModel = new AccountEmoticonModel(); + model->setSourceModel(accountEmoticonModel); + model->setShowEmojis(true); + model->setShowStickers(true); + accountEmoticonModel->setConnection(connection); +} + +void ModelTest::testDevicesProxyModel() +{ + auto model = new DevicesProxyModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + auto devicesModel = new DevicesModel(); + model->setSourceModel(devicesModel); + devicesModel->setConnection(dynamic_cast(connection)); +} + +void ModelTest::testCompletionProxyModel() +{ + auto model = new CompletionProxyModel(); + auto tester = new QAbstractItemModelTester(model); + tester->setUseFetchMore(true); + model->setSourceModel(&EmojiModel::instance()); +} + +QTEST_MAIN(ModelTest) +#include "modeltest.moc"