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.3% 172 / 0 / 175
Functions: 100.0% 25 / 0 / 25
Branches: 89.2% 206 / 0 / 231

performance/MutationPerformanceTracker.cpp
Line Branch Exec Source
1 #include "performance/MutationPerformanceTracker.h"
2
3 #include <QApplication>
4 #include <QEvent>
5 #include <QWidget>
6
7 #include <algorithm>
8
9 namespace MailJD::Performance {
10
11 namespace {
12 constexpr auto PerceivedMetric = "mutation.input_to_perceived_paint.v1";
13 constexpr auto AuthoritativeMetric =
14 "mutation.input_to_authoritative_paint.v1";
15 }
16
17 597 MutationPerformanceTracker &MutationPerformanceTracker::instance() {
18
4/7
✓ Branch 2 → 3 taken 13 times.
✓ Branch 2 → 8 taken 584 times.
✓ Branch 4 → 5 taken 13 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 13 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
597 static MutationPerformanceTracker tracker;
19 597 return tracker;
20 }
21
22 13 MutationPerformanceTracker::MutationPerformanceTracker(QObject *parent)
23 13 : QObject(parent) {}
24
25 12 void MutationPerformanceTracker::ensureEventFilterInstalled() {
26
5/6
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 6 taken 11 times.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 6 not taken.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 11 taken 11 times.
12 if (!m_eventFilterInstalled && qApp) {
27 1 qApp->installEventFilter(this);
28 1 m_eventFilterInstalled = true;
29 }
30 12 }
31
32 365 bool MutationPerformanceTracker::isActive() const {
33
4/4
✓ Branch 2 → 3 taken 365 times.
✓ Branch 3 → 4 taken 365 times.
✓ Branch 4 → 5 taken 12 times.
✓ Branch 4 → 13 taken 353 times.
389 return PerformanceTrace::instance().isEnabled() &&
34
4/7
✓ Branch 5 → 6 taken 12 times.
✓ Branch 6 → 7 taken 12 times.
✓ Branch 10 → 11 taken 12 times.
✓ Branch 11 → 12 taken 12 times.
✗ Branch 11 → 13 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 32 not taken.
389 PerformanceTrace::instance().selectedScenario().startsWith(
35
6/10
✓ Branch 14 → 15 taken 12 times.
✓ Branch 14 → 16 taken 353 times.
✓ Branch 16 → 17 taken 12 times.
✓ Branch 16 → 18 taken 353 times.
✓ Branch 18 → 19 taken 12 times.
✓ Branch 18 → 20 taken 353 times.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 24 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 28 not taken.
742 QStringLiteral("MUTATION."));
36 }
37
38 4 void MutationPerformanceTracker::watchViewport(QWidget *viewport) {
39 4 m_viewport = viewport;
40
2/2
✓ Branch 4 → 5 taken 3 times.
✓ Branch 4 → 6 taken 1 time.
4 if (isActive())
41 3 ensureEventFilterInstalled();
42 4 }
43
44 361 void MutationPerformanceTracker::beginMutation(
45 int itemCount, const QStringList &operations) {
46
3/3
✓ Branch 2 → 3 taken 361 times.
✓ Branch 3 → 4 taken 352 times.
✓ Branch 3 → 5 taken 9 times.
361 if (!isActive())
47 356 return;
48
1/1
✓ Branch 5 → 6 taken 9 times.
9 ensureEventFilterInstalled();
49
2/2
✓ Branch 6 → 7 taken 9 times.
✓ Branch 7 → 8 taken 9 times.
9 const QString selected = PerformanceTrace::instance().selectedScenario();
50 const bool operationMatches =
51
1/1
✓ Branch 10 → 11 taken 9 times.
9 std::any_of(operations.cbegin(), operations.cend(),
52 8 [&selected](const QString &operation) {
53
2/2
✓ Branch 8 → 9 taken 8 times.
✓ Branch 10 → 11 taken 8 times.
32 return selected.contains(QStringLiteral(".") + operation +
54
1/1
✓ Branch 9 → 10 taken 8 times.
32 QStringLiteral("."));
55 });
56
2/2
✓ Branch 11 → 12 taken 2 times.
✓ Branch 11 → 13 taken 7 times.
9 if (!operationMatches)
57 2 return;
58
7/8
✓ Branch 13 → 14 taken 7 times.
✓ Branch 14 → 15 taken 5 times.
✓ Branch 14 → 17 taken 2 times.
✓ Branch 15 → 16 taken 5 times.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 5 times.
✓ Branch 19 → 20 taken 2 times.
✓ Branch 19 → 26 taken 5 times.
7 if (m_perceived.isValid() || m_authoritative.isValid()) {
59
2/2
✓ Branch 21 → 22 taken 1 time.
✓ Branch 21 → 25 taken 1 time.
2 if (m_tokens.isEmpty())
60 1 m_itemCount = std::max(m_itemCount, std::max(0, itemCount));
61 2 return;
62 }
63 5 m_scenario = selected;
64 5 m_itemCount = std::max(0, itemCount);
65 5 m_tokens.clear();
66 5 m_terminalTokens.clear();
67 5 m_anyFailure = false;
68 5 m_perceivedPaintPending = false;
69 5 m_authoritativePaintPending = false;
70
1/1
✓ Branch 30 → 31 taken 5 times.
5 const qint64 startedNs = PerformanceTrace::monotonicNowNs();
71
1/1
✓ Branch 31 → 32 taken 5 times.
10 m_perceived = PerformanceTrace::instance().startMetric(
72
2/2
✓ Branch 33 → 34 taken 5 times.
✓ Branch 34 → 35 taken 5 times.
10 m_scenario, QString::fromLatin1(PerceivedMetric), startedNs);
73
3/3
✓ Branch 41 → 42 taken 5 times.
✓ Branch 44 → 45 taken 1 time.
✓ Branch 44 → 58 taken 4 times.
10 if (m_scenario.contains(QStringLiteral(".offline."))) {
74
1/1
✓ Branch 45 → 46 taken 1 time.
1 PerformanceTrace::instance().markProcessEvent(
75
2/2
✓ Branch 50 → 51 taken 1 time.
✓ Branch 52 → 53 taken 1 time.
2 m_scenario, QString::fromLatin1(AuthoritativeMetric) +
76
1/1
✓ Branch 51 → 52 taken 1 time.
3 QStringLiteral(".inapplicable"));
77 } else {
78
1/1
✓ Branch 58 → 59 taken 4 times.
8 m_authoritative = PerformanceTrace::instance().startMetric(
79
2/2
✓ Branch 60 → 61 taken 4 times.
✓ Branch 61 → 62 taken 4 times.
8 m_scenario, QString::fromLatin1(AuthoritativeMetric), startedNs);
80 }
81 9 }
82
83 148 void MutationPerformanceTracker::journalStarted() {
84
2/2
✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 11 taken 143 times.
148 if (m_perceived.isValid())
85
1/1
✓ Branch 7 → 8 taken 5 times.
10 m_perceived.startPhase(QStringLiteral("journal"));
86
2/2
✓ Branch 12 → 13 taken 4 times.
✓ Branch 12 → 20 taken 144 times.
148 if (m_authoritative.isValid())
87
1/1
✓ Branch 16 → 17 taken 4 times.
8 m_authoritative.startPhase(QStringLiteral("journal"));
88 148 }
89
90 147 void MutationPerformanceTracker::journalFinished(bool success, qint64 token) {
91
2/2
✓ Branch 3 → 4 taken 139 times.
✓ Branch 3 → 5 taken 8 times.
147 if (!m_perceived.isValid())
92 139 return;
93
1/1
✓ Branch 8 → 9 taken 8 times.
16 m_perceived.endPhase(QStringLiteral("journal"));
94
2/2
✓ Branch 12 → 13 taken 7 times.
✓ Branch 12 → 20 taken 1 time.
8 if (m_authoritative.isValid())
95
1/1
✓ Branch 16 → 17 taken 7 times.
14 m_authoritative.endPhase(QStringLiteral("journal"));
96
4/4
✓ Branch 20 → 21 taken 7 times.
✓ Branch 20 → 22 taken 1 time.
✓ Branch 21 → 22 taken 1 time.
✓ Branch 21 → 25 taken 6 times.
8 if (!success || token <= 0) {
97 2 finishPerceived(Outcome::Failed);
98 2 finishAuthoritative(Outcome::Failed);
99 2 return;
100 }
101 6 const bool firstToken = m_tokens.isEmpty();
102
1/1
✓ Branch 26 → 27 taken 6 times.
6 m_tokens.insert(token);
103
6/6
✓ Branch 27 → 28 taken 3 times.
✓ Branch 27 → 31 taken 3 times.
✓ Branch 29 → 30 taken 2 times.
✓ Branch 29 → 31 taken 1 time.
✓ Branch 32 → 33 taken 2 times.
✓ Branch 32 → 40 taken 4 times.
6 if (firstToken && m_authoritative.isValid())
104
1/1
✓ Branch 36 → 37 taken 2 times.
4 m_authoritative.startPhase(QStringLiteral("queue_wait"));
105 }
106
107 145 void MutationPerformanceTracker::cacheStarted() {
108
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 11 taken 143 times.
145 if (m_perceived.isValid())
109
1/1
✓ Branch 7 → 8 taken 2 times.
4 m_perceived.startPhase(QStringLiteral("cache"));
110
2/2
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 20 taken 144 times.
145 if (m_authoritative.isValid())
111
1/1
✓ Branch 16 → 17 taken 1 time.
2 m_authoritative.startPhase(QStringLiteral("cache"));
112 145 }
113
114 145 void MutationPerformanceTracker::cacheFinished() {
115
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 11 taken 143 times.
145 if (m_perceived.isValid())
116
1/1
✓ Branch 7 → 8 taken 2 times.
4 m_perceived.endPhase(QStringLiteral("cache"));
117
2/2
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 20 taken 144 times.
145 if (m_authoritative.isValid())
118
1/1
✓ Branch 16 → 17 taken 1 time.
2 m_authoritative.endPhase(QStringLiteral("cache"));
119 145 }
120
121 340 void MutationPerformanceTracker::modelBadgeStarted() {
122
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 11 taken 338 times.
340 if (m_perceived.isValid())
123
1/1
✓ Branch 7 → 8 taken 2 times.
4 m_perceived.startPhase(QStringLiteral("model_badge"));
124
2/2
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 20 taken 339 times.
340 if (m_authoritative.isValid())
125
1/1
✓ Branch 16 → 17 taken 1 time.
2 m_authoritative.startPhase(QStringLiteral("model_badge"));
126 340 }
127
128 340 void MutationPerformanceTracker::modelBadgeFinished() {
129
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 11 taken 338 times.
340 if (m_perceived.isValid())
130
1/1
✓ Branch 7 → 8 taken 2 times.
4 m_perceived.endPhase(QStringLiteral("model_badge"));
131
2/2
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 20 taken 339 times.
340 if (m_authoritative.isValid())
132
1/1
✓ Branch 16 → 17 taken 1 time.
2 m_authoritative.endPhase(QStringLiteral("model_badge"));
133 340 }
134
135 343 void MutationPerformanceTracker::perceivedCommitted() {
136
6/6
✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 7 taken 338 times.
✓ Branch 4 → 5 taken 3 times.
✓ Branch 4 → 7 taken 2 times.
✓ Branch 9 → 10 taken 340 times.
✓ Branch 9 → 11 taken 3 times.
346 if (!m_perceived.isValid() || m_perceivedPaintPending ||
137
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 3 times.
3 m_tokens.size() < m_itemCount)
138 340 return;
139
1/1
✓ Branch 14 → 15 taken 3 times.
6 m_perceived.startPhase(QStringLiteral("paint"));
140
2/2
✓ Branch 18 → 19 taken 2 times.
✓ Branch 18 → 26 taken 1 time.
3 if (m_authoritative.isValid())
141
1/1
✓ Branch 22 → 23 taken 2 times.
4 m_authoritative.startPhase(QStringLiteral("paint"));
142 3 m_perceivedPaintPending = true;
143
1/2
✓ Branch 27 → 28 taken 3 times.
✗ Branch 27 → 30 not taken.
3 if (m_viewport)
144 3 m_viewport->update();
145 }
146
147 33 void MutationPerformanceTracker::mutationDispatched(qint64 token) {
148
6/6
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 6 taken 27 times.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 5 times.
✓ Branch 8 → 9 taken 28 times.
✓ Branch 8 → 10 taken 5 times.
33 if (!m_authoritative.isValid() || !m_tokens.contains(token))
149 28 return;
150
1/1
✓ Branch 13 → 14 taken 5 times.
10 m_authoritative.endPhase(QStringLiteral("queue_wait"));
151
1/1
✓ Branch 19 → 20 taken 5 times.
10 m_authoritative.startPhase(QStringLiteral("protocol"));
152 }
153
154 49 void MutationPerformanceTracker::protocolFinished(qint64 token) {
155
6/6
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 7 taken 43 times.
✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 7 taken 1 time.
✓ Branch 8 → 9 taken 5 times.
✓ Branch 8 → 16 taken 44 times.
49 if (m_authoritative.isValid() && m_tokens.contains(token))
156
1/1
✓ Branch 12 → 13 taken 5 times.
10 m_authoritative.endPhase(QStringLiteral("protocol"));
157 49 }
158
159 46 void MutationPerformanceTracker::reconciliationStarted(qint64 token) {
160
6/6
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 7 taken 40 times.
✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 7 taken 1 time.
✓ Branch 8 → 9 taken 5 times.
✓ Branch 8 → 16 taken 41 times.
46 if (m_authoritative.isValid() && m_tokens.contains(token))
161
1/1
✓ Branch 12 → 13 taken 5 times.
10 m_authoritative.startPhase(QStringLiteral("reconcile"));
162 46 }
163
164 5 void MutationPerformanceTracker::reconciliationDeferred(qint64 token) {
165
6/6
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 6 taken 3 times.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 1 time.
✓ Branch 8 → 9 taken 4 times.
✓ Branch 8 → 10 taken 1 time.
5 if (!m_authoritative.isValid() || !m_tokens.contains(token))
166 4 return;
167
1/1
✓ Branch 13 → 14 taken 1 time.
2 m_authoritative.endPhase(QStringLiteral("reconcile"));
168
1/1
✓ Branch 19 → 20 taken 1 time.
2 m_authoritative.startPhase(QStringLiteral("queue_wait"));
169 }
170
171 64 void MutationPerformanceTracker::reconciliationFinished(qint64 token,
172 bool success) {
173
6/6
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 6 taken 58 times.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 5 times.
✓ Branch 8 → 9 taken 59 times.
✓ Branch 8 → 10 taken 5 times.
64 if (!m_authoritative.isValid() || !m_tokens.contains(token))
174 59 return;
175
1/1
✓ Branch 13 → 14 taken 5 times.
10 m_authoritative.endPhase(QStringLiteral("reconcile"));
176
1/1
✓ Branch 16 → 17 taken 5 times.
5 m_terminalTokens.insert(token);
177
4/4
✓ Branch 17 → 18 taken 3 times.
✓ Branch 17 → 19 taken 2 times.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 20 taken 2 times.
5 m_anyFailure = m_anyFailure || !success;
178
2/2
✓ Branch 23 → 24 taken 3 times.
✓ Branch 23 → 31 taken 2 times.
5 if (m_terminalTokens.size() < m_tokens.size())
179
1/1
✓ Branch 27 → 28 taken 3 times.
6 m_authoritative.startPhase(QStringLiteral("queue_wait"));
180 5 maybePrepareAuthoritativePaint();
181 }
182
183 6 void MutationPerformanceTracker::mutationQueuedOffline(qint64 token) {
184
2/2
✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 5 taken 1 time.
6 if (!m_tokens.contains(token))
185 5 return;
186
1/2
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 9 not taken.
1 if (!m_authoritative.isValid())
187
1/1
✓ Branch 7 → 8 taken 1 time.
1 m_terminalTokens.insert(token);
188 else
189 ✗ m_authoritative.startPhase(QStringLiteral("queue_wait"));
190 }
191
192 3 void MutationPerformanceTracker::reconciliationSuperseded(qint64 token) {
193 // Moving a message retires its source UID; it does not prove that an older
194 // flag request was read back. Do not turn that cancelled measurement green.
195
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 3 times.
3 if (m_tokens.contains(token)) finishAuthoritative(Outcome::Cancelled);
196 3 }
197
198 5 void MutationPerformanceTracker::maybePrepareAuthoritativePaint() {
199
3/4
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 10 not taken.
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 10 taken 3 times.
15 if (!m_authoritative.isValid() || m_tokens.isEmpty() ||
200
3/4
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 10 not taken.
✓ Branch 12 → 13 taken 3 times.
✓ Branch 12 → 14 taken 2 times.
15 m_terminalTokens.size() != m_tokens.size() ||
201
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 2 times.
2 m_authoritativePaintPending)
202 3 return;
203
1/1
✓ Branch 17 → 18 taken 2 times.
4 m_authoritative.startPhase(QStringLiteral("push_restart"));
204
1/1
✓ Branch 23 → 24 taken 2 times.
4 m_authoritative.endPhase(QStringLiteral("push_restart"));
205
1/1
✓ Branch 29 → 30 taken 2 times.
4 m_authoritative.startPhase(QStringLiteral("final_paint"));
206 2 m_authoritativePaintPending = true;
207
1/2
✓ Branch 33 → 34 taken 2 times.
✗ Branch 33 → 36 not taken.
2 if (m_viewport)
208 2 m_viewport->update();
209 }
210
211 5 void MutationPerformanceTracker::finishPerceived(Outcome outcome) {
212
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 5 times.
5 if (!m_perceived.isValid())
213 ✗ return;
214 5 m_perceived.finish(outcome, m_itemCount);
215 5 m_perceived = {};
216 5 m_perceivedPaintPending = false;
217 }
218
219 4 void MutationPerformanceTracker::finishAuthoritative(Outcome outcome) {
220
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 4 times.
4 if (!m_authoritative.isValid())
221 ✗ return;
222 4 m_authoritative.finish(outcome, m_itemCount);
223 4 m_authoritative = {};
224 4 m_authoritativePaintPending = false;
225 }
226
227 20 bool MutationPerformanceTracker::eventFilter(QObject *watched, QEvent *event) {
228
6/6
✓ Branch 3 → 4 taken 13 times.
✓ Branch 3 → 7 taken 7 times.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 9 times.
✓ Branch 8 → 9 taken 4 times.
✓ Branch 8 → 47 taken 16 times.
20 if (watched == m_viewport && event->type() == QEvent::Paint) {
229
5/6
✓ Branch 9 → 10 taken 3 times.
✓ Branch 9 → 13 taken 1 time.
✓ Branch 11 → 12 taken 3 times.
✗ Branch 11 → 13 not taken.
✓ Branch 14 → 15 taken 3 times.
✓ Branch 14 → 31 taken 1 time.
4 if (m_perceivedPaintPending && m_perceived.isValid()) {
230
1/1
✓ Branch 18 → 19 taken 3 times.
6 m_perceived.endPhase(QStringLiteral("paint"));
231
2/2
✓ Branch 22 → 23 taken 2 times.
✓ Branch 22 → 30 taken 1 time.
3 if (m_authoritative.isValid())
232
1/1
✓ Branch 26 → 27 taken 2 times.
4 m_authoritative.endPhase(QStringLiteral("paint"));
233 3 finishPerceived(Outcome::Success);
234 }
235
5/6
✓ Branch 31 → 32 taken 2 times.
✓ Branch 31 → 35 taken 2 times.
✓ Branch 33 → 34 taken 2 times.
✗ Branch 33 → 35 not taken.
✓ Branch 36 → 37 taken 2 times.
✓ Branch 36 → 47 taken 2 times.
4 if (m_authoritativePaintPending && m_authoritative.isValid()) {
236
1/1
✓ Branch 40 → 41 taken 2 times.
4 m_authoritative.endPhase(QStringLiteral("final_paint"));
237
2/2
✓ Branch 43 → 44 taken 1 time.
✓ Branch 43 → 45 taken 1 time.
2 finishAuthoritative(m_anyFailure ? Outcome::Failed : Outcome::Success);
238 }
239 }
240 20 return QObject::eventFilter(watched, event);
241 }
242
243 } // namespace MailJD::Performance
244