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: 91.4% 74 / 0 / 81
Functions: 100.0% 9 / 0 / 9
Branches: 68.7% 79 / 0 / 115

presentation/MessageCopyQueue.cpp
Line Branch Exec Source
1 #include "MessageCopyQueue.h"
2 #include "app/core/MailSessionCore.h"
3 #include "app/core/AccountSession.h"
4 #include "controller/MailController.h"
5 #include "data/MailCache.h"
6
7 795 MessageCopyQueue::MessageCopyQueue(MailSessionCore &session, QObject *parent)
8
1/1
✓ Branch 7 → 8 taken 795 times.
795 : QAbstractListModel(parent), m_session(session) {
9
1/1
✓ Branch 8 → 9 taken 795 times.
795 m_timer.setInterval(1000);
10
1/1
✓ Branch 9 → 10 taken 795 times.
795 connect(&m_timer, &QTimer::timeout, this, &MessageCopyQueue::refresh);
11
1/1
✓ Branch 12 → 13 taken 795 times.
795 connect(session.accounts(), &AccountSession::accountsLoaded, this, [this] {
12 793 beginResetModel();
13 793 m_rows.clear();
14 793 m_account.clear();
15 793 m_error.clear();
16 793 m_loadError.clear();
17 793 endResetModel();
18
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 793 times.
793 if (active()) refresh();
19 793 else emit stateChanged();
20 793 });
21
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2 times.
2 const auto completed = [this] { if (active()) refresh(); };
22
1/1
✓ Branch 15 → 16 taken 795 times.
795 connect(session.controller(), &MailController::appendMutationCompleted, this, completed);
23
1/1
✓ Branch 18 → 19 taken 795 times.
795 connect(session.controller(), &MailController::appendMutationFailed, this, completed);
24 795 }
25 817 int MessageCopyQueue::rowCount(const QModelIndex &parent) const {
26
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 817 times.
817 return parent.isValid() ? 0 : m_rows.size();
27 }
28 59 QHash<int, QByteArray> MessageCopyQueue::roleNames() const {
29 ✗ return {{Token, "copyToken"}, {Folder, "copyFolder"}, {State, "copyState"},
30
2/4
✓ Branch 9 → 10 taken 295 times.
✓ Branch 9 → 11 taken 59 times.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 16 not taken.
354 {Error, "copyError"}, {Retryable, "copyRetryable"}};
31 59 }
32 13 QVariant MessageCopyQueue::data(const QModelIndex &index, int role) const {
33
4/8
✓ Branch 3 → 4 taken 13 times.
✗ Branch 3 → 9 not taken.
✓ Branch 5 → 6 taken 13 times.
✗ Branch 5 → 9 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 13 times.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 13 times.
13 if (!index.isValid() || index.row() < 0 || index.row() >= m_rows.size()) return {};
34 13 const auto &row = m_rows.at(index.row());
35
3/3
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 20 taken 12 times.
✓ Branch 16 → 17 taken 1 time.
13 if (role == Token) return QString::number(row.token);
36
2/2
✓ Branch 20 → 21 taken 3 times.
✓ Branch 20 → 22 taken 9 times.
12 if (role == Folder) return row.targetFolder;
37
2/2
✓ Branch 22 → 23 taken 3 times.
✓ Branch 22 → 24 taken 6 times.
9 if (role == Error) return row.error;
38
2/2
✓ Branch 24 → 25 taken 3 times.
✓ Branch 24 → 26 taken 3 times.
6 if (role == Retryable) return row.phase == MutationPhase::Failed;
39
1/2
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 28 taken 3 times.
3 if (role != State) return {};
40
2/7
✓ Branch 28 → 29 taken 1 time.
✗ Branch 28 → 33 not taken.
✗ Branch 28 → 37 not taken.
✓ Branch 28 → 41 taken 2 times.
✗ Branch 28 → 45 not taken.
✗ Branch 28 → 49 not taken.
✗ Branch 28 → 53 not taken.
3 switch (row.phase) {
41
1/1
✓ Branch 29 → 30 taken 1 time.
1 case MutationPhase::Queued: return tr("Waiting to copy");
42 ✗ case MutationPhase::Dispatched: return tr("Copying…");
43 ✗ case MutationPhase::AwaitingVerification:
44 ✗ case MutationPhase::Ambiguous: return tr("Checking whether the copy arrived");
45
1/1
✓ Branch 41 → 42 taken 2 times.
2 case MutationPhase::Failed: return tr("Copy failed");
46 ✗ case MutationPhase::Quarantined: return tr("Needs review");
47 ✗ case MutationPhase::Confirmed: return tr("Copied");
48 }
49 ✗ return {};
50 }
51 2 void MessageCopyQueue::setActive(bool active) {
52
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2 times.
2 if (active == this->active()) return;
53
2/2
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 8 taken 1 time.
2 if (active) { m_timer.start(); refresh(); }
54 1 else m_timer.stop();
55 2 emit stateChanged();
56 }
57 4 void MessageCopyQueue::refresh() {
58 4 m_generation = m_session.accounts()->generation();
59 4 const auto &account = m_session.accounts()->primary();
60
1/2
✓ Branch 7 → 8 taken 4 times.
✗ Branch 7 → 10 not taken.
4 m_account = account ? account->name : QString{};
61
1/4
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 4 times.
✗ Branch 84 → 85 not taken.
✗ Branch 84 → 86 not taken.
8 const auto rows = m_account.isEmpty() ? std::optional<QList<MutationRecord>>(QList<MutationRecord>{})
62
2/3
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 17 taken 4 times.
✓ Branch 19 → 20 taken 4 times.
4 : m_session.cache()->journal().pendingAppendMutations(m_account, 100);
63
1/3
✓ Branch 23 → 24 taken 4 times.
✗ Branch 23 → 25 not taken.
✗ Branch 25 → 26 not taken.
4 m_loadError = rows ? QString{} : tr("The message copies could not be loaded.");
64 // Delegates (and a button the user is about to click) survive the
65 // once-per-second refresh: an unchanged token list only updates the rows
66 // whose state changed; only a changed list resets the model.
67
3/4
✓ Branch 29 → 30 taken 4 times.
✗ Branch 29 → 35 not taken.
✓ Branch 33 → 34 taken 3 times.
✓ Branch 33 → 35 taken 1 time.
4 bool sameTokens = rows && rows->size() == m_rows.size();
68
6/6
✓ Branch 41 → 42 taken 6 times.
✓ Branch 41 → 45 taken 1 time.
✓ Branch 43 → 44 taken 3 times.
✓ Branch 43 → 45 taken 3 times.
✓ Branch 46 → 37 taken 3 times.
✓ Branch 46 → 47 taken 4 times.
7 for (int i = 0; sameTokens && i < m_rows.size(); ++i)
69 3 sameTokens = m_rows.at(i).token == rows->at(i).token;
70
2/2
✓ Branch 47 → 48 taken 1 time.
✓ Branch 47 → 55 taken 3 times.
4 if (!sameTokens) {
71
1/1
✓ Branch 48 → 49 taken 1 time.
1 beginResetModel();
72 1 m_rows = rows.value_or(QList<MutationRecord>{});
73
1/1
✓ Branch 54 → 81 taken 1 time.
1 endResetModel();
74 } else {
75
2/2
✓ Branch 80 → 56 taken 3 times.
✓ Branch 80 → 81 taken 3 times.
6 for (int i = 0; i < m_rows.size(); ++i) {
76 3 const auto &before = m_rows.at(i);
77 3 const auto &after = rows->at(i);
78
7/8
✓ Branch 59 → 60 taken 2 times.
✓ Branch 59 → 65 taken 1 time.
✓ Branch 61 → 62 taken 1 time.
✓ Branch 61 → 65 taken 1 time.
✓ Branch 63 → 64 taken 1 time.
✗ Branch 63 → 65 not taken.
✓ Branch 66 → 67 taken 1 time.
✓ Branch 66 → 68 taken 2 times.
3 if (before.phase == after.phase && before.error == after.error && before.targetFolder == after.targetFolder)
79 1 continue;
80
1/1
✓ Branch 68 → 69 taken 2 times.
2 m_rows[i] = after;
81
4/4
✓ Branch 70 → 71 taken 2 times.
✓ Branch 72 → 73 taken 2 times.
✓ Branch 74 → 75 taken 2 times.
✓ Branch 75 → 76 taken 2 times.
2 emit dataChanged(index(i), index(i), {State, Error, Retryable, Folder});
82 }
83 }
84
1/1
✓ Branch 81 → 82 taken 4 times.
4 emit stateChanged();
85 4 }
86 2 bool MessageCopyQueue::retryCopy(const QString &token) {
87 2 bool valid = false;
88
1/1
✓ Branch 2 → 3 taken 2 times.
2 const qint64 id = token.toLongLong(&valid);
89
2/4
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 16 not taken.
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 16 not taken.
2 if (!valid || id <= 0 || m_generation != m_session.accounts()->generation() ||
90
5/10
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 16 not taken.
✓ Branch 11 → 12 taken 2 times.
✗ Branch 11 → 16 not taken.
✓ Branch 18 → 19 taken 2 times.
✗ Branch 18 → 20 not taken.
✓ Branch 20 → 21 taken 1 time.
✓ Branch 20 → 26 taken 1 time.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 33 not taken.
6 m_account != m_session.controller()->accountId() ||
91
3/3
✓ Branch 14 → 15 taken 2 times.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 17 taken 1 time.
2 !m_session.controller()->mutations()->retryAppendMutation(id)) {
92
1/1
✓ Branch 21 → 22 taken 1 time.
1 m_error = tr("This copy cannot be retried. Its saved content may be unavailable or its state has changed.");
93
1/1
✓ Branch 24 → 25 taken 1 time.
1 emit stateChanged();
94 1 return false;
95 }
96 1 m_error.clear();
97
1/1
✓ Branch 27 → 28 taken 1 time.
1 refresh();
98 1 return true;
99 }
100