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: 99.0% 191 / 0 / 193
Functions: 100.0% 33 / 0 / 33
Branches: 90.4% 206 / 0 / 228

performance/FolderPerformanceTracker.cpp
Line Branch Exec Source
1 #include "performance/FolderPerformanceTracker.h"
2
3 #include <QApplication>
4 #include <QEvent>
5 #include <QWidget>
6
7 #include <algorithm>
8
9 namespace MailJD::Performance {
10
11 namespace {
12
13 constexpr auto CachedMetric = "folder.input_to_cached_list_painted.v1";
14 constexpr auto AuthoritativeMetric = "folder.input_to_authoritative_ready.v1";
15
16 } // namespace
17
18 2723 FolderPerformanceTracker &FolderPerformanceTracker::instance() {
19
4/7
✓ Branch 2 → 3 taken 21 times.
✓ Branch 2 → 8 taken 2702 times.
✓ Branch 4 → 5 taken 21 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 21 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
2723 static FolderPerformanceTracker tracker;
20 2723 return tracker;
21 }
22
23 21 FolderPerformanceTracker::FolderPerformanceTracker(QObject *parent)
24 21 : QObject(parent) {}
25
26 13 void FolderPerformanceTracker::ensureEventFilterInstalled() {
27
5/6
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 6 taken 12 times.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 6 not taken.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 11 taken 12 times.
13 if (!m_eventFilterInstalled && qApp) {
28 1 qApp->installEventFilter(this);
29 1 m_eventFilterInstalled = true;
30 }
31 13 }
32
33 787 bool FolderPerformanceTracker::isActive() const {
34
4/4
✓ Branch 2 → 3 taken 787 times.
✓ Branch 3 → 4 taken 787 times.
✓ Branch 4 → 5 taken 17 times.
✓ Branch 4 → 13 taken 770 times.
821 return PerformanceTrace::instance().isEnabled() &&
35
4/7
✓ Branch 5 → 6 taken 17 times.
✓ Branch 6 → 7 taken 17 times.
✓ Branch 10 → 11 taken 17 times.
✓ Branch 11 → 12 taken 17 times.
✗ Branch 11 → 13 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 32 not taken.
821 PerformanceTrace::instance().selectedScenario().startsWith(
36
6/10
✓ Branch 14 → 15 taken 17 times.
✓ Branch 14 → 16 taken 770 times.
✓ Branch 16 → 17 taken 17 times.
✓ Branch 16 → 18 taken 770 times.
✓ Branch 18 → 19 taken 17 times.
✓ Branch 18 → 20 taken 770 times.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 24 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 28 not taken.
1591 QStringLiteral("FOLDER."));
37 }
38
39 7 void FolderPerformanceTracker::watchViewport(QWidget *viewport) {
40 7 m_viewport = viewport;
41
2/2
✓ Branch 4 → 5 taken 6 times.
✓ Branch 4 → 6 taken 1 time.
7 if (isActive())
42 6 ensureEventFilterInstalled();
43 7 }
44
45 7 void FolderPerformanceTracker::reset() {
46 7 m_folderPath.clear();
47 7 m_generation = 0;
48 7 m_folderId = -1;
49 7 m_cachedRows = -1;
50 7 m_authoritativeRows = -1;
51 7 m_cachedPaintPending = false;
52 7 m_authoritativePaintPending = false;
53 7 m_perceived = {};
54 7 m_authoritative = {};
55 7 }
56
57 769 void FolderPerformanceTracker::beginSwitch(const QString &folderPath,
58 quint64 generation) {
59
8/8
✓ Branch 3 → 4 taken 9 times.
✓ Branch 3 → 7 taken 760 times.
✓ Branch 5 → 6 taken 8 times.
✓ Branch 5 → 7 taken 1 time.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 7 times.
✓ Branch 9 → 10 taken 762 times.
✓ Branch 9 → 11 taken 7 times.
769 if (!isActive() || folderPath.isEmpty() || generation == 0)
60 762 return;
61 7 ensureEventFilterInstalled();
62
5/6
✓ Branch 13 → 14 taken 6 times.
✓ Branch 13 → 16 taken 1 time.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 6 times.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 21 taken 6 times.
7 if (m_perceived.isValid() || m_authoritative.isValid()) {
63 1 ++m_discardedGenerations;
64 1 finishPerceived(Outcome::Cancelled);
65 1 finishAuthoritative(Outcome::Cancelled);
66 }
67 7 reset();
68
2/2
✓ Branch 22 → 23 taken 7 times.
✓ Branch 23 → 24 taken 7 times.
7 m_scenario = PerformanceTrace::instance().selectedScenario();
69 7 m_folderPath = folderPath;
70 7 m_generation = generation;
71 7 const qint64 startedNs = PerformanceTrace::monotonicNowNs();
72
1/1
✓ Branch 28 → 29 taken 7 times.
14 m_perceived = PerformanceTrace::instance().startMetric(
73
2/2
✓ Branch 30 → 31 taken 7 times.
✓ Branch 31 → 32 taken 7 times.
14 m_scenario, QString::fromLatin1(CachedMetric), startedNs);
74
3/3
✓ Branch 38 → 39 taken 7 times.
✓ Branch 41 → 42 taken 1 time.
✓ Branch 41 → 55 taken 6 times.
14 if (m_scenario.contains(QStringLiteral(".offline."))) {
75 1 PerformanceTrace::instance().markProcessEvent(
76
1/1
✓ Branch 49 → 50 taken 1 time.
1 m_scenario,
77
1/1
✓ Branch 47 → 48 taken 1 time.
2 QString::fromLatin1(AuthoritativeMetric) +
78
1/1
✓ Branch 48 → 49 taken 1 time.
3 QStringLiteral(".inapplicable"));
79 } else {
80
1/1
✓ Branch 55 → 56 taken 6 times.
12 m_authoritative = PerformanceTrace::instance().startMetric(
81
2/2
✓ Branch 57 → 58 taken 6 times.
✓ Branch 58 → 59 taken 6 times.
12 m_scenario, QString::fromLatin1(AuthoritativeMetric), startedNs);
82 }
83
1/1
✓ Branch 66 → 67 taken 7 times.
14 m_perceived.startPhase(QStringLiteral("folder_lookup"));
84 }
85
86 43 bool FolderPerformanceTracker::generationMatches(quint64 generation) const {
87
3/4
✓ Branch 2 → 3 taken 43 times.
✗ Branch 2 → 5 not taken.
✓ Branch 3 → 4 taken 32 times.
✓ Branch 3 → 5 taken 11 times.
43 return generation > 0 && generation == m_generation;
88 }
89
90 767 void FolderPerformanceTracker::folderLookupFinished(qint64 folderId,
91 bool success) {
92
2/2
✓ Branch 3 → 4 taken 760 times.
✓ Branch 3 → 5 taken 7 times.
767 if (!m_perceived.isValid())
93 760 return;
94
1/1
✓ Branch 8 → 9 taken 7 times.
14 m_perceived.endPhase(QStringLiteral("folder_lookup"));
95
3/4
✓ Branch 11 → 12 taken 7 times.
✗ Branch 11 → 13 not taken.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 16 taken 6 times.
7 if (!success || folderId <= 0) {
96 1 finishPerceived(Outcome::Failed);
97 1 finishAuthoritative(Outcome::Failed);
98 1 return;
99 }
100 6 m_folderId = folderId;
101 }
102
103 764 void FolderPerformanceTracker::headerQueryStarted() {
104
2/2
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 11 taken 760 times.
764 if (m_perceived.isValid())
105
1/1
✓ Branch 7 → 8 taken 4 times.
8 m_perceived.startPhase(QStringLiteral("header_query"));
106 764 }
107
108 668 void FolderPerformanceTracker::labelsStarted() {
109
2/2
✓ Branch 3 → 4 taken 664 times.
✓ Branch 3 → 5 taken 4 times.
668 if (!m_perceived.isValid())
110 664 return;
111
1/1
✓ Branch 8 → 9 taken 4 times.
8 m_perceived.endPhase(QStringLiteral("header_query"));
112
1/1
✓ Branch 14 → 15 taken 4 times.
8 m_perceived.startPhase(QStringLiteral("label_query"));
113 }
114
115 669 void FolderPerformanceTracker::cacheQueriesFinished(int rowCount) {
116
2/2
✓ Branch 3 → 4 taken 664 times.
✓ Branch 3 → 5 taken 5 times.
669 if (!m_perceived.isValid())
117 664 return;
118
1/1
✓ Branch 8 → 9 taken 5 times.
10 m_perceived.endPhase(QStringLiteral("label_query"));
119 5 m_cachedRows = rowCount;
120 }
121
122 668 void FolderPerformanceTracker::modelUpdateStarted() {
123
2/2
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 11 taken 664 times.
668 if (m_perceived.isValid())
124
1/1
✓ Branch 7 → 8 taken 4 times.
8 m_perceived.startPhase(QStringLiteral("model_update"));
125 668 }
126
127 668 void FolderPerformanceTracker::modelUpdateFinished() {
128
2/2
✓ Branch 3 → 4 taken 664 times.
✓ Branch 3 → 5 taken 4 times.
668 if (!m_perceived.isValid())
129 664 return;
130
1/1
✓ Branch 8 → 9 taken 4 times.
8 m_perceived.endPhase(QStringLiteral("model_update"));
131 }
132
133 5 void FolderPerformanceTracker::proxyThreadRebuildStarted() {
134
2/2
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 11 taken 1 time.
5 if (m_perceived.isValid())
135
1/1
✓ Branch 7 → 8 taken 4 times.
8 m_perceived.startPhase(QStringLiteral("proxy_thread_rebuild"));
136 5 }
137
138 5 void FolderPerformanceTracker::proxyThreadRebuildFinished() {
139
2/2
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 11 taken 1 time.
5 if (m_perceived.isValid())
140
1/1
✓ Branch 7 → 8 taken 4 times.
8 m_perceived.endPhase(QStringLiteral("proxy_thread_rebuild"));
141 5 }
142
143 674 void FolderPerformanceTracker::cachedCommitted(qint64 folderId, int rowCount,
144 quint64 generation) {
145
2/2
✓ Branch 5 → 6 taken 7 times.
✓ Branch 5 → 8 taken 2 times.
683 if (!m_perceived.isValid() || !generationMatches(generation) ||
146
8/8
✓ Branch 3 → 4 taken 9 times.
✓ Branch 3 → 8 taken 665 times.
✓ Branch 6 → 7 taken 6 times.
✓ Branch 6 → 8 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 5 times.
✓ Branch 10 → 11 taken 669 times.
✓ Branch 10 → 12 taken 5 times.
683 folderId != m_folderId || rowCount != m_cachedRows) {
147 669 return;
148 }
149
1/1
✓ Branch 15 → 16 taken 5 times.
10 m_perceived.startPhase(QStringLiteral("list_paint"));
150 5 m_cachedPaintPending = true;
151
1/2
✓ Branch 19 → 20 taken 5 times.
✗ Branch 19 → 22 not taken.
5 if (m_viewport)
152 5 m_viewport->update();
153 }
154
155 666 void FolderPerformanceTracker::debounceStarted() {
156
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 11 taken 664 times.
666 if (m_authoritative.isValid())
157
1/1
✓ Branch 7 → 8 taken 2 times.
4 m_authoritative.startPhase(QStringLiteral("debounce"));
158 666 }
159
160 591 void FolderPerformanceTracker::debounceFinished() {
161
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 11 taken 589 times.
591 if (m_authoritative.isValid())
162
1/1
✓ Branch 7 → 8 taken 2 times.
4 m_authoritative.endPhase(QStringLiteral("debounce"));
163 591 }
164
165 591 void FolderPerformanceTracker::idleExitStarted() {
166
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 11 taken 589 times.
591 if (m_authoritative.isValid())
167
1/1
✓ Branch 7 → 8 taken 2 times.
4 m_authoritative.startPhase(QStringLiteral("idle_exit"));
168 591 }
169
170 591 void FolderPerformanceTracker::selectDispatched() {
171
2/2
✓ Branch 3 → 4 taken 589 times.
✓ Branch 3 → 5 taken 2 times.
591 if (!m_authoritative.isValid())
172 589 return;
173
1/1
✓ Branch 8 → 9 taken 2 times.
4 m_authoritative.endPhase(QStringLiteral("idle_exit"));
174
1/1
✓ Branch 14 → 15 taken 2 times.
4 m_authoritative.startPhase(QStringLiteral("select"));
175
1/1
✓ Branch 20 → 21 taken 2 times.
4 m_authoritative.startPhase(QStringLiteral("flags_fetch"));
176 }
177
178 17 void FolderPerformanceTracker::selected(qint64 folderId, quint64 generation) {
179
6/6
✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 7 taken 12 times.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 1 time.
✓ Branch 9 → 10 taken 14 times.
✓ Branch 9 → 11 taken 3 times.
21 if (!m_authoritative.isValid() || !generationMatches(generation) ||
180
2/2
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 3 times.
4 folderId != m_folderId)
181 14 return;
182
1/1
✓ Branch 14 → 15 taken 3 times.
6 m_authoritative.endPhase(QStringLiteral("select"));
183 }
184
185 9 void FolderPerformanceTracker::flagsStarted(quint64 generation) {
186
6/6
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 7 taken 6 times.
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 7 taken 1 time.
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 16 taken 7 times.
9 if (m_authoritative.isValid() && generationMatches(generation))
187
1/1
✓ Branch 12 → 13 taken 2 times.
4 m_authoritative.startPhase(QStringLiteral("flags_fetch"));
188 9 }
189
190 22 void FolderPerformanceTracker::flagsFinished(quint64 generation,
191 bool headerFetchFollows) {
192
6/6
✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 6 taken 17 times.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 4 times.
✓ Branch 8 → 9 taken 18 times.
✓ Branch 8 → 10 taken 4 times.
22 if (!m_authoritative.isValid() || !generationMatches(generation))
193 18 return;
194
1/1
✓ Branch 13 → 14 taken 4 times.
8 m_authoritative.endPhase(QStringLiteral("flags_fetch"));
195
2/2
✓ Branch 16 → 17 taken 2 times.
✓ Branch 16 → 18 taken 2 times.
4 if (headerFetchFollows)
196 2 headerFetchStarted(generation);
197 }
198
199 4 void FolderPerformanceTracker::headerFetchStarted(quint64 generation) {
200
6/6
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 7 taken 1 time.
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 7 taken 1 time.
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 16 taken 2 times.
4 if (m_authoritative.isValid() && generationMatches(generation))
201
1/1
✓ Branch 12 → 13 taken 2 times.
4 m_authoritative.startPhase(QStringLiteral("header_fetch"));
202 4 }
203
204 21 void FolderPerformanceTracker::cacheIndexStarted(quint64 generation) {
205
6/6
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 7 taken 17 times.
✓ Branch 5 → 6 taken 3 times.
✓ Branch 5 → 7 taken 1 time.
✓ Branch 8 → 9 taken 3 times.
✓ Branch 8 → 16 taken 18 times.
21 if (m_authoritative.isValid() && generationMatches(generation))
206
1/1
✓ Branch 12 → 13 taken 3 times.
6 m_authoritative.startPhase(QStringLiteral("cache_index"));
207 21 }
208
209 20 void FolderPerformanceTracker::cacheIndexFinished(quint64 generation, bool success) {
210
6/6
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 7 taken 16 times.
✓ Branch 5 → 6 taken 3 times.
✓ Branch 5 → 7 taken 1 time.
✓ Branch 8 → 9 taken 3 times.
✓ Branch 8 → 17 taken 17 times.
20 if (m_authoritative.isValid() && generationMatches(generation)) {
211
1/1
✓ Branch 12 → 13 taken 3 times.
6 m_authoritative.endPhase(QStringLiteral("cache_index"));
212
2/2
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 17 taken 2 times.
3 if (!success) finishAuthoritative(Outcome::Failed);
213 }
214 20 }
215
216 10 void FolderPerformanceTracker::headerFetchFinished(quint64 generation) {
217
6/6
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 7 taken 7 times.
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 7 taken 1 time.
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 16 taken 8 times.
10 if (m_authoritative.isValid() && generationMatches(generation))
218
1/1
✓ Branch 12 → 13 taken 2 times.
4 m_authoritative.endPhase(QStringLiteral("header_fetch"));
219 10 }
220
221 12 void FolderPerformanceTracker::pushRestarted(qint64 folderId, int rowCount,
222 quint64 generation) {
223
2/2
✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 8 taken 2 times.
19 if (!m_authoritative.isValid() || !generationMatches(generation) ||
224
8/8
✓ Branch 3 → 4 taken 7 times.
✓ Branch 3 → 8 taken 5 times.
✓ Branch 6 → 7 taken 4 times.
✓ Branch 6 → 8 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 3 times.
✓ Branch 10 → 11 taken 9 times.
✓ Branch 10 → 12 taken 3 times.
19 folderId != m_folderId || rowCount < 0)
225 9 return;
226 3 m_authoritativeRows = rowCount;
227
1/1
✓ Branch 15 → 16 taken 3 times.
6 m_authoritative.startPhase(QStringLiteral("push_restart"));
228
1/1
✓ Branch 21 → 22 taken 3 times.
6 m_authoritative.endPhase(QStringLiteral("push_restart"));
229
1/1
✓ Branch 27 → 28 taken 3 times.
6 m_authoritative.startPhase(QStringLiteral("list_paint"));
230 3 m_authoritativePaintPending = true;
231
1/2
✓ Branch 31 → 32 taken 3 times.
✗ Branch 31 → 34 not taken.
3 if (m_viewport)
232 3 m_viewport->update();
233 }
234
235 15 void FolderPerformanceTracker::staleGenerationDiscarded(quint64 generation) {
236
2/2
✓ Branch 2 → 3 taken 4 times.
✓ Branch 2 → 4 taken 11 times.
15 if (generation == m_generation)
237 4 return;
238 11 ++m_discardedGenerations;
239
2/2
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 17 taken 9 times.
11 if (isActive()) {
240
1/1
✓ Branch 12 → 13 taken 2 times.
4 PerformanceTrace::instance().markProcessEvent(
241
2/2
✓ Branch 10 → 11 taken 2 times.
✓ Branch 11 → 12 taken 2 times.
4 PerformanceTrace::instance().selectedScenario(),
242 4 QStringLiteral("stale_generation_discarded"), -1, 0,
243 2 static_cast<qint64>(m_discardedGenerations));
244 }
245 }
246
247 7 void FolderPerformanceTracker::finishPerceived(Outcome outcome) {
248
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 7 times.
7 if (!m_perceived.isValid())
249 ✗ return;
250
1/1
✓ Branch 6 → 7 taken 7 times.
7 m_perceived.finish(outcome, std::max(0, m_cachedRows));
251 7 m_perceived = {};
252 7 m_cachedPaintPending = false;
253 }
254
255 6 void FolderPerformanceTracker::finishAuthoritative(Outcome outcome) {
256
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 6 times.
6 if (!m_authoritative.isValid())
257 ✗ return;
258
1/1
✓ Branch 6 → 7 taken 6 times.
6 m_authoritative.finish(outcome, std::max(0, m_authoritativeRows));
259 6 m_authoritative = {};
260 6 m_authoritativePaintPending = false;
261 }
262
263 33 bool FolderPerformanceTracker::eventFilter(QObject *watched, QEvent *event) {
264
6/6
✓ Branch 3 → 4 taken 23 times.
✓ Branch 3 → 7 taken 10 times.
✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 7 taken 18 times.
✓ Branch 8 → 9 taken 5 times.
✓ Branch 8 → 35 taken 28 times.
33 if (watched == m_viewport && event->type() == QEvent::Paint) {
265
3/6
✓ Branch 9 → 10 taken 5 times.
✗ Branch 9 → 13 not taken.
✓ Branch 11 → 12 taken 5 times.
✗ Branch 11 → 13 not taken.
✓ Branch 14 → 15 taken 5 times.
✗ Branch 14 → 22 not taken.
5 if (m_cachedPaintPending && m_perceived.isValid()) {
266
1/1
✓ Branch 18 → 19 taken 5 times.
10 m_perceived.endPhase(QStringLiteral("list_paint"));
267 5 finishPerceived(Outcome::Success);
268 }
269
5/6
✓ Branch 22 → 23 taken 3 times.
✓ Branch 22 → 26 taken 2 times.
✓ Branch 24 → 25 taken 3 times.
✗ Branch 24 → 26 not taken.
✓ Branch 27 → 28 taken 3 times.
✓ Branch 27 → 35 taken 2 times.
5 if (m_authoritativePaintPending && m_authoritative.isValid()) {
270
1/1
✓ Branch 31 → 32 taken 3 times.
6 m_authoritative.endPhase(QStringLiteral("list_paint"));
271 3 finishAuthoritative(Outcome::Success);
272 }
273 }
274 33 return QObject::eventFilter(watched, event);
275 }
276
277 } // namespace MailJD::Performance
278