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% 79 / 0 / 79
Functions: 100.0% 10 / 0 / 10
Branches: 80.7% 117 / 0 / 145

presentation/QuickMailEventLink.cpp
Line Branch Exec Source
1 #include "QuickMailEventLink.h"
2
3 #include "QuickPimBackend.h"
4 #include "app/core/AccountSession.h"
5 #include "app/core/CalendarSyncCoordinator.h"
6 #include "app/core/MailSessionCore.h"
7 #include "data/CalendarStore.h"
8 #include "data/ICalendar.h"
9 #include "data/ImipInvitation.h"
10 #include "data/MailCache.h"
11
12 #include <QDateTime>
13 #include <QLoggingCategory>
14
15
4/7
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 8 taken 2 times.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
3 Q_LOGGING_CATEGORY(lcMailEventLink, "mailjd.quick.maillink")
16
17 namespace {
18 const QString kLinkProperty = QStringLiteral("X-MAILJD-MESSAGE-ID");
19 // Notes get the first lines of the mail, not the whole thread history.
20 constexpr int kExcerptLines = 12;
21 constexpr int kExcerptChars = 1200;
22
23 2 QString excerpt(const QString &body) {
24 2 QStringList lines;
25
4/5
✓ Branch 5 → 6 taken 2 times.
✓ Branch 6 → 7 taken 2 times.
✓ Branch 7 → 8 taken 2 times.
✓ Branch 40 → 9 taken 8 times.
✗ Branch 40 → 41 not taken.
8 for (const QString &line : body.split(QLatin1Char('\n'))) {
26
1/1
✓ Branch 10 → 11 taken 8 times.
8 const QString trimmed = line.trimmed();
27
3/3
✓ Branch 13 → 14 taken 8 times.
✓ Branch 14 → 15 taken 2 times.
✓ Branch 14 → 16 taken 6 times.
8 if (trimmed.startsWith(QLatin1Char('>'))) break; // the quoted history starts
28
6/9
✓ Branch 17 → 18 taken 2 times.
✓ Branch 17 → 24 taken 4 times.
✓ Branch 19 → 20 taken 2 times.
✗ Branch 19 → 23 not taken.
✓ Branch 20 → 21 taken 2 times.
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 2 times.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 6 times.
6 if (trimmed.isEmpty() && (lines.isEmpty() || lines.last().isEmpty())) continue;
29
1/1
✓ Branch 27 → 28 taken 6 times.
6 lines << trimmed;
30
1/2
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 6 times.
6 if (lines.size() == kExcerptLines) break;
31 10 }
32
3/3
✓ Branch 44 → 45 taken 2 times.
✓ Branch 45 → 46 taken 2 times.
✓ Branch 46 → 47 taken 2 times.
4 return lines.join(QLatin1Char('\n')).left(kExcerptChars).trimmed();
33 2 }
34 } // namespace
35
36 795 QuickMailEventLink::QuickMailEventLink(MailSessionCore &session, QuickPimBackend &pim,
37 795 std::function<MailId()> currentMail, QObject *parent)
38 795 : QObject(parent), m_session(session), m_pim(pim), m_currentMail(std::move(currentMail)) {}
39
40 1 QString QuickMailEventLink::seedComponent(const QString &uid, const QString &messageId) {
41 1 ICal::Component vevent;
42 1 vevent.name = QStringLiteral("VEVENT");
43 1 ICal::Property property;
44 1 property.name = QStringLiteral("UID");
45
1/1
✓ Branch 14 → 15 taken 1 time.
1 property.value = ICal::escapeText(uid);
46
1/1
✓ Branch 17 → 18 taken 1 time.
1 vevent.appendProperty(property);
47 1 property.name = QStringLiteral("DTSTAMP");
48
2/2
✓ Branch 24 → 25 taken 1 time.
✓ Branch 28 → 29 taken 1 time.
2 property.value = QDateTime::currentDateTimeUtc().toString(QStringLiteral("yyyyMMdd'T'HHmmss'Z'"));
49
1/1
✓ Branch 34 → 35 taken 1 time.
1 vevent.appendProperty(property);
50 1 property.name = kLinkProperty;
51
1/1
✓ Branch 36 → 37 taken 1 time.
1 property.value = ICal::escapeText(messageId);
52
1/1
✓ Branch 39 → 40 taken 1 time.
1 vevent.appendProperty(property);
53
1/1
✓ Branch 40 → 41 taken 1 time.
2 return ICal::serialize(vevent);
54 1 }
55
56 35 QString QuickMailEventLink::messageIdOf(const QString &veventText) {
57
2/2
✓ Branch 3 → 4 taken 33 times.
✓ Branch 3 → 5 taken 2 times.
35 if (!veventText.contains(kLinkProperty)) return {};
58
4/4
✓ Branch 8 → 9 taken 2 times.
✓ Branch 9 → 10 taken 2 times.
✓ Branch 10 → 11 taken 2 times.
✓ Branch 11 → 12 taken 2 times.
2 return ICal::unescapeText(ICal::parseFirst(veventText, QStringLiteral("VEVENT")).value(kLinkProperty)).trimmed();
59 }
60
61 2 QVariantMap QuickMailEventLink::eventDefaults() const {
62
1/1
✓ Branch 2 → 3 taken 2 times.
2 const QVariantMap reference = m_pim.currentMailReference();
63
2/3
✓ Branch 3 → 4 taken 2 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2 times.
2 if (reference.isEmpty()) return {};
64
4/4
✓ Branch 6 → 7 taken 2 times.
✓ Branch 12 → 13 taken 2 times.
✓ Branch 13 → 14 taken 2 times.
✓ Branch 14 → 15 taken 2 times.
6 QString notes = tr("From: %1").arg(reference.value(QStringLiteral("sender")).toString());
65
1/1
✓ Branch 21 → 22 taken 2 times.
2 const MailId mail = m_currentMail();
66
2/3
✓ Branch 23 → 24 taken 2 times.
✓ Branch 25 → 26 taken 2 times.
✗ Branch 25 → 41 not taken.
2 if (const auto body = m_session.cache()->displayBody(mail.folderId, mail.uid)) {
67
1/1
✓ Branch 27 → 28 taken 2 times.
2 const QString text = excerpt(body->textPlain);
68
3/4
✓ Branch 29 → 30 taken 2 times.
✗ Branch 29 → 39 not taken.
✓ Branch 33 → 34 taken 2 times.
✓ Branch 34 → 35 taken 2 times.
4 if (!text.isEmpty()) notes += QStringLiteral("\n\n") + text;
69 4 }
70
5/5
✓ Branch 42 → 43 taken 2 times.
✓ Branch 46 → 47 taken 2 times.
✓ Branch 47 → 48 taken 2 times.
✓ Branch 51 → 44 taken 2 times.
✓ Branch 51 → 52 taken 2 times.
4 qCInfo(lcMailEventLink) << "Appointment prefilled from the displayed mail";
71
1/1
✓ Branch 59 → 60 taken 2 times.
6 return {{QStringLiteral("summary"), reference.value(QStringLiteral("subject"))},
72 4 {QStringLiteral("description"), notes},
73
3/5
✓ Branch 72 → 73 taken 2 times.
✓ Branch 76 → 77 taken 6 times.
✓ Branch 76 → 78 taken 2 times.
✗ Branch 137 → 138 not taken.
✗ Branch 137 → 139 not taken.
12 {QStringLiteral("messageId"), reference.value(QStringLiteral("messageId"))}};
74 10 }
75
76 37 QString QuickMailEventLink::storedComponent(const QVariantMap &occurrence) const {
77 37 auto *sync = m_session.calendarSync();
78
3/6
✓ Branch 3 → 4 taken 37 times.
✗ Branch 3 → 6 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 37 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 37 times.
37 if (!sync || !sync->store()) return {};
79
2/2
✓ Branch 28 → 29 taken 37 times.
✓ Branch 29 → 30 taken 37 times.
148 const auto event = sync->store()->occurrenceEvent(occurrence.value(QStringLiteral("uid")).toString(),
80
2/2
✓ Branch 22 → 23 taken 37 times.
✓ Branch 23 → 24 taken 37 times.
111 occurrence.value(QStringLiteral("accountId")).toString(),
81
3/3
✓ Branch 16 → 17 taken 37 times.
✓ Branch 17 → 18 taken 37 times.
✓ Branch 30 → 31 taken 37 times.
185 occurrence.value(QStringLiteral("calendarPath")).toString(), {});
82
1/2
✓ Branch 48 → 49 taken 37 times.
✗ Branch 48 → 51 not taken.
37 return event ? event->icalRaw : QString();
83 37 }
84
85 34 QVariantMap QuickMailEventLink::linkedMail(const QVariantMap &occurrence) const {
86
2/2
✓ Branch 2 → 3 taken 34 times.
✓ Branch 3 → 4 taken 34 times.
34 const QString messageId = messageIdOf(storedComponent(occurrence));
87
3/3
✓ Branch 6 → 7 taken 33 times.
✓ Branch 6 → 8 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
68 return messageId.isEmpty() ? QVariantMap{} : m_pim.taskMailReference(messageId);
88 34 }
89
90 1 bool QuickMailEventLink::openLinkedMail(const QVariantMap &occurrence) {
91
2/2
✓ Branch 2 → 3 taken 1 time.
✓ Branch 3 → 4 taken 1 time.
1 const QString messageId = messageIdOf(storedComponent(occurrence));
92
6/6
✓ Branch 5 → 6 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 16 → 7 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
2 qCInfo(lcMailEventLink) << "Open linked mail:" << !messageId.isEmpty();
93
3/5
✓ Branch 18 → 19 taken 1 time.
✗ Branch 18 → 22 not taken.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 20 → 21 taken 1 time.
✗ Branch 20 → 22 not taken.
2 return !messageId.isEmpty() && m_pim.openTaskMail(messageId);
94 1 }
95
96 2 QVariantMap QuickMailEventLink::attendeeDraft(const QVariantMap &occurrence) const {
97
2/2
✓ Branch 5 → 6 taken 2 times.
✓ Branch 6 → 7 taken 2 times.
2 const ICal::Component vevent = ICal::parseFirst(storedComponent(occurrence), QStringLiteral("VEVENT"));
98 2 QStringList own;
99
3/4
✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 19 not taken.
✓ Branch 15 → 16 taken 2 times.
✓ Branch 16 → 17 taken 2 times.
2 if (const auto &primary = m_session.accounts()->primary()) own << primary->email.toLower();
100 2 QStringList to;
101
5/5
✓ Branch 22 → 23 taken 2 times.
✓ Branch 25 → 26 taken 2 times.
✓ Branch 26 → 27 taken 2 times.
✓ Branch 49 → 28 taken 4 times.
✓ Branch 49 → 50 taken 2 times.
6 for (const ICal::Property &attendee : vevent.propertiesNamed(QStringLiteral("ATTENDEE"))) {
102
1/1
✓ Branch 29 → 30 taken 4 times.
4 const QString email = Imip::addressOf(attendee.value);
103
6/8
✓ Branch 31 → 32 taken 4 times.
✗ Branch 31 → 36 not taken.
✓ Branch 33 → 34 taken 2 times.
✓ Branch 33 → 36 taken 2 times.
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 2 times.
✓ Branch 38 → 39 taken 2 times.
✓ Branch 38 → 40 taken 2 times.
4 if (email.isEmpty() || own.contains(email) || to.contains(email)) continue;
104
1/1
✓ Branch 40 → 41 taken 2 times.
2 to << email;
105 6 }
106 // The organizer of an invitation is one of the people to write to.
107
2/2
✓ Branch 54 → 55 taken 2 times.
✓ Branch 55 → 56 taken 2 times.
2 const QString organizer = Imip::addressOf(vevent.value(QStringLiteral("ORGANIZER")));
108
5/9
✓ Branch 60 → 61 taken 2 times.
✗ Branch 60 → 66 not taken.
✓ Branch 62 → 63 taken 2 times.
✗ Branch 62 → 66 not taken.
✓ Branch 64 → 65 taken 2 times.
✗ Branch 64 → 66 not taken.
✓ Branch 67 → 68 taken 2 times.
✗ Branch 67 → 69 not taken.
✓ Branch 68 → 69 taken 2 times.
2 if (!organizer.isEmpty() && !own.contains(organizer) && !to.contains(organizer)) to.prepend(organizer);
109
1/1
✓ Branch 75 → 76 taken 2 times.
6 return {{QStringLiteral("to"), to.join(QStringLiteral(", "))},
110
4/6
✓ Branch 84 → 85 taken 2 times.
✓ Branch 85 → 86 taken 2 times.
✓ Branch 89 → 90 taken 4 times.
✓ Branch 89 → 91 taken 2 times.
✗ Branch 143 → 144 not taken.
✗ Branch 143 → 145 not taken.
12 {QStringLiteral("subject"), occurrence.value(QStringLiteral("summary")).toString()}};
111 8 }
112