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: 98.9% 180 / 0 / 182
Functions: 100.0% 26 / 0 / 26
Branches: 90.4% 161 / 0 / 178

controller/BodyRequestRegistry.cpp
Line Branch Exec Source
1 #include "BodyRequestRegistry.h"
2
3 #include <algorithm>
4
5 22253 quint64 BodyRequestRegistry::selectDisplay(const MailId &mailId) {
6 22253 m_selectedMailId = mailId;
7 22253 ++m_displayGeneration;
8
1/1
✓ Branch 4 → 5 taken 22253 times.
22253 removeConsumers(BodyPurpose::Display, std::nullopt);
9 22253 return m_displayGeneration;
10 }
11
12 3695 void BodyRequestRegistry::clearDisplaySelection() {
13 3695 m_selectedMailId = {};
14 3695 ++m_displayGeneration;
15
1/1
✓ Branch 5 → 6 taken 3695 times.
3695 removeConsumers(BodyPurpose::Display, std::nullopt);
16 3695 }
17
18 10043 bool BodyRequestRegistry::isDisplayConsumer(const BodyConsumer &consumer) {
19 10043 return consumer.purpose == BodyPurpose::Display;
20 }
21
22 15 bool BodyRequestRegistry::sameConsumer(const BodyConsumer &left,
23 const BodyConsumer &right) {
24
4/4
✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 7 taken 13 times.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 7 taken 1 time.
16 return left.purpose == right.purpose && left.consumerId == right.consumerId &&
25
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 6 not taken.
1 (left.purpose != BodyPurpose::Display ||
26
1/2
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 7 not taken.
16 left.displayGeneration == right.displayGeneration);
27 }
28
29 21090 BodyRequestTicket BodyRequestRegistry::request(const MailId &mailId,
30 const QString &folderPath,
31 BodyPurpose purpose,
32 quint64 consumerId) {
33
6/6
✓ Branch 3 → 4 taken 21089 times.
✓ Branch 3 → 6 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 21088 times.
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 10 taken 21088 times.
21090 if (!mailId.isValid() || folderPath.isEmpty())
34 2 return {};
35
36 BodyConsumer consumer{purpose, consumerId,
37 21088 purpose == BodyPurpose::Display ? m_displayGeneration
38
2/2
✓ Branch 10 → 11 taken 21037 times.
✓ Branch 10 → 12 taken 51 times.
21088 : quint64(0)};
39
2/2
✓ Branch 13 → 14 taken 29 times.
✓ Branch 13 → 15 taken 21059 times.
21088 if (purpose == BodyPurpose::Prefetch)
40 29 ++m_prefetchStats.requested;
41 21088 const auto existing = m_byMail.constFind(mailId);
42
2/2
✓ Branch 18 → 19 taken 13 times.
✓ Branch 18 → 40 taken 21075 times.
21088 if (existing != m_byMail.cend()) {
43
1/1
✓ Branch 20 → 21 taken 13 times.
13 Entry &entry = m_byId[*existing];
44 const bool alreadyRegistered =
45
1/1
✓ Branch 23 → 24 taken 13 times.
13 std::any_of(entry.consumers.cbegin(), entry.consumers.cend(),
46 15 [&consumer](const BodyConsumer &candidate) {
47 15 return sameConsumer(candidate, consumer);
48 });
49
2/2
✓ Branch 24 → 25 taken 12 times.
✓ Branch 24 → 26 taken 1 time.
13 if (!alreadyRegistered)
50
1/1
✓ Branch 25 → 26 taken 12 times.
12 entry.consumers.append(consumer);
51
6/6
✓ Branch 26 → 27 taken 12 times.
✓ Branch 26 → 32 taken 1 time.
✓ Branch 27 → 28 taken 8 times.
✓ Branch 27 → 32 taken 4 times.
✓ Branch 33 → 34 taken 4 times.
✓ Branch 33 → 36 taken 9 times.
21 if (!entry.dispatched && purpose != BodyPurpose::Prefetch &&
52
3/3
✓ Branch 29 → 30 taken 8 times.
✓ Branch 30 → 31 taken 4 times.
✓ Branch 30 → 32 taken 4 times.
8 m_prefetchQueue.removeAll(*existing) > 0)
53
1/1
✓ Branch 35 → 36 taken 4 times.
4 m_demandQueue.enqueue(*existing);
54
2/2
✓ Branch 36 → 37 taken 4 times.
✓ Branch 36 → 38 taken 9 times.
13 if (purpose == BodyPurpose::Prefetch)
55 4 ++m_prefetchStats.deduplicated;
56 13 return {*existing, true};
57 }
58
59
4/4
✓ Branch 40 → 41 taken 25 times.
✓ Branch 40 → 44 taken 21050 times.
✓ Branch 45 → 46 taken 1 time.
✓ Branch 45 → 47 taken 21074 times.
21100 if (purpose == BodyPurpose::Prefetch &&
60
3/3
✓ Branch 41 → 42 taken 25 times.
✓ Branch 42 → 43 taken 1 time.
✓ Branch 42 → 44 taken 24 times.
25 queuedPrefetchCount() >= MaximumQueuedPrefetch) {
61 1 return {};
62 }
63
64 21074 const quint64 requestId = m_nextRequestId++;
65 21074 Entry entry;
66 21074 entry.request = BodyRequest{requestId, mailId, folderPath, purpose};
67
1/1
✓ Branch 51 → 52 taken 21074 times.
21074 entry.consumers.append(consumer);
68
1/1
✓ Branch 52 → 53 taken 21074 times.
21074 m_byId.insert(requestId, entry);
69
1/1
✓ Branch 53 → 54 taken 21074 times.
21074 m_byMail.insert(mailId, requestId);
70
2/2
✓ Branch 54 → 55 taken 24 times.
✓ Branch 54 → 56 taken 21050 times.
21074 if (purpose == BodyPurpose::Prefetch)
71
1/1
✓ Branch 55 → 57 taken 24 times.
24 m_prefetchQueue.enqueue(requestId);
72 else
73
1/1
✓ Branch 56 → 57 taken 21050 times.
21050 m_demandQueue.enqueue(requestId);
74 21074 return {requestId, false};
75 21074 }
76
77 2 bool BodyRequestRegistry::nextDispatchIsPrefetch() const {
78
3/4
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 7 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 7 not taken.
2 return !hasQueuedDemand() && queuedPrefetchCount() > 0;
79 }
80
81 6 bool BodyRequestRegistry::hasQueuedDemand() const {
82
2/2
✓ Branch 18 → 4 taken 2 times.
✓ Branch 18 → 19 taken 4 times.
6 for (const quint64 requestId : m_demandQueue) {
83 2 const auto it = m_byId.constFind(requestId);
84
3/6
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 12 not taken.
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 12 not taken.
✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 15 not taken.
2 if (it != m_byId.constEnd() && !it->dispatched) return true;
85 }
86 4 return false;
87 }
88
89 10055 std::optional<BodyRequest> BodyRequestRegistry::takeNextForDispatch(bool allowPrefetch) {
90 10069 auto take = [this](QQueue<quint64> &queue) -> std::optional<BodyRequest> {
91
2/2
✓ Branch 19 → 3 taken 10053 times.
✓ Branch 19 → 20 taken 16 times.
10069 while (!queue.isEmpty()) {
92
1/1
✓ Branch 3 → 4 taken 10053 times.
10053 const quint64 requestId = queue.dequeue();
93
1/1
✓ Branch 4 → 5 taken 10053 times.
10053 auto it = m_byId.find(requestId);
94
3/6
✓ Branch 7 → 8 taken 10053 times.
✗ Branch 7 → 10 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 10053 times.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 10053 times.
10053 if (it == m_byId.end() || it->dispatched)
95 ✗ continue;
96 10053 it->dispatched = true;
97 10053 return it->request;
98 }
99 16 return std::nullopt;
100 10055 };
101
102
3/3
✓ Branch 2 → 3 taken 10055 times.
✓ Branch 4 → 5 taken 10041 times.
✓ Branch 4 → 6 taken 14 times.
10055 if (auto demand = take(m_demandQueue))
103 10055 return demand;
104
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 13 taken 14 times.
14 if (!allowPrefetch) return std::nullopt;
105
1/1
✓ Branch 13 → 14 taken 14 times.
14 return take(m_prefetchQueue);
106 }
107
108 20054 bool BodyRequestRegistry::matchesResult(const BodyResult &result) const {
109 20054 const auto it = m_byId.constFind(result.requestId);
110
3/4
✓ Branch 5 → 6 taken 20054 times.
✗ Branch 5 → 12 not taken.
✓ Branch 8 → 9 taken 20053 times.
✓ Branch 8 → 12 taken 1 time.
40107 return it != m_byId.cend() && result.folderPath == it->request.folderPath &&
111
2/2
✓ Branch 10 → 11 taken 20052 times.
✓ Branch 10 → 12 taken 1 time.
40107 result.uid == it->request.mailId.uid;
112 }
113
114 std::optional<BodyRequestResolution>
115 20046 BodyRequestRegistry::complete(const BodyResult &result) {
116
1/1
✓ Branch 2 → 3 taken 20046 times.
20046 auto it = m_byId.find(result.requestId);
117
2/2
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 20042 times.
20046 if (it == m_byId.end())
118 4 return std::nullopt;
119
120 20042 const bool matched = matchesResult(result);
121 20042 Entry entry = *it;
122
1/1
✓ Branch 11 → 12 taken 20042 times.
20042 m_byId.erase(it);
123
1/1
✓ Branch 12 → 13 taken 20042 times.
20042 m_byMail.remove(entry.request.mailId);
124
1/1
✓ Branch 13 → 14 taken 20042 times.
20042 removeQueuedRequest(result.requestId);
125
126 20042 BodyRequestResolution resolution;
127 20042 resolution.request = entry.request;
128 20042 resolution.result = result;
129 20042 resolution.consumers = entry.consumers;
130
1/1
✓ Branch 19 → 20 taken 20042 times.
20042 const bool wasPrefetch = std::any_of(
131 entry.consumers.cbegin(), entry.consumers.cend(),
132 10041 [](const BodyConsumer &consumer) {
133 10041 return consumer.purpose == BodyPurpose::Prefetch;
134 });
135
136
2/2
✓ Branch 20 → 21 taken 2 times.
✓ Branch 20 → 29 taken 20040 times.
20042 if (!matched) {
137 2 resolution.result.outcome = BodyOutcome::Failed;
138
1/1
✓ Branch 21 → 22 taken 2 times.
2 resolution.result.bytes.clear();
139 2 resolution.result.error = QStringLiteral("Mismatched body response");
140 }
141
142
2/2
✓ Branch 29 → 30 taken 7 times.
✓ Branch 29 → 35 taken 20035 times.
20042 if (wasPrefetch) {
143
2/2
✓ Branch 30 → 31 taken 3 times.
✓ Branch 30 → 32 taken 4 times.
7 if (resolution.result.outcome == BodyOutcome::Loaded)
144 3 ++m_prefetchStats.completed;
145
2/2
✓ Branch 32 → 33 taken 1 time.
✓ Branch 32 → 34 taken 3 times.
4 else if (resolution.result.outcome == BodyOutcome::Cancelled)
146 1 ++m_prefetchStats.cancelled;
147 else
148 3 ++m_prefetchStats.failed;
149 }
150
151 20042 resolution.displayEligible =
152
1/1
✓ Branch 37 → 38 taken 20042 times.
20042 std::any_of(entry.consumers.cbegin(), entry.consumers.cend(),
153 10043 [this, &entry](const BodyConsumer &consumer) {
154 10043 return isDisplayConsumer(consumer) &&
155
5/6
✓ Branch 3 → 4 taken 10019 times.
✓ Branch 3 → 8 taken 24 times.
✓ Branch 4 → 5 taken 10019 times.
✗ Branch 4 → 8 not taken.
✓ Branch 6 → 7 taken 10018 times.
✓ Branch 6 → 8 taken 1 time.
20062 consumer.displayGeneration == m_displayGeneration &&
156 20062 entry.request.mailId == m_selectedMailId;
157 });
158 20042 return resolution;
159 20042 }
160
161 17 void BodyRequestRegistry::invalidateFolder(const QString &accountId, qint64 folderId) {
162
6/6
✓ Branch 3 → 4 taken 7 times.
✓ Branch 3 → 6 taken 10 times.
✓ Branch 4 → 5 taken 6 times.
✓ Branch 4 → 6 taken 1 time.
✓ Branch 7 → 8 taken 6 times.
✓ Branch 7 → 9 taken 11 times.
17 if (m_selectedMailId.accountId == accountId && m_selectedMailId.folderId == folderId)
163
1/1
✓ Branch 8 → 9 taken 6 times.
6 clearDisplaySelection();
164
1/1
✓ Branch 9 → 10 taken 17 times.
17 const auto requests = m_byId.keys();
165
2/2
✓ Branch 34 → 12 taken 3 times.
✓ Branch 34 → 35 taken 17 times.
20 for (quint64 requestId : requests) {
166 3 const auto &request = m_byId.value(requestId).request;
167
5/6
✓ Branch 15 → 16 taken 3 times.
✗ Branch 15 → 17 not taken.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 16 → 18 taken 2 times.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 21 taken 2 times.
3 if (request.mailId.accountId != accountId || request.mailId.folderId != folderId)
168 1 continue;
169
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 2 times.
2 if (request.purpose == BodyPurpose::Prefetch)
170 ✗ ++m_prefetchStats.cancelled;
171
1/1
✓ Branch 23 → 24 taken 2 times.
2 m_byMail.remove(request.mailId);
172
1/1
✓ Branch 24 → 25 taken 2 times.
2 m_byId.remove(requestId);
173
1/1
✓ Branch 25 → 26 taken 2 times.
2 removeQueuedRequest(requestId);
174 3 }
175 17 }
176
177 1234 void BodyRequestRegistry::removeConsumer(BodyPurpose purpose,
178 quint64 consumerId) {
179
1/1
✓ Branch 3 → 4 taken 1234 times.
1234 removeConsumers(purpose, consumerId);
180 1234 }
181
182 27182 void BodyRequestRegistry::removeConsumers(BodyPurpose purpose,
183 std::optional<quint64> consumerId) {
184 27182 QList<quint64> emptyRequests;
185
3/3
✓ Branch 2 → 3 taken 27182 times.
✓ Branch 33 → 4 taken 13076 times.
✓ Branch 33 → 34 taken 27182 times.
40258 for (auto it = m_byId.begin(); it != m_byId.end(); ++it) {
186 13076 auto &consumers = it->consumers;
187
1/1
✓ Branch 5 → 6 taken 13076 times.
13076 consumers.removeIf([purpose, consumerId](const BodyConsumer &consumer) {
188
2/2
✓ Branch 2 → 3 taken 11029 times.
✓ Branch 2 → 8 taken 1030 times.
23088 return consumer.purpose == purpose &&
189
4/4
✓ Branch 4 → 5 taken 16 times.
✓ Branch 4 → 7 taken 11013 times.
✓ Branch 6 → 7 taken 12 times.
✓ Branch 6 → 8 taken 4 times.
23088 (!consumerId || consumer.consumerId == *consumerId);
190 });
191
2/2
✓ Branch 7 → 8 taken 11045 times.
✓ Branch 7 → 9 taken 2031 times.
13076 if (it->dispatched)
192 11045 continue;
193
2/2
✓ Branch 10 → 11 taken 1002 times.
✓ Branch 10 → 14 taken 1029 times.
2031 if (consumers.isEmpty()) {
194
1/1
✓ Branch 12 → 13 taken 1002 times.
1002 emptyRequests.append(it.key());
195 1002 continue;
196 }
197
1/1
✓ Branch 16 → 17 taken 1029 times.
1029 const bool hasDemand = std::any_of(
198 1029 consumers.cbegin(), consumers.cend(), [](const BodyConsumer &consumer) {
199 1029 return consumer.purpose != BodyPurpose::Prefetch;
200 });
201
7/7
✓ Branch 17 → 18 taken 26 times.
✓ Branch 17 → 22 taken 1003 times.
✓ Branch 19 → 20 taken 26 times.
✓ Branch 20 → 21 taken 2 times.
✓ Branch 20 → 22 taken 24 times.
✓ Branch 23 → 24 taken 2 times.
✓ Branch 23 → 30 taken 1027 times.
1029 if (!hasDemand && m_demandQueue.removeAll(it.key()) > 0) {
202
3/3
✓ Branch 24 → 25 taken 2 times.
✓ Branch 25 → 26 taken 1 time.
✓ Branch 25 → 28 taken 1 time.
2 if (queuedPrefetchCount() < MaximumQueuedPrefetch)
203
1/1
✓ Branch 27 → 30 taken 1 time.
1 m_prefetchQueue.enqueue(it.key());
204 else
205
1/1
✓ Branch 29 → 30 taken 1 time.
1 emptyRequests.append(it.key());
206 }
207 }
208
209
4/4
✓ Branch 34 → 35 taken 27182 times.
✓ Branch 35 → 36 taken 27182 times.
✓ Branch 51 → 37 taken 1003 times.
✓ Branch 51 → 52 taken 27182 times.
28185 for (quint64 requestId : emptyRequests) {
210 const bool wasPrefetch =
211 1003 m_byId.value(requestId).request.purpose == BodyPurpose::Prefetch;
212
2/2
✓ Branch 40 → 41 taken 2 times.
✓ Branch 40 → 42 taken 1001 times.
1003 if (wasPrefetch)
213 2 ++m_prefetchStats.cancelled;
214 1003 const MailId mailId = m_byId.value(requestId).request.mailId;
215
1/1
✓ Branch 45 → 46 taken 1003 times.
1003 m_byId.remove(requestId);
216
1/1
✓ Branch 46 → 47 taken 1003 times.
1003 m_byMail.remove(mailId);
217
1/1
✓ Branch 47 → 48 taken 1003 times.
1003 removeQueuedRequest(requestId);
218 1003 }
219 27182 }
220
221 19 bool BodyRequestRegistry::contains(const MailId &mailId) const {
222 19 return m_byMail.contains(mailId);
223 }
224
225 std::optional<MailId>
226 67 BodyRequestRegistry::mailIdForRequest(quint64 requestId) const {
227 67 const auto it = m_byId.constFind(requestId);
228
2/2
✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 7 taken 62 times.
67 if (it == m_byId.cend())
229 5 return std::nullopt;
230 62 return it->request.mailId;
231 }
232
233 12 bool BodyRequestRegistry::hasDemandConsumer(quint64 requestId) const {
234 12 const auto it = m_byId.constFind(requestId);
235
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 12 times.
12 if (it == m_byId.cend()) return false;
236
1/1
✓ Branch 11 → 12 taken 12 times.
12 return std::any_of(it->consumers.cbegin(), it->consumers.cend(),
237 12 [](const BodyConsumer &consumer) {
238 12 return consumer.purpose != BodyPurpose::Prefetch;
239 12 });
240 }
241
242 50 qsizetype BodyRequestRegistry::queuedPrefetchCount() const {
243 50 return std::count_if(m_prefetchQueue.cbegin(), m_prefetchQueue.cend(),
244 85 [this](quint64 requestId) {
245 85 const auto it = m_byId.constFind(requestId);
246
2/4
✓ Branch 5 → 6 taken 85 times.
✗ Branch 5 → 9 not taken.
✓ Branch 7 → 8 taken 85 times.
✗ Branch 7 → 9 not taken.
85 return it != m_byId.cend() && !it->dispatched;
247 50 });
248 }
249
250 21047 void BodyRequestRegistry::removeQueuedRequest(quint64 requestId) {
251 21047 m_demandQueue.removeAll(requestId);
252 21047 m_prefetchQueue.removeAll(requestId);
253 21047 }
254