testfiletagmodel.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * Copyright (C) by Claudio Cambra <claudio.cambra@nextcloud.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. * for more details.
  13. */
  14. #include "gui/filetagmodel.h"
  15. #include <QTest>
  16. #include <QSignalSpy>
  17. #include <QDomDocument>
  18. #include <QAbstractItemModelTester>
  19. #include "accountmanager.h"
  20. #include "syncenginetestutils.h"
  21. using namespace OCC;
  22. namespace {
  23. const auto testTaglessXmlResponse = QByteArray("<?xml version='1.0'?>\n<d:multistatus xmlns:d=\"DAV:\">\n <d:response xmlns:d=\"DAV:\">\n <d:href xmlns:d=\"DAV:\">/remote.php/dav/files/tag/Documents/</d:href>\n <d:propstat xmlns:d=\"DAV:\">\n <d:prop xmlns:d=\"DAV:\">\n <nc:tags xmlns:nc=\"http://nextcloud.org/ns\"/>\n <nc:system-tags xmlns:nc=\"http://nextcloud.org/ns\"/>\n </d:prop>\n <d:status xmlns:d=\"DAV:\">HTTP/1.1 404 Not Found</d:status>\n </d:propstat>\n </d:response>\n</d:multistatus>\n");
  24. const auto testSystemAndNormalTagsOnlyXmlResponse = QByteArray("<?xml version='1.0'?>\n<d:multistatus xmlns:d=\"DAV:\">\n <d:response xmlns:d=\"DAV:\">\n <d:href xmlns:d=\"DAV:\">/remote.php/dav/files/tag/Documents/</d:href>\n <d:propstat xmlns:d=\"DAV:\">\n <d:prop xmlns:d=\"DAV:\">\n <nc:tags xmlns:nc=\"http://nextcloud.org/ns\">\n <oc:tag xmlns:oc=\"http://owncloud.org/ns\">test 0</oc:tag>\n <oc:tag xmlns:oc=\"http://owncloud.org/ns\">test 1</oc:tag>\n <oc:tag xmlns:oc=\"http://owncloud.org/ns\">test 2</oc:tag>\n <oc:tag xmlns:oc=\"http://owncloud.org/ns\">test 3</oc:tag>\n </nc:tags>\n <nc:system-tags xmlns:nc=\"http://nextcloud.org/ns\">\n <nc:system-tag xmlns:nc=\"http://nextcloud.org/ns\" oc:can-assign=\"true\" xmlns:oc=\"http://owncloud.org/ns\" oc:user-assignable=\"true\" oc:id=\"3\" oc:user-visible=\"true\">important</nc:system-tag>\n <nc:system-tag xmlns:nc=\"http://nextcloud.org/ns\" oc:can-assign=\"true\" xmlns:oc=\"http://owncloud.org/ns\" oc:user-assignable=\"true\" oc:id=\"4\" oc:user-visible=\"true\">marino</nc:system-tag>\n <nc:system-tag xmlns:nc=\"http://nextcloud.org/ns\" oc:can-assign=\"true\" xmlns:oc=\"http://owncloud.org/ns\" oc:user-assignable=\"true\" oc:id=\"5\" oc:user-visible=\"true\">marino2</nc:system-tag>\n <nc:system-tag xmlns:nc=\"http://nextcloud.org/ns\" oc:can-assign=\"true\" xmlns:oc=\"http://owncloud.org/ns\" oc:user-assignable=\"true\" oc:id=\"1\" oc:user-visible=\"true\">one</nc:system-tag>\n <nc:system-tag xmlns:nc=\"http://nextcloud.org/ns\" oc:can-assign=\"true\" xmlns:oc=\"http://owncloud.org/ns\" oc:user-assignable=\"true\" oc:id=\"2\" oc:user-visible=\"true\">two</nc:system-tag>\n </nc:system-tags>\n </d:prop>\n <d:status xmlns:d=\"DAV:\">HTTP/1.1 200 OK</d:status>\n </d:propstat>\n </d:response>\n</d:multistatus>\n");
  25. const auto testTagsOnlyXmlResponse = QByteArray("<?xml version='1.0'?>\n<d:multistatus xmlns:d=\"DAV:\">\n <d:response xmlns:d=\"DAV:\">\n <d:href xmlns:d=\"DAV:\">/remote.php/dav/files/tag/Documents/</d:href>\n <d:propstat xmlns:d=\"DAV:\">\n <d:prop xmlns:d=\"DAV:\">\n <nc:tags xmlns:nc=\"http://nextcloud.org/ns\">\n <oc:tag xmlns:oc=\"http://owncloud.org/ns\">test 0</oc:tag>\n <oc:tag xmlns:oc=\"http://owncloud.org/ns\">test 1</oc:tag>\n <oc:tag xmlns:oc=\"http://owncloud.org/ns\">test 2</oc:tag>\n <oc:tag xmlns:oc=\"http://owncloud.org/ns\">test 3</oc:tag>\n </nc:tags>\n </d:prop>\n <d:status xmlns:d=\"DAV:\">HTTP/1.1 200 OK</d:status>\n </d:propstat>\n </d:response>\n</d:multistatus>\n");
  26. const auto testSystemTagsOnlyXmlResponse = QByteArray("<?xml version='1.0'?>\n<d:multistatus xmlns:d=\"DAV:\">\n <d:response xmlns:d=\"DAV:\">\n <d:href xmlns:d=\"DAV:\">/remote.php/dav/files/tag/Documents/</d:href>\n <d:propstat xmlns:d=\"DAV:\">\n <d:prop xmlns:d=\"DAV:\">\n <nc:system-tags xmlns:nc=\"http://nextcloud.org/ns\">\n <nc:system-tag xmlns:nc=\"http://nextcloud.org/ns\" oc:can-assign=\"true\" xmlns:oc=\"http://owncloud.org/ns\" oc:user-assignable=\"true\" oc:id=\"3\" oc:user-visible=\"true\">important</nc:system-tag>\n <nc:system-tag xmlns:nc=\"http://nextcloud.org/ns\" oc:can-assign=\"true\" xmlns:oc=\"http://owncloud.org/ns\" oc:user-assignable=\"true\" oc:id=\"4\" oc:user-visible=\"true\">marino</nc:system-tag>\n <nc:system-tag xmlns:nc=\"http://nextcloud.org/ns\" oc:can-assign=\"true\" xmlns:oc=\"http://owncloud.org/ns\" oc:user-assignable=\"true\" oc:id=\"5\" oc:user-visible=\"true\">marino2</nc:system-tag>\n <nc:system-tag xmlns:nc=\"http://nextcloud.org/ns\" oc:can-assign=\"true\" xmlns:oc=\"http://owncloud.org/ns\" oc:user-assignable=\"true\" oc:id=\"1\" oc:user-visible=\"true\">one</nc:system-tag>\n <nc:system-tag xmlns:nc=\"http://nextcloud.org/ns\" oc:can-assign=\"true\" xmlns:oc=\"http://owncloud.org/ns\" oc:user-assignable=\"true\" oc:id=\"2\" oc:user-visible=\"true\">two</nc:system-tag>\n </nc:system-tags>\n </d:prop>\n <d:status xmlns:d=\"DAV:\">HTTP/1.1 200 OK</d:status>\n </d:propstat>\n </d:response>\n</d:multistatus>\n");
  27. const auto testErrorXmlResponse = QByteArray("<?xml version='1.0'?>\n<d:multistatus xmlns:d=\"DAV:\">\n <d:response xmlns:d=\"DAV:\">\n <d:href xmlns:d=\"DAV:\">/remote.php/dav/files/tag/</d:href>\n <d:propstat xmlns:d=\"DAV:\">\n <d:prop xmlns:d=\"DAV:\">\n <d:getlastmodified xmlns:d=\"DAV:\">Wed, 19 Apr 2023 15:09:16 GMT</d:getlastmodified>\n <d:resourcetype xmlns:d=\"DAV:\">\n <d:collection xmlns:d=\"DAV:\"/>\n </d:resourcetype>\n <d:quota-used-bytes xmlns:d=\"DAV:\">25789373</d:quota-used-bytes>\n <d:quota-available-bytes xmlns:d=\"DAV:\">-3</d:quota-available-bytes>\n <d:getetag xmlns:d=\"DAV:\">\"083237f7b434afbedeace283d655cc41\"</d:getetag>\n </d:prop>\n <d:status xmlns:d=\"DAV:\">HTTP/1.1 200 OK</d:status>\n </d:propstat>\n </d:response>\n</d:multistatus>\n");
  28. const QString testUser = "admin";
  29. const QString testFilePath = "Documents";
  30. const QString testUrlPath = "/remote.php/dav/files/" + testUser + '/' + testFilePath;
  31. constexpr auto testNumTags = 9;
  32. }
  33. class TestFileTagModel : public QObject
  34. {
  35. Q_OBJECT
  36. private:
  37. AccountPtr _account;
  38. AccountStatePtr _accountState;
  39. QScopedPointer<FakeQNAM> _fakeQnam;
  40. QStringList _expectedTags;
  41. private slots:
  42. void initTestCase()
  43. {
  44. _fakeQnam.reset(new FakeQNAM({}));
  45. _fakeQnam->setOverride([this](QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice * const device) {
  46. Q_UNUSED(device);
  47. QNetworkReply *reply = nullptr;
  48. const auto path = req.url().path();
  49. auto requestDom = QDomDocument();
  50. const auto parsedCorrectly = requestDom.setContent(device);
  51. const auto tagElems = requestDom.elementsByTagName("tags");
  52. const auto systemTagElems = requestDom.elementsByTagName("system-tags");
  53. if (!parsedCorrectly || !req.url().toString().startsWith(_accountState->account()->url().toString())) {
  54. reply = new FakePropfindReply(testErrorXmlResponse, op, req, this);
  55. }
  56. if (path.contains(testUrlPath)) {
  57. if (tagElems.count() > 0 && systemTagElems.count() > 0) {
  58. reply = new FakePropfindReply(testSystemAndNormalTagsOnlyXmlResponse, op, req, this);
  59. } else if (tagElems.count() > 0) {
  60. reply = new FakePropfindReply(testTagsOnlyXmlResponse, op, req, this);
  61. } else if (systemTagElems.count() > 0) {
  62. reply = new FakePropfindReply(testSystemTagsOnlyXmlResponse, op, req, this);
  63. } else {
  64. reply = new FakePropfindReply(testTaglessXmlResponse, op, req, this);
  65. }
  66. }
  67. if (!reply) {
  68. reply = new FakePropfindReply(testErrorXmlResponse, op, req, this);
  69. }
  70. return reply;
  71. });
  72. _account = Account::create();
  73. _account->setCredentials(new FakeCredentials{_fakeQnam.data()});
  74. _account->setUrl(QUrl(("owncloud://somehost/owncloud")));
  75. _accountState = new AccountState(_account);
  76. AccountManager::instance()->addAccount(_account);
  77. _expectedTags = QStringList{
  78. "test 0",
  79. "test 1",
  80. "test 2",
  81. "test 3",
  82. "important",
  83. "marino",
  84. "marino2",
  85. "one",
  86. "two"
  87. };
  88. }
  89. void testModelMainProps()
  90. {
  91. auto fileTagModel = FileTagModel(testFilePath, _account);
  92. const auto fileTagModelTester = QAbstractItemModelTester(&fileTagModel);
  93. QSignalSpy fileTagsChanged(&fileTagModel, &FileTagModel::totalTagsChanged);
  94. fileTagsChanged.wait(1000);
  95. QCOMPARE(fileTagModel.serverRelativePath(), testFilePath);
  96. QCOMPARE(fileTagModel.account(), _account);
  97. QSignalSpy serverRelativePathChangedSpy(&fileTagModel, &FileTagModel::serverRelativePathChanged);
  98. fileTagModel.setServerRelativePath("");
  99. QCOMPARE(serverRelativePathChangedSpy.count(), 1);
  100. QCOMPARE(fileTagModel.serverRelativePath(), "");
  101. QSignalSpy accountChangedSpy(&fileTagModel, &FileTagModel::accountChanged);
  102. const AccountPtr testAccount;
  103. fileTagModel.setAccount(testAccount);
  104. QCOMPARE(accountChangedSpy.count(), 1);
  105. QCOMPARE(fileTagModel.account(), testAccount);
  106. }
  107. void testModelTagFetch()
  108. {
  109. auto fileTagModel = FileTagModel(testFilePath, _account);
  110. const auto fileTagModelTester = QAbstractItemModelTester(&fileTagModel);
  111. QSignalSpy fileTagsChanged(&fileTagModel, &FileTagModel::totalTagsChanged);
  112. fileTagsChanged.wait(1000);
  113. const auto modelTotalTags = fileTagModel.totalTags();
  114. QCOMPARE(modelTotalTags, testNumTags);
  115. for (auto i = 0; i < modelTotalTags; ++i) {
  116. const auto index = fileTagModel.index(i);
  117. const auto tag = index.data();
  118. QCOMPARE(tag.toString(), _expectedTags[i]);
  119. }
  120. }
  121. void testModelMaxTags()
  122. {
  123. auto fileTagModel = FileTagModel(testFilePath, _account);
  124. const auto fileTagModelTester = QAbstractItemModelTester(&fileTagModel);
  125. QSignalSpy fileTagsChanged(&fileTagModel, &FileTagModel::totalTagsChanged);
  126. fileTagsChanged.wait(1000);
  127. constexpr auto testMaxTags = 3;
  128. Q_ASSERT(testMaxTags < testNumTags);
  129. QSignalSpy maxTagsChangedSpy(&fileTagModel, &FileTagModel::maxTagsChanged);
  130. fileTagModel.setMaxTags(testMaxTags);
  131. QCOMPARE(maxTagsChangedSpy.count(), 1);
  132. QCOMPARE(fileTagModel.maxTags(), testMaxTags);
  133. QCOMPARE(fileTagModel.rowCount(), testMaxTags);
  134. }
  135. };
  136. QTEST_MAIN(TestFileTagModel)
  137. #include "testfiletagmodel.moc"