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: 92.2% 94 / 0 / 102
Functions: 88.9% 16 / 0 / 18
Branches: 72.9% 102 / 0 / 140

performance/ThreadSelectionPerformanceTracker.cpp
Line Branch Exec Source
1 #include "performance/ThreadSelectionPerformanceTracker.h"
2
3 #include <QApplication>
4 #include <QEvent>
5
6 namespace MailJD::Performance {
7
8 namespace {
9
10 constexpr auto SelectionMetric = "thread.selection_to_quick_frame.v1";
11 // A missing frame confirmation within this window is `timeout`, never
12 // an implicit success (P90.0: no probe may finish "fast" without the
13 // visible side).
14 constexpr int SelectionTimeoutMs = 15000;
15 // Input older than this window no longer explains a selection.
16 constexpr qint64 OriginFreshNs = 750 * 1000 * 1000;
17
18 } // namespace
19
20 20279 ThreadSelectionPerformanceTracker &ThreadSelectionPerformanceTracker::instance() {
21
4/7
✓ Branch 2 → 3 taken 22 times.
✓ Branch 2 → 8 taken 20257 times.
✓ Branch 4 → 5 taken 22 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 22 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
20279 static ThreadSelectionPerformanceTracker tracker;
22 20279 return tracker;
23 }
24
25 22 ThreadSelectionPerformanceTracker::ThreadSelectionPerformanceTracker(
26 22 QObject *parent)
27
1/1
✓ Branch 6 → 7 taken 22 times.
22 : QObject(parent) {
28
1/1
✓ Branch 8 → 9 taken 22 times.
22 m_timeout.setSingleShot(true);
29
1/1
✓ Branch 9 → 10 taken 22 times.
22 m_timeout.setInterval(SelectionTimeoutMs);
30
1/1
✓ Branch 10 → 11 taken 22 times.
22 m_timeout.callOnTimeout(this, [this] {
31
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 5 not taken.
1 if (m_operation.isValid()) finish(Outcome::Timeout);
32 1 });
33 22 }
34
35 20906 bool ThreadSelectionPerformanceTracker::isActive() const {
36
4/4
✓ Branch 2 → 3 taken 20906 times.
✓ Branch 3 → 4 taken 20906 times.
✓ Branch 4 → 5 taken 11 times.
✓ Branch 4 → 13 taken 20895 times.
20928 return PerformanceTrace::instance().isEnabled() &&
37
5/7
✓ Branch 5 → 6 taken 11 times.
✓ Branch 6 → 7 taken 11 times.
✓ Branch 10 → 11 taken 11 times.
✓ Branch 11 → 12 taken 9 times.
✓ Branch 11 → 13 taken 2 times.
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 32 not taken.
20928 PerformanceTrace::instance().selectedScenario().startsWith(
38
6/10
✓ Branch 14 → 15 taken 11 times.
✓ Branch 14 → 16 taken 20895 times.
✓ Branch 16 → 17 taken 11 times.
✓ Branch 16 → 18 taken 20895 times.
✓ Branch 18 → 19 taken 11 times.
✓ Branch 18 → 20 taken 20895 times.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 24 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 28 not taken.
41823 QStringLiteral("THREAD_SELECTION."));
39 }
40
41 765 void ThreadSelectionPerformanceTracker::prepare() {
42
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 765 times.
765 if (isActive()) ensureEventFilterInstalled();
43 765 }
44
45 16 void ThreadSelectionPerformanceTracker::reset() {
46 16 m_selection = MailId{};
47 16 m_operation = {};
48 16 m_visibleRevision = -1;
49 16 m_catchupRevision = -1;
50 16 }
51
52 8 void ThreadSelectionPerformanceTracker::finish(Outcome outcome, qint64 itemCount) {
53
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 8 times.
8 if (!m_operation.isValid()) return;
54 8 m_timeout.stop();
55 8 m_operation.finish(outcome, itemCount);
56 8 reset();
57 }
58
59 8 void ThreadSelectionPerformanceTracker::ensureEventFilterInstalled() {
60
5/6
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 6 taken 7 times.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 6 not taken.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 11 taken 7 times.
8 if (!m_eventFilterInstalled && qApp) {
61 1 qApp->installEventFilter(this);
62 1 m_eventFilterInstalled = true;
63 }
64 8 }
65
66 5 bool ThreadSelectionPerformanceTracker::eventFilter(QObject *watched,
67 QEvent *event) {
68 Q_UNUSED(watched)
69
3/3
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 12 taken 1 time.
✓ Branch 3 → 20 taken 3 times.
5 switch (event->type()) {
70 1 case QEvent::MouseButtonPress:
71 case QEvent::MouseButtonDblClick:
72 case QEvent::Wheel:
73 case QEvent::TabletPress:
74 case QEvent::TouchBegin:
75 1 m_lastInputClass = QStringLiteral("pointer");
76 1 m_lastInputNs = PerformanceTrace::monotonicNowNs();
77 1 break;
78 1 case QEvent::KeyPress:
79 1 m_lastInputClass = QStringLiteral("keyboard");
80 1 m_lastInputNs = PerformanceTrace::monotonicNowNs();
81 1 break;
82 3 default:
83 3 break;
84 }
85 5 return QObject::eventFilter(watched, event);
86 }
87
88 2 QString ThreadSelectionPerformanceTracker::classifyOrigin() const {
89
3/4
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 5 not taken.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 13 taken 1 time.
4 if (m_lastInputNs == 0 ||
90
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 1 time.
2 PerformanceTrace::monotonicNowNs() - m_lastInputNs > OriginFreshNs)
91 1 return QStringLiteral("other");
92 1 return m_lastInputClass;
93 }
94
95 9 void ThreadSelectionPerformanceTracker::beginSelection(const MailId &mailId,
96 const QString &origin) {
97
6/7
✓ Branch 2 → 3 taken 9 times.
✓ Branch 3 → 4 taken 8 times.
✓ Branch 3 → 6 taken 1 time.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 8 times.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 8 times.
9 if (!isActive() || !mailId.isValid()) return;
98
1/1
✓ Branch 10 → 11 taken 8 times.
8 ensureEventFilterInstalled();
99
3/3
✓ Branch 11 → 12 taken 8 times.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 24 taken 7 times.
8 if (m_operation.isValid()) {
100
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 1 time.
1 if (mailId == m_selection) return;
101 // A newer selection replaces the probe; the old one never reached its
102 // frame and must not pollute the distribution.
103
1/1
✓ Branch 16 → 17 taken 1 time.
1 PerformanceTrace::instance().markProcessEvent(
104
1/1
✓ Branch 20 → 21 taken 1 time.
1 m_scenario, QStringLiteral("selection_superseded"));
105
1/1
✓ Branch 23 → 24 taken 1 time.
1 finish(Outcome::Cancelled);
106 }
107 8 reset();
108
2/2
✓ Branch 25 → 26 taken 8 times.
✓ Branch 26 → 27 taken 8 times.
8 m_scenario = PerformanceTrace::instance().selectedScenario();
109 8 m_selection = mailId;
110
1/1
✓ Branch 30 → 31 taken 8 times.
16 m_operation = PerformanceTrace::instance().startMetric(
111
2/2
✓ Branch 32 → 33 taken 8 times.
✓ Branch 33 → 34 taken 8 times.
16 m_scenario, QString::fromLatin1(SelectionMetric));
112 // Origin tokens are a fixed enumeration from the callers or the
113 // input classifier, never free user text.
114 const QString originToken =
115
8/18
✓ Branch 46 → 47 taken 4 times.
✓ Branch 46 → 52 taken 1 time.
✓ Branch 51 → 52 taken 2 times.
✓ Branch 51 → 53 taken 2 times.
✓ Branch 60 → 61 taken 5 times.
✓ Branch 60 → 62 taken 3 times.
✓ Branch 62 → 63 taken 8 times.
✗ Branch 62 → 64 not taken.
✓ Branch 64 → 65 taken 8 times.
✗ Branch 64 → 66 not taken.
✗ Branch 100 → 101 not taken.
✗ Branch 100 → 102 not taken.
✗ Branch 104 → 105 not taken.
✗ Branch 104 → 106 not taken.
✗ Branch 108 → 109 not taken.
✗ Branch 108 → 110 not taken.
✗ Branch 112 → 113 not taken.
✗ Branch 112 → 114 not taken.
25 origin == QStringLiteral("pointer") || origin == QStringLiteral("keyboard") ||
116
6/10
✓ Branch 54 → 55 taken 4 times.
✓ Branch 54 → 56 taken 4 times.
✓ Branch 56 → 57 taken 4 times.
✓ Branch 56 → 58 taken 4 times.
✓ Branch 58 → 59 taken 5 times.
✓ Branch 58 → 60 taken 3 times.
✗ Branch 92 → 93 not taken.
✗ Branch 92 → 94 not taken.
✗ Branch 96 → 97 not taken.
✗ Branch 96 → 98 not taken.
12 origin == QStringLiteral("restore")
117
2/2
✓ Branch 41 → 42 taken 5 times.
✓ Branch 41 → 52 taken 3 times.
8 ? origin
118
1/1
✓ Branch 53 → 54 taken 2 times.
16 : classifyOrigin();
119
1/1
✓ Branch 66 → 67 taken 8 times.
8 PerformanceTrace::instance().markProcessEvent(
120
1/1
✓ Branch 71 → 72 taken 8 times.
8 m_scenario,
121
1/1
✓ Branch 70 → 71 taken 8 times.
16 QStringLiteral("selection_origin.") + originToken);
122
1/1
✓ Branch 75 → 76 taken 8 times.
8 m_timeout.start();
123 8 }
124
125 3 void ThreadSelectionPerformanceTracker::visiblePagePublished(qint64 revision,
126 int rowCount) {
127
5/6
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 5 not taken.
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 2 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 2 times.
3 if (!m_operation.isValid() || m_visibleRevision >= 0) return;
128 2 m_visibleRevision = revision;
129
1/1
✓ Branch 12 → 13 taken 2 times.
4 m_operation.mark(QStringLiteral("visible_page"), rowCount);
130 }
131
132 3 void ThreadSelectionPerformanceTracker::indexCatchupFinished(qint64 revision) {
133
5/6
✓ Branch 3 → 4 taken 3 times.
✗ Branch 3 → 5 not taken.
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 2 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 2 times.
3 if (!m_operation.isValid() || m_catchupRevision >= 0) return;
134 2 m_catchupRevision = revision;
135
1/1
✓ Branch 12 → 13 taken 2 times.
4 m_operation.mark(QStringLiteral("index_catchup"));
136 }
137
138 1 void ThreadSelectionPerformanceTracker::authoritativeSyncFinished(qint64 folderId) {
139
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
1 if (!m_operation.isValid()) return;
140
1/1
✓ Branch 8 → 9 taken 1 time.
2 m_operation.mark(QStringLiteral("authoritative_sync"), folderId);
141 }
142
143 7 void ThreadSelectionPerformanceTracker::quickFramePresented(const MailId &mailId) {
144
6/6
✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 6 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 5 times.
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 10 taken 5 times.
7 if (!m_operation.isValid() || !(mailId == m_selection)) return;
145 5 finish(Outcome::Success);
146 }
147
148 ✗ void ThreadSelectionPerformanceTracker::selectionSuperseded() {
149 ✗ if (!m_operation.isValid()) return;
150 ✗ PerformanceTrace::instance().markProcessEvent(
151 ✗ m_scenario, QStringLiteral("selection_superseded"));
152 ✗ finish(Outcome::Cancelled);
153 }
154
155 93 void ThreadSelectionPerformanceTracker::folderSwitched() {
156
2/2
✓ Branch 3 → 4 taken 92 times.
✓ Branch 3 → 5 taken 1 time.
93 if (!m_operation.isValid()) return;
157 1 PerformanceTrace::instance().markProcessEvent(
158
1/1
✓ Branch 9 → 10 taken 1 time.
1 m_scenario, QStringLiteral("selection_folder_changed"));
159 1 finish(Outcome::Cancelled);
160 }
161
162 ✗ void ThreadSelectionPerformanceTracker::fail() {
163 ✗ if (!m_operation.isValid()) return;
164 ✗ finish(Outcome::Failed);
165 }
166
167 } // namespace MailJD::Performance
168