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: 88.9% 48 / 0 / 54
Functions: 100.0% 4 / 0 / 4
Branches: 76.2% 77 / 0 / 101

data/IdentityChoice.cpp
Line Branch Exec Source
1 #include "IdentityChoice.h"
2
3 #include <QRegularExpression>
4
5 namespace IdentityChoice {
6
7 48 QStringList addressesOf(const QString &header) {
8 48 QStringList out;
9
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 48 times.
48 if (header.size() > 64 * 1024) return out;
10 // Quoted display names may contain commas, brackets and @: drop them first.
11
4/7
✓ Branch 5 → 6 taken 7 times.
✓ Branch 5 → 18 taken 41 times.
✓ Branch 7 → 8 taken 7 times.
✗ Branch 7 → 18 not taken.
✓ Branch 12 → 13 taken 7 times.
✗ Branch 86 → 87 not taken.
✗ Branch 86 → 88 not taken.
55 static const QRegularExpression quoted(QStringLiteral("\"(?:[^\"\\\\]|\\\\.)*\""));
12 48 QString rest = header;
13
1/1
✓ Branch 19 → 20 taken 48 times.
48 rest.remove(quoted);
14 // Angle-bracketed addresses, then bare ones.
15
4/7
✓ Branch 20 → 21 taken 7 times.
✓ Branch 20 → 33 taken 41 times.
✓ Branch 22 → 23 taken 7 times.
✗ Branch 22 → 33 not taken.
✓ Branch 27 → 28 taken 7 times.
✗ Branch 96 → 97 not taken.
✗ Branch 96 → 98 not taken.
55 static const QRegularExpression bracketed(QStringLiteral("<([^<>\\s]+@[^<>\\s]+)>"));
16
8/8
✓ Branch 34 → 35 taken 48 times.
✓ Branch 36 → 37 taken 8 times.
✓ Branch 37 → 38 taken 8 times.
✓ Branch 38 → 39 taken 8 times.
✓ Branch 39 → 40 taken 8 times.
✓ Branch 44 → 45 taken 56 times.
✓ Branch 45 → 36 taken 8 times.
✓ Branch 45 → 46 taken 48 times.
56 for (auto it = bracketed.globalMatch(rest); it.hasNext();) out.append(it.next().captured(1).toLower());
17
1/1
✓ Branch 47 → 48 taken 48 times.
48 rest.remove(bracketed);
18
4/7
✓ Branch 48 → 49 taken 7 times.
✓ Branch 48 → 61 taken 41 times.
✓ Branch 50 → 51 taken 7 times.
✗ Branch 50 → 61 not taken.
✓ Branch 55 → 56 taken 7 times.
✗ Branch 119 → 120 not taken.
✗ Branch 119 → 121 not taken.
55 static const QRegularExpression bare(QStringLiteral("[^\\s,;:<>\"()]+@[^\\s,;:<>\"()]+"));
19
8/8
✓ Branch 62 → 63 taken 48 times.
✓ Branch 64 → 65 taken 31 times.
✓ Branch 65 → 66 taken 31 times.
✓ Branch 66 → 67 taken 31 times.
✓ Branch 67 → 68 taken 31 times.
✓ Branch 72 → 73 taken 79 times.
✓ Branch 73 → 64 taken 31 times.
✓ Branch 73 → 74 taken 48 times.
79 for (auto it = bare.globalMatch(rest); it.hasNext();) out.append(it.next().captured().toLower());
20
1/1
✓ Branch 75 → 76 taken 48 times.
48 out.removeDuplicates();
21 48 return out;
22 48 }
23
24 22 QString withoutPlusTag(const QString &address) {
25 22 const qsizetype at = address.lastIndexOf(QLatin1Char('@'));
26 22 const qsizetype plus = address.indexOf(QLatin1Char('+'));
27
5/6
✓ Branch 8 → 9 taken 22 times.
✗ Branch 8 → 11 not taken.
✓ Branch 9 → 10 taken 5 times.
✓ Branch 9 → 11 taken 17 times.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 12 taken 4 times.
22 if (at <= 0 || plus <= 0 || plus > at) return address;
28
3/3
✓ Branch 12 → 13 taken 4 times.
✓ Branch 13 → 14 taken 4 times.
✓ Branch 14 → 15 taken 4 times.
4 return address.left(plus) + address.mid(at);
29 }
30
31 33 Choice forReply(const QList<Identity> &identities, const Original &original) {
32 33 Choice choice;
33
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 33 times.
33 if (identities.isEmpty()) return choice;
34 66 const QList<QPair<QString, QString>> headers{{QStringLiteral("to"), original.to},
35 66 {QStringLiteral("cc"), original.cc},
36 66 {QStringLiteral("delivered-to"), original.deliveredTo},
37
2/4
✓ Branch 23 → 24 taken 132 times.
✓ Branch 23 → 25 taken 33 times.
✗ Branch 95 → 96 not taken.
✗ Branch 95 → 97 not taken.
198 {QStringLiteral("x-original-to"), original.xOriginalTo}};
38 37 const auto match = [&](const QString &address, bool ownAccountOnly) -> const Identity * {
39
2/2
✓ Branch 33 → 4 taken 51 times.
✓ Branch 33 → 34 taken 5 times.
56 for (const Identity &identity : identities) {
40
6/6
✓ Branch 5 → 6 taken 45 times.
✓ Branch 5 → 9 taken 6 times.
✓ Branch 7 → 8 taken 4 times.
✓ Branch 7 → 9 taken 41 times.
✓ Branch 10 → 11 taken 4 times.
✓ Branch 10 → 12 taken 47 times.
51 if (ownAccountOnly && identity.accountId != original.accountId) continue;
41
1/1
✓ Branch 12 → 13 taken 47 times.
47 const QString email = identity.email.toLower();
42
9/11
✓ Branch 14 → 15 taken 16 times.
✓ Branch 14 → 18 taken 31 times.
✓ Branch 15 → 16 taken 16 times.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 17 → 19 taken 15 times.
✓ Branch 20 → 21 taken 16 times.
✓ Branch 20 → 22 taken 31 times.
✓ Branch 22 → 23 taken 32 times.
✓ Branch 22 → 24 taken 15 times.
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 38 not taken.
47 if (email == address || email == withoutPlusTag(address)) return &identity;
43 47 }
44 5 return nullptr;
45 33 };
46
2/2
✓ Branch 63 → 35 taken 35 times.
✓ Branch 63 → 64 taken 1 time.
36 for (const bool ownAccountOnly : {true, false}) {
47
2/2
✓ Branch 61 → 37 taken 47 times.
✓ Branch 61 → 62 taken 3 times.
50 for (const auto &[name, value] : headers) {
48
5/5
✓ Branch 40 → 41 taken 47 times.
✓ Branch 41 → 42 taken 47 times.
✓ Branch 42 → 43 taken 47 times.
✓ Branch 53 → 44 taken 37 times.
✓ Branch 53 → 54 taken 15 times.
52 for (const QString &address : addressesOf(value)) {
49
3/3
✓ Branch 45 → 46 taken 37 times.
✓ Branch 46 → 47 taken 32 times.
✓ Branch 46 → 51 taken 5 times.
37 if (const Identity *identity = match(address, ownAccountOnly)) {
50 32 choice.identityId = identity->id;
51 32 choice.matchedAddress = address;
52 32 choice.header = name;
53 32 return choice;
54 }
55 47 }
56 }
57 }
58
1/2
✓ Branch 77 → 66 taken 1 time.
✗ Branch 77 → 78 not taken.
1 for (const Identity &identity : identities)
59
3/6
✓ Branch 68 → 69 taken 1 time.
✗ Branch 68 → 71 not taken.
✓ Branch 69 → 70 taken 1 time.
✗ Branch 69 → 71 not taken.
✓ Branch 72 → 73 taken 1 time.
✗ Branch 72 → 75 not taken.
1 if (identity.accountId == original.accountId && identity.isDefault) {
60 1 choice.identityId = identity.id;
61 1 return choice;
62 }
63 ✗ for (const Identity &identity : identities)
64 ✗ if (identity.accountId == original.accountId) {
65 ✗ choice.identityId = identity.id;
66 ✗ return choice;
67 }
68 ✗ choice.identityId = identities.first().id;
69 ✗ return choice;
70 198 }
71
72 } // namespace IdentityChoice
73