diff options
author | Claudio Cambra <claudio.cambra@nextcloud.com> | 2022-10-18 18:15:10 +0300 |
---|---|---|
committer | Claudio Cambra <claudio.cambra@nextcloud.com> | 2022-10-31 20:06:10 +0300 |
commit | 7ba6969e65b4491e3ba7f866a3ddd3e0556b1fc9 (patch) | |
tree | b01ab44d37ac17cd4678444bc0d2f10a8f7eeca3 | |
parent | a0ff46a7fbb94ed4a815244f14a7ef1caa9f1d97 (diff) |
Moved all server mocking code for share model test to independent ShareTestUtils file
Signed-off-by: Claudio Cambra <claudio.cambra@nextcloud.com>
-rw-r--r-- | src/gui/folderman.h | 3 | ||||
-rw-r--r-- | test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | test/sharetestutils.cpp | 442 | ||||
-rw-r--r-- | test/sharetestutils.h | 136 | ||||
-rw-r--r-- | test/testhelper.cpp | 18 | ||||
-rw-r--r-- | test/testhelper.h | 2 | ||||
-rw-r--r-- | test/testsharemodel.cpp | 920 |
7 files changed, 801 insertions, 721 deletions
diff --git a/src/gui/folderman.h b/src/gui/folderman.h index 8cc499cd8..6409cc8b4 100644 --- a/src/gui/folderman.h +++ b/src/gui/folderman.h @@ -28,6 +28,7 @@ class TestFolderMan; class TestCfApiShellExtensionsIPC; class TestShareModel; +class ShareTestHelper; namespace OCC { @@ -380,7 +381,7 @@ private: friend class OCC::Application; friend class ::TestFolderMan; friend class ::TestCfApiShellExtensionsIPC; - friend class ::TestShareModel; + friend class ::ShareTestHelper; }; } // namespace OCC diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 820984631..d3cd1f93a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(testutils pushnotificationstestutils.cpp themeutils.cpp testhelper.cpp + sharetestutils.cpp ) target_link_libraries(testutils PUBLIC Nextcloud::sync Qt5::Test) diff --git a/test/sharetestutils.cpp b/test/sharetestutils.cpp new file mode 100644 index 000000000..7f481a612 --- /dev/null +++ b/test/sharetestutils.cpp @@ -0,0 +1,442 @@ +/* + * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "sharetestutils.h" + +#include "testhelper.h" + +using namespace OCC; + +FakeShareDefinition::FakeShareDefinition(ShareTestHelper *helper, + const Share::ShareType type, + const QString &shareWith, + const QString &displayString, + const QString &password, + const QString ¬e, + const QString &expiration) +{ + ++helper->latestShareId; + const auto idString = QString::number(helper->latestShareId); + + + fileDefinition = helper->fakeFileDefinition; + shareId = idString; + shareCanDelete = true; + shareCanEdit = true; + shareUidOwner = helper->account->davUser();; + shareDisplayNameOwner = helper->account->davDisplayName(); + sharePassword = password; + sharePermissions = static_cast<int>(SharePermissions(SharePermissionRead | + SharePermissionUpdate | + SharePermissionCreate | + SharePermissionDelete | + SharePermissionShare)); + shareNote = note; + shareHideDownload = 0; + shareExpiration = expiration; + shareSendPasswordByTalk = false; + shareType = type; + + const auto token = QString(QStringLiteral("GQ4aLrZEdJJkopW-") + idString); + // Weird, but it's what the server does + const auto finalShareWith = type == Share::TypeLink ? password : shareWith; + const auto shareWithDisplayName = type == Share::TypeLink ? QStringLiteral("(Shared Link)") : displayString; + const auto linkLabel = type == Share::TypeLink ? displayString : QString(); + const auto linkName = linkShareLabel; + const auto linkUrl = type == Share::TypeLink ? QString(helper->account->davUrl().toString() + QStringLiteral("/s/") + token) : QString(); + + shareShareWith = finalShareWith; + shareShareWithDisplayName = shareWithDisplayName; + shareToken = token; + linkShareName = linkName; + linkShareLabel = linkLabel; + linkShareUrl = linkUrl; +} + +QJsonObject FakeShareDefinition::toShareJsonObject() const +{ + QJsonObject newShareJson; + newShareJson.insert("uid_file_owner", fileDefinition.fileOwnerUid); + newShareJson.insert("displayname_file_owner", fileDefinition.fileOwnerDisplayName); + newShareJson.insert("file_target", fileDefinition.fileTarget); + newShareJson.insert("has_preview", fileDefinition.fileHasPreview); + newShareJson.insert("file_parent", fileDefinition.fileFileParent); + newShareJson.insert("file_source", fileDefinition.fileSource); + newShareJson.insert("item_source", fileDefinition.fileItemSource); + newShareJson.insert("item_type", fileDefinition.fileItemType); + newShareJson.insert("mail_send", fileDefinition.fileMailSend); + newShareJson.insert("mimetype", fileDefinition.fileMimeType); + newShareJson.insert("parent", fileDefinition.fileParent); + newShareJson.insert("path", fileDefinition.filePath); + newShareJson.insert("storage", fileDefinition.fileStorage); + newShareJson.insert("storage_id", fileDefinition.fileStorageId); + newShareJson.insert("id", shareId); + newShareJson.insert("can_delete", shareCanDelete); + newShareJson.insert("can_edit", shareCanEdit); + newShareJson.insert("uid_owner", shareUidOwner); + newShareJson.insert("displayname_owner", shareDisplayNameOwner); + newShareJson.insert("password", sharePassword); + newShareJson.insert("permissions", sharePermissions); + newShareJson.insert("note", shareNote); + newShareJson.insert("hide_download", shareHideDownload); + newShareJson.insert("expiration", shareExpiration); + newShareJson.insert("send_password_by_talk", shareSendPasswordByTalk); + newShareJson.insert("share_type", shareType); + newShareJson.insert("share_with", shareShareWith); + newShareJson.insert("share_with_displayname", shareShareWithDisplayName); + newShareJson.insert("token", shareToken); + newShareJson.insert("name", linkShareName); + newShareJson.insert("label", linkShareLabel); + newShareJson.insert("url", linkShareUrl); + + return newShareJson; +} + +QByteArray FakeShareDefinition::toRequestReply() const +{ + const auto shareJson = toShareJsonObject(); + return jsonValueToOccReply(shareJson); +} + +// Below is ShareTestHelper +ShareTestHelper::ShareTestHelper(QObject *parent) + : QObject(parent) +{ +} + +ShareTestHelper::~ShareTestHelper() +{ + const auto folder = FolderMan::instance()->folder(fakeFolder.localPath()); + if (folder) { + FolderMan::instance()->removeFolder(folder); + } + AccountManager::instance()->deleteAccount(accountState.data()); +} + +void ShareTestHelper::setup() +{ + _fakeQnam.reset(new FakeQNAM({})); + _fakeQnam->setOverride([this](const QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *device) { + return qnamOverride(op, req, device); + }); + + account = Account::create(); + account->setCredentials(new FakeCredentials{_fakeQnam.data()}); + account->setUrl(QUrl(("owncloud://somehost/owncloud"))); + account->setCapabilities(_fakeCapabilities); + accountState = new AccountState(account); + AccountManager::instance()->addAccount(account); + + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + fakeFolder.localModifier().insert(testFileName); + + const auto folderMan = FolderMan::instance(); + QCOMPARE(folderMan, &fm); + QVERIFY(folderMan->addFolder(accountState.data(), folderDefinition(fakeFolder.localPath()))); + const auto folder = FolderMan::instance()->folder(fakeFolder.localPath()); + QVERIFY(folder); + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + + const auto fakeFileInfo = fakeFolder.remoteModifier().find(testFileName); + QVERIFY(fakeFileInfo); + fakeFileInfo->permissions.setPermission(RemotePermissions::CanReshare); + QVERIFY(fakeFolder.syncOnce()); + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + QVERIFY(fakeFileInfo->permissions.CanReshare); + + _fakeCapabilities = QVariantMap { + {QStringLiteral("files_sharing"), QVariantMap { + {QStringLiteral("api_enabled"), true}, + {QStringLiteral("default_permissions"), 19}, + {QStringLiteral("public"), QVariantMap { + {QStringLiteral("enabled"), true}, + {QStringLiteral("expire_date"), QVariantMap { + {QStringLiteral("days"), 30}, + {QStringLiteral("enforced"), false}, + }}, + {QStringLiteral("expire_date_internal"), QVariantMap { + {QStringLiteral("days"), 30}, + {QStringLiteral("enforced"), false}, + }}, + {QStringLiteral("expire_date_remote"), QVariantMap { + {QStringLiteral("days"), 30}, + {QStringLiteral("enforced"), false}, + }}, + {QStringLiteral("password"), QVariantMap { + {QStringLiteral("enforced"), false}, + }}, + }}, + {QStringLiteral("sharebymail"), QVariantMap { + {QStringLiteral("enabled"), true}, + {QStringLiteral("password"), QVariantMap { + {QStringLiteral("enforced"), false}, + }}, + }}, + }}, + }; + + // Generate test data + // Properties that apply to the file generally + const auto fileOwnerUid = account->davUser(); + const auto fileOwnerDisplayName = account->davDisplayName(); + const auto fileTarget = QString(QStringLiteral("/") + fakeFileInfo->name); + const auto fileHasPreview = true; + const auto fileFileParent = QString(fakeFolder.remoteModifier().fileId); + const auto fileSource = QString(fakeFileInfo->fileId); + const auto fileItemSource = fileSource; + const auto fileItemType = QStringLiteral("file"); + const auto fileMailSend = 0; + const auto fileMimeType = QStringLiteral("text/markdown"); + const auto fileParent = QString(); + const auto filePath = fakeFileInfo->path(); + const auto fileStorage = 3; + const auto fileStorageId = QString(QStringLiteral("home::") + account->davUser()); + + fakeFileDefinition = FakeFileReplyDefinition { + fileOwnerUid, + fileOwnerDisplayName, + fileTarget, + fileHasPreview, + fileFileParent, + fileSource, + fileItemSource, + fileItemType, + fileMailSend, + fileMimeType, + fileParent, + filePath, + fileStorage, + fileStorageId, + }; + + emit setupSucceeded(); +} + +QNetworkReply *ShareTestHelper::qnamOverride(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *device) +{ + QNetworkReply *reply = nullptr; + + const auto reqUrl = req.url(); + const auto reqRawPath = reqUrl.path(); + const auto reqPath = reqRawPath.startsWith("/owncloud/") ? reqRawPath.mid(10) : reqRawPath; + qDebug() << req.url() << reqPath << op; + + // Properly formatted PROPFIND URL goes something like: + // https://cloud.nextcloud.com/remote.php/dav/files/claudio/Readme.md + if(reqPath.endsWith(testFileName) && req.attribute(QNetworkRequest::CustomVerbAttribute) == "PROPFIND") { + + reply = new FakePropfindReply(fakeFolder.remoteModifier(), op, req, this); + + } else if (req.url().toString().startsWith(accountState->account()->url().toString()) && + reqPath.startsWith(QStringLiteral("ocs/v2.php/apps/files_sharing/api/v1/shares"))) { + + if (op == QNetworkAccessManager::PostOperation) { + reply = handleSharePostOperation(op, req, device); + + } else if(req.attribute(QNetworkRequest::CustomVerbAttribute) == "DELETE") { + reply = handleShareDeleteOperation(op, req, reqPath); + + } else if(op == QNetworkAccessManager::PutOperation) { + reply = handleSharePutOperation(op, req, reqPath, device); + + } else if(req.attribute(QNetworkRequest::CustomVerbAttribute) == "GET") { + reply = handleShareGetOperation(op, req, reqPath); + } + } else { + reply = new FakeErrorReply(op, req, this, 404, _fake404Response); + } + + return reply; +} + +QNetworkReply *ShareTestHelper::handleSharePostOperation(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *device) +{ + QNetworkReply *reply = nullptr; + + // POST https://somehost/owncloud/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json + // Header: { Ocs-APIREQUEST: true, Content-Type: application/x-www-form-urlencoded, X-Request-ID: 1527752d-e147-4da7-89b8-fb06315a5fad, } + // Data: [path=file.md&shareType=3]" + const QUrlQuery urlQuery(req.url()); + const auto formatParam = urlQuery.queryItemValue(QStringLiteral("format")); + + if (formatParam == QStringLiteral("json")) { + device->open(QIODevice::ReadOnly); + const auto requestBody = device->readAll(); + device->close(); + + const auto requestData = requestBody.split('&'); + // We don't care about path since we know the file we are testing with + auto requestShareType = -10; // Just in case + QString requestShareWith; + QString requestName; + QString requestPassword; + + for(const auto &data : requestData) { + const auto requestDataUrl = QUrl::fromPercentEncoding(data); + const QString requestDataUrlString(requestDataUrl); + + if (data.contains("shareType=")) { + const auto shareTypeString = requestDataUrlString.mid(10); + requestShareType = Share::ShareType(shareTypeString.toInt()); + } else if (data.contains("shareWith=")) { + requestShareWith = data.mid(10); + } else if (data.contains("name=")) { + requestName = data.mid(5); + } else if (data.contains("password=")) { + requestPassword = data.mid(9); + } + } + + if (requestPassword.isEmpty() && + ((requestShareType == Share::TypeEmail && account->capabilities().shareEmailPasswordEnforced()) || + (requestShareType == Share::TypeLink && account->capabilities().sharePublicLinkEnforcePassword()))) { + + reply = new FakePayloadReply(op, req, _fake403Response, searchResultsReplyDelay, _fakeQnam.data()); + + } else if (requestShareType >= 0) { + const auto shareType = Share::ShareType(requestShareType); + reply = new FakePayloadReply(op, req, createNewShare(shareType, requestShareWith, requestPassword), searchResultsReplyDelay, _fakeQnam.data()); + } + } + + return reply; +} + +QNetworkReply *ShareTestHelper::handleSharePutOperation(const QNetworkAccessManager::Operation op, const QNetworkRequest &req, const QString &reqPath, QIODevice *device) +{ + QNetworkReply *reply = nullptr; + + const auto splitUrlPath = reqPath.split('/'); + const auto shareId = splitUrlPath.last(); + + const QUrlQuery urlQuery(req.url()); + const auto formatParam = urlQuery.queryItemValue(QStringLiteral("format")); + + if (formatParam == QStringLiteral("json")) { + device->open(QIODevice::ReadOnly); + const auto requestBody = device->readAll(); + device->close(); + + const auto requestData = requestBody.split('&'); + + const auto existingShareIterator = std::find_if(_sharesReplyData.cbegin(), _sharesReplyData.cend(), [&shareId](const QJsonValue &value) { + return value.toObject().value("id").toString() == shareId; + }); + + if (existingShareIterator == _sharesReplyData.cend()) { + reply = new FakeErrorReply(op, req, this, 404, _fake404Response); + } else { + const auto existingShareValue = *existingShareIterator; + auto shareObject = existingShareValue.toObject(); + + for (const auto &requestDataItem : requestData) { + const auto requestSplit = requestDataItem.split('='); + auto requestKey = requestSplit.first(); + auto requestValue = requestSplit.last(); + + // We send expireDate without time but the server returns with time at 00:00:00 + if (requestKey == "expireDate") { + requestKey = "expiration"; + requestValue.append(" 00:00:00"); + } + + shareObject.insert(QString(requestKey), QString(requestValue)); + } + + _sharesReplyData.replace(existingShareIterator - _sharesReplyData.cbegin(), shareObject); + reply = new FakePayloadReply(op, req, jsonValueToOccReply(shareObject), searchResultsReplyDelay, _fakeQnam.data()); + } + } + + return reply; +} + + +QNetworkReply *ShareTestHelper::handleShareDeleteOperation(const QNetworkAccessManager::Operation op, const QNetworkRequest &req, const QString &reqPath) +{ + QNetworkReply *reply = nullptr; + + const auto splitUrlPath = reqPath.split('/'); + const auto shareId = splitUrlPath.last(); + + const auto existingShareIterator = std::find_if(_sharesReplyData.cbegin(), _sharesReplyData.cend(), [&shareId](const QJsonValue &value) { + return value.toObject().value("id").toString() == shareId; + }); + + if (existingShareIterator == _sharesReplyData.cend()) { + reply = new FakeErrorReply(op, req, this, 404, _fake404Response); + } else { + _sharesReplyData.removeAt(existingShareIterator - _sharesReplyData.cbegin()); + reply = new FakePayloadReply(op, req, _fake200JsonResponse, searchResultsReplyDelay, _fakeQnam.data()); + } + + return reply; +} + +QNetworkReply *ShareTestHelper::handleShareGetOperation(const QNetworkAccessManager::Operation op, const QNetworkRequest &req, const QString &reqPath) +{ + QNetworkReply *reply = nullptr; + + // Properly formatted request to fetch shares goes something like: + // GET https://somehost/owncloud/ocs/v2.php/apps/files_sharing/api/v1/shares?path=file.md&reshares=true&format=json + // Header: { Ocs-APIREQUEST: true, Content-Type: application/x-www-form-urlencoded, X-Request-ID: 8ba8960d-ca0d-45ba-abf4-03ab95ba6064, } + // Data: [] + const auto urlQuery = QUrlQuery(req.url()); + const auto pathParam = urlQuery.queryItemValue(QStringLiteral("path")); + const auto resharesParam = urlQuery.queryItemValue(QStringLiteral("reshares")); + const auto formatParam = urlQuery.queryItemValue(QStringLiteral("format")); + + if (formatParam != QStringLiteral("json") || (!pathParam.isEmpty() && !pathParam.endsWith(QString(testFileName)))) { + reply = new FakeErrorReply(op, req, this, 400, _fake400Response); + } else if (reqPath.contains(QStringLiteral("ocs/v2.php/apps/files_sharing/api/v1/shares"))) { + reply = new FakePayloadReply(op, req, jsonValueToOccReply(_sharesReplyData), searchResultsReplyDelay, _fakeQnam.data()); + } + + return reply; +} + +const QByteArray ShareTestHelper::createNewShare(const Share::ShareType shareType, const QString &shareWith, const QString &password) +{ + const auto displayString = shareType == Share::TypeLink ? QString() : shareWith; + const FakeShareDefinition newShareDefinition(this, + shareType, + shareWith, + displayString, + password); + + _sharesReplyData.append(newShareDefinition.toShareJsonObject()); + return newShareDefinition.toRequestReply(); +} + +int ShareTestHelper::shareCount() const +{ + return _sharesReplyData.count(); +} + +void ShareTestHelper::appendShareReplyData(const FakeShareDefinition &definition) +{ + _sharesReplyData.append(definition.toShareJsonObject()); +} + +void ShareTestHelper::resetTestShares() +{ + _sharesReplyData = QJsonArray(); +} + +void ShareTestHelper::resetTestData() +{ + resetTestShares(); + account->setCapabilities(_fakeCapabilities); +} diff --git a/test/sharetestutils.h b/test/sharetestutils.h new file mode 100644 index 000000000..c539547fe --- /dev/null +++ b/test/sharetestutils.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#pragma once + +#include <QObject> +#include <QJsonArray> +#include <QJsonObject> +#include <QJsonDocument> +#include <QNetworkReply> +#include <QNetworkRequest> + +#include "gui/accountmanager.h" +#include "gui/folderman.h" +#include "gui/sharemanager.h" + +#include "syncenginetestutils.h" + +using namespace OCC; + +struct FakeFileReplyDefinition +{ + QString fileOwnerUid; + QString fileOwnerDisplayName; + QString fileTarget; + bool fileHasPreview; + QString fileFileParent; + QString fileSource; + QString fileItemSource; + QString fileItemType; + int fileMailSend; + QString fileMimeType; + QString fileParent; + QString filePath; + int fileStorage; + QString fileStorageId; +}; + +struct FakeShareDefinition +{ + FakeShareDefinition() = default; + FakeShareDefinition(ShareTestHelper *helper, + const Share::ShareType type, + const QString &shareWith, + const QString &displayString, + const QString &password = QString(), + const QString ¬e = QString(), + const QString &expiration = QString()); + + FakeFileReplyDefinition fileDefinition; + QString shareId; + bool shareCanDelete; + bool shareCanEdit; + QString shareUidOwner; + QString shareDisplayNameOwner; + QString sharePassword; + int sharePermissions; + QString shareNote; + int shareHideDownload; + QString shareExpiration; + bool shareSendPasswordByTalk; + int shareType; + QString shareShareWith; + QString shareShareWithDisplayName; + QString shareToken; + QString linkShareName; + QString linkShareLabel; + QString linkShareUrl; + + [[nodiscard]] QJsonObject toShareJsonObject() const; + [[nodiscard]] QByteArray toRequestReply() const; +}; + +class ShareTestHelper : public QObject +{ + Q_OBJECT + +public: + ShareTestHelper(QObject *parent = nullptr); + ~ShareTestHelper() override; + + FolderMan fm; + FakeFolder fakeFolder{FileInfo{}}; + FakeFileReplyDefinition fakeFileDefinition; + + AccountPtr account; + AccountStatePtr accountState; + + int latestShareId = 0; + + static constexpr auto testFileName = "file.md"; + static constexpr auto searchResultsReplyDelay = 100; + static constexpr auto expectedDtFormat = "yyyy-MM-dd 00:00:00"; + + const QByteArray createNewShare(const Share::ShareType shareType, const QString &shareWith, const QString &password); + [[nodiscard]] int shareCount() const; + +signals: + void setupSucceeded(); + +public slots: + void setup(); + void appendShareReplyData(const FakeShareDefinition &definition); + void resetTestShares(); + void resetTestData(); + +private slots: + [[nodiscard]] QNetworkReply *qnamOverride(const QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *device); + [[nodiscard]] QNetworkReply *handleSharePostOperation(const QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *device); + [[nodiscard]] QNetworkReply *handleSharePutOperation(const QNetworkAccessManager::Operation op, const QNetworkRequest &req, const QString &reqPath, QIODevice *device); + [[nodiscard]] QNetworkReply *handleShareDeleteOperation(const QNetworkAccessManager::Operation op, const QNetworkRequest &req, const QString &reqPath); + [[nodiscard]] QNetworkReply *handleShareGetOperation(const QNetworkAccessManager::Operation op, const QNetworkRequest &req, const QString &reqPath); + +private: + QScopedPointer<FakeQNAM> _fakeQnam; + + QByteArray _fake404Response = R"({"ocs":{"meta":{"status":"failure","statuscode":404,"message":"Invalid query, please check the syntax. API specifications are here: http:\/\/www.freedesktop.org\/wiki\/Specifications\/open-collaboration-services.\n"},"data":[]}})"; + QByteArray _fake403Response = R"({"ocs":{"meta":{"status":"failure","statuscode":403,"message":"Operation not allowed."},"data":[]}})"; + QByteArray _fake400Response = R"({"ocs":{"meta":{"status":"failure","statuscode":400,"message":"Parameter is incorrect.\n"},"data":[]}})"; + QByteArray _fake200JsonResponse = R"({"ocs":{"data":[],"meta":{"message":"OK","status":"ok","statuscode":200}}})"; + + QJsonArray _sharesReplyData; + QVariantMap _fakeCapabilities; + QSet<int> _liveShareIds; +}; diff --git a/test/testhelper.cpp b/test/testhelper.cpp index 8ba0f151b..2a540965f 100644 --- a/test/testhelper.cpp +++ b/test/testhelper.cpp @@ -1,4 +1,6 @@ #include "testhelper.h" +#include <QJsonObject> +#include <QJsonDocument> OCC::FolderDefinition folderDefinition(const QString &path) { @@ -8,3 +10,19 @@ OCC::FolderDefinition folderDefinition(const QString &path) d.alias = path; return d; } + + +const QByteArray jsonValueToOccReply(const QJsonValue &jsonValue) +{ + QJsonObject root; + QJsonObject ocs; + QJsonObject meta; + + meta.insert("statuscode", 200); + + ocs.insert(QStringLiteral("data"), jsonValue); + ocs.insert(QStringLiteral("meta"), meta); + root.insert(QStringLiteral("ocs"), ocs); + + return QJsonDocument(root).toJson(); +} diff --git a/test/testhelper.h b/test/testhelper.h index 40379577c..2ddb859e5 100644 --- a/test/testhelper.h +++ b/test/testhelper.h @@ -18,4 +18,6 @@ public: OCC::FolderDefinition folderDefinition(const QString &path); +const QByteArray jsonValueToOccReply(const QJsonValue &jsonValue); + #endif // TESTHELPER_H diff --git a/test/testsharemodel.cpp b/test/testsharemodel.cpp index 04c5fcd05..9a3b10853 100644 --- a/test/testsharemodel.cpp +++ b/test/testsharemodel.cpp @@ -15,627 +15,88 @@ #include "gui/filedetails/sharemodel.h" #include <QTest> +#include <QAbstractItemModelTester> #include <QSignalSpy> #include <QFileInfo> #include <QFlags> +#include <QDateTime> +#include <QTimeZone> -#include "accountmanager.h" -#include "folderman.h" -#include "syncenginetestutils.h" -#include "testhelper.h" +#include "sharetestutils.h" #include "libsync/theme.h" using namespace OCC; -static QByteArray fake404Response = R"( -{"ocs":{"meta":{"status":"failure","statuscode":404,"message":"Invalid query, please check the syntax. API specifications are here: http:\/\/www.freedesktop.org\/wiki\/Specifications\/open-collaboration-services.\n"},"data":[]}} -)"; - -static QByteArray fake403Response = R"( -{"ocs":{"meta":{"status":"failure","statuscode":403,"message":"Operation not allowed."},"data":[]}} -)"; - -static QByteArray fake400Response = R"( -{"ocs":{"meta":{"status":"failure","statuscode":400,"message":"Parameter is incorrect.\n"},"data":[]}} -)"; - -static QByteArray fake200JsonResponse = R"( -{"ocs":{"data":[],"meta":{"message":"OK","status":"ok","statuscode":200}}} -)"; - -constexpr auto testFileName = "file.md"; -constexpr auto searchResultsReplyDelay = 100; -constexpr auto expectedDtFormat = "yyyy-MM-dd 00:00:00"; - class TestShareModel : public QObject { Q_OBJECT -public: - TestShareModel() = default; - ~TestShareModel() override - { - const auto folder = FolderMan::instance()->folder(_fakeFolder.localPath()); - if (folder) { - FolderMan::instance()->removeFolder(folder); - } - AccountManager::instance()->deleteAccount(_accountState.data()); - } - - struct FakeFileReplyDefinition - { - QString fileOwnerUid; - QString fileOwnerDisplayName; - QString fileTarget; - bool fileHasPreview; - QString fileFileParent; - QString fileSource; - QString fileItemSource; - QString fileItemType; - int fileMailSend; - QString fileMimeType; - QString fileParent; - QString filePath; - int fileStorage; - QString fileStorageId; - }; - - struct FakeShareDefinition - { - FakeFileReplyDefinition fileDefinition; - QString shareId; - bool shareCanDelete; - bool shareCanEdit; - QString shareUidOwner; - QString shareDisplayNameOwner; - QString sharePassword; - int sharePermissions; - QString shareNote; - int shareHideDownload; - QString shareExpiration; - bool shareSendPasswordByTalk; - int shareType; - QString shareShareWith; - QString shareShareWithDisplayName; - QString shareToken; - QString linkShareName; - QString linkShareLabel; - QString linkShareUrl; - }; - - const QByteArray fakeSharesResponse() const - { - QJsonObject root; - QJsonObject ocs; - QJsonObject meta; - - meta.insert("statuscode", 200); - - ocs.insert(QStringLiteral("data"), _sharesReplyData); - ocs.insert(QStringLiteral("meta"), meta); - root.insert(QStringLiteral("ocs"), ocs); - - return QJsonDocument(root).toJson(); - } - - QJsonObject shareDefinitionToJson(const FakeShareDefinition &definition) - { - QJsonObject newShareJson; - newShareJson.insert("uid_file_owner", definition.fileDefinition.fileOwnerUid); - newShareJson.insert("displayname_file_owner", definition.fileDefinition.fileOwnerDisplayName); - newShareJson.insert("file_target", definition.fileDefinition.fileTarget); - newShareJson.insert("has_preview", definition.fileDefinition.fileHasPreview); - newShareJson.insert("file_parent", definition.fileDefinition.fileFileParent); - newShareJson.insert("file_source", definition.fileDefinition.fileSource); - newShareJson.insert("item_source", definition.fileDefinition.fileItemSource); - newShareJson.insert("item_type", definition.fileDefinition.fileItemType); - newShareJson.insert("mail_send", definition.fileDefinition.fileMailSend); - newShareJson.insert("mimetype", definition.fileDefinition.fileMimeType); - newShareJson.insert("parent", definition.fileDefinition.fileParent); - newShareJson.insert("path", definition.fileDefinition.filePath); - newShareJson.insert("storage", definition.fileDefinition.fileStorage); - newShareJson.insert("storage_id", definition.fileDefinition.fileStorageId); - newShareJson.insert("id", definition.shareId); - newShareJson.insert("can_delete", definition.shareCanDelete); - newShareJson.insert("can_edit", definition.shareCanEdit); - newShareJson.insert("uid_owner", definition.shareUidOwner); - newShareJson.insert("displayname_owner", definition.shareDisplayNameOwner); - newShareJson.insert("password", definition.sharePassword); - newShareJson.insert("permissions", definition.sharePermissions); - newShareJson.insert("note", definition.shareNote); - newShareJson.insert("hide_download", definition.shareHideDownload); - newShareJson.insert("expiration", definition.shareExpiration); - newShareJson.insert("send_password_by_talk", definition.shareSendPasswordByTalk); - newShareJson.insert("share_type", definition.shareType); - newShareJson.insert("share_with", definition.shareShareWith); // Doesn't seem to make sense but is server behaviour - newShareJson.insert("share_with_displayname", definition.shareShareWithDisplayName); - newShareJson.insert("token", definition.shareToken); - newShareJson.insert("name", definition.linkShareName); - newShareJson.insert("label", definition.linkShareLabel); - newShareJson.insert("url", definition.linkShareUrl); - - return newShareJson; - } - - void appendShareReplyData(const FakeShareDefinition &definition) - { - const auto shareJson = shareDefinitionToJson(definition); - _sharesReplyData.append(shareJson); - } - - const QByteArray createNewShare(const Share::ShareType shareType, const QString &shareWith) - { - ++_latestShareId; - const auto newShareId = QString::number(_latestShareId); - const auto newShareCanDelete = true; - const auto newShareCanEdit = true; - const auto newShareUidOwner = _account->davUser(); - const auto newShareDisplayNameOwner = _account->davDisplayName(); - const auto newSharePassword = QString(); - const auto newSharePermissions = static_cast<int>(SharePermissions(SharePermissionRead | - SharePermissionUpdate | - SharePermissionCreate | - SharePermissionDelete | - SharePermissionShare)); - const auto newShareNote = QString(); - const auto newShareHideDownload = 0; - const auto newShareExpiration = QString(); - const auto newShareSendPasswordByTalk = false; - const auto newShareType = shareType; - const auto newShareShareWith = shareType == Share::TypeLink ? newSharePassword : shareWith; - const auto newShareShareWithDisplayName = shareType == Share::TypeLink ? QStringLiteral("(Shared Link)") : shareWith; - const auto newShareToken = QString::number(qHash(newShareId + _fakeFileDefinition.filePath)); - const auto newLinkShareName = QString(); - const auto newLinkShareLabel = QString(); - const auto newLinkShareUrl = shareType == Share::TypeLink ? QString(_account->davUrl().toString() + QStringLiteral("/s/") + newShareToken) : QString(); - - const FakeShareDefinition newShareDefinition { - _fakeFileDefinition, - newShareId, - newShareCanDelete, - newShareCanEdit, - newShareUidOwner, - newShareDisplayNameOwner, - newSharePassword, - newSharePermissions, - newShareNote, - newShareHideDownload, - newShareExpiration, - newShareSendPasswordByTalk, - newShareType, - newShareShareWith, - newShareShareWithDisplayName, - newShareToken, - newLinkShareName, - newLinkShareLabel, - newLinkShareUrl, - }; - - const auto shareJson = shareDefinitionToJson(newShareDefinition); - _sharesReplyData.append(shareJson); - return shareWrappedAsReply(shareJson); - } - - QByteArray shareWrappedAsReply(const QJsonObject &shareObject) - { - QJsonObject root; - QJsonObject ocs; - QJsonObject meta; - - meta.insert("statuscode", 200); - - ocs.insert(QStringLiteral("data"), shareObject); - ocs.insert(QStringLiteral("meta"), meta); - root.insert(QStringLiteral("ocs"), ocs); - - return QJsonDocument(root).toJson(); - } - - void resetTestData() - { - _sharesReplyData = QJsonArray(); - _account->setCapabilities(_fakeCapabilities); - } - private: - FolderMan _fm; - FakeFolder _fakeFolder{FileInfo{}}; + ShareTestHelper helper; - AccountPtr _account; - AccountStatePtr _accountState; - QScopedPointer<FakeQNAM> _fakeQnam; - FakeFileReplyDefinition _fakeFileDefinition; FakeShareDefinition _testLinkShareDefinition; FakeShareDefinition _testEmailShareDefinition; FakeShareDefinition _testUserShareDefinition; FakeShareDefinition _testRemoteShareDefinition; - QJsonArray _sharesReplyData; - QVariantMap _fakeCapabilities; - QSet<int> _liveShareIds; - int _latestShareId = 0; private slots: void initTestCase() { - _fakeQnam.reset(new FakeQNAM({})); - _fakeQnam->setOverride([this](QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *device) { - QNetworkReply *reply = nullptr; - - const auto reqUrl = req.url(); - const auto reqRawPath = reqUrl.path(); - const auto reqPath = reqRawPath.startsWith("/owncloud/") ? reqRawPath.mid(10) : reqRawPath; - qDebug() << req.url() << reqPath << op; - - // Properly formatted PROPFIND URL goes something like: - // https://cloud.nextcloud.com/remote.php/dav/files/claudio/Readme.md - if(reqPath.endsWith(testFileName) && req.attribute(QNetworkRequest::CustomVerbAttribute) == "PROPFIND") { - - reply = new FakePropfindReply(_fakeFolder.remoteModifier(), op, req, this); - - } else if (req.url().toString().startsWith(_accountState->account()->url().toString()) && - reqPath.startsWith(QStringLiteral("ocs/v2.php/apps/files_sharing/api/v1/shares")) && - op == QNetworkAccessManager::PostOperation) { - - // POST https://somehost/owncloud/ocs/v2.php/apps/files_sharing/api/v1/shares?format=json - // Header: { Ocs-APIREQUEST: true, Content-Type: application/x-www-form-urlencoded, X-Request-ID: 1527752d-e147-4da7-89b8-fb06315a5fad, } - // Data: [path=file.md&shareType=3]" - const QUrlQuery urlQuery(req.url()); - const auto formatParam = urlQuery.queryItemValue(QStringLiteral("format")); - - if (formatParam == QStringLiteral("json")) { - device->open(QIODevice::ReadOnly); - const auto requestBody = device->readAll(); - device->close(); - - const auto requestData = requestBody.split('&'); - // We don't care about path since we know the file we are testing with - auto requestShareType = -10; // Just in case - QString requestShareWith; - QString requestName; - QString requestPassword; - - for(const auto &data : requestData) { - const auto requestDataUrl = QUrl::fromPercentEncoding(data); - const QString requestDataUrlString(requestDataUrl); - - if (data.contains("shareType=")) { - const auto shareTypeString = requestDataUrlString.mid(10); - requestShareType = Share::ShareType(shareTypeString.toInt()); - } else if (data.contains("shareWith=")) { - requestShareWith = data.mid(10); - } else if (data.contains("name=")) { - requestName = data.mid(5); - } else if (data.contains("password=")) { - requestPassword = data.mid(9); - } - } - - if (requestPassword.isEmpty() && - ((requestShareType == Share::TypeEmail && _account->capabilities().shareEmailPasswordEnforced()) || - (requestShareType == Share::TypeLink && _account->capabilities().sharePublicLinkEnforcePassword()))) { - - reply = new FakePayloadReply(op, req, fake403Response, searchResultsReplyDelay, _fakeQnam.data()); - - } else if (requestShareType >= 0) { - const auto shareType = Share::ShareType(requestShareType); - reply = new FakePayloadReply(op, req, createNewShare(shareType, requestShareWith), searchResultsReplyDelay, _fakeQnam.data()); - } - } - - } else if(req.url().toString().startsWith(_accountState->account()->url().toString()) && - reqPath.startsWith(QStringLiteral("ocs/v2.php/apps/files_sharing/api/v1/shares")) && - req.attribute(QNetworkRequest::CustomVerbAttribute) == "DELETE") { - - const auto splitUrlPath = reqPath.split('/'); - const auto shareId = splitUrlPath.last(); - - const auto existingShareIterator = std::find_if(_sharesReplyData.cbegin(), _sharesReplyData.cend(), [&shareId](const QJsonValue &value) { - return value.toObject().value("id").toString() == shareId; - }); - - if (existingShareIterator == _sharesReplyData.cend()) { - reply = new FakeErrorReply(op, req, this, 404, fake404Response); - } else { - _sharesReplyData.removeAt(existingShareIterator - _sharesReplyData.cbegin()); - reply = new FakePayloadReply(op, req, fake200JsonResponse, searchResultsReplyDelay, _fakeQnam.data()); - } - - } else if(req.url().toString().startsWith(_accountState->account()->url().toString()) && - reqPath.startsWith(QStringLiteral("ocs/v2.php/apps/files_sharing/api/v1/shares")) && - op == QNetworkAccessManager::PutOperation) { - - const auto splitUrlPath = reqPath.split('/'); - const auto shareId = splitUrlPath.last(); - - const QUrlQuery urlQuery(req.url()); - const auto formatParam = urlQuery.queryItemValue(QStringLiteral("format")); - - if (formatParam == QStringLiteral("json")) { - device->open(QIODevice::ReadOnly); - const auto requestBody = device->readAll(); - device->close(); - - const auto requestData = requestBody.split('&'); - - const auto existingShareIterator = std::find_if(_sharesReplyData.cbegin(), _sharesReplyData.cend(), [&shareId](const QJsonValue &value) { - return value.toObject().value("id").toString() == shareId; - }); - - if (existingShareIterator == _sharesReplyData.cend()) { - reply = new FakeErrorReply(op, req, this, 404, fake404Response); - } else { - const auto existingShareValue = *existingShareIterator; - auto shareObject = existingShareValue.toObject(); - - for (const auto &requestDataItem : requestData) { - const auto requestSplit = requestDataItem.split('='); - auto requestKey = requestSplit.first(); - auto requestValue = requestSplit.last(); - - // We send expireDate without time but the server returns with time at 00:00:00 - if (requestKey == "expireDate") { - requestKey = "expiration"; - requestValue.append(" 00:00:00"); - } - - shareObject.insert(QString(requestKey), QString(requestValue)); - } - - _sharesReplyData.replace(existingShareIterator - _sharesReplyData.cbegin(), shareObject); - reply = new FakePayloadReply(op, req, shareWrappedAsReply(shareObject), searchResultsReplyDelay, _fakeQnam.data()); - } - } - - } else if(req.url().toString().startsWith(_accountState->account()->url().toString()) && - reqPath.startsWith(QStringLiteral("ocs/v2.php/apps/files_sharing/api/v1/shares")) && - req.attribute(QNetworkRequest::CustomVerbAttribute) == "GET") { - - // Properly formatted request to fetch shares goes something like: - // GET https://somehost/owncloud/ocs/v2.php/apps/files_sharing/api/v1/shares?path=file.md&reshares=true&format=json - // Header: { Ocs-APIREQUEST: true, Content-Type: application/x-www-form-urlencoded, X-Request-ID: 8ba8960d-ca0d-45ba-abf4-03ab95ba6064, } - // Data: [] - const auto urlQuery = QUrlQuery(req.url()); - const auto pathParam = urlQuery.queryItemValue(QStringLiteral("path")); - const auto resharesParam = urlQuery.queryItemValue(QStringLiteral("reshares")); - const auto formatParam = urlQuery.queryItemValue(QStringLiteral("format")); - - if (formatParam != QStringLiteral("json") || (!pathParam.isEmpty() && pathParam != QString(testFileName))) { - reply = new FakeErrorReply(op, req, this, 400, fake400Response); - } else if (reqPath.contains(QStringLiteral("ocs/v2.php/apps/files_sharing/api/v1/shares"))) { - reply = new FakePayloadReply(op, req, fakeSharesResponse(), searchResultsReplyDelay, _fakeQnam.data()); - } - - } else if (!req.url().toString().startsWith(_accountState->account()->url().toString())) { - reply = new FakeErrorReply(op, req, this, 404, fake404Response); - } else if (!reply) { - return qobject_cast<QNetworkReply*>(new FakeErrorReply(op, req, this, 404, QByteArrayLiteral("{error: \"Not found!\"}"))); - } - - return reply; - }); - - _fakeCapabilities = QVariantMap { - {QStringLiteral("files_sharing"), QVariantMap { - {QStringLiteral("api_enabled"), true}, - {QStringLiteral("default_permissions"), 19}, - {QStringLiteral("public"), QVariantMap { - {QStringLiteral("enabled"), true}, - {QStringLiteral("expire_date"), QVariantMap { - {QStringLiteral("days"), 30}, - {QStringLiteral("enforced"), false}, - }}, - {QStringLiteral("expire_date_internal"), QVariantMap { - {QStringLiteral("days"), 30}, - {QStringLiteral("enforced"), false}, - }}, - {QStringLiteral("expire_date_remote"), QVariantMap { - {QStringLiteral("days"), 30}, - {QStringLiteral("enforced"), false}, - }}, - {QStringLiteral("password"), QVariantMap { - {QStringLiteral("enforced"), false}, - }}, - }}, - {QStringLiteral("sharebymail"), QVariantMap { - {QStringLiteral("enabled"), true}, - {QStringLiteral("password"), QVariantMap { - {QStringLiteral("enforced"), false}, - }}, - }}, - }}, - }; - - _account = Account::create(); - _account->setCredentials(new FakeCredentials{_fakeQnam.data()}); - _account->setUrl(QUrl(("owncloud://somehost/owncloud"))); - _account->setCapabilities(_fakeCapabilities); - _accountState = new AccountState(_account); - AccountManager::instance()->addAccount(_account); - - QCOMPARE(_fakeFolder.currentLocalState(), _fakeFolder.currentRemoteState()); - _fakeFolder.localModifier().insert(testFileName); - - const auto folderMan = FolderMan::instance(); - QCOMPARE(folderMan, &_fm); - QVERIFY(folderMan->addFolder(_accountState.data(), folderDefinition(_fakeFolder.localPath()))); - const auto folder = FolderMan::instance()->folder(_fakeFolder.localPath()); - QVERIFY(folder); - QVERIFY(_fakeFolder.syncOnce()); - QCOMPARE(_fakeFolder.currentLocalState(), _fakeFolder.currentRemoteState()); - ItemCompletedSpy completeSpy(_fakeFolder); - - const auto fakeFileInfo = _fakeFolder.remoteModifier().find(testFileName); - QVERIFY(fakeFileInfo); - fakeFileInfo->permissions.setPermission(RemotePermissions::CanReshare); - QVERIFY(_fakeFolder.syncOnce()); - QCOMPARE(_fakeFolder.currentLocalState(), _fakeFolder.currentRemoteState()); - QVERIFY(fakeFileInfo->permissions.CanReshare); - - // Generate test data - // Properties that apply to the file generally - const auto fileOwnerUid = _account->davUser(); - const auto fileOwnerDisplayName = _account->davDisplayName(); - const auto fileTarget = QString(QStringLiteral("/") + fakeFileInfo->name); - const auto fileHasPreview = true; - const auto fileFileParent = QString(_fakeFolder.remoteModifier().fileId); - const auto fileSource = QString(fakeFileInfo->fileId); - const auto fileItemSource = fileSource; - const auto fileItemType = QStringLiteral("file"); - const auto fileMailSend = 0; - const auto fileMimeType = QStringLiteral("text/markdown"); - const auto fileParent = QString(); - const auto filePath = fakeFileInfo->path(); - const auto fileStorage = 3; - const auto fileStorageId = QString(QStringLiteral("home::") + _account->davUser()); - - _fakeFileDefinition = FakeFileReplyDefinition { - fileOwnerUid, - fileOwnerDisplayName, - fileTarget, - fileHasPreview, - fileFileParent, - fileSource, - fileItemSource, - fileItemType, - fileMailSend, - fileMimeType, - fileParent, - filePath, - fileStorage, - fileStorageId, - }; + QSignalSpy helperSetupSucceeded(&helper, &ShareTestHelper::setupSucceeded); + helper.setup(); + QCOMPARE(helperSetupSucceeded.count(), 1); const auto testSharePassword = "3|$argon2id$v=19$m=65536," "t=4," "p=1$M2FoLnliWkhIZkwzWjFBQg$BPraP+JUqP1sV89rkymXpCGxHBlCct6bZ39xUGaYQ5w"; - const auto testShareToken = "GQ4aLrZEdJJkopW"; - const auto testShareCanDelete = true; - const auto testShareCanEdit = true; - const auto testShareUidOwner = _account->davUser(); - const auto testShareDisplayNameOwner = _account->davDisplayName(); - const auto testSharePermissions = static_cast<int>(SharePermissions(SharePermissionRead | - SharePermissionUpdate | - SharePermissionCreate | - SharePermissionDelete | - SharePermissionShare)); const auto testShareNote = QStringLiteral("This is a note!"); - const auto testShareHideDownload = 0; - const auto testShareExpiration = QDate::currentDate().addDays(1).toString(expectedDtFormat); - const auto testShareSendPasswordByTalk = false; - - ++_latestShareId; - const auto linkShareShareWith = testSharePassword; // Weird, but it's what the server does - const auto linkShareShareWithDisplayName = QStringLiteral("(Shared Link)"); - const auto linkShareUrl = QString(_account->davUrl().toString() + QStringLiteral("/s/") + testShareToken); - - _testLinkShareDefinition = FakeShareDefinition { - _fakeFileDefinition, - QString::number(_latestShareId), - testShareCanDelete, - testShareCanEdit, - testShareUidOwner, - testShareDisplayNameOwner, - testSharePassword, - testSharePermissions, - testShareNote, - testShareHideDownload, - testShareExpiration, - testShareSendPasswordByTalk, - Share::TypeLink, - linkShareShareWith, - linkShareShareWithDisplayName, - testShareToken, - QStringLiteral("Link share name"), - QStringLiteral("Link share label"), - linkShareUrl, - }; + const auto testShareExpiration = QDate::currentDate().addDays(1).toString(helper.expectedDtFormat); + + const auto linkShareLabel = QStringLiteral("Link share label"); + _testLinkShareDefinition = FakeShareDefinition(&helper, + Share::TypeLink, + {}, + linkShareLabel, + testSharePassword, + testShareNote, + testShareExpiration); - ++_latestShareId; const auto emailShareShareWith = QStringLiteral("test-email@nextcloud.com"); const auto emailShareShareWithDisplayName = QStringLiteral("Test email"); + _testEmailShareDefinition = FakeShareDefinition(&helper, + Share::TypeEmail, + emailShareShareWith, + emailShareShareWithDisplayName, + testSharePassword, + testShareNote, + testShareExpiration); - _testEmailShareDefinition = FakeShareDefinition { - _fakeFileDefinition, - QString::number(_latestShareId), - testShareCanDelete, - testShareCanEdit, - testShareUidOwner, - testShareDisplayNameOwner, - testSharePassword, - testSharePermissions, - testShareNote, - testShareHideDownload, - testShareExpiration, - testShareSendPasswordByTalk, - Share::TypeEmail, - emailShareShareWith, - emailShareShareWithDisplayName, - testShareToken, - {}, - {}, - {}, - }; - ++_latestShareId; const auto userShareShareWith = QStringLiteral("user"); const auto userShareShareWithDisplayName("A Nextcloud user"); + _testUserShareDefinition = FakeShareDefinition(&helper, + Share::TypeUser, + userShareShareWith, + userShareShareWithDisplayName); + - _testUserShareDefinition = FakeShareDefinition { - _fakeFileDefinition, - QString::number(_latestShareId), - testShareCanDelete, - testShareCanEdit, - testShareUidOwner, - testShareDisplayNameOwner, - testSharePassword, - testSharePermissions, - testShareNote, - testShareHideDownload, - testShareExpiration, - testShareSendPasswordByTalk, - Share::TypeUser, - userShareShareWith, - userShareShareWithDisplayName, - testShareToken, - {}, - {}, - {}, - }; - ++_latestShareId; const auto remoteShareShareWith = QStringLiteral("remote_share"); const auto remoteShareShareWithDisplayName("A remote share"); - - _testRemoteShareDefinition = FakeShareDefinition { - _fakeFileDefinition, - QString::number(_latestShareId), - testShareCanDelete, - testShareCanEdit, - testShareUidOwner, - testShareDisplayNameOwner, - testSharePassword, - testSharePermissions, - testShareNote, - testShareHideDownload, - testShareExpiration, - testShareSendPasswordByTalk, - Share::TypeRemote, - remoteShareShareWith, - remoteShareShareWithDisplayName, - testShareToken, - {}, - {}, - {}, - }; + _testRemoteShareDefinition = FakeShareDefinition(&helper, + Share::TypeRemote, + remoteShareShareWith, + remoteShareShareWithDisplayName); qRegisterMetaType<ShareePtr>("ShareePtr"); } void testSetAccountAndPath() { - resetTestData(); + helper.resetTestData(); // Test with a link share - appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -648,16 +109,16 @@ private slots: QSignalSpy sharingEnabledChanged(&model, &ShareModel::sharingEnabledChanged); QSignalSpy publicLinkSharesEnabledChanged(&model, &ShareModel::publicLinkSharesEnabledChanged); - model.setAccountState(_accountState.data()); + model.setAccountState(helper.accountState.data()); QCOMPARE(accountStateChanged.count(), 1); // Check all the account-related properties of the model - QCOMPARE(model.accountConnected(), _accountState->isConnected()); - QCOMPARE(model.sharingEnabled(), _account->capabilities().shareAPI()); - QCOMPARE(model.publicLinkSharesEnabled() && Theme::instance()->linkSharing(), _account->capabilities().sharePublicLink()); + QCOMPARE(model.accountConnected(), helper.accountState->isConnected()); + QCOMPARE(model.sharingEnabled(), helper.account->capabilities().shareAPI()); + QCOMPARE(model.publicLinkSharesEnabled() && Theme::instance()->linkSharing(), helper.account->capabilities().sharePublicLink()); QCOMPARE(Theme::instance()->userGroupSharing(), model.userGroupSharingEnabled()); - const QString localPath(_fakeFolder.localPath() + testFileName); + const QString localPath(helper.fakeFolder.localPath() + helper.testFileName); model.setLocalPath(localPath); QCOMPARE(localPathChanged.count(), 1); QCOMPARE(model.localPath(), localPath); @@ -665,11 +126,12 @@ private slots: void testSuccessfulFetchShares() { - resetTestData(); + helper.resetTestData(); // Test with a link share and a user/group email share "from the server" - appendShareReplyData(_testLinkShareDefinition); - appendShareReplyData(_testEmailShareDefinition); - appendShareReplyData(_testUserShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testEmailShareDefinition); + helper.appendShareReplyData(_testUserShareDefinition); + QCOMPARE(helper.shareCount(), 3); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -677,18 +139,18 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(model.rowCount(), helper.shareCount()); } void testFetchSharesFailedError() { - resetTestData(); + helper.resetTestData(); // Test with a link share "from the server" - appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -697,8 +159,8 @@ private slots: QSignalSpy serverError(&model, &ShareModel::serverError); // Test fetching the shares of a file that does not exist - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + "wrong-filename-oops.md"); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + "wrong-filename-oops.md"); QVERIFY(serverError.wait(3000)); QCOMPARE(model.hasInitialShareFetchCompleted(), true); QCOMPARE(model.rowCount(), 0); // Make sure no placeholder @@ -706,10 +168,11 @@ private slots: void testCorrectFetchOngoingSignalling() { - resetTestData(); + helper.resetTestData(); // Test with a link share "from the server" - appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -720,11 +183,11 @@ private slots: // Make sure we are correctly signalling the loading state of the fetch // Model resets twice when we set account and local path, resetting all model state. - model.setAccountState(_accountState.data()); + model.setAccountState(helper.accountState.data()); QCOMPARE(fetchOngoingChanged.count(), 1); QCOMPARE(model.fetchOngoing(), false); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); // If we can grab shares it then indicates fetch ongoing... QCOMPARE(fetchOngoingChanged.count(), 3); QCOMPARE(model.fetchOngoing(), true); @@ -736,10 +199,11 @@ private slots: void testCorrectInitialFetchCompleteSignalling() { - resetTestData(); + helper.resetTestData(); // Test with a link share "from the server" - appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -752,12 +216,12 @@ private slots: // Make sure we are correctly signalling the loading state of the fetch // Model resets twice when we set account and local path, resetting all model state. - model.setAccountState(_accountState.data()); + model.setAccountState(helper.accountState.data()); QCOMPARE(accountStateChanged.count(), 1); QCOMPARE(hasInitialShareFetchCompletedChanged.count(), 1); QCOMPARE(model.hasInitialShareFetchCompleted(), false); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QCOMPARE(localPathChanged.count(), 1); QCOMPARE(hasInitialShareFetchCompletedChanged.count(), 2); QCOMPARE(model.hasInitialShareFetchCompleted(), false); @@ -771,9 +235,10 @@ private slots: // Link shares and user group shares have slightly different behaviour in model.data() void testModelLinkShareData() { - resetTestData(); + helper.resetTestData(); // Test with a link share "from the server" - appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -781,11 +246,11 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(model.rowCount(), helper.shareCount()); const auto shareIndex = model.index(model.rowCount() - 1, 0, {}); QVERIFY(!shareIndex.data(Qt::DisplayRole).toString().isEmpty()); @@ -801,7 +266,7 @@ private slots: QCOMPARE(shareIndex.data(ShareModel::PasswordRole).toString(), QString()); QCOMPARE(shareIndex.data(ShareModel::EditingAllowedRole).toBool(), SharePermissions(_testLinkShareDefinition.sharePermissions).testFlag(SharePermissionUpdate)); - const auto expectedLinkShareExpireDate = QDate::fromString(_testLinkShareDefinition.shareExpiration, expectedDtFormat); + const auto expectedLinkShareExpireDate = QDate::fromString(_testLinkShareDefinition.shareExpiration, helper.expectedDtFormat); QCOMPARE(shareIndex.data(ShareModel::ExpireDateEnabledRole).toBool(), expectedLinkShareExpireDate.isValid()); QCOMPARE(shareIndex.data(ShareModel::ExpireDateRole).toLongLong(), expectedLinkShareExpireDate.startOfDay(Qt::UTC).toMSecsSinceEpoch()); @@ -811,9 +276,10 @@ private slots: void testModelEmailShareData() { - resetTestData(); + helper.resetTestData(); // Test with a user/group email share "from the server" - appendShareReplyData(_testEmailShareDefinition); + helper.appendShareReplyData(_testEmailShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -821,8 +287,8 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); QCOMPARE(model.rowCount(), 2); // Remember about placeholder link share @@ -838,7 +304,7 @@ private slots: QCOMPARE(shareIndex.data(ShareModel::PasswordRole).toString(), QString()); QCOMPARE(shareIndex.data(ShareModel::EditingAllowedRole).toBool(), SharePermissions(_testEmailShareDefinition.sharePermissions).testFlag(SharePermissionUpdate)); - const auto expectedShareExpireDate = QDate::fromString(_testEmailShareDefinition.shareExpiration, expectedDtFormat); + const auto expectedShareExpireDate = QDate::fromString(_testEmailShareDefinition.shareExpiration, helper.expectedDtFormat); QCOMPARE(shareIndex.data(ShareModel::ExpireDateEnabledRole).toBool(), expectedShareExpireDate.isValid()); QCOMPARE(shareIndex.data(ShareModel::ExpireDateRole).toLongLong(), expectedShareExpireDate.startOfDay(Qt::UTC).toMSecsSinceEpoch()); @@ -848,9 +314,10 @@ private slots: void testModelUserShareData() { - resetTestData(); + helper.resetTestData(); // Test with a user/group user share "from the server" - appendShareReplyData(_testUserShareDefinition); + helper.appendShareReplyData(_testUserShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -858,8 +325,8 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); QCOMPARE(model.rowCount(), 2); // Remember about placeholder link share @@ -875,7 +342,7 @@ private slots: QCOMPARE(shareIndex.data(ShareModel::PasswordRole).toString(), QString()); QCOMPARE(shareIndex.data(ShareModel::EditingAllowedRole).toBool(), SharePermissions(_testUserShareDefinition.sharePermissions).testFlag(SharePermissionUpdate)); - const auto expectedShareExpireDate = QDate::fromString(_testUserShareDefinition.shareExpiration, expectedDtFormat); + const auto expectedShareExpireDate = QDate::fromString(_testUserShareDefinition.shareExpiration, helper.expectedDtFormat); QCOMPARE(shareIndex.data(ShareModel::ExpireDateEnabledRole).toBool(), expectedShareExpireDate.isValid()); QCOMPARE(shareIndex.data(ShareModel::ExpireDateRole).toLongLong(), expectedShareExpireDate.startOfDay(Qt::UTC).toMSecsSinceEpoch()); @@ -885,17 +352,18 @@ private slots: // Check correct user avatar const auto avatarUrl = shareIndex.data(ShareModel::AvatarUrlRole).toString(); const auto relativeAvatarPath = QString("remote.php/dav/avatars/%1/%2.png").arg(_testUserShareDefinition.shareShareWith, QString::number(64)); - const auto expectedAvatarPath = Utility::concatUrlPath(_account->url(), relativeAvatarPath).toString(); + const auto expectedAvatarPath = Utility::concatUrlPath(helper.account->url(), relativeAvatarPath).toString(); const QString expectedUrl(QStringLiteral("image://tray-image-provider/") + expectedAvatarPath); QCOMPARE(avatarUrl, expectedUrl); } void testSuccessfulCreateShares() { - resetTestData(); + helper.resetTestData(); // Test with an existing link share - appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -903,18 +371,18 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 1); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 1); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); // Test if it gets added model.createNewLinkShare(); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 2); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 2); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); // Test if it's the type we wanted const auto newLinkShareIndex = model.index(model.rowCount() - 1, 0, {}); @@ -924,8 +392,8 @@ private slots: const ShareePtr sharee(new Sharee("testsharee@nextcloud.com", "Test sharee", Sharee::Type::Email)); model.createNewUserGroupShare(sharee); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 3); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 3); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); // Test if it's the type we wanted const auto newUserGroupShareIndex = model.index(model.rowCount() - 1, 0, {}); @@ -935,20 +403,20 @@ private slots: const auto password = QStringLiteral("a pretty bad password but good thing it doesn't matter!"); model.createNewLinkShareWithPassword(password); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 4); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 4); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); model.createNewUserGroupShareWithPassword(sharee, password); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 5); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 5); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); - resetTestData(); + helper.resetTestData(); } void testEnforcePasswordShares() { - resetTestData(); + helper.resetTestData(); // Enforce passwords for shares in capabilities const QVariantMap enforcePasswordsCapabilities { @@ -982,12 +450,13 @@ private slots: }}, }; - _account->setCapabilities(enforcePasswordsCapabilities); - QVERIFY(_account->capabilities().sharePublicLinkEnforcePassword()); - QVERIFY(_account->capabilities().shareEmailPasswordEnforced()); + helper.account->setCapabilities(enforcePasswordsCapabilities); + QVERIFY(helper.account->capabilities().sharePublicLinkEnforcePassword()); + QVERIFY(helper.account->capabilities().shareEmailPasswordEnforced()); // Test with a link share "from the server" - appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -995,11 +464,11 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(model.rowCount(), helper.shareCount()); // Confirm that the model requests a password QSignalSpy requestPasswordForLinkShare(&model, &ShareModel::requestPasswordForLinkShare); @@ -1014,11 +483,12 @@ private slots: // Test that the model data is correctly reporting that passwords are enforced const auto shareIndex = model.index(model.rowCount() - 1, 0, {}); QCOMPARE(shareIndex.data(ShareModel::PasswordEnforcedRole).toBool(), true); + QCOMPARE(shareIndex.data(ShareModel::PasswordProtectEnabledRole).toBool(), true); } void testEnforceExpireDate() { - resetTestData(); + helper.resetTestData(); const auto internalExpireDays = 45; const auto publicExpireDays = 30; @@ -1056,15 +526,16 @@ private slots: }}, }; - _account->setCapabilities(enforcePasswordsCapabilities); - QVERIFY(_account->capabilities().sharePublicLinkEnforceExpireDate()); - QVERIFY(_account->capabilities().shareInternalEnforceExpireDate()); - QVERIFY(_account->capabilities().shareRemoteEnforceExpireDate()); + helper.account->setCapabilities(enforcePasswordsCapabilities); + QVERIFY(helper.account->capabilities().sharePublicLinkEnforceExpireDate()); + QVERIFY(helper.account->capabilities().shareInternalEnforceExpireDate()); + QVERIFY(helper.account->capabilities().shareRemoteEnforceExpireDate()); // Test with shares "from the server" - appendShareReplyData(_testLinkShareDefinition); - appendShareReplyData(_testEmailShareDefinition); - appendShareReplyData(_testRemoteShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testEmailShareDefinition); + helper.appendShareReplyData(_testRemoteShareDefinition); + QCOMPARE(helper.shareCount(), 3); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -1072,11 +543,11 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(model.rowCount(), helper.shareCount()); // Test that the model data is correctly reporting that expire dates are enforced for all share types for(auto i = 0; i < model.rowCount(); ++i) { @@ -1108,10 +579,11 @@ private slots: void testSuccessfulDeleteShares() { - resetTestData(); + helper.resetTestData(); // Test with an existing link share - appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -1119,33 +591,33 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 1); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 1); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); // Create share model.createNewLinkShare(); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 2); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 2); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); // Test if it gets deleted properly const auto latestLinkShare = model.index(model.rowCount() - 1, 0, {}).data(ShareModel::ShareRole).value<SharePtr>(); QSignalSpy shareDeleted(latestLinkShare.data(), &LinkShare::shareDeleted); model.deleteShare(latestLinkShare); QVERIFY(shareDeleted.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 1); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 1); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); - resetTestData(); + helper.resetTestData(); } void testPlaceholderLinkShare() { - resetTestData(); + helper.resetTestData(); // Start with no shares; should show the placeholder link share ShareModel model; @@ -1154,8 +626,8 @@ private slots: QSignalSpy hasInitialShareFetchCompletedChanged(&model, &ShareModel::hasInitialShareFetchCompletedChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(hasInitialShareFetchCompletedChanged.wait(5000)); QVERIFY(model.hasInitialShareFetchCompleted()); QCOMPARE(model.rowCount(), 1); // There should be a placeholder now @@ -1168,8 +640,8 @@ private slots: const ShareePtr sharee(new Sharee("testsharee@nextcloud.com", "Test sharee", Sharee::Type::Email)); model.createNewUserGroupShare(sharee); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 1); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count() + 1); + QCOMPARE(helper.shareCount(), 1); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount() + 1); QVERIFY(placeholderLinkShareIndex.isValid()); QCOMPARE(placeholderLinkShareIndex.data(ShareModel::ShareTypeRole).toInt(), Share::TypePlaceholderLink); @@ -1177,8 +649,8 @@ private slots: // Now try adding a link share, which should remove the placeholder model.createNewLinkShare(); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 2); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 2); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); QVERIFY(!placeholderLinkShareIndex.isValid()); @@ -1187,21 +659,22 @@ private slots: QSignalSpy shareDeleted(latestLinkShare.data(), &LinkShare::shareDeleted); model.deleteShare(latestLinkShare); QVERIFY(shareDeleted.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 1); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count() + 1); + QCOMPARE(helper.shareCount(), 1); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount() + 1); const auto newPlaceholderLinkShareIndex = model.index(model.rowCount() - 1, 0, {}); QCOMPARE(newPlaceholderLinkShareIndex.data(ShareModel::ShareTypeRole).toInt(), Share::TypePlaceholderLink); - resetTestData(); + helper.resetTestData(); } void testSuccessfulToggleAllowEditing() { - resetTestData(); + helper.resetTestData(); // Test with an existing link share - appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -1209,12 +682,12 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 1); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 1); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); const auto shareIndex = model.index(model.rowCount() - 1, 0, {}); QCOMPARE(shareIndex.data(ShareModel::EditingAllowedRole).toBool(), SharePermissions(_testLinkShareDefinition.sharePermissions).testFlag(SharePermissionUpdate)); @@ -1229,11 +702,12 @@ private slots: void testSuccessfulPasswordSet() { - resetTestData(); + helper.resetTestData(); // Test with an existing link share. // This one has a pre-existing password - appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -1241,12 +715,12 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 1); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 1); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); const auto shareIndex = model.index(model.rowCount() - 1, 0, {}); QCOMPARE(shareIndex.data(ShareModel::PasswordProtectEnabledRole).toBool(), true); @@ -1269,11 +743,12 @@ private slots: void testSuccessfulExpireDateSet() { - resetTestData(); + helper.resetTestData(); // Test with an existing link share. // This one has a pre-existing expire date - appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -1281,12 +756,12 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 1); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 1); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); // Check what we know const auto shareIndex = model.index(model.rowCount() - 1, 0, {}); @@ -1318,11 +793,12 @@ private slots: void testSuccessfulNoteSet() { - resetTestData(); + helper.resetTestData(); // Test with an existing link share. // This one has a pre-existing password - appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -1330,12 +806,12 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 1); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 1); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); const auto shareIndex = model.index(model.rowCount() - 1, 0, {}); QCOMPARE(shareIndex.data(ShareModel::NoteEnabledRole).toBool(), true); @@ -1359,10 +835,11 @@ private slots: void testSuccessfulLinkShareLabelSet() { - resetTestData(); + helper.resetTestData(); // Test with an existing link share. - appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -1370,12 +847,12 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 1); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 1); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); const auto shareIndex = model.index(model.rowCount() - 1, 0, {}); QCOMPARE(shareIndex.data(ShareModel::LinkShareLabelRole).toBool(), true); @@ -1391,11 +868,12 @@ private slots: void testSharees() { - resetTestData(); + helper.resetTestData(); - appendShareReplyData(_testLinkShareDefinition); - appendShareReplyData(_testEmailShareDefinition); - appendShareReplyData(_testUserShareDefinition); + helper.appendShareReplyData(_testLinkShareDefinition); + helper.appendShareReplyData(_testEmailShareDefinition); + helper.appendShareReplyData(_testUserShareDefinition); + QCOMPARE(helper.shareCount(), 3); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -1403,11 +881,11 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(model.rowCount(), helper.shareCount()); QCOMPARE(model.sharees().count(), 2); // Link shares don't have sharees @@ -1415,8 +893,8 @@ private slots: const ShareePtr sharee(new Sharee("testsharee@nextcloud.com", "Test sharee", Sharee::Type::Email)); model.createNewUserGroupShare(sharee); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 4); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 4); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); const auto sharees = model.sharees(); QCOMPARE(sharees.count(), 3); // Link shares don't have sharees @@ -1428,7 +906,7 @@ private slots: const auto sharePtr = shareIndex.data(ShareModel::ShareRole).value<SharePtr>(); model.deleteShare(sharePtr); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(model.rowCount(), helper.shareCount()); // Now check the sharee is gone QCOMPARE(model.sharees().count(), 2); @@ -1436,13 +914,14 @@ private slots: void testSharePropertySetError() { - resetTestData(); + helper.resetTestData(); // Serve a broken share definition from the server to force an error auto brokenLinkShareDefinition = _testLinkShareDefinition; brokenLinkShareDefinition.shareId = QString(); - appendShareReplyData(brokenLinkShareDefinition); + helper.appendShareReplyData(brokenLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); ShareModel model; QAbstractItemModelTester modelTester(&model); @@ -1450,16 +929,17 @@ private slots: QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged); - model.setAccountState(_accountState.data()); - model.setLocalPath(_fakeFolder.localPath() + testFileName); + model.setAccountState(helper.accountState.data()); + model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName); QVERIFY(sharesChanged.wait(5000)); - QCOMPARE(_sharesReplyData.count(), 1); // Check our test is working! - QCOMPARE(model.rowCount(), _sharesReplyData.count()); + QCOMPARE(helper.shareCount(), 1); // Check our test is working! + QCOMPARE(model.rowCount(), helper.shareCount()); // Reset the fake server to pretend like nothing is wrong there - _sharesReplyData = QJsonArray(); - appendShareReplyData(_testLinkShareDefinition); + helper.resetTestShares(); + helper.appendShareReplyData(_testLinkShareDefinition); + QCOMPARE(helper.shareCount(), 1); // Now try changing a property of the share const auto shareIndex = model.index(model.rowCount() - 1, 0, {}); |