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: 96.3% 181 / 0 / 188
Functions: 100.0% 11 / 0 / 11
Branches: 80.1% 250 / 0 / 312

data/IcsFile.cpp
Line Branch Exec Source
1 #include "IcsFile.h"
2
3 #include "ICalEventCodec.h"
4 #include "ICalTime.h"
5 #include "ICalendar.h"
6
7 #include <QHash>
8 #include <QLoggingCategory>
9 #include <QSet>
10
11
4/7
✓ Branch 2 → 3 taken 6 times.
✓ Branch 2 → 8 taken 24 times.
✓ Branch 4 → 5 taken 6 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 6 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
30 Q_LOGGING_CATEGORY(lcIcsFile, "mailjd.calendar.ics")
12
13 namespace IcsFile {
14
15 namespace {
16
17 // S106-126: MaxBytes is enforced here, for every caller (the subscription
18 // download is capped at the network layer only above it).
19 29 bool withinSize(const QString &text, QString *error) {
20
8/11
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 7 taken 27 times.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 2 times.
✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 11 taken 27 times.
✓ Branch 11 → 12 taken 27 times.
✓ Branch 11 → 13 taken 2 times.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 40 not taken.
29 if (text.size() <= MaxBytes / 3 || text.toUtf8().size() <= MaxBytes)
21 27 return true;
22
7/7
✓ Branch 13 → 14 taken 2 times.
✓ Branch 17 → 18 taken 2 times.
✓ Branch 18 → 19 taken 2 times.
✓ Branch 19 → 20 taken 2 times.
✓ Branch 20 → 21 taken 2 times.
✓ Branch 24 → 15 taken 2 times.
✓ Branch 24 → 25 taken 2 times.
4 qCWarning(lcIcsFile) << "Calendar file refused: larger than" << MaxBytes << "bytes";
23
2/3
✓ Branch 25 → 26 taken 2 times.
✗ Branch 25 → 36 not taken.
✓ Branch 30 → 31 taken 2 times.
6 if (error) *error = QStringLiteral("The calendar file is larger than %1 MB").arg(MaxBytes / (1024 * 1024));
24 2 return false;
25 }
26
27 // The TZIDs the components use (properties of the components and of their
28 // sub-components such as VALARM).
29 196 void collectZones(const ICal::Component &component, QSet<QString> *zones) {
30
2/2
✓ Branch 18 → 4 taken 808 times.
✓ Branch 18 → 19 taken 196 times.
1004 for (const ICal::Property &property : component.properties) {
31
1/1
✓ Branch 8 → 9 taken 808 times.
808 const QString tzid = property.parameter(QStringLiteral("TZID"));
32
3/3
✓ Branch 12 → 13 taken 16 times.
✓ Branch 12 → 15 taken 792 times.
✓ Branch 13 → 14 taken 16 times.
808 if (!tzid.isEmpty()) zones->insert(tzid);
33 808 }
34
1/3
✗ Branch 22 → 23 not taken.
✗ Branch 25 → 21 not taken.
✓ Branch 25 → 26 taken 196 times.
196 for (const ICal::Component &child : component.components) collectZones(child, zones);
35 196 }
36
37 // S106-127: each entry carries only the VTIMEZONEs its own components use
38 // (every zone of the file in every entry amplified a 0.4 MB file to
39 // 380 MB), and all entries together stay within kMaximumResourceBytes.
40 constexpr qint64 kMaximumResourceBytes = 4 * MaxBytes;
41
42 188 ICal::Component entryBase(const ICal::Component &base, const QList<ICal::Component> &own) {
43 188 QSet<QString> zones;
44
3/3
✓ Branch 6 → 7 taken 196 times.
✓ Branch 9 → 5 taken 196 times.
✓ Branch 9 → 10 taken 188 times.
384 for (const ICal::Component &component : own) collectZones(component, &zones);
45 188 ICal::Component result = base;
46
1/1
✓ Branch 11 → 12 taken 188 times.
188 result.components.removeIf([&zones](const ICal::Component &child) {
47
2/2
✓ Branch 4 → 5 taken 11 times.
✓ Branch 4 → 14 taken 4 times.
26 return child.name == QLatin1String("VTIMEZONE") &&
48
15/25
✓ Branch 8 → 9 taken 11 times.
✓ Branch 9 → 10 taken 11 times.
✓ Branch 10 → 11 taken 11 times.
✓ Branch 12 → 13 taken 7 times.
✓ Branch 12 → 14 taken 4 times.
✓ Branch 15 → 16 taken 11 times.
✓ Branch 15 → 17 taken 4 times.
✓ Branch 17 → 18 taken 11 times.
✓ Branch 17 → 19 taken 4 times.
✓ Branch 19 → 20 taken 11 times.
✓ Branch 19 → 21 taken 4 times.
✓ Branch 21 → 22 taken 11 times.
✓ Branch 21 → 23 taken 4 times.
✓ Branch 23 → 24 taken 11 times.
✓ Branch 23 → 25 taken 4 times.
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 33 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 37 not taken.
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 41 not taken.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 45 not taken.
37 !zones.contains(ICal::unescapeText(child.value(QStringLiteral("TZID"))).trimmed());
49 });
50 188 return result;
51 188 }
52
53 188 bool withinBudget(qint64 *used, const QString &resourceText, QString *error) {
54 188 *used += resourceText.size();
55
2/2
✓ Branch 3 → 4 taken 187 times.
✓ Branch 3 → 5 taken 1 time.
188 if (*used <= kMaximumResourceBytes)
56 187 return true;
57
5/5
✓ Branch 5 → 6 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 16 → 7 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
2 qCWarning(lcIcsFile) << "Calendar file refused: its entries would take more than"
58
2/2
✓ Branch 11 → 12 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
1 << kMaximumResourceBytes << "characters";
59
1/2
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 25 not taken.
2 if (error) *error = QStringLiteral("The calendar file is too complex to import");
60 1 return false;
61 }
62
63 } // namespace
64
65 18 QList<Entry> read(const QString &text, QString *error) {
66 18 QList<Entry> entries;
67
3/3
✓ Branch 2 → 3 taken 18 times.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 6 taken 17 times.
18 if (!withinSize(text, error)) return entries;
68
1/1
✓ Branch 9 → 10 taken 17 times.
17 const ICal::Component calendar = ICal::parseFirst(text, QStringLiteral("VCALENDAR"), error);
69
2/2
✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 16 taken 16 times.
17 if (calendar.name.isEmpty()) return entries;
70 16 ICal::Component base;
71 16 base.name = calendar.name;
72 16 base.properties = calendar.properties;
73
1/1
✓ Branch 21 → 22 taken 16 times.
16 base.removeProperties(QStringLiteral("METHOD"));
74
2/2
✓ Branch 33 → 26 taken 4047 times.
✓ Branch 33 → 34 taken 16 times.
4063 for (const ICal::Component &component : calendar.components)
75
3/3
✓ Branch 29 → 30 taken 7 times.
✓ Branch 29 → 31 taken 4040 times.
✓ Branch 30 → 31 taken 7 times.
4047 if (component.name != QLatin1String("VEVENT")) base.components.append(component);
76 // VEVENTs grouped by UID in file order.
77 16 QStringList order;
78 16 QHash<QString, QList<ICal::Component>> byUid;
79
2/2
✓ Branch 93 → 36 taken 4047 times.
✓ Branch 93 → 94 taken 16 times.
4063 for (const ICal::Component &component : calendar.components) {
80
2/2
✓ Branch 39 → 40 taken 7 times.
✓ Branch 39 → 41 taken 4040 times.
4049 if (component.name != QLatin1String("VEVENT")) continue;
81
3/3
✓ Branch 44 → 45 taken 4040 times.
✓ Branch 45 → 46 taken 4040 times.
✓ Branch 46 → 47 taken 4040 times.
4040 const QString uid = ICal::unescapeText(component.value(QStringLiteral("UID"))).trimmed();
82
2/2
✓ Branch 52 → 53 taken 2 times.
✓ Branch 52 → 64 taken 4038 times.
4040 if (uid.isEmpty()) {
83
5/5
✓ Branch 53 → 54 taken 2 times.
✓ Branch 57 → 58 taken 2 times.
✓ Branch 58 → 59 taken 2 times.
✓ Branch 62 → 55 taken 2 times.
✓ Branch 62 → 63 taken 2 times.
4 qCWarning(lcIcsFile) << "Skipping VEVENT without UID";
84 2 continue;
85 2 }
86
2/2
✓ Branch 65 → 66 taken 4030 times.
✓ Branch 65 → 82 taken 8 times.
4038 if (!byUid.contains(uid)) {
87
1/2
✗ Branch 67 → 68 not taken.
✓ Branch 67 → 81 taken 4030 times.
4030 if (order.size() == MaxEntries) {
88 ✗ qCWarning(lcIcsFile) << "Calendar file has more than" << MaxEntries << "appointments; the rest is skipped";
89 ✗ break;
90 }
91
1/1
✓ Branch 81 → 82 taken 4030 times.
4030 order.append(uid);
92 }
93
2/2
✓ Branch 82 → 83 taken 4038 times.
✓ Branch 83 → 84 taken 4038 times.
4038 byUid[uid].append(component);
94 4040 }
95 16 qint64 used = 0;
96
4/4
✓ Branch 94 → 95 taken 16 times.
✓ Branch 95 → 96 taken 16 times.
✓ Branch 160 → 97 taken 184 times.
✓ Branch 160 → 161 taken 15 times.
199 for (const QString &uid : order) {
97
1/1
✓ Branch 99 → 100 taken 184 times.
184 ICal::Component resource = entryBase(base, byUid.value(uid));
98 // A VTODO or VJOURNAL of the file belongs to no appointment.
99
1/1
✓ Branch 104 → 105 taken 184 times.
184 resource.removeComponents(QStringLiteral("VTODO"));
100
1/1
✓ Branch 110 → 111 taken 184 times.
184 resource.removeComponents(QStringLiteral("VJOURNAL"));
101
5/5
✓ Branch 114 → 115 taken 184 times.
✓ Branch 115 → 116 taken 184 times.
✓ Branch 118 → 119 taken 192 times.
✓ Branch 121 → 117 taken 192 times.
✓ Branch 121 → 122 taken 184 times.
376 for (const ICal::Component &vevent : byUid.value(uid)) resource.components.append(vevent);
102
1/1
✓ Branch 123 → 124 taken 184 times.
184 const QString resourceText = ICal::serialize(resource);
103
3/3
✓ Branch 124 → 125 taken 184 times.
✓ Branch 125 → 126 taken 1 time.
✓ Branch 125 → 128 taken 183 times.
184 if (!withinBudget(&used, resourceText, error)) return {};
104
1/1
✓ Branch 128 → 129 taken 183 times.
183 const ICalTime::ZoneResolver resolver(resource);
105 183 Entry entry;
106 183 entry.uid = uid;
107
4/4
✓ Branch 131 → 132 taken 183 times.
✓ Branch 132 → 133 taken 183 times.
✓ Branch 144 → 134 taken 191 times.
✓ Branch 144 → 145 taken 183 times.
374 for (const ICal::Component &vevent : byUid.value(uid)) {
108
1/1
✓ Branch 135 → 136 taken 191 times.
191 CalendarEvent row = ICalEventCodec::eventFromComponent(vevent, resolver);
109 191 row.resourceIcal = resourceText;
110 // The master leads the series.
111
4/4
✓ Branch 137 → 138 taken 191 times.
✓ Branch 138 → 139 taken 183 times.
✓ Branch 138 → 140 taken 8 times.
✓ Branch 139 → 141 taken 183 times.
191 if (!row.recurrenceId.isValid()) entry.rows.prepend(row);
112
1/1
✓ Branch 140 → 141 taken 8 times.
8 else entry.rows.append(row);
113 374 }
114
1/1
✓ Branch 146 → 147 taken 183 times.
183 entries.append(entry);
115 185 }
116
7/7
✓ Branch 161 → 162 taken 15 times.
✓ Branch 165 → 166 taken 15 times.
✓ Branch 166 → 167 taken 15 times.
✓ Branch 168 → 169 taken 15 times.
✓ Branch 169 → 170 taken 15 times.
✓ Branch 173 → 163 taken 15 times.
✓ Branch 173 → 174 taken 15 times.
30 qCInfo(lcIcsFile) << "Read" << entries.size() << "appointments from a calendar file";
117 15 return entries;
118 18 }
119
120 9 QByteArray write(const QList<QList<CalendarEvent>> &series) {
121 9 ICal::Component calendar;
122 9 calendar.name = QStringLiteral("VCALENDAR");
123 9 ICal::Property version;
124 9 version.name = QStringLiteral("VERSION");
125 9 version.value = QStringLiteral("2.0");
126 9 ICal::Property prodid;
127 9 prodid.name = QStringLiteral("PRODID");
128 9 prodid.value = QStringLiteral("-//MailJD//MailJD Calendar//EN");
129
1/1
✓ Branch 32 → 33 taken 9 times.
9 calendar.appendProperty(version);
130
1/1
✓ Branch 33 → 34 taken 9 times.
9 calendar.appendProperty(prodid);
131 9 QSet<QString> zones;
132 9 QList<ICal::Component> events;
133
2/2
✓ Branch 104 → 37 taken 14 times.
✓ Branch 104 → 105 taken 9 times.
23 for (const QList<CalendarEvent> &rows : series) {
134
1/2
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 14 times.
14 if (rows.isEmpty()) continue;
135 14 CalendarEvent master = rows.first();
136 14 QList<CalendarEvent> exceptions;
137
2/2
✓ Branch 52 → 45 taken 22 times.
✓ Branch 52 → 53 taken 14 times.
36 for (const CalendarEvent &row : rows) {
138
3/3
✓ Branch 46 → 47 taken 22 times.
✓ Branch 47 → 48 taken 14 times.
✓ Branch 47 → 49 taken 8 times.
22 if (!row.recurrenceId.isValid()) master = row;
139
1/1
✓ Branch 49 → 50 taken 8 times.
8 else exceptions.append(row);
140 }
141 const ICal::Component resource =
142
3/3
✓ Branch 56 → 57 taken 14 times.
✓ Branch 57 → 58 taken 14 times.
✓ Branch 58 → 59 taken 14 times.
14 ICal::parseFirst(QString::fromUtf8(ICalEventCodec::buildResource(master, exceptions, master.resourceIcal)));
143
2/2
✓ Branch 96 → 65 taken 23 times.
✓ Branch 96 → 97 taken 14 times.
37 for (const ICal::Component &component : resource.components) {
144
2/2
✓ Branch 68 → 69 taken 1 time.
✓ Branch 68 → 90 taken 22 times.
23 if (component.name == QLatin1String("VTIMEZONE")) {
145
3/3
✓ Branch 72 → 73 taken 1 time.
✓ Branch 73 → 74 taken 1 time.
✓ Branch 74 → 75 taken 1 time.
1 const QString tzid = ICal::unescapeText(component.value(QStringLiteral("TZID"))).trimmed();
146
1/2
✗ Branch 80 → 81 not taken.
✓ Branch 80 → 82 taken 1 time.
1 if (zones.contains(tzid)) continue;
147
1/1
✓ Branch 82 → 83 taken 1 time.
1 zones.insert(tzid);
148
1/1
✓ Branch 83 → 84 taken 1 time.
1 calendar.components.append(component);
149
2/4
✓ Branch 86 → 87 taken 1 time.
✗ Branch 86 → 89 not taken.
✓ Branch 92 → 93 taken 22 times.
✗ Branch 92 → 94 not taken.
23 } else if (component.name == QLatin1String("VEVENT")) {
150
1/1
✓ Branch 93 → 94 taken 22 times.
22 events.append(component);
151 }
152 }
153 14 }
154
1/1
✓ Branch 105 → 106 taken 9 times.
9 calendar.components.append(events);
155
2/2
✓ Branch 106 → 107 taken 9 times.
✓ Branch 107 → 108 taken 9 times.
18 return ICal::serialize(calendar).toUtf8();
156 9 }
157
158 11 QList<TodoEntry> readTodos(const QString &text, QString *error) {
159 11 QList<TodoEntry> entries;
160
3/3
✓ Branch 2 → 3 taken 11 times.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 6 taken 10 times.
11 if (!withinSize(text, error)) return entries;
161
1/1
✓ Branch 9 → 10 taken 10 times.
10 const ICal::Component calendar = ICal::parseFirst(text, QStringLiteral("VCALENDAR"), error);
162
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 16 taken 10 times.
10 if (calendar.name.isEmpty()) return entries;
163 10 ICal::Component base;
164 10 base.name = calendar.name;
165 10 base.properties = calendar.properties;
166
1/1
✓ Branch 21 → 22 taken 10 times.
10 base.removeProperties(QStringLiteral("METHOD"));
167
2/2
✓ Branch 33 → 26 taken 32 times.
✓ Branch 33 → 34 taken 10 times.
42 for (const ICal::Component &component : calendar.components)
168
3/3
✓ Branch 29 → 30 taken 2 times.
✓ Branch 29 → 31 taken 30 times.
✓ Branch 30 → 31 taken 2 times.
32 if (component.name == QLatin1String("VTIMEZONE")) base.components.append(component);
169 10 QStringList order;
170 10 QHash<QString, QList<ICal::Component>> byUid;
171
2/2
✓ Branch 93 → 36 taken 32 times.
✓ Branch 93 → 94 taken 10 times.
42 for (const ICal::Component &component : calendar.components) {
172
2/2
✓ Branch 39 → 40 taken 28 times.
✓ Branch 39 → 41 taken 4 times.
32 if (component.name != QLatin1String("VTODO")) continue;
173
3/3
✓ Branch 44 → 45 taken 4 times.
✓ Branch 45 → 46 taken 4 times.
✓ Branch 46 → 47 taken 4 times.
4 const QString uid = ICal::unescapeText(component.value(QStringLiteral("UID"))).trimmed();
174
1/2
✗ Branch 52 → 53 not taken.
✓ Branch 52 → 64 taken 4 times.
4 if (uid.isEmpty()) {
175 ✗ qCWarning(lcIcsFile) << "Skipping VTODO without UID";
176 ✗ continue;
177 ✗ }
178
1/2
✓ Branch 65 → 66 taken 4 times.
✗ Branch 65 → 82 not taken.
4 if (!byUid.contains(uid)) {
179
1/2
✗ Branch 67 → 68 not taken.
✓ Branch 67 → 81 taken 4 times.
4 if (order.size() == MaxEntries) {
180 ✗ qCWarning(lcIcsFile) << "Calendar file has more than" << MaxEntries << "tasks; the rest is skipped";
181 ✗ break;
182 }
183
1/1
✓ Branch 81 → 82 taken 4 times.
4 order.append(uid);
184 }
185
2/2
✓ Branch 82 → 83 taken 4 times.
✓ Branch 83 → 84 taken 4 times.
4 byUid[uid].append(component);
186 4 }
187 10 qint64 used = 0;
188
4/4
✓ Branch 94 → 95 taken 10 times.
✓ Branch 95 → 96 taken 10 times.
✓ Branch 131 → 97 taken 4 times.
✓ Branch 131 → 132 taken 10 times.
14 for (const QString &uid : order) {
189
1/1
✓ Branch 99 → 100 taken 4 times.
4 ICal::Component resource = entryBase(base, byUid.value(uid));
190
5/5
✓ Branch 102 → 103 taken 4 times.
✓ Branch 103 → 104 taken 4 times.
✓ Branch 106 → 107 taken 4 times.
✓ Branch 109 → 105 taken 4 times.
✓ Branch 109 → 110 taken 4 times.
8 for (const ICal::Component &vtodo : byUid.value(uid)) resource.components.append(vtodo);
191
1/1
✓ Branch 111 → 112 taken 4 times.
4 const QString resourceText = ICal::serialize(resource);
192
2/3
✓ Branch 112 → 113 taken 4 times.
✗ Branch 113 → 114 not taken.
✓ Branch 113 → 116 taken 4 times.
4 if (!withinBudget(&used, resourceText, error)) return {};
193 4 entries.append({uid, resourceText});
194 4 }
195
7/7
✓ Branch 132 → 133 taken 10 times.
✓ Branch 136 → 137 taken 10 times.
✓ Branch 137 → 138 taken 10 times.
✓ Branch 139 → 140 taken 10 times.
✓ Branch 140 → 141 taken 10 times.
✓ Branch 144 → 134 taken 10 times.
✓ Branch 144 → 145 taken 10 times.
20 qCInfo(lcIcsFile) << "Read" << entries.size() << "tasks from a calendar file";
196 10 return entries;
197 15 }
198
199 1 QByteArray writeTodos(const QStringList &resources) {
200 1 ICal::Component calendar;
201 1 calendar.name = QStringLiteral("VCALENDAR");
202 1 ICal::Property version;
203 1 version.name = QStringLiteral("VERSION");
204 1 version.value = QStringLiteral("2.0");
205 1 ICal::Property prodid;
206 1 prodid.name = QStringLiteral("PRODID");
207 1 prodid.value = QStringLiteral("-//MailJD//MailJD Tasks//EN");
208
1/1
✓ Branch 32 → 33 taken 1 time.
1 calendar.appendProperty(version);
209
1/1
✓ Branch 33 → 34 taken 1 time.
1 calendar.appendProperty(prodid);
210 1 QSet<QString> zones;
211 1 QList<ICal::Component> todos;
212
2/2
✓ Branch 81 → 37 taken 2 times.
✓ Branch 81 → 82 taken 1 time.
3 for (const QString &text : resources) {
213
1/1
✓ Branch 41 → 42 taken 2 times.
2 const ICal::Component resource = ICal::parseFirst(text, QStringLiteral("VCALENDAR"));
214
2/2
✓ Branch 77 → 46 taken 3 times.
✓ Branch 77 → 78 taken 2 times.
5 for (const ICal::Component &component : resource.components) {
215
2/2
✓ Branch 49 → 50 taken 1 time.
✓ Branch 49 → 71 taken 2 times.
3 if (component.name == QLatin1String("VTIMEZONE")) {
216
3/3
✓ Branch 53 → 54 taken 1 time.
✓ Branch 54 → 55 taken 1 time.
✓ Branch 55 → 56 taken 1 time.
1 const QString tzid = ICal::unescapeText(component.value(QStringLiteral("TZID"))).trimmed();
217
1/2
✗ Branch 61 → 62 not taken.
✓ Branch 61 → 63 taken 1 time.
1 if (zones.contains(tzid)) continue;
218
1/1
✓ Branch 63 → 64 taken 1 time.
1 zones.insert(tzid);
219
1/1
✓ Branch 64 → 65 taken 1 time.
1 calendar.components.append(component);
220
2/4
✓ Branch 67 → 68 taken 1 time.
✗ Branch 67 → 70 not taken.
✓ Branch 73 → 74 taken 2 times.
✗ Branch 73 → 75 not taken.
3 } else if (component.name == QLatin1String("VTODO")) {
221
1/1
✓ Branch 74 → 75 taken 2 times.
2 todos.append(component);
222 }
223 }
224 2 }
225
1/1
✓ Branch 82 → 83 taken 1 time.
1 calendar.components.append(todos);
226
2/2
✓ Branch 83 → 84 taken 1 time.
✓ Branch 84 → 85 taken 1 time.
2 return ICal::serialize(calendar).toUtf8();
227 1 }
228
229 12 QString fileName(const QString &title) {
230 12 QString name;
231
6/6
✓ Branch 2 → 3 taken 12 times.
✓ Branch 3 → 4 taken 12 times.
✓ Branch 5 → 6 taken 12 times.
✓ Branch 6 → 7 taken 12 times.
✓ Branch 25 → 8 taken 83 times.
✓ Branch 25 → 26 taken 12 times.
95 for (const QChar c : title.trimmed().left(80)) {
232
8/15
✓ Branch 9 → 10 taken 83 times.
✗ Branch 9 → 15 not taken.
✓ Branch 13 → 14 taken 83 times.
✓ Branch 14 → 15 taken 4 times.
✓ Branch 14 → 16 taken 79 times.
✓ Branch 17 → 18 taken 83 times.
✗ Branch 17 → 19 not taken.
✓ Branch 19 → 20 taken 83 times.
✗ Branch 19 → 21 not taken.
✓ Branch 21 → 22 taken 4 times.
✓ Branch 21 → 23 taken 79 times.
✗ Branch 65 → 66 not taken.
✗ Branch 65 → 67 not taken.
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 71 not taken.
166 if (c.category() == QChar::Other_Control || QStringLiteral("/\\:*?\"<>|").contains(c)) continue;
233
1/1
✓ Branch 23 → 24 taken 79 times.
79 name += c;
234 12 }
235 // No hidden files and no "..": leading dots go.
236
8/9
✓ Branch 28 → 29 taken 5 times.
✓ Branch 31 → 32 taken 17 times.
✓ Branch 32 → 33 taken 12 times.
✓ Branch 32 → 37 taken 5 times.
✓ Branch 35 → 36 taken 12 times.
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 38 taken 12 times.
✓ Branch 39 → 28 taken 5 times.
✓ Branch 39 → 40 taken 12 times.
17 while (name.startsWith(QLatin1Char('.')) || name.startsWith(QLatin1Char(' '))) name.remove(0, 1);
237
1/1
✓ Branch 40 → 41 taken 12 times.
12 name = name.trimmed();
238
5/7
✓ Branch 47 → 48 taken 2 times.
✓ Branch 47 → 51 taken 10 times.
✓ Branch 52 → 53 taken 12 times.
✓ Branch 55 → 56 taken 2 times.
✓ Branch 55 → 57 taken 10 times.
✗ Branch 83 → 84 not taken.
✗ Branch 83 → 85 not taken.
26 return (name.isEmpty() ? QStringLiteral("appointment") : name) + QStringLiteral(".ics");
239 12 }
240
241 } // namespace IcsFile
242