MailJDTourDownloadDocsQualityTestsCoverage

Which source lines and branches the tests execute. Lines 91.5 %, branches 75.0 % (minimum 85 % and 72 %). main @ 399ffe3d · 21 October 2026 · pipeline 7238.

GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 2 / 0 / 2
Functions: 100.0% 2 / 0 / 2
Branches: -% 0 / 0 / 0

controller/MailMoveCommands.h
Line Branch Exec Source
1 #pragma once
2
3 #include <QList>
4 #include <QObject>
5 #include <QPair>
6 #include <QPointer>
7 #include <QString>
8 #include <QStringList>
9 #include <functional>
10 #include <memory>
11 #include <optional>
12
13 #include "controller/FolderContext.h"
14 #include "data/MailSelectionMutation.h"
15 #include "data/Models.h"
16
17 class ImapService;
18 class MailCache;
19 class MailListModel;
20 class MailMutationPipeline;
21 class MailThreadModel;
22 class UndoManager;
23
24 // Move commands of the controller (Sprint 91 S91.4.4, plan correction:
25 // extracted from MailController to bring it below 3,000 lines): visual-first
26 // moves and worker-journaled selection moves, cross-folder moves on the
27 // body connection, move results of both connections, rollback and the
28 // Message-ID based undo. Callers reach it as `controller.moves()`.
29 //
30 // Owner: MailController (value member). GUI thread. Durable dispatch goes
31 // through the mutation pipeline (reference). The connections, the body
32 // connection's selected folder, the body-fetch SELECT suppression flag, the
33 // folder context, the undo manager and the selection-action generation stay
34 // owned by the controller and are read (and where the moved code wrote them,
35 // written) by reference. The controller connects the move-result signals of
36 // both connections to this unit at their former positions. Folder reopen,
37 // resync, folder-id resolution, loaded-row headers and the body connection
38 // are reached through Deps; controller signals keep their emitter.
39 class MailMoveCommands final : public QObject {
40 102 Q_OBJECT
41 public:
42 struct Deps {
43 std::function<void()> ensureBodyConnection;
44 std::function<std::optional<MailHeader>(qint64 folderId, qint64 uid)> loadedHeader;
45 std::function<void(const QString &folderPath)> onFolderSelected;
46 std::function<qint64(const QString &folderPath)> resolveFolderId;
47 std::function<void()> resyncCurrentFolder;
48 // MailController signals (the emitter stays the controller).
49 std::function<void(const QString &)> statusMessage;
50 std::function<void(const QString &)> actionError;
51 std::function<void(qint64 folderId, const QList<qint64> &uids)> movesVisuallyPending;
52 std::function<void(qint64 folderId, const QList<qint64> &uids)> movesVisuallySettled;
53 std::function<void(const QString &folder, int count)> unreadCountChanged;
54 };
55 MailMoveCommands(ImapService *imap, ImapService *const &bodyImap,
56 QString &bodyImapSelectedFolder, bool &bodyFetchSelect, MailCache *cache,
57 MailListModel *model, MailThreadModel *const &threadModel,
58 FolderContext &folder, MailMutationPipeline &mutations,
59 const QPointer<UndoManager> &undoManager,
60 const quint64 &selectionActionGeneration, Deps deps,
61 QObject *parent = nullptr);
62
63 // Adopt worker-journaled intent without rebuilding a loaded-header UID list.
64 bool adoptSelectionMove(const MailSelectionMoveResult &action);
65 void moveSelection(std::shared_ptr<const MailSelectionSnapshot> selection,
66 const QString &targetFolder,
67 std::function<void(MailSelectionMoveResult)> callback = {});
68 void moveMailToFolder(qint64 uid, const QString &targetFolder);
69 void moveMailsToFolder(const QList<qint64> &uids, const QString &targetFolder);
70 void moveMailsToFolderFrom(const QList<qint64> &uids, qint64 srcFolderId,
71 const QString &srcFolder,
72 const QString &targetFolder);
73 // T-407: Cross-folder move via m_bodyImap
74 void crossFolderMove(const QString &srcFolder, const QList<qint64> &uids,
75 const QString &targetFolder);
76 // T-211: Undo a mail move (async IMAP flow)
77 void undoMove(const QList<MailHeader> &headers,
78 const QString &sourceFolder, const QString &fromFolder);
79 // Visual-first move of loaded rows and its rollback after a failed
80 // journal write (also driven directly by tests).
81 void startMove(qint64 folderId, const QString &folderPath,
82 const QList<qint64> &uids, const QString &targetFolder);
83 void rollbackVisualMove(qint64 folderId, const QList<MailHeader> &headers,
84 const QString &error);
85
86 public slots:
87 // T-100: Move result handlers
88 void onMessageMoved(qint64 uid, const QString &targetFolder);
89 void onMessagesMoved(const QList<qint64> &uids, const QString &targetFolder);
90 void onMoveError(const QString &error);
91
92 // T-79.E2/M6: move results on the body connection (cross-folder moves)
93 void onBodyImapMessagesMoved(const QList<qint64> &uids,
94 const QString &targetFolder);
95 void onBodyImapMoveError(const QString &error);
96
97 // Watchdog of the undo-move SELECT/SEARCH chain (30 s; tests shorten it).
98 1 void setUndoChainTimeoutMs(int ms) { m_undoChainTimeoutMs = ms; }
99
100 private:
101 // S106-187: state of one undo-move Message-ID search chain.
102 struct UndoSearchChain {
103 struct Outcome {
104 QString messageId;
105 QList<qint64> uids;
106 };
107 QStringList messageIds;
108 QList<Outcome> outcomes;
109 QString fencedFolder;
110 quint32 fencedUidValidity = 0;
111 quint64 awaitedSequence = 0;
112 QMetaObject::Connection selectConnection;
113 QMetaObject::Connection searchConnection;
114 bool done = false;
115 };
116
117 // undoMove step (S91.4.3).
118 void journalAndDispatchUndo(const QList<qint64> &foundUids, const QStringList &messageIds,
119 const QString &sourceFolder, const QString &fromFolder,
120 const QString &capturedFolder);
121
122 ImapService *m_imap;
123 ImapService *const &m_bodyImap; // MailController (lazy body connection)
124 QString &m_bodyImapSelectedFolder; // connection state, MailController
125 bool &m_bodyFetchSelect; // SELECT suppression, MailController
126 MailCache *m_cache;
127 MailListModel *m_model;
128 MailThreadModel *const &m_threadModel; // MailController::setThreadModel
129 FolderContext &m_folder; // MailController::m_folder
130 MailMutationPipeline &m_mutations; // MailController::m_mutations
131 const QPointer<UndoManager> &m_undoManager;
132 const quint64 &m_selectionActionGeneration;
133 Deps m_deps;
134 int m_undoChainTimeoutMs = 30000;
135 // T-79.E2/M6: cross-folder moves in flight on the body connection:
136 // (source folderId, uids). Success removes the source-folder cache rows;
137 // failure restores the optimistically removed model rows.
138 QList<QPair<qint64, QList<qint64>>> m_pendingCrossFolderMoves;
139 };
140