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% 6 / 0 / 6
Functions: 100.0% 6 / 0 / 6
Branches: -% 0 / 0 / 0

service/ImapBodyFetch.h
Line Branch Exec Source
1 #pragma once
2
3 #include <QByteArray>
4 #include <QString>
5
6 #include <functional>
7
8 #include "data/MailRequest.h"
9 #include "service/ImapResponseParser.h"
10 #include "service/ImapService.h"
11
12 class ImapCommandTable;
13 class ImapPushSession;
14 class QObject;
15
16 // Body downloads of one IMAP connection (Sprint 92 S92.1.5, extracted from
17 // ImapService): uncorrelated and request-id correlated body fetches
18 // (BODY.PEEK[]<0.limit>), the pipelined SELECT + FETCH of the body
19 // connection with selected-mailbox reuse (P90.9), the configured message
20 // size limit, the one retry after an empty OK, and the single terminal
21 // BodyResult of the active request (with the E2E completion knobs).
22 //
23 // Owner: ImapService (std::unique_ptr), connection thread. Plain class.
24 // It owns the active body request; the line reader correlates literals
25 // through references to it and the service's SELECT handler reads it. The
26 // selected-mailbox state stays with the service and is read/written
27 // through SelectedMailbox references; commands go through the command
28 // table, push restart through the push session; the bodyRequestCompleted,
29 // bodyMailboxSelected and errorOccurred signals through notifiers (the
30 // emitter stays ImapService).
31 class ImapBodyFetch {
32 public:
33 using State = ImapService::State;
34
35 // References to the service's selected-mailbox state.
36 struct SelectedMailbox {
37 const QString &selectedFolder;
38 int &messageCount;
39 quint32 &uidValidity;
40 quint64 &highestModseq;
41 };
42 struct Deps {
43 // ImapService signals.
44 std::function<void(const BodyResult &result)> bodyRequestCompleted;
45 std::function<void(quint64 requestId, bool success)> bodyMailboxSelected;
46 std::function<void(const QString &error)> errorOccurred;
47 };
48 ImapBodyFetch(QObject *owner, ImapCommandTable &commands, ImapPushSession &push,
49 const State &state, SelectedMailbox mailbox, Deps deps);
50
51 void fetchBody(qint64 uid);
52 void fetchBody(qint64 uid, qint64 maxBytes);
53 void requestBody(quint64 requestId, qint64 uid);
54 static qint64 configuredMaxMessageBytes();
55 void fetchBodyWithLimits(quint64 requestId, qint64 uid,
56 qint64 acceptedBytes, qint64 requestedBytes);
57 void selectAndFetchBody(const QString &folderPath, qint64 uid);
58 void requestBodyInFolder(quint64 requestId, const QString &folderPath,
59 qint64 uid);
60 static QString buildFetchBodyCommand(qint64 uid, qint64 maxBytes = -1);
61 void invalidateBodyFetch();
62 // Forgets the active request without completing it (session lifecycle;
63 // the caller completes the request first).
64 void resetActiveRequest();
65 void completeBodyRequest(BodyOutcome outcome, QByteArray bytes = {},
66 const QString &error = {}, qint64 maxBytes = 0);
67 // Completes a request whose FETCH was never written (dispatched=false).
68 void completeUndispatched(quint64 requestId, const QString &folderPath, qint64 uid);
69 // S106-001: completes every request still parked in the serialized queue
70 // as undispatched. The session lifecycle calls it right after it cleared
71 // the command queue, which destroys the parked lambdas — without a
72 // completion the body transport stayed busy for the rest of the session.
73 void cancelParkedRequests();
74 #ifdef MAILJD_E2E_TESTING
75 void setNextBodyCompletionForE2e(int delayMs, bool fail,
76 const QString &folderPath = {}, qint64 uid = 0);
77 #endif
78 void handleTaggedFetchBody(const TaggedResponse &response);
79
80 // Active body request (single owner: this unit; the line reader and the
81 // service's SELECT handler and lifecycle use these references).
82 1417 qint64 &activeBodyFetchUid() { return m_activeBodyFetchUid; }
83 1479 quint64 &activeBodyRequestId() { return m_activeBodyRequestId; }
84 5 QString &activeBodyRequestFolder() { return m_activeBodyRequestFolder; }
85 1409 qint64 &activeBodyFetchLimit() { return m_activeBodyFetchLimit; }
86 1409 qint64 &activeBodyFetchRequestBytes() { return m_activeBodyFetchRequestBytes; }
87 1499 bool &bodyFetchRequiresSelect() { return m_bodyFetchRequiresSelect; }
88
89 private:
90 QObject *m_owner; // context of the delayed E2E completion
91 ImapCommandTable &m_commands;
92 ImapPushSession &m_push;
93 const State &m_state; // ImapService::m_state
94 SelectedMailbox m_mailbox;
95 Deps m_deps;
96
97 qint64 m_activeBodyFetchUid = -1;
98 quint64 m_activeBodyRequestId = 0;
99 QString m_activeBodyRequestFolder;
100 qint64 m_activeBodyFetchLimit = 0;
101 qint64 m_activeBodyFetchRequestBytes = 0;
102 bool m_bodyFetchRequiresSelect = false;
103 // One re-fetch after an empty OK body response (see handleTaggedFetchBody).
104 bool m_bodyFetchRetried = false;
105 // Identified requests waiting in the serialized command queue (S106-001).
106 struct ParkedRequest {
107 quint64 ticket = 0;
108 quint64 requestId = 0;
109 QString folderPath;
110 qint64 uid = 0;
111 };
112 QList<ParkedRequest> m_parkedRequests;
113 quint64 m_nextParkTicket = 0;
114 // Parks `run` in the serialized queue; an identified request is tracked
115 // until the queue runs it or the session drops it.
116 void park(quint64 requestId, const QString &folderPath, qint64 uid, std::function<void()> run);
117 // Keep the object layout identical for all consumers of mailjd_app_lib.
118 // mailjd_app_lib defines MAILJD_E2E_TESTING for its own code only, so
119 // conditionally compiling data members would make non-E2E test executables
120 // allocate a smaller object than its constructor initializes.
121 int m_e2eNextBodyCompletionDelayMs = 0;
122 bool m_e2eFailNextBodyCompletion = false;
123 QString m_e2eBodyCompletionFolder;
124 qint64 m_e2eBodyCompletionUid = 0;
125 };
126