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: 100.0% 57 / 0 / 57
Functions: 100.0% 5 / 0 / 5
Branches: 75.9% 101 / 0 / 133

data/MailAddressIndex.cpp
Line Branch Exec Source
1 #include "MailAddressIndex.h"
2
3 #include <QRegularExpression>
4 #include <QSet>
5 #include <QUrl>
6
7 namespace MailAddressIndex {
8
9 667111 QString normalize(const QString &address) {
10
1/1
✓ Branch 2 → 3 taken 667111 times.
667111 QString text = address.trimmed();
11
4/7
✓ Branch 3 → 4 taken 49 times.
✓ Branch 3 → 16 taken 667062 times.
✓ Branch 5 → 6 taken 49 times.
✗ Branch 5 → 16 not taken.
✓ Branch 10 → 11 taken 49 times.
✗ Branch 111 → 112 not taken.
✗ Branch 111 → 113 not taken.
667160 static const QRegularExpression angle(QStringLiteral("<([^<>\\s]+@[^<>\\s]+)>"));
12
5/5
✓ Branch 17 → 18 taken 667111 times.
✓ Branch 18 → 19 taken 667111 times.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 24 taken 667110 times.
✓ Branch 20 → 21 taken 1 time.
667111 if (const auto match = angle.match(text); match.hasMatch()) text = match.captured(1);
13
4/4
✓ Branch 26 → 27 taken 667111 times.
✓ Branch 27 → 28 taken 1 time.
✓ Branch 27 → 32 taken 667110 times.
✓ Branch 28 → 29 taken 1 time.
667111 if (text.startsWith(QLatin1String("mailto:"), Qt::CaseInsensitive)) text = text.mid(7);
14 667111 const qsizetype at = text.lastIndexOf(QLatin1Char('@'));
15
8/8
✓ Branch 35 → 36 taken 667109 times.
✓ Branch 35 → 42 taken 2 times.
✓ Branch 37 → 38 taken 667108 times.
✓ Branch 37 → 42 taken 1 time.
✓ Branch 41 → 42 taken 1 time.
✓ Branch 41 → 43 taken 667107 times.
✓ Branch 44 → 45 taken 4 times.
✓ Branch 44 → 46 taken 667107 times.
667111 if (at <= 0 || at == text.size() - 1 || text.indexOf(QLatin1Char('@')) != at) return {};
16
2/2
✓ Branch 46 → 47 taken 667107 times.
✓ Branch 47 → 48 taken 667107 times.
667107 const QString local = text.left(at).toLower();
17
2/2
✓ Branch 49 → 50 taken 667107 times.
✓ Branch 50 → 51 taken 667107 times.
667107 const QString domain = text.mid(at + 1).toLower();
18
8/16
✓ Branch 56 → 57 taken 667107 times.
✓ Branch 57 → 58 taken 667107 times.
✓ Branch 58 → 59 taken 667106 times.
✓ Branch 58 → 66 taken 1 time.
✓ Branch 76 → 77 taken 667107 times.
✗ Branch 76 → 78 not taken.
✓ Branch 78 → 79 taken 667107 times.
✗ Branch 78 → 80 not taken.
✓ Branch 80 → 81 taken 1 time.
✓ Branch 80 → 82 taken 667106 times.
✗ Branch 140 → 141 not taken.
✗ Branch 140 → 142 not taken.
✗ Branch 144 → 145 not taken.
✗ Branch 144 → 146 not taken.
✗ Branch 148 → 149 not taken.
✗ Branch 148 → 150 not taken.
2668427 if (local.contains(QRegularExpression(QStringLiteral("[\\s<>,;]"))) ||
19
10/18
✓ Branch 63 → 64 taken 667106 times.
✓ Branch 64 → 65 taken 667106 times.
✗ Branch 65 → 66 not taken.
✓ Branch 65 → 67 taken 667106 times.
✓ Branch 68 → 69 taken 667106 times.
✓ Branch 68 → 70 taken 1 time.
✓ Branch 70 → 71 taken 667106 times.
✓ Branch 70 → 72 taken 1 time.
✓ Branch 72 → 73 taken 667106 times.
✓ Branch 72 → 74 taken 1 time.
✓ Branch 74 → 75 taken 667107 times.
✗ Branch 74 → 76 not taken.
✗ Branch 127 → 128 not taken.
✗ Branch 127 → 129 not taken.
✗ Branch 131 → 132 not taken.
✗ Branch 131 → 133 not taken.
✗ Branch 135 → 136 not taken.
✗ Branch 135 → 137 not taken.
1334213 domain.contains(QRegularExpression(QStringLiteral("[\\s<>,;@]"))))
20 1 return {};
21 // IDNA: "bücher.example" and "xn--bcher-kva.example" are one domain.
22
1/1
✓ Branch 83 → 84 taken 667106 times.
667106 const QByteArray ace = QUrl::toAce(domain);
23
4/8
✗ Branch 85 → 86 not taken.
✓ Branch 85 → 87 taken 667106 times.
✓ Branch 87 → 88 taken 667106 times.
✓ Branch 88 → 89 taken 667106 times.
✓ Branch 89 → 90 taken 667106 times.
✗ Branch 89 → 91 not taken.
✗ Branch 154 → 155 not taken.
✗ Branch 154 → 156 not taken.
667106 const QString asciiDomain = ace.isEmpty() ? domain : QString::fromLatin1(ace).toLower();
24
2/2
✓ Branch 93 → 94 taken 667106 times.
✓ Branch 94 → 95 taken 667106 times.
667106 return local + QLatin1Char('@') + asciiDomain;
25 667111 }
26
27 1251931 QStringList parse(const QString &headerValue) {
28 // Split on commas outside quotes; then take <addr> or a bare address.
29
4/7
✓ Branch 2 → 3 taken 64 times.
✓ Branch 2 → 15 taken 1251867 times.
✓ Branch 4 → 5 taken 64 times.
✗ Branch 4 → 15 not taken.
✓ Branch 9 → 10 taken 64 times.
✗ Branch 59 → 60 not taken.
✗ Branch 59 → 61 not taken.
1251995 static const QRegularExpression angle(QStringLiteral("<([^<>\\s]+@[^<>\\s]+)>"));
30
4/7
✓ Branch 15 → 16 taken 64 times.
✓ Branch 15 → 28 taken 1251867 times.
✓ Branch 17 → 18 taken 64 times.
✗ Branch 17 → 28 not taken.
✓ Branch 22 → 23 taken 64 times.
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 71 not taken.
1251995 static const QRegularExpression bare(QStringLiteral("([^\\s<>,;\"']+@[^\\s<>,;\"']+)"));
31 1251931 QStringList result;
32 1251931 QString current;
33 1251931 bool quoted = false;
34 1253742 const auto flush = [&] {
35
1/1
✓ Branch 3 → 4 taken 1253742 times.
1253742 const QRegularExpressionMatch inAngle = angle.match(current);
36
5/5
✓ Branch 4 → 5 taken 1253742 times.
✓ Branch 5 → 6 taken 37047 times.
✓ Branch 5 → 7 taken 1216695 times.
✓ Branch 6 → 9 taken 37047 times.
✓ Branch 8 → 9 taken 1216695 times.
2470437 const QRegularExpressionMatch plain = inAngle.hasMatch() ? inAngle : bare.match(current);
37
3/3
✓ Branch 9 → 10 taken 1253742 times.
✓ Branch 10 → 11 taken 666931 times.
✓ Branch 10 → 19 taken 586811 times.
1253742 if (plain.hasMatch()) {
38
2/2
✓ Branch 11 → 12 taken 666931 times.
✓ Branch 12 → 13 taken 666931 times.
666931 const QString address = normalize(plain.captured(1));
39
2/3
✓ Branch 15 → 16 taken 666931 times.
✗ Branch 15 → 17 not taken.
✓ Branch 16 → 17 taken 666931 times.
666931 if (!address.isEmpty()) result.append(address);
40 666931 }
41 1253742 current.clear();
42 1253742 };
43
2/2
✓ Branch 47 → 30 taken 14503400 times.
✓ Branch 47 → 48 taken 1251931 times.
15755331 for (const QChar c : headerValue) {
44
2/2
✓ Branch 33 → 34 taken 926 times.
✓ Branch 33 → 35 taken 14502474 times.
14503400 if (c == QLatin1Char('"')) quoted = !quoted;
45
6/6
✓ Branch 38 → 39 taken 2274 times.
✓ Branch 38 → 41 taken 14501126 times.
✓ Branch 39 → 40 taken 1811 times.
✓ Branch 39 → 41 taken 463 times.
✓ Branch 42 → 43 taken 1811 times.
✓ Branch 42 → 45 taken 14501589 times.
14503400 if (c == QLatin1Char(',') && !quoted) {
46
1/1
✓ Branch 43 → 44 taken 1811 times.
1811 flush();
47 1811 continue;
48 }
49
1/1
✓ Branch 45 → 46 taken 14501589 times.
14501589 current.append(c);
50 }
51
1/1
✓ Branch 48 → 49 taken 1251931 times.
1251931 flush();
52 1251931 return result;
53 1251931 }
54
55 411375 QList<Entry> entriesOf(const MailHeader &header) {
56 411375 QList<Entry> entries;
57 411375 QSet<QString> seen;
58 1234125 const auto add = [&](const QString &field, int role) {
59
5/5
✓ Branch 2 → 3 taken 1234125 times.
✓ Branch 3 → 4 taken 1234125 times.
✓ Branch 4 → 5 taken 1234125 times.
✓ Branch 29 → 6 taken 654266 times.
✓ Branch 29 → 30 taken 1234124 times.
1888390 for (const QString &address : parse(field)) {
60
2/2
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 654265 times.
654266 if (entries.size() >= MaxEntries) return;
61
2/2
✓ Branch 10 → 11 taken 654265 times.
✓ Branch 11 → 12 taken 654265 times.
654265 const QString key = QString::number(role) + address;
62
2/2
✓ Branch 14 → 15 taken 1 time.
✓ Branch 14 → 16 taken 654264 times.
654265 if (seen.contains(key)) continue;
63
1/1
✓ Branch 16 → 17 taken 654264 times.
654264 seen.insert(key);
64 654264 entries.append({address, role});
65 1888390 }
66
1/3
✓ Branch 18 → 19 taken 654264 times.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 45 not taken.
654264 };
67
1/1
✓ Branch 3 → 4 taken 411375 times.
411375 add(header.from, From);
68
1/1
✓ Branch 4 → 5 taken 411375 times.
411375 add(header.to, To);
69
1/1
✓ Branch 5 → 6 taken 411375 times.
411375 add(header.cc, Cc);
70 411375 return entries;
71 411375 }
72
73 } // namespace MailAddressIndex
74