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: 99.5% 206 / 0 / 207
Functions: 100.0% 11 / 0 / 11
Branches: 73.1% 507 / 0 / 694

data/ICalTodoCodec.cpp
Line Branch Exec Source
1 #include "ICalTodoCodec.h"
2 #include "ICalEventCodec.h"
3 #include "util/MessageId.h"
4 #include <QLoggingCategory>
5 #include <QSet>
6 #include <algorithm>
7
8
3/7
✓ Branch 2 → 3 taken 2 times.
✗ Branch 2 → 8 not taken.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 2 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
2 Q_LOGGING_CATEGORY(lcTodoCodec, "mailjd.tasks.codec")
9 namespace ICalTodoCodec {
10 966 CalendarTask taskFromComponent(const ICal::Component &component, const ICalTime::ZoneResolver &resolver) {
11 966 CalendarTask task;
12
4/4
✓ Branch 3 → 4 taken 966 times.
✓ Branch 4 → 5 taken 966 times.
✓ Branch 5 → 6 taken 966 times.
✓ Branch 6 → 7 taken 966 times.
966 task.uid = ICal::unescapeText(component.value("UID")).trimmed();
13
3/3
✓ Branch 12 → 13 taken 966 times.
✓ Branch 13 → 14 taken 966 times.
✓ Branch 14 → 15 taken 966 times.
966 task.summary = ICal::unescapeText(component.value("SUMMARY"));
14
3/3
✓ Branch 19 → 20 taken 966 times.
✓ Branch 20 → 21 taken 966 times.
✓ Branch 21 → 22 taken 966 times.
966 task.description = ICal::unescapeText(component.value("DESCRIPTION"));
15
4/4
✓ Branch 26 → 27 taken 966 times.
✓ Branch 27 → 28 taken 966 times.
✓ Branch 28 → 29 taken 966 times.
✓ Branch 29 → 30 taken 966 times.
966 task.status = component.value("STATUS").trimmed().toUpper();
16
2/2
✓ Branch 36 → 37 taken 93 times.
✓ Branch 36 → 44 taken 873 times.
1059 if (task.status.isEmpty()) task.status = QStringLiteral("NEEDS-ACTION");
17
3/3
✓ Branch 44 → 45 taken 966 times.
✓ Branch 45 → 46 taken 966 times.
✓ Branch 46 → 47 taken 966 times.
966 task.priority = component.value("PRIORITY").toInt();
18
3/3
✓ Branch 49 → 50 taken 966 times.
✓ Branch 50 → 51 taken 966 times.
✓ Branch 51 → 52 taken 966 times.
966 task.percentComplete = component.value("PERCENT-COMPLETE").toInt();
19 4830 const auto date = [&](const QString &name, QDateTime *stamp, bool *dateOnly = nullptr) {
20
2/2
✓ Branch 3 → 4 taken 1943 times.
✓ Branch 3 → 10 taken 2887 times.
4830 if (const auto *property = component.property(name)) {
21
1/1
✓ Branch 4 → 5 taken 1943 times.
1943 const auto parsed = ICalTime::parseProperty(*property, resolver);
22 1943 *stamp = parsed.dateTime;
23
2/2
✓ Branch 6 → 7 taken 528 times.
✓ Branch 6 → 8 taken 1415 times.
1943 if (dateOnly) *dateOnly = parsed.dateOnly;
24 1943 }
25 4830 };
26
2/2
✓ Branch 54 → 55 taken 966 times.
✓ Branch 55 → 56 taken 966 times.
966 date("DUE", &task.due, &task.dueAllDay);
27
2/2
✓ Branch 57 → 58 taken 966 times.
✓ Branch 58 → 59 taken 966 times.
966 date("DTSTART", &task.dtStart, &task.startAllDay);
28
2/2
✓ Branch 60 → 61 taken 966 times.
✓ Branch 61 → 62 taken 966 times.
966 date("COMPLETED", &task.completedAt);
29
2/2
✓ Branch 63 → 64 taken 966 times.
✓ Branch 64 → 65 taken 966 times.
966 date("CREATED", &task.created);
30
2/2
✓ Branch 66 → 67 taken 966 times.
✓ Branch 67 → 68 taken 966 times.
966 date("LAST-MODIFIED", &task.lastModified);
31
4/4
✓ Branch 69 → 70 taken 966 times.
✓ Branch 70 → 71 taken 966 times.
✓ Branch 72 → 73 taken 95 times.
✓ Branch 72 → 94 taken 871 times.
966 if (const auto *organizer = component.property("ORGANIZER"))
32
14/19
✓ Branch 73 → 74 taken 95 times.
✓ Branch 74 → 75 taken 95 times.
✓ Branch 76 → 77 taken 3 times.
✓ Branch 76 → 83 taken 92 times.
✓ Branch 77 → 78 taken 3 times.
✓ Branch 78 → 79 taken 3 times.
✓ Branch 79 → 80 taken 3 times.
✗ Branch 79 → 81 not taken.
✓ Branch 82 → 85 taken 3 times.
✓ Branch 83 → 84 taken 92 times.
✓ Branch 84 → 85 taken 92 times.
✓ Branch 87 → 88 taken 92 times.
✓ Branch 87 → 89 taken 3 times.
✓ Branch 89 → 90 taken 3 times.
✓ Branch 89 → 91 taken 92 times.
✗ Branch 276 → 277 not taken.
✗ Branch 276 → 278 not taken.
✗ Branch 280 → 281 not taken.
✗ Branch 280 → 282 not taken.
95 task.organizer = organizer->parameter("CN").isEmpty() ? organizer->value.mid(organizer->value.startsWith("mailto:", Qt::CaseInsensitive) ? 7 : 0) : organizer->parameter("CN");
33
4/4
✓ Branch 94 → 95 taken 966 times.
✓ Branch 95 → 96 taken 966 times.
✓ Branch 96 → 97 taken 966 times.
✓ Branch 97 → 98 taken 966 times.
966 task.relatedMessageId = MessageId::canonicalFirst(ICal::unescapeText(component.value("X-MAILJD-MESSAGE-ID")));
34
2/2
✓ Branch 103 → 104 taken 966 times.
✓ Branch 104 → 105 taken 966 times.
966 task.rrule = component.value("RRULE");
35
6/6
✓ Branch 108 → 109 taken 966 times.
✓ Branch 109 → 110 taken 966 times.
✓ Branch 111 → 112 taken 966 times.
✓ Branch 112 → 113 taken 966 times.
✓ Branch 139 → 114 taken 184 times.
✓ Branch 139 → 140 taken 782 times.
966 for (const auto &property : component.propertiesNamed("RELATED-TO")) {
36
3/3
✓ Branch 115 → 116 taken 184 times.
✓ Branch 116 → 117 taken 184 times.
✓ Branch 117 → 118 taken 184 times.
184 const QString type = property.parameter("RELTYPE").toUpper();
37
4/6
✓ Branch 121 → 122 taken 168 times.
✓ Branch 121 → 125 taken 16 times.
✓ Branch 124 → 125 taken 168 times.
✗ Branch 124 → 126 not taken.
✓ Branch 127 → 128 taken 184 times.
✗ Branch 127 → 132 not taken.
184 if (type.isEmpty() || type == QLatin1String("PARENT")) {
38
1/1
✓ Branch 128 → 129 taken 184 times.
184 task.parentUid = ICal::unescapeText(property.value); break;
39 }
40 1150 }
41
6/6
✓ Branch 141 → 142 taken 966 times.
✓ Branch 142 → 143 taken 966 times.
✓ Branch 144 → 145 taken 966 times.
✓ Branch 145 → 146 taken 966 times.
✓ Branch 167 → 147 taken 274 times.
✓ Branch 167 → 168 taken 966 times.
1240 for (const auto &property : component.propertiesNamed("CATEGORIES"))
42
5/5
✓ Branch 148 → 149 taken 274 times.
✓ Branch 149 → 150 taken 274 times.
✓ Branch 150 → 151 taken 274 times.
✓ Branch 163 → 152 taken 399 times.
✓ Branch 163 → 164 taken 274 times.
673 for (const auto &value : ICal::splitValues(property.value))
43
4/5
✓ Branch 153 → 154 taken 399 times.
✓ Branch 156 → 157 taken 399 times.
✗ Branch 156 → 161 not taken.
✓ Branch 157 → 158 taken 399 times.
✓ Branch 158 → 159 taken 399 times.
1639 if (!task.tags.contains(ICal::unescapeText(value))) task.tags << ICal::unescapeText(value);
44
4/4
✓ Branch 169 → 170 taken 966 times.
✓ Branch 170 → 171 taken 966 times.
✓ Branch 171 → 172 taken 966 times.
✓ Branch 172 → 173 taken 966 times.
966 task.sortOrder = std::clamp(component.value("X-APPLE-SORT-ORDER").toLongLong(), -kTaskSortOrderLimit,
45 kTaskSortOrderLimit);
46
2/2
✓ Branch 175 → 176 taken 966 times.
✓ Branch 176 → 177 taken 966 times.
966 task.previousStatus = component.value("X-MAILJD-PREVIOUS-STATUS");
47
3/3
✓ Branch 180 → 181 taken 966 times.
✓ Branch 181 → 182 taken 966 times.
✓ Branch 182 → 183 taken 966 times.
966 task.previousPercent = component.value("X-MAILJD-PREVIOUS-PERCENT").toInt();
48
1/1
✓ Branch 185 → 186 taken 966 times.
966 const QDateTime anchor = task.dtStart.isValid()
49
3/5
✓ Branch 186 → 187 taken 119 times.
✓ Branch 186 → 192 taken 847 times.
✗ Branch 187 → 188 not taken.
✓ Branch 187 → 191 taken 119 times.
✗ Branch 188 → 189 not taken.
966 ? task.startAllDay ? QDateTime(task.dtStart.date(),QTime(0,0)) : task.dtStart
50
5/7
✗ Branch 189 → 190 not taken.
✗ Branch 190 → 197 not taken.
✓ Branch 192 → 193 taken 117 times.
✓ Branch 192 → 196 taken 730 times.
✓ Branch 193 → 194 taken 117 times.
✓ Branch 194 → 195 taken 117 times.
✓ Branch 195 → 197 taken 117 times.
966 : task.dueAllDay ? QDateTime(task.due.date(),QTime(0,0)) : task.due;
51
5/5
✓ Branch 197 → 198 taken 162 times.
✓ Branch 197 → 201 taken 804 times.
✓ Branch 198 → 199 taken 162 times.
✓ Branch 199 → 200 taken 162 times.
✓ Branch 200 → 202 taken 162 times.
966 const QDateTime end = task.dueAllDay ? QDateTime(task.due.date(),QTime(0,0)) : task.due;
52
1/1
✓ Branch 202 → 203 taken 966 times.
966 task.alarmTimes = ICalEventCodec::alarmTimes(component, anchor, end, resolver);
53
1/1
✓ Branch 205 → 206 taken 966 times.
966 task.icalRaw = ICal::serialize(component);
54 966 return task;
55 966 }
56
57 908 bool parseResource(const QString &text, Resource *resource, QString *error) {
58
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 908 times.
908 if (!resource) return false;
59
1/1
✓ Branch 7 → 8 taken 908 times.
908 resource->calendar = ICal::parseFirst(text, QStringLiteral("VCALENDAR"), error);
60
1/1
✓ Branch 12 → 13 taken 908 times.
908 resource->tasks.clear();
61
2/2
✓ Branch 14 → 15 taken 2 times.
✓ Branch 14 → 16 taken 906 times.
908 if (resource->calendar.name.isEmpty()) return false;
62
1/1
✓ Branch 16 → 17 taken 906 times.
906 const ICalTime::ZoneResolver resolver(resource->calendar);
63
6/6
✓ Branch 17 → 18 taken 906 times.
✓ Branch 18 → 19 taken 906 times.
✓ Branch 20 → 21 taken 906 times.
✓ Branch 21 → 22 taken 906 times.
✓ Branch 48 → 23 taken 341 times.
✓ Branch 48 → 49 taken 906 times.
1247 for (const auto &component : resource->calendar.componentsNamed("VTODO")) {
64
1/1
✓ Branch 24 → 25 taken 341 times.
341 auto task = taskFromComponent(component, resolver);
65
7/7
✓ Branch 26 → 27 taken 1 time.
✓ Branch 26 → 38 taken 340 times.
✓ Branch 27 → 28 taken 1 time.
✓ Branch 31 → 32 taken 1 time.
✓ Branch 32 → 33 taken 1 time.
✓ Branch 36 → 29 taken 1 time.
✓ Branch 36 → 37 taken 1 time.
342 if (task.uid.isEmpty()) { qCWarning(lcTodoCodec) << "Skipping VTODO without UID"; continue; }
66 340 task.resourceIcal = text;
67
1/1
✓ Branch 39 → 40 taken 340 times.
340 resource->tasks << task;
68 1247 }
69 906 return true;
70 906 }
71
72 namespace {
73 1378 bool sameDate(const QDateTime &a, bool aDate, const QDateTime &b, bool bDate) {
74
6/6
✓ Branch 2 → 3 taken 1360 times.
✓ Branch 2 → 6 taken 18 times.
✓ Branch 5 → 6 taken 33 times.
✓ Branch 5 → 7 taken 1327 times.
✓ Branch 8 → 9 taken 51 times.
✓ Branch 8 → 10 taken 1327 times.
1378 if (aDate != bDate || a.isValid() != b.isValid()) return false;
75
2/2
✓ Branch 11 → 12 taken 1087 times.
✓ Branch 11 → 13 taken 240 times.
1327 if (!a.isValid()) return true;
76
14/19
✓ Branch 13 → 14 taken 76 times.
✓ Branch 13 → 18 taken 164 times.
✓ Branch 14 → 15 taken 76 times.
✓ Branch 15 → 16 taken 76 times.
✓ Branch 18 → 19 taken 164 times.
✓ Branch 19 → 20 taken 150 times.
✓ Branch 19 → 25 taken 14 times.
✓ Branch 20 → 21 taken 150 times.
✓ Branch 21 → 22 taken 150 times.
✓ Branch 23 → 24 taken 150 times.
✗ Branch 23 → 25 not taken.
✓ Branch 28 → 29 taken 150 times.
✓ Branch 28 → 30 taken 90 times.
✓ Branch 30 → 31 taken 150 times.
✓ Branch 30 → 32 taken 90 times.
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 36 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 40 not taken.
240 return aDate ? a.date() == b.date() : a == b && ICalTime::zoneId(a, false) == ICalTime::zoneId(b, false);
77 }
78 579 void writeDate(ICal::Component *component, const QString &name, const QDateTime &stamp,
79 bool dateOnly, const ICalTime::ZoneResolver &resolver) {
80
4/4
✓ Branch 2 → 3 taken 579 times.
✓ Branch 3 → 4 taken 380 times.
✓ Branch 3 → 6 taken 199 times.
✓ Branch 4 → 5 taken 380 times.
579 if (!stamp.isValid()) { component->removeProperties(name); return; }
81 199 ICal::Property property;
82
3/3
✓ Branch 6 → 7 taken 199 times.
✓ Branch 7 → 8 taken 9 times.
✓ Branch 7 → 9 taken 190 times.
199 if (const auto *existing = component->property(name)) property = *existing;
83 199 property.name = name;
84 199 QString tzid;
85
3/3
✓ Branch 10 → 11 taken 199 times.
✓ Branch 11 → 12 taken 35 times.
✓ Branch 11 → 38 taken 164 times.
199 if (stamp.timeSpec() == Qt::TimeZone) {
86
2/2
✓ Branch 12 → 13 taken 35 times.
✓ Branch 13 → 14 taken 35 times.
35 tzid = property.parameter("TZID");
87
15/19
✓ Branch 18 → 19 taken 5 times.
✓ Branch 18 → 23 taken 30 times.
✓ Branch 19 → 20 taken 5 times.
✓ Branch 20 → 21 taken 5 times.
✓ Branch 22 → 23 taken 1 time.
✓ Branch 22 → 24 taken 4 times.
✓ Branch 25 → 26 taken 5 times.
✓ Branch 25 → 27 taken 30 times.
✓ Branch 27 → 28 taken 5 times.
✓ Branch 27 → 29 taken 30 times.
✓ Branch 29 → 30 taken 31 times.
✓ Branch 29 → 38 taken 4 times.
✓ Branch 30 → 31 taken 31 times.
✓ Branch 31 → 32 taken 31 times.
✓ Branch 32 → 33 taken 31 times.
✗ Branch 49 → 50 not taken.
✗ Branch 49 → 51 not taken.
✗ Branch 53 → 54 not taken.
✗ Branch 53 → 55 not taken.
35 if (tzid.isEmpty() || resolver.resolve(tzid) != stamp.timeZone()) tzid = QString::fromUtf8(stamp.timeZone().id());
88 }
89
1/1
✓ Branch 38 → 39 taken 199 times.
199 ICalTime::writeProperty(&property, stamp, dateOnly, tzid);
90
1/1
✓ Branch 39 → 40 taken 199 times.
199 component->setProperty(property);
91 199 }
92 }
93
94 365 ICal::Component taskComponent(const CalendarTask &task, const ICalTime::ZoneResolver &resolver) {
95 365 ICal::Component component;
96
2/2
✓ Branch 3 → 4 taken 228 times.
✓ Branch 3 → 15 taken 137 times.
365 if (!task.icalRaw.isEmpty()) {
97
1/1
✓ Branch 7 → 8 taken 228 times.
228 component = ICal::parseFirst(task.icalRaw, QStringLiteral("VTODO"));
98 // Never replace an unreadable remote resource with a partial fresh one.
99
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 228 times.
228 if (component.name.isEmpty()) return {};
100 }
101 365 const bool fresh = component.name.isEmpty();
102
3/63
✓ Branch 16 → 17 taken 137 times.
✓ Branch 16 → 23 taken 228 times.
✓ Branch 23 → 24 taken 228 times.
✗ Branch 349 → 350 not taken.
✗ Branch 349 → 352 not taken.
✗ Branch 350 → 351 not taken.
✗ Branch 350 → 352 not taken.
✗ Branch 353 → 354 not taken.
✗ Branch 353 → 356 not taken.
✗ Branch 354 → 355 not taken.
✗ Branch 354 → 356 not taken.
✗ Branch 357 → 358 not taken.
✗ Branch 357 → 360 not taken.
✗ Branch 358 → 359 not taken.
✗ Branch 358 → 360 not taken.
✗ Branch 361 → 362 not taken.
✗ Branch 361 → 364 not taken.
✗ Branch 362 → 363 not taken.
✗ Branch 362 → 364 not taken.
✗ Branch 365 → 366 not taken.
✗ Branch 365 → 368 not taken.
✗ Branch 366 → 367 not taken.
✗ Branch 366 → 368 not taken.
✗ Branch 369 → 370 not taken.
✗ Branch 369 → 372 not taken.
✗ Branch 370 → 371 not taken.
✗ Branch 370 → 372 not taken.
✗ Branch 373 → 374 not taken.
✗ Branch 373 → 376 not taken.
✗ Branch 374 → 375 not taken.
✗ Branch 374 → 376 not taken.
✗ Branch 377 → 378 not taken.
✗ Branch 377 → 380 not taken.
✗ Branch 378 → 379 not taken.
✗ Branch 378 → 380 not taken.
✗ Branch 381 → 382 not taken.
✗ Branch 381 → 384 not taken.
✗ Branch 382 → 383 not taken.
✗ Branch 382 → 384 not taken.
✗ Branch 385 → 386 not taken.
✗ Branch 385 → 388 not taken.
✗ Branch 386 → 387 not taken.
✗ Branch 386 → 388 not taken.
✗ Branch 389 → 390 not taken.
✗ Branch 389 → 392 not taken.
✗ Branch 390 → 391 not taken.
✗ Branch 390 → 392 not taken.
✗ Branch 393 → 394 not taken.
✗ Branch 393 → 396 not taken.
✗ Branch 394 → 395 not taken.
✗ Branch 394 → 396 not taken.
✗ Branch 397 → 398 not taken.
✗ Branch 397 → 400 not taken.
✗ Branch 398 → 399 not taken.
✗ Branch 398 → 400 not taken.
✗ Branch 401 → 402 not taken.
✗ Branch 401 → 404 not taken.
✗ Branch 402 → 403 not taken.
✗ Branch 402 → 404 not taken.
✗ Branch 405 → 406 not taken.
✗ Branch 405 → 408 not taken.
✗ Branch 406 → 407 not taken.
✗ Branch 406 → 408 not taken.
365 const auto before = fresh ? CalendarTask{} : taskFromComponent(component, resolver);
103
5/5
✓ Branch 24 → 25 taken 137 times.
✓ Branch 24 → 37 taken 228 times.
✓ Branch 31 → 32 taken 137 times.
✓ Branch 32 → 33 taken 137 times.
✓ Branch 33 → 34 taken 137 times.
502 if (fresh) { component.name = QStringLiteral("VTODO"); component.setPropertyValue("UID", ICal::escapeText(task.uid)); }
104 365 bool changed = fresh;
105 365 bool significant = false;
106 3068 const auto text = [&](const QString &name, const QString &oldValue, const QString &value, bool escaped = true) {
107
6/6
✓ Branch 2 → 3 taken 2060 times.
✓ Branch 2 → 6 taken 1008 times.
✓ Branch 4 → 5 taken 1886 times.
✓ Branch 4 → 6 taken 174 times.
✓ Branch 7 → 8 taken 1886 times.
✓ Branch 7 → 9 taken 1182 times.
3068 if (!fresh && oldValue == value) return;
108
2/2
✓ Branch 10 → 11 taken 487 times.
✓ Branch 10 → 12 taken 695 times.
1182 if (value.isEmpty()) component.removeProperties(name);
109
6/6
✓ Branch 13 → 14 taken 283 times.
✓ Branch 13 → 20 taken 412 times.
✓ Branch 14 → 15 taken 258 times.
✓ Branch 14 → 16 taken 25 times.
✓ Branch 15 → 17 taken 258 times.
✓ Branch 17 → 18 taken 283 times.
695 else if (auto *existing = component.property(name)) existing->setValue(escaped ? ICal::escapeText(value) : value);
110
4/4
✓ Branch 20 → 21 taken 355 times.
✓ Branch 20 → 22 taken 57 times.
✓ Branch 21 → 23 taken 355 times.
✓ Branch 23 → 24 taken 412 times.
412 else component.setPropertyValue(name, escaped ? ICal::escapeText(value) : value);
111 1182 changed = true;
112 365 };
113
2/2
✓ Branch 37 → 38 taken 365 times.
✓ Branch 38 → 39 taken 365 times.
365 text("SUMMARY", before.summary, task.summary);
114
2/2
✓ Branch 40 → 41 taken 365 times.
✓ Branch 41 → 42 taken 365 times.
365 text("DESCRIPTION", before.description, task.description);
115
2/2
✓ Branch 43 → 44 taken 365 times.
✓ Branch 44 → 45 taken 365 times.
365 text("X-MAILJD-MESSAGE-ID", before.relatedMessageId, task.relatedMessageId);
116
2/2
✓ Branch 46 → 47 taken 365 times.
✓ Branch 47 → 48 taken 365 times.
365 text("UID", before.uid, task.uid);
117
2/2
✓ Branch 49 → 50 taken 365 times.
✓ Branch 50 → 51 taken 365 times.
365 text("STATUS", before.status, task.status);
118 365 significant |= before.status != task.status;
119
8/8
✓ Branch 53 → 54 taken 137 times.
✓ Branch 53 → 55 taken 228 times.
✓ Branch 54 → 55 taken 14 times.
✓ Branch 54 → 63 taken 123 times.
✓ Branch 55 → 56 taken 242 times.
✓ Branch 56 → 57 taken 242 times.
✓ Branch 57 → 58 taken 242 times.
✓ Branch 58 → 59 taken 242 times.
365 if (!fresh || task.priority > 0) text("PRIORITY", QString::number(before.priority), QString::number(task.priority), false);
120
8/8
✓ Branch 63 → 64 taken 137 times.
✓ Branch 63 → 65 taken 228 times.
✓ Branch 64 → 65 taken 23 times.
✓ Branch 64 → 73 taken 114 times.
✓ Branch 65 → 66 taken 251 times.
✓ Branch 66 → 67 taken 251 times.
✓ Branch 67 → 68 taken 251 times.
✓ Branch 68 → 69 taken 251 times.
365 if (!fresh || task.percentComplete > 0) text("PERCENT-COMPLETE", QString::number(before.percentComplete), QString::number(task.percentComplete), false);
121
2/2
✓ Branch 73 → 74 taken 365 times.
✓ Branch 74 → 75 taken 365 times.
365 text("X-MAILJD-PREVIOUS-STATUS", before.previousStatus, task.previousStatus);
122
2/2
✓ Branch 76 → 77 taken 15 times.
✓ Branch 76 → 85 taken 350 times.
365 if (before.previousPercent != task.previousPercent)
123
3/3
✓ Branch 77 → 78 taken 15 times.
✓ Branch 79 → 80 taken 15 times.
✓ Branch 80 → 81 taken 15 times.
15 text("X-MAILJD-PREVIOUS-PERCENT", {}, QString::number(task.previousPercent), false);
124 1232 const auto date = [&](const QString &name, const QDateTime &oldStamp, bool oldDate, const QDateTime &stamp, bool dateOnly) {
125
6/6
✓ Branch 2 → 3 taken 684 times.
✓ Branch 2 → 6 taken 548 times.
✓ Branch 4 → 5 taken 653 times.
✓ Branch 4 → 6 taken 31 times.
✓ Branch 7 → 8 taken 653 times.
✓ Branch 7 → 9 taken 579 times.
1232 if (!fresh && sameDate(oldStamp, oldDate, stamp, dateOnly)) return;
126 579 writeDate(&component, name, stamp, dateOnly, resolver); changed = true;
127
6/6
✓ Branch 12 → 13 taken 432 times.
✓ Branch 12 → 16 taken 147 times.
✓ Branch 15 → 16 taken 137 times.
✓ Branch 15 → 17 taken 295 times.
✓ Branch 18 → 19 taken 284 times.
✓ Branch 18 → 20 taken 295 times.
579 if (name == QLatin1String("DUE") || name == QLatin1String("DTSTART")) significant = true;
128 365 };
129
2/2
✓ Branch 85 → 86 taken 365 times.
✓ Branch 86 → 87 taken 365 times.
365 date("DUE", before.due, before.dueAllDay, task.due, task.dueAllDay);
130
2/2
✓ Branch 88 → 89 taken 365 times.
✓ Branch 89 → 90 taken 365 times.
365 date("DTSTART", before.dtStart, before.startAllDay, task.dtStart, task.startAllDay);
131
2/2
✓ Branch 91 → 92 taken 365 times.
✓ Branch 92 → 93 taken 365 times.
365 date("COMPLETED", before.completedAt, false, task.completedAt, false);
132
8/8
✓ Branch 94 → 95 taken 137 times.
✓ Branch 94 → 106 taken 228 times.
✓ Branch 95 → 96 taken 137 times.
✓ Branch 96 → 97 taken 17 times.
✓ Branch 96 → 98 taken 120 times.
✓ Branch 98 → 99 taken 120 times.
✓ Branch 100 → 101 taken 137 times.
✓ Branch 101 → 102 taken 137 times.
365 if (fresh) date("CREATED", {}, false, task.created.isValid() ? task.created : QDateTime::currentDateTimeUtc(), false);
133
2/2
✓ Branch 106 → 107 taken 365 times.
✓ Branch 107 → 108 taken 365 times.
365 text("RRULE", before.rrule, task.rrule, false);
134 365 significant |= before.rrule != task.rrule;
135
2/2
✓ Branch 111 → 112 taken 6 times.
✓ Branch 111 → 169 taken 359 times.
365 if (before.parentUid != task.parentUid) {
136 6 auto properties = component.properties;
137
1/1
✓ Branch 113 → 114 taken 6 times.
6 component.properties.clear();
138
4/4
✓ Branch 114 → 115 taken 6 times.
✓ Branch 115 → 116 taken 6 times.
✓ Branch 147 → 117 taken 53 times.
✓ Branch 147 → 148 taken 6 times.
59 for (const auto &property : properties)
139
2/2
✓ Branch 120 → 121 taken 1 time.
✓ Branch 120 → 131 taken 52 times.
54 if (property.name != QLatin1String("RELATED-TO") ||
140
19/31
✓ Branch 121 → 122 taken 1 time.
✓ Branch 122 → 123 taken 1 time.
✓ Branch 124 → 125 taken 1 time.
✗ Branch 124 → 132 not taken.
✓ Branch 126 → 127 taken 1 time.
✓ Branch 127 → 128 taken 1 time.
✓ Branch 128 → 129 taken 1 time.
✗ Branch 130 → 131 not taken.
✓ Branch 130 → 132 taken 1 time.
✓ Branch 133 → 134 taken 1 time.
✓ Branch 133 → 135 taken 52 times.
✓ Branch 135 → 136 taken 1 time.
✓ Branch 135 → 137 taken 52 times.
✓ Branch 137 → 138 taken 1 time.
✓ Branch 137 → 139 taken 52 times.
✓ Branch 139 → 140 taken 1 time.
✓ Branch 139 → 141 taken 52 times.
✓ Branch 141 → 142 taken 1 time.
✓ Branch 141 → 143 taken 52 times.
✓ Branch 143 → 144 taken 52 times.
✓ Branch 143 → 145 taken 1 time.
✗ Branch 481 → 482 not taken.
✗ Branch 481 → 483 not taken.
✗ Branch 485 → 486 not taken.
✗ Branch 485 → 487 not taken.
✗ Branch 489 → 490 not taken.
✗ Branch 489 → 491 not taken.
✗ Branch 494 → 495 not taken.
✗ Branch 494 → 496 not taken.
✗ Branch 498 → 499 not taken.
✗ Branch 498 → 500 not taken.
54 (!property.parameter("RELTYPE").isEmpty() && property.parameter("RELTYPE").toUpper() != QLatin1String("PARENT")))
141
1/1
✓ Branch 144 → 145 taken 52 times.
52 component.properties << property;
142
2/2
✓ Branch 149 → 150 taken 5 times.
✓ Branch 149 → 167 taken 1 time.
6 if (!task.parentUid.isEmpty()) {
143
1/1
✓ Branch 156 → 157 taken 5 times.
10 ICal::Property parent; parent.name = QStringLiteral("RELATED-TO"); parent.value = ICal::escapeText(task.parentUid);
144
4/4
✓ Branch 159 → 160 taken 5 times.
✓ Branch 160 → 161 taken 5 times.
✓ Branch 161 → 162 taken 5 times.
✓ Branch 164 → 165 taken 5 times.
5 parent.setParameter("RELTYPE", "PARENT"); component.appendProperty(parent);
145 5 }
146 6 changed = true;
147 6 }
148
3/3
✓ Branch 169 → 170 taken 365 times.
✓ Branch 170 → 171 taken 2 times.
✓ Branch 170 → 194 taken 363 times.
365 if (before.tags != task.tags) {
149
2/2
✓ Branch 171 → 172 taken 2 times.
✓ Branch 172 → 173 taken 2 times.
2 component.removeProperties("CATEGORIES"); QStringList values;
150
4/4
✓ Branch 177 → 178 taken 2 times.
✓ Branch 178 → 179 taken 2 times.
✓ Branch 182 → 176 taken 2 times.
✓ Branch 182 → 183 taken 2 times.
4 for (const auto &tag : task.tags) values << ICal::escapeText(tag);
151
4/5
✓ Branch 184 → 185 taken 2 times.
✗ Branch 184 → 192 not taken.
✓ Branch 186 → 187 taken 2 times.
✓ Branch 187 → 188 taken 2 times.
✓ Branch 188 → 189 taken 2 times.
2 if (!values.isEmpty()) component.setPropertyValue("CATEGORIES", values.join(','));
152 2 changed = true;
153 2 }
154
5/5
✓ Branch 194 → 195 taken 5 times.
✓ Branch 194 → 203 taken 360 times.
✓ Branch 195 → 196 taken 5 times.
✓ Branch 197 → 198 taken 5 times.
✓ Branch 198 → 199 taken 5 times.
365 if (before.sortOrder != task.sortOrder) text("X-APPLE-SORT-ORDER", {}, QString::number(task.sortOrder), false);
155 // F-25 (SPRINT-104): an untouched relative reminder follows its anchor.
156 // When DUE or DTSTART changed and the task still carries the alarm
157 // times derived from the OLD anchor, re-derive them from the updated
158 // component: the relative trigger ("15 minutes before") keeps its
159 // meaning and stays relative, instead of being frozen as an absolute
160 // stamp on the old day (reproduced: due moved a week ahead, the alarm
161 // stayed at the old 08:45 and was written as TRIGGER;VALUE=DATE-TIME).
162 const bool anchorChanged =
163
3/3
✓ Branch 203 → 204 taken 365 times.
✓ Branch 204 → 205 taken 329 times.
✓ Branch 204 → 207 taken 36 times.
694 !sameDate(before.due, before.dueAllDay, task.due, task.dueAllDay) ||
164
2/3
✓ Branch 205 → 206 taken 329 times.
✗ Branch 206 → 207 not taken.
✓ Branch 206 → 208 taken 329 times.
329 !sameDate(before.dtStart, before.startAllDay, task.dtStart, task.startAllDay);
165 const QList<QDateTime> alarms =
166
3/3
✓ Branch 210 → 211 taken 36 times.
✓ Branch 211 → 212 taken 32 times.
✓ Branch 211 → 214 taken 4 times.
36 (anchorChanged && task.alarmTimes == before.alarmTimes)
167
3/5
✓ Branch 212 → 213 taken 32 times.
✓ Branch 215 → 216 taken 32 times.
✓ Branch 215 → 217 taken 333 times.
✗ Branch 543 → 544 not taken.
✗ Branch 543 → 545 not taken.
397 ? taskFromComponent(component, resolver).alarmTimes
168
2/2
✓ Branch 209 → 210 taken 36 times.
✓ Branch 209 → 214 taken 329 times.
401 : task.alarmTimes;
169
4/4
✓ Branch 217 → 218 taken 365 times.
✓ Branch 218 → 219 taken 365 times.
✓ Branch 220 → 221 taken 4 times.
✓ Branch 220 → 298 taken 361 times.
365 if (taskFromComponent(component, resolver).alarmTimes != alarms) {
170 4 QList<ICal::Component> kept;
171
3/4
✓ Branch 221 → 222 taken 4 times.
✓ Branch 222 → 223 taken 4 times.
✗ Branch 252 → 224 not taken.
✓ Branch 252 → 253 taken 4 times.
4 for (const auto &child : component.components)
172 ✗ if (child.name != QLatin1String("VALARM") || !QStringList{"DISPLAY", "AUDIO", ""}.contains(child.value("ACTION"))) kept << child;
173 4 component.components = kept;
174
2/2
✓ Branch 295 → 256 taken 5 times.
✓ Branch 295 → 296 taken 4 times.
9 for (const auto &stamp : alarms) {
175 10 ICal::Component alarm; alarm.name = QStringLiteral("VALARM");
176
6/6
✓ Branch 263 → 264 taken 5 times.
✓ Branch 264 → 265 taken 5 times.
✓ Branch 265 → 266 taken 5 times.
✓ Branch 268 → 269 taken 5 times.
✓ Branch 269 → 270 taken 5 times.
✓ Branch 270 → 271 taken 5 times.
5 alarm.setPropertyValue("ACTION", "DISPLAY"); alarm.setPropertyValue("DESCRIPTION", ICal::escapeText(task.summary));
177
3/3
✓ Branch 279 → 280 taken 5 times.
✓ Branch 280 → 281 taken 5 times.
✓ Branch 281 → 282 taken 5 times.
10 ICal::Property trigger; trigger.name = QStringLiteral("TRIGGER"); trigger.setParameter("VALUE", "DATE-TIME");
178
3/3
✓ Branch 284 → 285 taken 5 times.
✓ Branch 285 → 286 taken 5 times.
✓ Branch 289 → 290 taken 5 times.
5 trigger.value = ICalTime::formatValue(stamp.toUTC(), false); alarm.appendProperty(trigger);
179
1/1
✓ Branch 290 → 291 taken 5 times.
5 component.components << alarm;
180 5 }
181 4 changed = true;
182 4 }
183
10/12
✓ Branch 298 → 299 taken 99 times.
✓ Branch 298 → 302 taken 266 times.
✓ Branch 299 → 300 taken 99 times.
✓ Branch 300 → 301 taken 99 times.
✓ Branch 301 → 302 taken 8 times.
✓ Branch 301 → 303 taken 91 times.
✓ Branch 304 → 305 taken 99 times.
✓ Branch 304 → 306 taken 266 times.
✓ Branch 306 → 307 taken 274 times.
✓ Branch 306 → 336 taken 91 times.
✗ Branch 607 → 608 not taken.
✗ Branch 607 → 609 not taken.
365 if (changed || !component.hasProperty("DTSTAMP")) {
184
2/2
✓ Branch 307 → 308 taken 274 times.
✓ Branch 308 → 309 taken 274 times.
274 const QString now = ICalTime::formatValue(QDateTime::currentDateTimeUtc(), false);
185
4/4
✓ Branch 310 → 311 taken 274 times.
✓ Branch 311 → 312 taken 274 times.
✓ Branch 313 → 314 taken 274 times.
✓ Branch 314 → 315 taken 274 times.
274 component.setPropertyValue("DTSTAMP", now); component.setPropertyValue("LAST-MODIFIED", now);
186
16/20
✓ Branch 316 → 317 taken 137 times.
✓ Branch 316 → 318 taken 137 times.
✓ Branch 317 → 318 taken 33 times.
✓ Branch 317 → 334 taken 104 times.
✓ Branch 318 → 319 taken 137 times.
✓ Branch 318 → 320 taken 33 times.
✓ Branch 320 → 321 taken 33 times.
✓ Branch 321 → 322 taken 33 times.
✓ Branch 322 → 323 taken 33 times.
✓ Branch 324 → 325 taken 170 times.
✓ Branch 325 → 326 taken 170 times.
✓ Branch 326 → 327 taken 170 times.
✓ Branch 329 → 330 taken 33 times.
✓ Branch 329 → 331 taken 137 times.
✓ Branch 331 → 332 taken 33 times.
✓ Branch 331 → 333 taken 137 times.
✗ Branch 625 → 626 not taken.
✗ Branch 625 → 627 not taken.
✗ Branch 629 → 630 not taken.
✗ Branch 629 → 631 not taken.
274 if (fresh || significant) component.setPropertyValue("SEQUENCE", QString::number(fresh ? 0 : component.value("SEQUENCE").toInt() + 1));
187 274 }
188 365 return component;
189 365 }
190
191 366 QByteArray buildResource(const CalendarTask &task) {
192 366 ICal::Component calendar;
193
2/2
✓ Branch 3 → 4 taken 180 times.
✓ Branch 3 → 44 taken 186 times.
366 if (!task.resourceIcal.isEmpty()) {
194 // S106-148 (Sprint 97 writer guard): lines the parser skipped would be
195 // missing from the rewritten resource and so deleted on the server.
196 180 QList<ICal::Component> parsed;
197 180 int skipped = 0;
198
2/3
✓ Branch 4 → 5 taken 180 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 8 taken 180 times.
180 if (!ICal::parse(task.resourceIcal, &parsed, nullptr, &skipped)) return {};
199
2/2
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 23 taken 179 times.
180 if (skipped > 0) {
200
7/7
✓ Branch 9 → 10 taken 1 time.
✓ Branch 13 → 14 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 20 → 11 taken 1 time.
✓ Branch 20 → 21 taken 1 time.
2 qCWarning(lcTodoCodec) << "Task resource has" << skipped << "unreadable lines; not rewritten";
201 1 return {};
202 }
203
3/4
✓ Branch 23 → 24 taken 179 times.
✓ Branch 24 → 25 taken 179 times.
✓ Branch 33 → 26 taken 179 times.
✗ Branch 33 → 34 not taken.
179 for (const auto &component : parsed)
204
1/2
✓ Branch 29 → 30 taken 179 times.
✗ Branch 29 → 31 not taken.
179 if (component.name == QLatin1String("VCALENDAR")) { calendar = component; break; }
205
1/2
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 38 taken 179 times.
179 if (calendar.name.isEmpty()) return {};
206 180 }
207
2/2
✓ Branch 45 → 46 taken 186 times.
✓ Branch 45 → 63 taken 179 times.
365 if (calendar.name.isEmpty()) {
208
3/3
✓ Branch 52 → 53 taken 186 times.
✓ Branch 53 → 54 taken 186 times.
✓ Branch 54 → 55 taken 186 times.
186 calendar.name = QStringLiteral("VCALENDAR"); calendar.setPropertyValue("VERSION", "2.0");
209
3/3
✓ Branch 57 → 58 taken 186 times.
✓ Branch 58 → 59 taken 186 times.
✓ Branch 59 → 60 taken 186 times.
186 calendar.setPropertyValue("PRODID", "-//MailJD//CalDAV Client//EN");
210 }
211
1/1
✓ Branch 63 → 64 taken 365 times.
365 const ICalTime::ZoneResolver resolver(calendar);
212
1/1
✓ Branch 64 → 65 taken 365 times.
365 const auto todo = taskComponent(task, resolver);
213
1/2
✗ Branch 66 → 67 not taken.
✓ Branch 66 → 68 taken 365 times.
365 if (todo.name.isEmpty()) return {};
214 365 bool replaced = false;
215 // S106-959: compare the UID the way the parser derived task.uid (unescaped,
216 // trimmed); the raw escaped text never matched a UID with , ; \ or a line
217 // break, and every save appended another master VTODO.
218
4/4
✓ Branch 68 → 69 taken 365 times.
✓ Branch 69 → 70 taken 365 times.
✓ Branch 101 → 71 taken 180 times.
✓ Branch 101 → 102 taken 186 times.
366 for (auto &child : calendar.components)
219
12/24
✓ Branch 74 → 75 taken 180 times.
✗ Branch 74 → 85 not taken.
✓ Branch 75 → 76 taken 180 times.
✓ Branch 76 → 77 taken 180 times.
✓ Branch 77 → 78 taken 180 times.
✓ Branch 78 → 79 taken 180 times.
✓ Branch 80 → 81 taken 179 times.
✓ Branch 80 → 85 taken 1 time.
✓ Branch 90 → 91 taken 180 times.
✗ Branch 90 → 92 not taken.
✓ Branch 92 → 93 taken 180 times.
✗ Branch 92 → 94 not taken.
✓ Branch 94 → 95 taken 180 times.
✗ Branch 94 → 96 not taken.
✓ Branch 96 → 97 taken 179 times.
✓ Branch 96 → 99 taken 1 time.
✗ Branch 209 → 210 not taken.
✗ Branch 209 → 211 not taken.
✗ Branch 213 → 214 not taken.
✗ Branch 213 → 215 not taken.
✗ Branch 217 → 218 not taken.
✗ Branch 217 → 219 not taken.
✗ Branch 221 → 222 not taken.
✗ Branch 221 → 223 not taken.
539 if (child.name == QLatin1String("VTODO") && ICal::unescapeText(child.value("UID")).trimmed() == task.uid &&
220
6/10
✓ Branch 81 → 82 taken 179 times.
✓ Branch 82 → 83 taken 179 times.
✓ Branch 83 → 84 taken 179 times.
✗ Branch 83 → 85 not taken.
✓ Branch 86 → 87 taken 179 times.
✓ Branch 86 → 88 taken 1 time.
✓ Branch 88 → 89 taken 180 times.
✗ Branch 88 → 90 not taken.
✗ Branch 205 → 206 not taken.
✗ Branch 205 → 207 not taken.
359 !child.hasProperty("RECURRENCE-ID")) {
221 179 child = todo; replaced = true; break;
222 }
223
3/3
✓ Branch 102 → 103 taken 186 times.
✓ Branch 102 → 104 taken 179 times.
✓ Branch 103 → 104 taken 186 times.
365 if (!replaced) calendar.components << todo;
224
2/2
✓ Branch 104 → 105 taken 365 times.
✓ Branch 105 → 106 taken 365 times.
365 calendar.removeProperties("METHOD");
225 365 QSet<QString> defined;
226
5/10
✓ Branch 108 → 109 taken 365 times.
✓ Branch 109 → 110 taken 365 times.
✓ Branch 111 → 112 taken 365 times.
✓ Branch 112 → 113 taken 365 times.
✗ Branch 115 → 116 not taken.
✗ Branch 116 → 117 not taken.
✗ Branch 117 → 118 not taken.
✗ Branch 118 → 119 not taken.
✗ Branch 124 → 114 not taken.
✓ Branch 124 → 125 taken 365 times.
365 for (const auto &zone : calendar.componentsNamed("VTIMEZONE")) defined.insert(ICal::unescapeText(zone.value("TZID")));
227
2/2
✓ Branch 172 → 128 taken 3575 times.
✓ Branch 172 → 173 taken 365 times.
3940 for (const auto &property : todo.properties) {
228
2/2
✓ Branch 129 → 130 taken 3575 times.
✓ Branch 130 → 131 taken 3575 times.
3575 const QString tzid = property.parameter("TZID");
229
6/6
✓ Branch 133 → 134 taken 79 times.
✓ Branch 133 → 136 taken 3496 times.
✓ Branch 135 → 136 taken 19 times.
✓ Branch 135 → 137 taken 60 times.
✓ Branch 138 → 139 taken 3515 times.
✓ Branch 138 → 140 taken 60 times.
3575 if (tzid.isEmpty() || defined.contains(tzid)) continue;
230
1/1
✓ Branch 140 → 141 taken 60 times.
60 const auto zone = resolver.resolve(tzid);
231
2/3
✓ Branch 141 → 142 taken 60 times.
✗ Branch 142 → 143 not taken.
✓ Branch 142 → 145 taken 60 times.
60 if (!zone.isValid()) return {};
232
5/7
✓ Branch 145 → 146 taken 60 times.
✓ Branch 146 → 147 taken 60 times.
✗ Branch 146 → 148 not taken.
✓ Branch 147 → 149 taken 60 times.
✗ Branch 148 → 149 not taken.
✓ Branch 149 → 150 taken 60 times.
✓ Branch 150 → 151 taken 60 times.
60 auto definition = ICalTime::vtimezoneFor(zone, (task.due.isValid() ? task.due.date() : QDate::currentDate()).year());
233
5/5
✓ Branch 151 → 152 taken 60 times.
✓ Branch 152 → 153 taken 60 times.
✓ Branch 153 → 154 taken 60 times.
✓ Branch 156 → 157 taken 60 times.
✓ Branch 157 → 158 taken 60 times.
60 definition.setPropertyValue("TZID", ICal::escapeText(tzid)); calendar.components.prepend(definition); defined.insert(tzid);
234 3575 }
235
2/2
✓ Branch 173 → 174 taken 365 times.
✓ Branch 174 → 175 taken 365 times.
365 return ICal::serialize(calendar).toUtf8();
236 366 }
237
238 171 void adoptPushedResource(CalendarTask *task, const QByteArray &body) {
239 171 Resource resource;
240
6/12
✓ Branch 2 → 3 taken 171 times.
✗ Branch 2 → 6 not taken.
✓ Branch 3 → 4 taken 171 times.
✓ Branch 4 → 5 taken 171 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 171 times.
✓ Branch 8 → 9 taken 171 times.
✗ Branch 8 → 10 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 171 times.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 48 not taken.
171 if (!task || !parseResource(QString::fromUtf8(body), &resource)) return;
241
3/4
✓ Branch 12 → 13 taken 171 times.
✓ Branch 13 → 14 taken 171 times.
✓ Branch 38 → 15 taken 171 times.
✗ Branch 38 → 39 not taken.
171 for (const auto &candidate : resource.tasks)
242
10/22
✓ Branch 17 → 18 taken 171 times.
✗ Branch 17 → 24 not taken.
✓ Branch 18 → 19 taken 171 times.
✓ Branch 19 → 20 taken 171 times.
✓ Branch 20 → 21 taken 171 times.
✓ Branch 21 → 22 taken 171 times.
✓ Branch 22 → 23 taken 171 times.
✗ Branch 22 → 24 not taken.
✓ Branch 25 → 26 taken 171 times.
✗ Branch 25 → 27 not taken.
✓ Branch 27 → 28 taken 171 times.
✗ Branch 27 → 29 not taken.
✓ Branch 29 → 30 taken 171 times.
✗ Branch 29 → 31 not taken.
✓ Branch 31 → 32 taken 171 times.
✗ Branch 31 → 36 not taken.
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 52 not taken.
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 56 not taken.
✗ Branch 58 → 59 not taken.
✗ Branch 58 → 60 not taken.
171 if (candidate.uid == task->uid && !ICal::parseFirst(candidate.icalRaw, "VTODO").hasProperty("RECURRENCE-ID")) {
243 171 task->icalRaw = candidate.icalRaw; task->resourceIcal = candidate.resourceIcal;
244 // S106-133: the reminder times derive from the pushed component. A
245 // stale list (from before the anchor moved) would read as a manual
246 // reminder edit on the next save and freeze the relative trigger as
247 // an absolute stamp on the old day.
248 171 task->alarmTimes = candidate.alarmTimes;
249 171 return;
250 }
251 171 }
252 }
253