Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/desktop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Cambra <claudio.cambra@nextcloud.com>2022-10-17 11:37:14 +0300
committerClaudio Cambra <claudio.cambra@nextcloud.com>2022-10-31 20:06:09 +0300
commita0ff46a7fbb94ed4a815244f14a7ef1caa9f1d97 (patch)
treea562b57bfcc292d1f449a6b2781994f530d7ddc8
parente021f256345564193ebde2857903eaa5462cf5d1 (diff)
Add testing for ShareeModel
Signed-off-by: Claudio Cambra <claudio.cambra@nextcloud.com>
-rw-r--r--test/CMakeLists.txt1
-rw-r--r--test/testshareemodel.cpp442
2 files changed, 443 insertions, 0 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 7ede2c3f2..820984631 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -65,6 +65,7 @@ nextcloud_add_test(ActivityData)
nextcloud_add_test(TalkReply)
nextcloud_add_test(LockFile)
nextcloud_add_test(ShareModel)
+nextcloud_add_test(ShareeModel)
if( UNIX AND NOT APPLE )
nextcloud_add_test(InotifyWatcher)
diff --git a/test/testshareemodel.cpp b/test/testshareemodel.cpp
new file mode 100644
index 000000000..c9560a75f
--- /dev/null
+++ b/test/testshareemodel.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 "gui/filedetails/shareemodel.h"
+
+#include <QTest>
+#include <QSignalSpy>
+
+#include "accountmanager.h"
+#include "syncenginetestutils.h"
+#include "testhelper.h"
+
+using namespace OCC;
+
+static QByteArray fake400Response = R"(
+{"ocs":{"meta":{"status":"failure","statuscode":400,"message":"Parameter is incorrect.\n"},"data":[]}}
+)";
+
+constexpr auto searchResultsReplyDelay = 100;
+
+class TestShareeModel : public QObject
+{
+ Q_OBJECT
+
+public:
+ ~TestShareeModel() override
+ {
+ AccountManager::instance()->deleteAccount(_accountState.data());
+ };
+
+ struct FakeShareeDefinition
+ {
+ QString label;
+
+ QString shareWith;
+ Sharee::Type type;
+ QString shareWithAdditionalInfo;
+ };
+
+ void appendShareeToReply(const FakeShareeDefinition &definition)
+ {
+ QJsonObject newShareeJson;
+ newShareeJson.insert("label", definition.label);
+
+ QJsonObject newShareeValueJson;
+ newShareeValueJson.insert("shareWith", definition.shareWith);
+ newShareeValueJson.insert("shareType", definition.type);
+ newShareeValueJson.insert("shareWithAdditionalInfo", definition.shareWithAdditionalInfo);
+
+ newShareeJson.insert("value", newShareeValueJson);
+
+ QString category;
+ switch(definition.type) {
+ case Sharee::Circle:
+ category = QStringLiteral("circles");
+ break;
+ case Sharee::Email:
+ category = QStringLiteral("emails");
+ break;
+ case Sharee::Federated:
+ category = QStringLiteral("remotes");
+ break;
+ case Sharee::Group:
+ category = QStringLiteral("groups");
+ break;
+ case Sharee::Room:
+ category = QStringLiteral("rooms");
+ break;
+ case Sharee::User:
+ category = QStringLiteral("users");
+ break;
+ }
+
+ auto shareesInCategory = _shareesMap.value(category).toJsonArray();
+ shareesInCategory.append(newShareeJson);
+ _shareesMap.insert(category, shareesInCategory);
+ }
+
+ void standardReplyPopulate()
+ {
+ appendShareeToReply(_michaelUserDefinition);
+ appendShareeToReply(_liamUserDefinition);
+ appendShareeToReply(_iqbalUserDefinition);
+ appendShareeToReply(_universityGroupDefinition);
+ appendShareeToReply(_testEmailDefinition);
+ }
+
+ QVariantMap filteredSharees(const QString &searchString)
+ {
+ if (searchString.isEmpty()) {
+ return _shareesMap;
+ }
+
+ QVariantMap returnSharees;
+ QJsonArray exactMatches;
+
+ for (auto it = _shareesMap.constKeyValueBegin(); it != _shareesMap.constKeyValueEnd(); ++it) {
+ const auto shareesCategory = it->first;
+ const auto shareesArray = it->second.toJsonArray();
+ QJsonArray filteredShareesArray;
+
+ std::copy_if(shareesArray.cbegin(), shareesArray.cend(), std::back_inserter(filteredShareesArray), [&searchString](const QJsonValue &shareeValue) {
+ const auto shareeObject = shareeValue.toObject().value("value").toObject();
+ const auto shareeShareWith = shareeObject.value("shareWith").toString();
+ return shareeShareWith.contains(searchString, Qt::CaseInsensitive);
+ });
+
+ std::copy_if(filteredShareesArray.cbegin(), filteredShareesArray.cend(), std::back_inserter(exactMatches), [&searchString](const QJsonValue &shareeValue) {
+ const auto shareeObject = shareeValue.toObject().value("value").toObject();
+ const auto shareeShareWith = shareeObject.value("shareWith").toString();
+ return shareeShareWith == searchString;
+ });
+
+ returnSharees.insert(shareesCategory, filteredShareesArray);
+ }
+
+ returnSharees.insert(QStringLiteral("exact"), exactMatches);
+
+ return returnSharees;
+ }
+
+ QByteArray testShareesReply(const QString &searchString)
+ {
+ QJsonObject root;
+ QJsonObject ocs;
+ QJsonObject meta;
+
+ meta.insert("statuscode", 200);
+
+ const auto resultSharees = filteredSharees(searchString);
+ const auto shareesJsonObject = QJsonObject::fromVariantMap(resultSharees);
+
+ ocs.insert(QStringLiteral("data"), shareesJsonObject);
+ ocs.insert(QStringLiteral("meta"), meta);
+ root.insert(QStringLiteral("ocs"), ocs);
+
+ return QJsonDocument(root).toJson();
+ }
+
+ int shareesCount(const QString &searchString)
+ {
+ const auto sharees = filteredSharees(searchString);
+
+ auto count = 0;
+ const auto shareesCategories = sharees.values();
+ for (const auto &shareesArrayValue : shareesCategories) {
+ const auto shareesArray = shareesArrayValue.toJsonArray();
+ count += shareesArray.count();
+ }
+
+ return count;
+ }
+
+ void resetTestData()
+ {
+ _alwaysReturnErrors = false;
+ _shareesMap.clear();
+ }
+
+
+private:
+ AccountPtr _account;
+ AccountStatePtr _accountState;
+ QScopedPointer<FakeQNAM> _fakeQnam;
+
+ QVariantMap _shareesMap;
+
+ // Some fake sharees of different categories
+ // ALL OF THEM CONTAIN AN 'I' !! Important for testing
+ FakeShareeDefinition _michaelUserDefinition {
+ QStringLiteral("Michael"),
+ QStringLiteral("michael"),
+ Sharee::User,
+ {},
+ };
+ FakeShareeDefinition _liamUserDefinition {
+ QStringLiteral("Liam"),
+ QStringLiteral("liam"),
+ Sharee::User,
+ {},
+ };
+ FakeShareeDefinition _iqbalUserDefinition {
+ QStringLiteral("Iqbal"),
+ QStringLiteral("iqbal"),
+ Sharee::User,
+ {},
+ };
+
+ FakeShareeDefinition _universityGroupDefinition {
+ QStringLiteral("University"),
+ QStringLiteral("university"),
+ Sharee::Group,
+ {},
+ };
+
+ FakeShareeDefinition _testEmailDefinition {
+ QStringLiteral("test.email@nextcloud.com"),
+ QStringLiteral("test.email@nextcloud.com"),
+ Sharee::Email,
+ {},
+ };
+
+ bool _alwaysReturnErrors = false;
+
+private slots:
+ void initTestCase()
+ {
+ _fakeQnam.reset(new FakeQNAM({}));
+ _fakeQnam->setOverride([this](QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *device) {
+ Q_UNUSED(device);
+
+ QNetworkReply *reply = nullptr;
+
+ if (_alwaysReturnErrors) {
+ reply = new FakeErrorReply(op, req, this, 400, fake400Response);
+ return reply;
+ }
+
+ 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;
+
+ if(req.url().toString().startsWith(_accountState->account()->url().toString()) &&
+ reqPath == QStringLiteral("ocs/v2.php/apps/files_sharing/api/v1/sharees") &&
+ req.attribute(QNetworkRequest::CustomVerbAttribute) == "GET") {
+
+ const auto urlQuery = QUrlQuery(req.url());
+ const auto searchParam = urlQuery.queryItemValue(QStringLiteral("search"));
+ const auto itemTypeParam = urlQuery.queryItemValue(QStringLiteral("itemType"));
+ const auto pageParam = urlQuery.queryItemValue(QStringLiteral("page"));
+ const auto perPageParam = urlQuery.queryItemValue(QStringLiteral("perPage"));
+ const auto lookupParam = urlQuery.queryItemValue(QStringLiteral("lookup"));
+ const auto formatParam = urlQuery.queryItemValue(QStringLiteral("format"));
+
+ if (formatParam != QStringLiteral("json")) {
+ reply = new FakeErrorReply(op, req, this, 400, fake400Response);
+ } else {
+ reply = new FakePayloadReply(op, req, testShareesReply(searchParam), searchResultsReplyDelay, _fakeQnam.data());
+ }
+ }
+
+ return reply;
+ });
+
+ _account = Account::create();
+ _account->setCredentials(new FakeCredentials{_fakeQnam.data()});
+ _account->setUrl(QUrl(("owncloud://somehost/owncloud")));
+ _accountState = new AccountState(_account);
+ AccountManager::instance()->addAccount(_account);
+
+ // Let's verify our test is working -- all sharees have an I in their "shareWith"
+ standardReplyPopulate();
+ const auto searchString = QStringLiteral("i");
+ QCOMPARE(shareesCount(searchString), 5);
+
+ const auto emailSearchString = QStringLiteral("email");
+ QCOMPARE(shareesCount(emailSearchString), 1);
+ }
+
+ void testSetAccountAndPath()
+ {
+ resetTestData();
+
+ ShareeModel model;
+ QAbstractItemModelTester modelTester(&model);
+ QCOMPARE(model.rowCount(), 0);
+
+ QSignalSpy accountStateChanged(&model, &ShareeModel::accountStateChanged);
+ QSignalSpy shareItemIsFolderChanged(&model, &ShareeModel::shareItemIsFolderChanged);
+ QSignalSpy searchStringChanged(&model, &ShareeModel::searchStringChanged);
+ QSignalSpy lookupModeChanged(&model, &ShareeModel::lookupModeChanged);
+ QSignalSpy shareeBlocklistChanged(&model, &ShareeModel::shareeBlocklistChanged);
+
+ model.setAccountState(_accountState.data());
+ QCOMPARE(accountStateChanged.count(), 1);
+ QCOMPARE(model.accountState(), _accountState.data());
+
+ const auto shareItemIsFolder = !model.shareItemIsFolder();
+ model.setShareItemIsFolder(shareItemIsFolder);
+ QCOMPARE(shareItemIsFolderChanged.count(), 1);
+ QCOMPARE(model.shareItemIsFolder(), shareItemIsFolder);
+
+ const auto searchString = QStringLiteral("search string");
+ model.setSearchString(searchString);
+ QCOMPARE(searchStringChanged.count(), 1);
+ QCOMPARE(model.searchString(), searchString);
+
+ const auto lookupMode = ShareeModel::LookupMode::GlobalSearch;
+ model.setLookupMode(lookupMode);
+ QCOMPARE(lookupModeChanged.count(), 1);
+ QCOMPARE(model.lookupMode(), lookupMode);
+
+ const ShareePtr sharee(new Sharee(_testEmailDefinition.shareWith, _testEmailDefinition.label, _testEmailDefinition.type));
+ const QVariantList shareeBlocklist {QVariant::fromValue(sharee)};
+ model.setShareeBlocklist(shareeBlocklist);
+ QCOMPARE(shareeBlocklistChanged.count(), 1);
+ QCOMPARE(model.shareeBlocklist(), shareeBlocklist);
+ }
+
+ void testShareesFetch()
+ {
+ resetTestData();
+ standardReplyPopulate();
+
+ ShareeModel model;
+ QAbstractItemModelTester modelTester(&model);
+ QCOMPARE(model.rowCount(), 0);
+
+ model.setAccountState(_accountState.data());
+
+ QSignalSpy shareesReady(&model, &ShareeModel::shareesReady);
+ const auto searchString = QStringLiteral("i");
+ model.setSearchString(searchString);
+ QVERIFY(shareesReady.wait(3000));
+ QCOMPARE(model.rowCount(), shareesCount(searchString));
+
+ const auto emailSearchString = QStringLiteral("email");
+ model.setSearchString(emailSearchString);
+ QVERIFY(shareesReady.wait(3000));
+ QCOMPARE(model.rowCount(), shareesCount(emailSearchString));
+ }
+
+ void testFetchSignalling()
+ {
+ resetTestData();
+ standardReplyPopulate();
+
+ ShareeModel model;
+ QAbstractItemModelTester modelTester(&model);
+ QCOMPARE(model.rowCount(), 0);
+
+ model.setAccountState(_accountState.data());
+ QSignalSpy fetchOngoingChanged(&model, &ShareeModel::fetchOngoingChanged);
+ const auto searchString = QStringLiteral("i");
+ model.setSearchString(searchString);
+
+ QVERIFY(fetchOngoingChanged.wait(1000));
+ QCOMPARE(model.fetchOngoing(), true);
+ QVERIFY(fetchOngoingChanged.wait(3000));
+ QCOMPARE(model.fetchOngoing(), false);
+ }
+
+ void testData()
+ {
+ resetTestData();
+ appendShareeToReply(_testEmailDefinition);
+
+ ShareeModel model;
+ QAbstractItemModelTester modelTester(&model);
+ QCOMPARE(model.rowCount(), 0);
+
+ model.setAccountState(_accountState.data());
+ const auto searchString = QStringLiteral("i");
+ model.setSearchString(searchString);
+
+ QSignalSpy shareesReady(&model, &ShareeModel::shareesReady);
+ QVERIFY(shareesReady.wait(3000));
+ QCOMPARE(model.rowCount(), shareesCount(searchString));
+
+ const auto shareeIndex = model.index(0, 0, {});
+
+ const ShareePtr expectedSharee(new Sharee(_testEmailDefinition.shareWith, _testEmailDefinition.label, _testEmailDefinition.type));
+ const auto sharee = shareeIndex.data(ShareeModel::ShareeRole).value<ShareePtr>();
+ QCOMPARE(sharee->format(), expectedSharee->format());
+ QCOMPARE(sharee->shareWith(), expectedSharee->shareWith());
+ QCOMPARE(sharee->displayName(), expectedSharee->displayName());
+ QCOMPARE(sharee->type(), expectedSharee->type());
+
+ const auto expectedShareeDisplay = QString(_testEmailDefinition.label + QStringLiteral(" (email)"));
+ const auto shareeDisplay = shareeIndex.data(Qt::DisplayRole).toString();
+ QCOMPARE(shareeDisplay, expectedShareeDisplay);
+
+ const auto expectedAutoCompleterStringMatch = QString(_testEmailDefinition.label +
+ QStringLiteral(" (") +
+ _testEmailDefinition.shareWith +
+ QStringLiteral(")"));
+ const auto autoCompleterStringMatch = shareeIndex.data(ShareeModel::AutoCompleterStringMatchRole).toString();
+ QCOMPARE(autoCompleterStringMatch, expectedAutoCompleterStringMatch);
+ }
+
+ void testBlocklist()
+ {
+ resetTestData();
+ standardReplyPopulate();
+
+ ShareeModel model;
+ QAbstractItemModelTester modelTester(&model);
+ QCOMPARE(model.rowCount(), 0);
+
+ model.setAccountState(_accountState.data());
+
+ const ShareePtr sharee(new Sharee(_testEmailDefinition.shareWith, _testEmailDefinition.label, _testEmailDefinition.type));
+ const QVariantList shareeBlocklist {QVariant::fromValue(sharee)};
+ model.setShareeBlocklist(shareeBlocklist);
+
+ QSignalSpy shareesReady(&model, &ShareeModel::shareesReady);
+ const auto searchString = QStringLiteral("i");
+ model.setSearchString(searchString);
+ QVERIFY(shareesReady.wait(3000));
+ QCOMPARE(model.rowCount(), shareesCount(searchString) - 1);
+
+ const ShareePtr shareeTwo(new Sharee(_michaelUserDefinition.shareWith, _michaelUserDefinition.label, _michaelUserDefinition.type));
+ const QVariantList largerShareeBlocklist {QVariant::fromValue(sharee), QVariant::fromValue(shareeTwo)};
+ model.setShareeBlocklist(largerShareeBlocklist);
+ QCOMPARE(model.rowCount(), shareesCount(searchString) - 2);
+ }
+
+ void testServerError()
+ {
+ resetTestData();
+ _alwaysReturnErrors = true;
+
+ ShareeModel model;
+ QAbstractItemModelTester modelTester(&model);
+ QCOMPARE(model.rowCount(), 0);
+
+ model.setAccountState(_accountState.data());
+
+ QSignalSpy displayErrorMessage(&model, &ShareeModel::displayErrorMessage);
+ QSignalSpy fetchOngoingChanged(&model, &ShareeModel::fetchOngoingChanged);
+ model.setSearchString(QStringLiteral("i"));
+ QVERIFY(displayErrorMessage.wait(3000));
+
+ QCOMPARE(fetchOngoingChanged.count(), 2);
+ QCOMPARE(model.fetchOngoing(), false);
+ }
+};
+
+QTEST_MAIN(TestShareeModel)
+#include "testshareemodel.moc"