testsharemodel.cpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  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/filedetails/sharemodel.h"
  15. #include <QTest>
  16. #include <QAbstractItemModelTester>
  17. #include <QSignalSpy>
  18. #include <QFileInfo>
  19. #include <QFlags>
  20. #include <QDateTime>
  21. #include <QTimeZone>
  22. #include "sharetestutils.h"
  23. #include "libsync/theme.h"
  24. using namespace OCC;
  25. class TestShareModel : public QObject
  26. {
  27. Q_OBJECT
  28. private:
  29. ShareTestHelper helper;
  30. FakeShareDefinition _testLinkShareDefinition;
  31. FakeShareDefinition _testEmailShareDefinition;
  32. FakeShareDefinition _testUserShareDefinition;
  33. FakeShareDefinition _testRemoteShareDefinition;
  34. private slots:
  35. void initTestCase()
  36. {
  37. QSignalSpy helperSetupSucceeded(&helper, &ShareTestHelper::setupSucceeded);
  38. helper.setup();
  39. QCOMPARE(helperSetupSucceeded.count(), 1);
  40. const auto testSharePassword = "3|$argon2id$v=19$m=65536,"
  41. "t=4,"
  42. "p=1$M2FoLnliWkhIZkwzWjFBQg$BPraP+JUqP1sV89rkymXpCGxHBlCct6bZ39xUGaYQ5w";
  43. const auto testShareNote = QStringLiteral("This is a note!");
  44. const auto testShareExpiration = QDate::currentDate().addDays(1).toString(helper.expectedDtFormat);
  45. const auto linkShareLabel = QStringLiteral("Link share label");
  46. _testLinkShareDefinition = FakeShareDefinition(&helper,
  47. Share::TypeLink,
  48. {},
  49. linkShareLabel,
  50. testSharePassword,
  51. testShareNote,
  52. testShareExpiration);
  53. const auto emailShareShareWith = QStringLiteral("test-email@nextcloud.com");
  54. const auto emailShareShareWithDisplayName = QStringLiteral("Test email");
  55. _testEmailShareDefinition = FakeShareDefinition(&helper,
  56. Share::TypeEmail,
  57. emailShareShareWith,
  58. emailShareShareWithDisplayName,
  59. testSharePassword,
  60. testShareNote,
  61. testShareExpiration);
  62. const auto userShareShareWith = QStringLiteral("user");
  63. const auto userShareShareWithDisplayName("A Nextcloud user");
  64. _testUserShareDefinition = FakeShareDefinition(&helper,
  65. Share::TypeUser,
  66. userShareShareWith,
  67. userShareShareWithDisplayName);
  68. const auto remoteShareShareWith = QStringLiteral("remote_share");
  69. const auto remoteShareShareWithDisplayName("A remote share");
  70. _testRemoteShareDefinition = FakeShareDefinition(&helper,
  71. Share::TypeRemote,
  72. remoteShareShareWith,
  73. remoteShareShareWithDisplayName);
  74. qRegisterMetaType<ShareePtr>("ShareePtr");
  75. }
  76. void testSetAccountAndPath()
  77. {
  78. helper.resetTestData();
  79. // Test with a link share
  80. helper.appendShareReplyData(_testLinkShareDefinition);
  81. QCOMPARE(helper.shareCount(), 1);
  82. ShareModel model;
  83. QAbstractItemModelTester modelTester(&model);
  84. QCOMPARE(model.rowCount(), 0);
  85. QSignalSpy accountStateChanged(&model, &ShareModel::accountStateChanged);
  86. QSignalSpy localPathChanged(&model, &ShareModel::localPathChanged);
  87. QSignalSpy accountConnectedChanged(&model, &ShareModel::accountConnectedChanged);
  88. QSignalSpy sharingEnabledChanged(&model, &ShareModel::sharingEnabledChanged);
  89. QSignalSpy publicLinkSharesEnabledChanged(&model, &ShareModel::publicLinkSharesEnabledChanged);
  90. model.setAccountState(helper.accountState.data());
  91. QCOMPARE(accountStateChanged.count(), 1);
  92. // Check all the account-related properties of the model
  93. QCOMPARE(model.accountConnected(), helper.accountState->isConnected());
  94. QCOMPARE(model.sharingEnabled(), helper.account->capabilities().shareAPI());
  95. QCOMPARE(model.publicLinkSharesEnabled() && Theme::instance()->linkSharing(), helper.account->capabilities().sharePublicLink());
  96. QCOMPARE(Theme::instance()->userGroupSharing(), model.userGroupSharingEnabled());
  97. const QString localPath(helper.fakeFolder.localPath() + helper.testFileName);
  98. model.setLocalPath(localPath);
  99. QCOMPARE(localPathChanged.count(), 1);
  100. QCOMPARE(model.localPath(), localPath);
  101. }
  102. void testSuccessfulFetchShares()
  103. {
  104. helper.resetTestData();
  105. // Test with a link share and a user/group email share "from the server"
  106. helper.appendShareReplyData(_testLinkShareDefinition);
  107. helper.appendShareReplyData(_testEmailShareDefinition);
  108. helper.appendShareReplyData(_testUserShareDefinition);
  109. QCOMPARE(helper.shareCount(), 3);
  110. ShareModel model;
  111. QAbstractItemModelTester modelTester(&model);
  112. QCOMPARE(model.rowCount(), 0);
  113. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  114. model.setAccountState(helper.accountState.data());
  115. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  116. QVERIFY(sharesChanged.wait(5000));
  117. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share
  118. }
  119. void testFetchSharesFailedError()
  120. {
  121. helper.resetTestData();
  122. // Test with a link share "from the server"
  123. helper.appendShareReplyData(_testLinkShareDefinition);
  124. ShareModel model;
  125. QAbstractItemModelTester modelTester(&model);
  126. QCOMPARE(model.rowCount(), 0);
  127. QSignalSpy serverError(&model, &ShareModel::serverError);
  128. // Test fetching the shares of a file that does not exist
  129. model.setAccountState(helper.accountState.data());
  130. model.setLocalPath(helper.fakeFolder.localPath() + "wrong-filename-oops.md");
  131. QVERIFY(serverError.wait(3000));
  132. QCOMPARE(model.hasInitialShareFetchCompleted(), true);
  133. QCOMPARE(model.rowCount(), 0); // Make sure no placeholder nor internal link share
  134. }
  135. void testCorrectFetchOngoingSignalling()
  136. {
  137. helper.resetTestData();
  138. // Test with a link share "from the server"
  139. helper.appendShareReplyData(_testLinkShareDefinition);
  140. QCOMPARE(helper.shareCount(), 1);
  141. ShareModel model;
  142. QAbstractItemModelTester modelTester(&model);
  143. QCOMPARE(model.rowCount(), 0);
  144. QSignalSpy fetchOngoingChanged(&model, &ShareModel::fetchOngoingChanged);
  145. // Make sure we are correctly signalling the loading state of the fetch
  146. // Model resets twice when we set account and local path, resetting all model state.
  147. model.setAccountState(helper.accountState.data());
  148. QCOMPARE(fetchOngoingChanged.count(), 1);
  149. QCOMPARE(model.fetchOngoing(), false);
  150. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  151. // If we can grab shares it then indicates fetch ongoing...
  152. QCOMPARE(fetchOngoingChanged.count(), 3);
  153. QCOMPARE(model.fetchOngoing(), true);
  154. // Then indicates fetch finished when done.
  155. QVERIFY(fetchOngoingChanged.wait(3000));
  156. QCOMPARE(model.fetchOngoing(), false);
  157. }
  158. void testCorrectInitialFetchCompleteSignalling()
  159. {
  160. helper.resetTestData();
  161. // Test with a link share "from the server"
  162. helper.appendShareReplyData(_testLinkShareDefinition);
  163. QCOMPARE(helper.shareCount(), 1);
  164. ShareModel model;
  165. QAbstractItemModelTester modelTester(&model);
  166. QCOMPARE(model.rowCount(), 0);
  167. QSignalSpy accountStateChanged(&model, &ShareModel::accountStateChanged);
  168. QSignalSpy localPathChanged(&model, &ShareModel::localPathChanged);
  169. QSignalSpy hasInitialShareFetchCompletedChanged(&model, &ShareModel::hasInitialShareFetchCompletedChanged);
  170. // Make sure we are correctly signalling the loading state of the fetch
  171. // Model resets twice when we set account and local path, resetting all model state.
  172. model.setAccountState(helper.accountState.data());
  173. QCOMPARE(accountStateChanged.count(), 1);
  174. QCOMPARE(hasInitialShareFetchCompletedChanged.count(), 1);
  175. QCOMPARE(model.hasInitialShareFetchCompleted(), false);
  176. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  177. QCOMPARE(localPathChanged.count(), 1);
  178. QCOMPARE(hasInitialShareFetchCompletedChanged.count(), 2);
  179. QCOMPARE(model.hasInitialShareFetchCompleted(), false);
  180. // Once we have acquired shares from the server the initial share fetch is completed
  181. QVERIFY(hasInitialShareFetchCompletedChanged.wait(3000));
  182. QCOMPARE(hasInitialShareFetchCompletedChanged.count(), 3);
  183. QCOMPARE(model.hasInitialShareFetchCompleted(), true);
  184. }
  185. // Link shares and user group shares have slightly different behaviour in model.data()
  186. void testModelLinkShareData()
  187. {
  188. helper.resetTestData();
  189. // Test with a link share "from the server"
  190. helper.appendShareReplyData(_testLinkShareDefinition);
  191. QCOMPARE(helper.shareCount(), 1);
  192. ShareModel model;
  193. QAbstractItemModelTester modelTester(&model);
  194. QCOMPARE(model.rowCount(), 0);
  195. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  196. model.setAccountState(helper.accountState.data());
  197. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  198. QVERIFY(sharesChanged.wait(5000));
  199. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Remember internal link share!
  200. // Placeholder link share gets added after we are done parsing fetched shares, and the
  201. // internal link share is added after we receive a reply from the PROPFIND, which we
  202. // send before fetching the shares, so it will be added first.
  203. //
  204. // Hence we grab the remote share in between.
  205. const auto shareIndex = model.index(model.rowCount() - 1, 0, {});
  206. QVERIFY(!shareIndex.data(Qt::DisplayRole).toString().isEmpty());
  207. QCOMPARE(shareIndex.data(ShareModel::ShareTypeRole).toInt(), _testLinkShareDefinition.shareType);
  208. QCOMPARE(shareIndex.data(ShareModel::ShareIdRole).toString(), _testLinkShareDefinition.shareId);
  209. QCOMPARE(shareIndex.data(ShareModel::LinkRole).toString(), _testLinkShareDefinition.linkShareUrl);
  210. QCOMPARE(shareIndex.data(ShareModel::LinkShareNameRole).toString(), _testLinkShareDefinition.linkShareName);
  211. QCOMPARE(shareIndex.data(ShareModel::LinkShareLabelRole).toString(), _testLinkShareDefinition.linkShareLabel);
  212. QCOMPARE(shareIndex.data(ShareModel::NoteEnabledRole).toBool(), !_testLinkShareDefinition.shareNote.isEmpty());
  213. QCOMPARE(shareIndex.data(ShareModel::NoteRole).toString(), _testLinkShareDefinition.shareNote);
  214. QCOMPARE(shareIndex.data(ShareModel::PasswordProtectEnabledRole).toBool(), !_testLinkShareDefinition.sharePassword.isEmpty());
  215. // We don't expose the fetched password to the user as it's useless to them
  216. QCOMPARE(shareIndex.data(ShareModel::PasswordRole).toString(), QString());
  217. QCOMPARE(shareIndex.data(ShareModel::EditingAllowedRole).toBool(), SharePermissions(_testLinkShareDefinition.sharePermissions).testFlag(SharePermissionUpdate));
  218. const auto expectedLinkShareExpireDate = QDate::fromString(_testLinkShareDefinition.shareExpiration, helper.expectedDtFormat);
  219. QCOMPARE(shareIndex.data(ShareModel::ExpireDateEnabledRole).toBool(), expectedLinkShareExpireDate.isValid());
  220. QCOMPARE(shareIndex.data(ShareModel::ExpireDateRole).toLongLong(), expectedLinkShareExpireDate.startOfDay(Qt::UTC).toMSecsSinceEpoch());
  221. const auto iconUrl = shareIndex.data(ShareModel::IconUrlRole).toString();
  222. QVERIFY(iconUrl.contains("public.svg"));
  223. }
  224. void testModelEmailShareData()
  225. {
  226. helper.resetTestData();
  227. // Test with a user/group email share "from the server"
  228. helper.appendShareReplyData(_testEmailShareDefinition);
  229. QCOMPARE(helper.shareCount(), 1);
  230. ShareModel model;
  231. QAbstractItemModelTester modelTester(&model);
  232. QCOMPARE(model.rowCount(), 0);
  233. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  234. model.setAccountState(helper.accountState.data());
  235. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  236. QVERIFY(sharesChanged.wait(5000));
  237. QCOMPARE(model.rowCount(), 3); // Remember about placeholder and internal link share
  238. // Placeholder link share gets added after we are done parsing fetched shares, and the
  239. // internal link share is added after we receive a reply from the PROPFIND, which we
  240. // send before fetching the shares, so it will be added first.
  241. //
  242. // Hence we grab the remote share in between.
  243. const auto shareIndex = model.index(1, 0, {});
  244. QVERIFY(!shareIndex.data(Qt::DisplayRole).toString().isEmpty());
  245. QCOMPARE(shareIndex.data(ShareModel::ShareTypeRole).toInt(), _testEmailShareDefinition.shareType);
  246. QCOMPARE(shareIndex.data(ShareModel::ShareIdRole).toString(), _testEmailShareDefinition.shareId);
  247. QCOMPARE(shareIndex.data(ShareModel::NoteEnabledRole).toBool(), !_testEmailShareDefinition.shareNote.isEmpty());
  248. QCOMPARE(shareIndex.data(ShareModel::NoteRole).toString(), _testEmailShareDefinition.shareNote);
  249. QCOMPARE(shareIndex.data(ShareModel::PasswordProtectEnabledRole).toBool(), !_testEmailShareDefinition.sharePassword.isEmpty());
  250. // We don't expose the fetched password to the user as it's useless to them
  251. QCOMPARE(shareIndex.data(ShareModel::PasswordRole).toString(), QString());
  252. QCOMPARE(shareIndex.data(ShareModel::EditingAllowedRole).toBool(), SharePermissions(_testEmailShareDefinition.sharePermissions).testFlag(SharePermissionUpdate));
  253. const auto expectedShareExpireDate = QDate::fromString(_testEmailShareDefinition.shareExpiration, helper.expectedDtFormat);
  254. QCOMPARE(shareIndex.data(ShareModel::ExpireDateEnabledRole).toBool(), expectedShareExpireDate.isValid());
  255. QCOMPARE(shareIndex.data(ShareModel::ExpireDateRole).toLongLong(), expectedShareExpireDate.startOfDay(Qt::UTC).toMSecsSinceEpoch());
  256. const auto iconUrl = shareIndex.data(ShareModel::IconUrlRole).toString();
  257. QVERIFY(iconUrl.contains("email.svg"));
  258. }
  259. void testModelUserShareData()
  260. {
  261. helper.resetTestData();
  262. // Test with a user/group user share "from the server"
  263. helper.appendShareReplyData(_testUserShareDefinition);
  264. QCOMPARE(helper.shareCount(), 1);
  265. ShareModel model;
  266. QAbstractItemModelTester modelTester(&model);
  267. QCOMPARE(model.rowCount(), 0);
  268. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  269. model.setAccountState(helper.accountState.data());
  270. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  271. QVERIFY(sharesChanged.wait(5000));
  272. QCOMPARE(model.rowCount(), 3); // Remember about placeholder and internal link share
  273. // Placeholder link share gets added after we are done parsing fetched shares, and the
  274. // internal link share is added after we receive a reply from the PROPFIND, which we
  275. // send before fetching the shares, so it will be added first.
  276. //
  277. // Hence we grab the remote share in between.
  278. const auto shareIndex = model.index(1, 0, {});
  279. QVERIFY(!shareIndex.data(Qt::DisplayRole).toString().isEmpty());
  280. QCOMPARE(shareIndex.data(ShareModel::ShareTypeRole).toInt(), _testUserShareDefinition.shareType);
  281. QCOMPARE(shareIndex.data(ShareModel::ShareIdRole).toString(), _testUserShareDefinition.shareId);
  282. QCOMPARE(shareIndex.data(ShareModel::NoteEnabledRole).toBool(), !_testUserShareDefinition.shareNote.isEmpty());
  283. QCOMPARE(shareIndex.data(ShareModel::NoteRole).toString(), _testUserShareDefinition.shareNote);
  284. QCOMPARE(shareIndex.data(ShareModel::PasswordProtectEnabledRole).toBool(), !_testUserShareDefinition.sharePassword.isEmpty());
  285. // We don't expose the fetched password to the user as it's useless to them
  286. QCOMPARE(shareIndex.data(ShareModel::PasswordRole).toString(), QString());
  287. QCOMPARE(shareIndex.data(ShareModel::EditingAllowedRole).toBool(), SharePermissions(_testUserShareDefinition.sharePermissions).testFlag(SharePermissionUpdate));
  288. const auto expectedShareExpireDate = QDate::fromString(_testUserShareDefinition.shareExpiration, helper.expectedDtFormat);
  289. QCOMPARE(shareIndex.data(ShareModel::ExpireDateEnabledRole).toBool(), expectedShareExpireDate.isValid());
  290. QCOMPARE(shareIndex.data(ShareModel::ExpireDateRole).toLongLong(), expectedShareExpireDate.startOfDay(Qt::UTC).toMSecsSinceEpoch());
  291. const auto iconUrl = shareIndex.data(ShareModel::IconUrlRole).toString();
  292. QVERIFY(iconUrl.contains("user.svg"));
  293. // Check correct user avatar
  294. const auto avatarUrl = shareIndex.data(ShareModel::AvatarUrlRole).toString();
  295. const auto relativeAvatarPath = QString("remote.php/dav/avatars/%1/%2.png").arg(_testUserShareDefinition.shareShareWith, QString::number(64));
  296. const auto expectedAvatarPath = Utility::concatUrlPath(helper.account->url(), relativeAvatarPath).toString();
  297. const QString expectedUrl(QStringLiteral("image://tray-image-provider/") + expectedAvatarPath);
  298. QCOMPARE(avatarUrl, expectedUrl);
  299. }
  300. void testSuccessfulCreateShares()
  301. {
  302. helper.resetTestData();
  303. // Test with an existing link share
  304. helper.appendShareReplyData(_testLinkShareDefinition);
  305. QCOMPARE(helper.shareCount(), 1);
  306. ShareModel model;
  307. QAbstractItemModelTester modelTester(&model);
  308. QCOMPARE(model.rowCount(), 0);
  309. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  310. model.setAccountState(helper.accountState.data());
  311. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  312. QVERIFY(sharesChanged.wait(5000));
  313. QCOMPARE(helper.shareCount(), 1); // Check our test is working!
  314. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  315. // Test if it gets added
  316. model.createNewLinkShare();
  317. QVERIFY(sharesChanged.wait(5000));
  318. QCOMPARE(helper.shareCount(), 2); // Check our test is working!
  319. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  320. // Test if it's the type we wanted
  321. const auto newLinkShareIndex = model.index(model.rowCount() - 1, 0, {});
  322. QCOMPARE(newLinkShareIndex.data(ShareModel::ShareTypeRole).toInt(), Share::TypeLink);
  323. // Do it again with a different type
  324. const ShareePtr sharee(new Sharee("testsharee@nextcloud.com", "Test sharee", Sharee::Type::Email));
  325. model.createNewUserGroupShare(sharee);
  326. QVERIFY(sharesChanged.wait(5000));
  327. QCOMPARE(helper.shareCount(), 3); // Check our test is working!
  328. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  329. // Test if it's the type we wanted
  330. const auto newUserGroupShareIndex = model.index(model.rowCount() - 1, 0, {});
  331. QCOMPARE(newUserGroupShareIndex.data(ShareModel::ShareTypeRole).toInt(), Share::TypeEmail);
  332. // Confirm correct addition of share with password
  333. const auto password = QStringLiteral("a pretty bad password but good thing it doesn't matter!");
  334. model.createNewLinkShareWithPassword(password);
  335. QVERIFY(sharesChanged.wait(5000));
  336. QCOMPARE(helper.shareCount(), 4); // Check our test is working!
  337. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  338. model.createNewUserGroupShareWithPassword(sharee, password);
  339. QVERIFY(sharesChanged.wait(5000));
  340. QCOMPARE(helper.shareCount(), 5); // Check our test is working!
  341. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  342. helper.resetTestData();
  343. }
  344. void testEnforcePasswordShares()
  345. {
  346. helper.resetTestData();
  347. // Enforce passwords for shares in capabilities
  348. const QVariantMap enforcePasswordsCapabilities {
  349. {QStringLiteral("files_sharing"), QVariantMap {
  350. {QStringLiteral("api_enabled"), true},
  351. {QStringLiteral("default_permissions"), 19},
  352. {QStringLiteral("public"), QVariantMap {
  353. {QStringLiteral("enabled"), true},
  354. {QStringLiteral("expire_date"), QVariantMap {
  355. {QStringLiteral("days"), 30},
  356. {QStringLiteral("enforced"), false},
  357. }},
  358. {QStringLiteral("expire_date_internal"), QVariantMap {
  359. {QStringLiteral("days"), 30},
  360. {QStringLiteral("enforced"), false},
  361. }},
  362. {QStringLiteral("expire_date_remote"), QVariantMap {
  363. {QStringLiteral("days"), 30},
  364. {QStringLiteral("enforced"), false},
  365. }},
  366. {QStringLiteral("password"), QVariantMap {
  367. {QStringLiteral("enforced"), true},
  368. }},
  369. }},
  370. {QStringLiteral("sharebymail"), QVariantMap {
  371. {QStringLiteral("enabled"), true},
  372. {QStringLiteral("password"), QVariantMap {
  373. {QStringLiteral("enforced"), true},
  374. }},
  375. }},
  376. }},
  377. };
  378. helper.account->setCapabilities(enforcePasswordsCapabilities);
  379. QVERIFY(helper.account->capabilities().sharePublicLinkEnforcePassword());
  380. QVERIFY(helper.account->capabilities().shareEmailPasswordEnforced());
  381. // Test with a link share "from the server"
  382. helper.appendShareReplyData(_testLinkShareDefinition);
  383. QCOMPARE(helper.shareCount(), 1);
  384. ShareModel model;
  385. QAbstractItemModelTester modelTester(&model);
  386. QCOMPARE(model.rowCount(), 0);
  387. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  388. model.setAccountState(helper.accountState.data());
  389. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  390. QVERIFY(sharesChanged.wait(5000));
  391. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  392. // Confirm that the model requests a password
  393. QSignalSpy requestPasswordForLinkShare(&model, &ShareModel::requestPasswordForLinkShare);
  394. model.createNewLinkShare();
  395. QVERIFY(requestPasswordForLinkShare.wait(3000));
  396. QSignalSpy requestPasswordForEmailShare(&model, &ShareModel::requestPasswordForEmailSharee);
  397. const ShareePtr sharee(new Sharee("testsharee@nextcloud.com", "Test sharee", Sharee::Type::Email));
  398. model.createNewUserGroupShare(sharee);
  399. QCOMPARE(requestPasswordForEmailShare.count(), 1);
  400. // Test that the model data is correctly reporting that passwords are enforced
  401. const auto shareIndex = model.index(model.rowCount() - 1, 0, {});
  402. QCOMPARE(shareIndex.data(ShareModel::PasswordEnforcedRole).toBool(), true);
  403. QCOMPARE(shareIndex.data(ShareModel::PasswordProtectEnabledRole).toBool(), true);
  404. }
  405. void testEnforceExpireDate()
  406. {
  407. helper.resetTestData();
  408. const auto internalExpireDays = 45;
  409. const auto publicExpireDays = 30;
  410. const auto remoteExpireDays = 25;
  411. // Enforce expire dates for shares in capabilities
  412. const QVariantMap enforcePasswordsCapabilities {
  413. {QStringLiteral("files_sharing"), QVariantMap {
  414. {QStringLiteral("api_enabled"), true},
  415. {QStringLiteral("default_permissions"), 19},
  416. {QStringLiteral("public"), QVariantMap {
  417. {QStringLiteral("enabled"), true},
  418. {QStringLiteral("expire_date"), QVariantMap {
  419. {QStringLiteral("days"), publicExpireDays},
  420. {QStringLiteral("enforced"), true},
  421. }},
  422. {QStringLiteral("expire_date_internal"), QVariantMap {
  423. {QStringLiteral("days"), internalExpireDays},
  424. {QStringLiteral("enforced"), true},
  425. }},
  426. {QStringLiteral("expire_date_remote"), QVariantMap {
  427. {QStringLiteral("days"), remoteExpireDays},
  428. {QStringLiteral("enforced"), true},
  429. }},
  430. {QStringLiteral("password"), QVariantMap {
  431. {QStringLiteral("enforced"), false},
  432. }},
  433. }},
  434. {QStringLiteral("sharebymail"), QVariantMap {
  435. {QStringLiteral("enabled"), true},
  436. {QStringLiteral("password"), QVariantMap {
  437. {QStringLiteral("enforced"), true},
  438. }},
  439. }},
  440. }},
  441. };
  442. helper.account->setCapabilities(enforcePasswordsCapabilities);
  443. QVERIFY(helper.account->capabilities().sharePublicLinkEnforceExpireDate());
  444. QVERIFY(helper.account->capabilities().shareInternalEnforceExpireDate());
  445. QVERIFY(helper.account->capabilities().shareRemoteEnforceExpireDate());
  446. // Test with shares "from the server"
  447. helper.appendShareReplyData(_testLinkShareDefinition);
  448. helper.appendShareReplyData(_testEmailShareDefinition);
  449. helper.appendShareReplyData(_testRemoteShareDefinition);
  450. QCOMPARE(helper.shareCount(), 3);
  451. ShareModel model;
  452. QAbstractItemModelTester modelTester(&model);
  453. QCOMPARE(model.rowCount(), 0);
  454. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  455. model.setAccountState(helper.accountState.data());
  456. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  457. QVERIFY(sharesChanged.wait(5000));
  458. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  459. // Test that the model data is correctly reporting that expire dates are enforced for all share types
  460. for(auto i = 0; i < model.rowCount(); ++i) {
  461. const auto shareIndex = model.index(i, 0, {});
  462. const auto shareType = shareIndex.data(ShareModel::ShareTypeRole).toInt();
  463. const auto expectTrue = shareType != ShareModel::ShareTypePlaceholderLink &&
  464. shareType != ShareModel::ShareTypeInternalLink;
  465. QCOMPARE(shareIndex.data(ShareModel::ExpireDateEnforcedRole).toBool(), expectTrue);
  466. QDateTime expectedExpireDateTime;
  467. switch(shareType) {
  468. case Share::TypeInternalLink:
  469. case Share::TypePlaceholderLink:
  470. return;
  471. case Share::TypeUser:
  472. case Share::TypeGroup:
  473. case Share::TypeCircle:
  474. case Share::TypeRoom:
  475. expectedExpireDateTime = QDate::currentDate().addDays(internalExpireDays).startOfDay(QTimeZone::utc());
  476. break;
  477. case Share::TypeLink:
  478. case Share::TypeEmail:
  479. expectedExpireDateTime = QDate::currentDate().addDays(publicExpireDays).startOfDay(QTimeZone::utc());
  480. break;
  481. case Share::TypeRemote:
  482. expectedExpireDateTime = QDate::currentDate().addDays(remoteExpireDays).startOfDay(QTimeZone::utc());
  483. break;
  484. }
  485. QCOMPARE(shareIndex.data(ShareModel::EnforcedMaximumExpireDateRole).toLongLong(), expectedExpireDateTime.toMSecsSinceEpoch());
  486. }
  487. }
  488. void testSuccessfulDeleteShares()
  489. {
  490. helper.resetTestData();
  491. // Test with an existing link share
  492. helper.appendShareReplyData(_testLinkShareDefinition);
  493. QCOMPARE(helper.shareCount(), 1);
  494. ShareModel model;
  495. QAbstractItemModelTester modelTester(&model);
  496. QCOMPARE(model.rowCount(), 0);
  497. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  498. model.setAccountState(helper.accountState.data());
  499. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  500. QVERIFY(sharesChanged.wait(5000));
  501. QCOMPARE(helper.shareCount(), 1); // Check our test is working!
  502. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  503. // Create share
  504. model.createNewLinkShare();
  505. QVERIFY(sharesChanged.wait(5000));
  506. QCOMPARE(helper.shareCount(), 2); // Check our test is working!
  507. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  508. // Test if it gets deleted properly
  509. const auto latestLinkShare = model.index(model.rowCount() - 1, 0, {}).data(ShareModel::ShareRole).value<SharePtr>();
  510. QSignalSpy shareDeleted(latestLinkShare.data(), &LinkShare::shareDeleted);
  511. model.deleteShare(latestLinkShare);
  512. QVERIFY(shareDeleted.wait(5000));
  513. QCOMPARE(helper.shareCount(), 1); // Check our test is working!
  514. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  515. helper.resetTestData();
  516. }
  517. void testPlaceholderLinkShare()
  518. {
  519. helper.resetTestData();
  520. // Start with no shares; should show the placeholder link share
  521. ShareModel model;
  522. QAbstractItemModelTester modelTester(&model);
  523. QCOMPARE(model.rowCount(), 0); // There should be no placeholder yet
  524. QSignalSpy hasInitialShareFetchCompletedChanged(&model, &ShareModel::hasInitialShareFetchCompletedChanged);
  525. model.setAccountState(helper.accountState.data());
  526. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  527. QVERIFY(hasInitialShareFetchCompletedChanged.wait(5000));
  528. QVERIFY(model.hasInitialShareFetchCompleted());
  529. QCOMPARE(model.rowCount(), 2); // There should be a placeholder and internal link share now
  530. const QPersistentModelIndex placeholderLinkShareIndex(model.index(model.rowCount() - 1, 0, {}));
  531. QCOMPARE(placeholderLinkShareIndex.data(ShareModel::ShareTypeRole).toInt(), Share::TypePlaceholderLink);
  532. // Test adding a user group share -- we should still be showing a placeholder link share
  533. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  534. const ShareePtr sharee(new Sharee("testsharee@nextcloud.com", "Test sharee", Sharee::Type::Email));
  535. model.createNewUserGroupShare(sharee);
  536. QVERIFY(sharesChanged.wait(5000));
  537. QCOMPARE(helper.shareCount(), 1); // Check our test is working!
  538. QCOMPARE(model.rowCount(), helper.shareCount() + 2); // Internal link share too!
  539. QVERIFY(placeholderLinkShareIndex.isValid());
  540. QCOMPARE(placeholderLinkShareIndex.data(ShareModel::ShareTypeRole).toInt(), Share::TypePlaceholderLink);
  541. // Now try adding a link share, which should remove the placeholder
  542. model.createNewLinkShare();
  543. QVERIFY(sharesChanged.wait(5000));
  544. QCOMPARE(helper.shareCount(), 2); // Check our test is working!
  545. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  546. QVERIFY(!placeholderLinkShareIndex.isValid());
  547. // Now delete the only link share, which should bring back the placeholder link share
  548. const auto latestLinkShare = model.index(model.rowCount() - 1, 0, {}).data(ShareModel::ShareRole).value<SharePtr>();
  549. QSignalSpy shareDeleted(latestLinkShare.data(), &LinkShare::shareDeleted);
  550. model.deleteShare(latestLinkShare);
  551. QVERIFY(shareDeleted.wait(5000));
  552. QCOMPARE(helper.shareCount(), 1); // Check our test is working!
  553. QCOMPARE(model.rowCount(), helper.shareCount() + 2); // Internal link share too!
  554. const auto newPlaceholderLinkShareIndex = model.index(model.rowCount() - 1, 0, {});
  555. QCOMPARE(newPlaceholderLinkShareIndex.data(ShareModel::ShareTypeRole).toInt(), Share::TypePlaceholderLink);
  556. helper.resetTestData();
  557. }
  558. void testSuccessfulToggleAllowEditing()
  559. {
  560. helper.resetTestData();
  561. // Test with an existing link share
  562. helper.appendShareReplyData(_testLinkShareDefinition);
  563. QCOMPARE(helper.shareCount(), 1);
  564. ShareModel model;
  565. QAbstractItemModelTester modelTester(&model);
  566. QCOMPARE(model.rowCount(), 0);
  567. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  568. model.setAccountState(helper.accountState.data());
  569. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  570. QVERIFY(sharesChanged.wait(5000));
  571. QCOMPARE(helper.shareCount(), 1); // Check our test is working!
  572. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  573. const auto shareIndex = model.index(model.rowCount() - 1, 0, {});
  574. QCOMPARE(shareIndex.data(ShareModel::EditingAllowedRole).toBool(), SharePermissions(_testLinkShareDefinition.sharePermissions).testFlag(SharePermissionUpdate));
  575. const auto share = shareIndex.data(ShareModel::ShareRole).value<SharePtr>();
  576. QSignalSpy permissionsSet(share.data(), &Share::permissionsSet);
  577. model.toggleShareAllowEditing(share, false);
  578. QVERIFY(permissionsSet.wait(3000));
  579. QCOMPARE(shareIndex.data(ShareModel::EditingAllowedRole).toBool(), false);
  580. }
  581. void testSuccessfulPasswordSet()
  582. {
  583. helper.resetTestData();
  584. // Test with an existing link share.
  585. // This one has a pre-existing password
  586. helper.appendShareReplyData(_testLinkShareDefinition);
  587. QCOMPARE(helper.shareCount(), 1);
  588. ShareModel model;
  589. QAbstractItemModelTester modelTester(&model);
  590. QCOMPARE(model.rowCount(), 0);
  591. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  592. model.setAccountState(helper.accountState.data());
  593. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  594. QVERIFY(sharesChanged.wait(5000));
  595. QCOMPARE(helper.shareCount(), 1); // Check our test is working!
  596. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  597. const auto shareIndex = model.index(model.rowCount() - 1, 0, {});
  598. QCOMPARE(shareIndex.data(ShareModel::PasswordProtectEnabledRole).toBool(), true);
  599. const auto share = shareIndex.data(ShareModel::ShareRole).value<SharePtr>();
  600. QSignalSpy passwordSet(share.data(), &Share::passwordSet);
  601. model.toggleSharePasswordProtect(share, false);
  602. QVERIFY(passwordSet.wait(3000));
  603. QCOMPARE(shareIndex.data(ShareModel::PasswordProtectEnabledRole).toBool(), false);
  604. const auto password = QStringLiteral("a pretty bad password but good thing it doesn't matter!");
  605. model.setSharePassword(share, password);
  606. QVERIFY(passwordSet.wait(3000));
  607. QCOMPARE(shareIndex.data(ShareModel::PasswordProtectEnabledRole).toBool(), true);
  608. // The model stores the recently set password.
  609. // We want to present the user with it in the UI while the model is alive
  610. QCOMPARE(shareIndex.data(ShareModel::PasswordRole).toString(), password);
  611. }
  612. void testSuccessfulExpireDateSet()
  613. {
  614. helper.resetTestData();
  615. // Test with an existing link share.
  616. // This one has a pre-existing expire date
  617. helper.appendShareReplyData(_testLinkShareDefinition);
  618. QCOMPARE(helper.shareCount(), 1);
  619. ShareModel model;
  620. QAbstractItemModelTester modelTester(&model);
  621. QCOMPARE(model.rowCount(), 0);
  622. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  623. model.setAccountState(helper.accountState.data());
  624. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  625. QVERIFY(sharesChanged.wait(5000));
  626. QCOMPARE(helper.shareCount(), 1); // Check our test is working!
  627. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  628. // Check what we know
  629. const auto shareIndex = model.index(model.rowCount() - 1, 0, {});
  630. QCOMPARE(shareIndex.data(ShareModel::ExpireDateEnabledRole).toBool(), true);
  631. // Disable expire date
  632. const auto sharePtr = shareIndex.data(ShareModel::ShareRole).value<SharePtr>();
  633. const auto linkSharePtr = sharePtr.dynamicCast<LinkShare>(); // Need to connect to signal
  634. QSignalSpy expireDateSet(linkSharePtr.data(), &LinkShare::expireDateSet);
  635. model.toggleShareExpirationDate(sharePtr, false);
  636. QVERIFY(expireDateSet.wait(3000));
  637. QCOMPARE(shareIndex.data(ShareModel::ExpireDateEnabledRole).toBool(), false);
  638. // Set a new expire date
  639. const auto expireDateMsecs = QDate::currentDate().addDays(10).startOfDay(Qt::UTC).toMSecsSinceEpoch();
  640. model.setShareExpireDate(linkSharePtr, expireDateMsecs);
  641. QVERIFY(expireDateSet.wait(3000));
  642. QCOMPARE(shareIndex.data(ShareModel::ExpireDateRole).toLongLong(), expireDateMsecs);
  643. QCOMPARE(shareIndex.data(ShareModel::ExpireDateEnabledRole).toBool(), true);
  644. // Test the QML-specific slot
  645. const QVariant newExpireDateMsecs = QDate::currentDate().addDays(20).startOfDay(Qt::UTC).toMSecsSinceEpoch();
  646. model.setShareExpireDateFromQml(QVariant::fromValue(sharePtr), newExpireDateMsecs);
  647. QVERIFY(expireDateSet.wait(3000));
  648. QCOMPARE(shareIndex.data(ShareModel::ExpireDateRole).toLongLong(), newExpireDateMsecs);
  649. QCOMPARE(shareIndex.data(ShareModel::ExpireDateEnabledRole).toBool(), true);
  650. }
  651. void testSuccessfulNoteSet()
  652. {
  653. helper.resetTestData();
  654. // Test with an existing link share.
  655. // This one has a pre-existing password
  656. helper.appendShareReplyData(_testLinkShareDefinition);
  657. QCOMPARE(helper.shareCount(), 1);
  658. ShareModel model;
  659. QAbstractItemModelTester modelTester(&model);
  660. QCOMPARE(model.rowCount(), 0);
  661. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  662. model.setAccountState(helper.accountState.data());
  663. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  664. QVERIFY(sharesChanged.wait(5000));
  665. QCOMPARE(helper.shareCount(), 1); // Check our test is working!
  666. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  667. const auto shareIndex = model.index(model.rowCount() - 1, 0, {});
  668. QCOMPARE(shareIndex.data(ShareModel::NoteEnabledRole).toBool(), true);
  669. const auto sharePtr = shareIndex.data(ShareModel::ShareRole).value<SharePtr>();
  670. const auto linkSharePtr = sharePtr.dynamicCast<LinkShare>(); // Need to connect to signal
  671. QSignalSpy noteSet(linkSharePtr.data(), &LinkShare::noteSet);
  672. model.toggleShareNoteToRecipient(sharePtr, false);
  673. QVERIFY(noteSet.wait(3000));
  674. QCOMPARE(shareIndex.data(ShareModel::NoteEnabledRole).toBool(), false);
  675. const auto note = QStringLiteral("Don't forget to test everything!");
  676. model.setShareNote(sharePtr, note);
  677. QVERIFY(noteSet.wait(3000));
  678. QCOMPARE(shareIndex.data(ShareModel::NoteEnabledRole).toBool(), true);
  679. // The model stores the recently set password.
  680. // We want to present the user with it in the UI while the model is alive
  681. QCOMPARE(shareIndex.data(ShareModel::NoteRole).toString(), note);
  682. }
  683. void testSuccessfulLinkShareLabelSet()
  684. {
  685. helper.resetTestData();
  686. // Test with an existing link share.
  687. helper.appendShareReplyData(_testLinkShareDefinition);
  688. QCOMPARE(helper.shareCount(), 1);
  689. ShareModel model;
  690. QAbstractItemModelTester modelTester(&model);
  691. QCOMPARE(model.rowCount(), 0);
  692. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  693. model.setAccountState(helper.accountState.data());
  694. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  695. QVERIFY(sharesChanged.wait(5000));
  696. QCOMPARE(helper.shareCount(), 1); // Check our test is working!
  697. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  698. const auto shareIndex = model.index(model.rowCount() - 1, 0, {});
  699. QCOMPARE(shareIndex.data(ShareModel::LinkShareLabelRole).toBool(), true);
  700. const auto sharePtr = shareIndex.data(ShareModel::ShareRole).value<SharePtr>();
  701. const auto linkSharePtr = sharePtr.dynamicCast<LinkShare>(); // Need to connect to signal
  702. QSignalSpy labelSet(linkSharePtr.data(), &LinkShare::labelSet);
  703. const auto label = QStringLiteral("New link share label!");
  704. model.setLinkShareLabel(linkSharePtr, label);
  705. QVERIFY(labelSet.wait(3000));
  706. QCOMPARE(shareIndex.data(ShareModel::LinkShareLabelRole).toString(), label);
  707. }
  708. void testSharees()
  709. {
  710. helper.resetTestData();
  711. helper.appendShareReplyData(_testLinkShareDefinition);
  712. helper.appendShareReplyData(_testEmailShareDefinition);
  713. helper.appendShareReplyData(_testUserShareDefinition);
  714. QCOMPARE(helper.shareCount(), 3);
  715. ShareModel model;
  716. QAbstractItemModelTester modelTester(&model);
  717. QCOMPARE(model.rowCount(), 0);
  718. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  719. model.setAccountState(helper.accountState.data());
  720. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  721. QVERIFY(sharesChanged.wait(5000));
  722. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  723. QCOMPARE(model.sharees().count(), 2); // Link shares don't have sharees
  724. // Test adding a user group share -- we should still be showing a placeholder link share
  725. const ShareePtr sharee(new Sharee("testsharee@nextcloud.com", "Test sharee", Sharee::Type::Email));
  726. model.createNewUserGroupShare(sharee);
  727. QVERIFY(sharesChanged.wait(5000));
  728. QCOMPARE(helper.shareCount(), 4); // Check our test is working!
  729. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  730. const auto sharees = model.sharees();
  731. QCOMPARE(sharees.count(), 3); // Link shares don't have sharees
  732. const auto lastSharee = sharees.last().value<ShareePtr>();
  733. QVERIFY(lastSharee);
  734. // Remove the user group share we just added
  735. const auto shareIndex = model.index(model.rowCount() - 1, 0, {});
  736. const auto sharePtr = shareIndex.data(ShareModel::ShareRole).value<SharePtr>();
  737. model.deleteShare(sharePtr);
  738. QVERIFY(sharesChanged.wait(5000));
  739. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  740. // Now check the sharee is gone
  741. QCOMPARE(model.sharees().count(), 2);
  742. }
  743. void testSharePropertySetError()
  744. {
  745. helper.resetTestData();
  746. // Serve a broken share definition from the server to force an error
  747. auto brokenLinkShareDefinition = _testLinkShareDefinition;
  748. brokenLinkShareDefinition.shareId = QString();
  749. helper.appendShareReplyData(brokenLinkShareDefinition);
  750. QCOMPARE(helper.shareCount(), 1);
  751. ShareModel model;
  752. QAbstractItemModelTester modelTester(&model);
  753. QCOMPARE(model.rowCount(), 0);
  754. QSignalSpy sharesChanged(&model, &ShareModel::sharesChanged);
  755. model.setAccountState(helper.accountState.data());
  756. model.setLocalPath(helper.fakeFolder.localPath() + helper.testFileName);
  757. QVERIFY(sharesChanged.wait(5000));
  758. QCOMPARE(helper.shareCount(), 1); // Check our test is working!
  759. QCOMPARE(model.rowCount(), helper.shareCount() + 1); // Internal link share!
  760. // Reset the fake server to pretend like nothing is wrong there
  761. helper.resetTestShares();
  762. helper.appendShareReplyData(_testLinkShareDefinition);
  763. QCOMPARE(helper.shareCount(), 1);
  764. // Now try changing a property of the share
  765. const auto shareIndex = model.index(model.rowCount() - 1, 0, {});
  766. const auto share = shareIndex.data(ShareModel::ShareRole).value<SharePtr>();
  767. QSignalSpy serverError(&model, &ShareModel::serverError);
  768. model.toggleShareAllowEditing(share, false);
  769. QVERIFY(serverError.wait(3000));
  770. // Specific signal for password set error
  771. QSignalSpy passwordSetError(&model, &ShareModel::passwordSetError);
  772. const auto password = QStringLiteral("a pretty bad password but good thing it doesn't matter!");
  773. model.setSharePassword(share, password);
  774. QVERIFY(passwordSetError.wait(3000));
  775. }
  776. };
  777. QTEST_MAIN(TestShareModel)
  778. #include "testsharemodel.moc"