File indexing completed on 2024-11-24 04:53:30

0001 /* Copyright (C) 2006 - 2014 Jan Kundrát <jkt@flaska.net>
0002 
0003    This file is part of the Trojita Qt IMAP e-mail client,
0004    http://trojita.flaska.net/
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU General Public License as
0008    published by the Free Software Foundation; either version 2 of
0009    the License or (at your option) version 3 or any later version
0010    accepted by the membership of KDE e.V. (or its successor approved
0011    by the membership of KDE e.V.), which shall act as a proxy
0012    defined in Section 14 of version 3 of the license.
0013 
0014    This program is distributed in the hope that it will be useful,
0015    but WITHOUT ANY WARRANTY; without even the implied warranty of
0016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017    GNU General Public License for more details.
0018 
0019    You should have received a copy of the GNU General Public License
0020    along with this program.  If not, see <http://www.gnu.org/licenses/>.
0021 */
0022 
0023 #include "test_Imap_CopyAndFlagOperations.h"
0024 #include "Utils/FakeCapabilitiesInjector.h"
0025 #include "Streams/FakeSocket.h"
0026 #include "Imap/Model/ItemRoles.h"
0027 #include "Imap/Model/MailboxTree.h"
0028 #include "Imap/Model/MsgListModel.h"
0029 #include "Imap/Model/ThreadingMsgListModel.h"
0030 #include "Imap/Tasks/ObtainSynchronizedMailboxTask.h"
0031 
0032 using namespace Imap::Mailbox;
0033 
0034 void CopyAndFlagTest::testMoveRfc3501()
0035 {
0036     helperMove(JUST_3501);
0037 }
0038 
0039 void CopyAndFlagTest::testMoveUidPlus()
0040 {
0041     helperMove(HAS_UIDPLUS);
0042 }
0043 
0044 void CopyAndFlagTest::testMoveRfcMove()
0045 {
0046     helperMove(HAS_MOVE);
0047 }
0048 
0049 void CopyAndFlagTest::helperMove(const MoveFeatures serverFeatures)
0050 {
0051     FakeCapabilitiesInjector injector(model);
0052     switch (serverFeatures) {
0053     case JUST_3501:
0054         // nothing is needed
0055         break;
0056     case HAS_UIDPLUS:
0057         injector.injectCapability(QStringLiteral("UIDPLUS"));
0058         break;
0059     case HAS_MOVE:
0060         injector.injectCapability(QStringLiteral("MOVE"));
0061         break;
0062     }
0063 
0064     // Push the data to the cache
0065     existsA = 3;
0066     uidNextA = 5;
0067     uidValidityA = 666;
0068     for (uint i = 1; i <= existsA; ++i)
0069         uidMapA << i;
0070     helperSyncAWithMessagesEmptyState();
0071     helperCheckCache();
0072     helperVerifyUidMapA();
0073     QString mailbox = QStringLiteral("a");
0074     QString del = QStringLiteral("\\Deleted");
0075     Q_FOREACH(const auto uid, uidMapA) {
0076         // No message shall be marked as deleted
0077         QVERIFY(!model->cache()->msgFlags(mailbox, uid).contains(del));
0078     }
0079 
0080     // FIXME: this API sucks rather hard; it will have to change to use indexes at some point, if only for sanity
0081     auto aMailboxPtr = dynamic_cast<TreeItemMailbox *>(Model::realTreeItem(idxA));
0082     Q_ASSERT(aMailboxPtr);
0083     model->copyMoveMessages(aMailboxPtr, QStringLiteral("b"), Imap::Uids() << 2, MOVE);
0084 
0085     if (serverFeatures == HAS_MOVE) {
0086         cClient(t.mk("UID MOVE 2 b\r\n"));
0087         cServer("* 2 EXPUNGE\r\n" + t.last("OK moved\r\n"));
0088         --existsA;
0089         uidMapA.remove(1);
0090         helperCheckCache();
0091         helperVerifyUidMapA();
0092         Q_FOREACH(const auto uid, uidMapA) {
0093             // None message shall be marked as deleted
0094             QVERIFY(!model->cache()->msgFlags(mailbox, uid).contains(del));
0095         }
0096         cEmpty();
0097     } else {
0098         cClient(t.mk("UID COPY 2 b\r\n"));
0099         cServer(t.last("OK copied\r\n"));
0100         cClient(t.mk("UID STORE 2 +FLAGS.SILENT \\Deleted\r\n"));
0101         cServer(t.last("OK stored\r\n"));
0102         QVERIFY(model->cache()->msgFlags(mailbox, 2).contains(del));
0103         if (serverFeatures == HAS_UIDPLUS) {
0104             cClient(t.mk("UID EXPUNGE 2\r\n"));
0105             cServer("* 2 EXPUNGE\r\n" + t.last("OK expunged\r\n"));
0106             --existsA;
0107             uidMapA.remove(1);
0108             helperCheckCache();
0109             helperVerifyUidMapA();
0110             Q_FOREACH(const auto uid, uidMapA) {
0111                 // None message shall be marked as deleted
0112                 QVERIFY(!model->cache()->msgFlags(mailbox, uid).contains(del));
0113             }
0114         }
0115         cEmpty();
0116     }
0117     justKeepTask();
0118 }
0119 
0120 void CopyAndFlagTest::testUpdateAllFlags()
0121 {
0122     // Push the data to the cache
0123     existsA = 4;
0124     uidNextA = 5;
0125     uidValidityA = 666;
0126     for (uint i = 1; i <= existsA; ++i)
0127         uidMapA << i;
0128     // cannot use helperSyncAWithMessagesEmptyState(), we want to have control over the flags
0129     QCOMPARE(model->rowCount(msgListA), 0);
0130     cClient(t.mk("SELECT a\r\n"));
0131     cServer("* 4 EXISTS\r\n"
0132             "* OK [UIDVALIDITY 666] UIDs valid\r\n"
0133             "* OK [UIDNEXT 5] Predicted next UID\r\n"
0134             + t.last("OK selected\r\n"));
0135     cClient(t.mk("UID SEARCH ALL\r\n"));
0136     cServer("* SEARCH 3 4 2 1\r\n" + t.last("OK search\r\n"));
0137     cClient(t.mk("FETCH 1:4 (FLAGS)\r\n"));
0138     cServer("* 1 FETCH (FLAGS ())\r\n"
0139             "* 2 FETCH (FLAGS (\\SEEN))\r\n"
0140             "* 3 FETCH (FLAGS (\\Answered \\Seen))\r\n"
0141             "* 4 FETCH (FLAGS (\\Answered))\r\n"
0142             + t.last("OK fetched\r\n"));
0143     helperCheckCache();
0144     helperVerifyUidMapA();
0145     QString mailbox = QStringLiteral("a");
0146     QString seen = QStringLiteral("\\Seen");
0147     QVERIFY(!msgListA.model()->index(0, 0, msgListA).data(RoleMessageIsMarkedRead).toBool());
0148     QVERIFY(!model->cache()->msgFlags(mailbox, 1).contains(seen));
0149     QVERIFY(msgListA.model()->index(1, 0, msgListA).data(RoleMessageIsMarkedRead).toBool());
0150     QVERIFY(model->cache()->msgFlags(mailbox, 2).contains(seen));
0151     QVERIFY(msgListA.model()->index(2, 0, msgListA).data(RoleMessageIsMarkedRead).toBool());
0152     QVERIFY(model->cache()->msgFlags(mailbox, 3).contains(seen));
0153     QVERIFY(!msgListA.model()->index(3, 0, msgListA).data(RoleMessageIsMarkedRead).toBool());
0154     QVERIFY(!model->cache()->msgFlags(mailbox, 4).contains(seen));
0155 
0156     // Mark all messages as read
0157     model->markMailboxAsRead(idxA);
0158     cClient(t.mk("STORE 1:* +FLAGS.SILENT \\Seen\r\n"));
0159     cServer(t.last("OK stored\r\n"));
0160     for (uint i = 0; i < existsA; ++i) {
0161         QVERIFY(msgListA.model()->index(i, 0, msgListA).data(RoleMessageIsMarkedRead).toBool());
0162         QVERIFY(model->cache()->msgFlags(mailbox, uidMapA[i]).contains(seen));
0163     }
0164 
0165     cEmpty();
0166     justKeepTask();
0167 }
0168 
0169 QTEST_GUILESS_MAIN(CopyAndFlagTest)