data/MergeValidation.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "MergeValidation.h" | ||
| 2 | |||
| 3 | #include "ICalMergePlan.h" | ||
| 4 | #include "ICalTime.h" | ||
| 5 | #include "ICalendar.h" | ||
| 6 | #include "SettingsMergePlan.h" | ||
| 7 | #include "SieveMergePlan.h" | ||
| 8 | #include "SieveRuleCodec.h" | ||
| 9 | #include "VCardCodec.h" | ||
| 10 | #include "VCardMergePlan.h" | ||
| 11 | |||
| 12 | #include <QSet> | ||
| 13 | |||
| 14 | namespace MergeValidation { | ||
| 15 | |||
| 16 | namespace { | ||
| 17 | |||
| 18 | using Problems = QList<Merge::ValidationProblem>; | ||
| 19 | |||
| 20 | 17 | void add(Problems *problems, const Merge::Plan &plan, const QString &rule, const QStringList &candidates, | |
| 21 | const QString &message) { | ||
| 22 | 17 | QStringList items; | |
| 23 |
2/2✓ Branch 15 → 4 taken 59 times.
✓ Branch 15 → 16 taken 17 times.
|
76 | for (const QString &id : candidates) |
| 24 |
7/7✓ Branch 5 → 6 taken 59 times.
✓ Branch 6 → 7 taken 47 times.
✓ Branch 6 → 10 taken 12 times.
✓ Branch 8 → 9 taken 29 times.
✓ Branch 8 → 10 taken 18 times.
✓ Branch 11 → 12 taken 29 times.
✓ Branch 11 → 13 taken 30 times.
|
59 | if (plan.indexOf(id) >= 0 && !items.contains(id)) |
| 25 |
1/1✓ Branch 12 → 13 taken 29 times.
|
29 | items.append(id); |
| 26 | 17 | problems->append({rule, items, message}); | |
| 27 | 34 | } | |
| 28 | |||
| 29 | 111 | QString keyOf(const ICal::Component &component) { | |
| 30 |
1/1✓ Branch 5 → 6 taken 111 times.
|
111 | const ICal::Property *recurrence = component.property(QStringLiteral("RECURRENCE-ID")); |
| 31 |
4/4✓ Branch 16 → 17 taken 111 times.
✓ Branch 19 → 20 taken 111 times.
✓ Branch 20 → 21 taken 111 times.
✓ Branch 21 → 22 taken 111 times.
|
333 | return component.name + QLatin1Char(':') + component.value(QStringLiteral("UID")) + QLatin1Char(':') + |
| 32 |
4/4✓ Branch 8 → 9 taken 3 times.
✓ Branch 8 → 10 taken 108 times.
✓ Branch 9 → 11 taken 3 times.
✓ Branch 22 → 23 taken 111 times.
|
333 | (recurrence ? recurrence->value.trimmed() : QString()); |
| 33 | } | ||
| 34 | |||
| 35 | // The items of `names` in component `key`: one per property, or one per | ||
| 36 | // value of a D-8 list; a one-sided component carries the whole value. | ||
| 37 | 9 | QStringList itemsOf(const Merge::Plan &plan, const QString &key, const QStringList &names) { | |
| 38 | 9 | QStringList ids; | |
| 39 |
2/2✓ Branch 17 → 4 taken 20 times.
✓ Branch 17 → 18 taken 9 times.
|
29 | for (const QString &name : names) |
| 40 |
3/3✓ Branch 8 → 9 taken 20 times.
✓ Branch 9 → 10 taken 20 times.
✓ Branch 10 → 11 taken 20 times.
|
20 | ids.append(key + QStringLiteral("::") + name); |
| 41 |
2/2✓ Branch 31 → 20 taken 41 times.
✓ Branch 31 → 32 taken 9 times.
|
50 | for (const Merge::Item &item : plan.items) |
| 42 |
5/6✓ Branch 22 → 23 taken 41 times.
✗ Branch 22 → 26 not taken.
✓ Branch 24 → 25 taken 19 times.
✓ Branch 24 → 26 taken 22 times.
✓ Branch 27 → 28 taken 19 times.
✓ Branch 27 → 29 taken 22 times.
|
41 | if (item.parent == key && names.contains(item.name)) |
| 43 |
1/1✓ Branch 28 → 29 taken 19 times.
|
19 | ids.append(item.id); |
| 44 |
1/1✓ Branch 32 → 33 taken 9 times.
|
9 | ids.append(key); |
| 45 | 9 | return ids; | |
| 46 | ✗ | } | |
| 47 | |||
| 48 | // The EXDATE value items of a master that exclude `instant`. | ||
| 49 | 1 | QStringList exdateItems(const Merge::Plan &plan, const QString &masterKey, const QDateTime &instant, | |
| 50 | const ICalTime::ZoneResolver &zones) { | ||
| 51 | 1 | QStringList ids; | |
| 52 |
2/2✓ Branch 68 → 4 taken 7 times.
✓ Branch 68 → 69 taken 1 time.
|
8 | for (const Merge::Item &item : plan.items) { |
| 53 |
6/6✓ Branch 6 → 7 taken 6 times.
✓ Branch 6 → 10 taken 1 time.
✓ Branch 9 → 10 taken 5 times.
✓ Branch 9 → 11 taken 1 time.
✓ Branch 12 → 13 taken 6 times.
✓ Branch 12 → 14 taken 1 time.
|
7 | if (item.parent != masterKey || item.name != QLatin1String("EXDATE")) |
| 54 | 6 | continue; | |
| 55 |
2/2✓ Branch 64 → 16 taken 2 times.
✓ Branch 64 → 65 taken 1 time.
|
3 | for (const Merge::Value *value : {&item.local, &item.server}) { |
| 56 |
2/2✓ Branch 16 → 17 taken 1 time.
✓ Branch 16 → 18 taken 1 time.
|
2 | if (!value->present) |
| 57 | 1 | continue; | |
| 58 |
1/1✓ Branch 27 → 28 taken 1 time.
|
3 | const ICal::Component parsed = ICal::parseFirst(QStringLiteral("BEGIN:X\r\n") + value->text + |
| 59 |
1/1✓ Branch 28 → 29 taken 1 time.
|
3 | QStringLiteral("\r\nEND:X\r\n"), |
| 60 |
1/1✓ Branch 29 → 30 taken 1 time.
|
3 | QStringLiteral("X")); |
| 61 |
2/2✓ Branch 60 → 40 taken 1 time.
✓ Branch 60 → 61 taken 1 time.
|
2 | for (const ICal::Property &property : parsed.properties) |
| 62 |
5/5✓ Branch 41 → 42 taken 1 time.
✓ Branch 42 → 43 taken 1 time.
✓ Branch 43 → 44 taken 1 time.
✓ Branch 56 → 45 taken 1 time.
✓ Branch 56 → 57 taken 1 time.
|
2 | for (const ICalTime::Value &excluded : ICalTime::parseList(property, zones)) |
| 63 |
4/7✓ Branch 46 → 47 taken 1 time.
✓ Branch 47 → 48 taken 1 time.
✗ Branch 47 → 51 not taken.
✓ Branch 49 → 50 taken 1 time.
✗ Branch 49 → 51 not taken.
✓ Branch 52 → 53 taken 1 time.
✗ Branch 52 → 54 not taken.
|
1 | if (excluded.dateTime == instant && !ids.contains(item.id)) |
| 64 |
1/1✓ Branch 53 → 54 taken 1 time.
|
2 | ids.append(item.id); |
| 65 | 1 | } | |
| 66 | } | ||
| 67 | 1 | return ids; | |
| 68 | ✗ | } | |
| 69 | |||
| 70 | 8 | QSet<QString> uidsOf(const QString &text, bool vcard) { | |
| 71 | 8 | QSet<QString> uids; | |
| 72 |
2/2✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 18 taken 4 times.
|
8 | if (vcard) { |
| 73 | 4 | ICal::Component card; | |
| 74 | 4 | QString error; | |
| 75 | 4 | int skipped = 0; | |
| 76 |
2/3✓ Branch 4 → 5 taken 4 times.
✓ Branch 5 → 6 taken 4 times.
✗ Branch 5 → 15 not taken.
|
4 | if (VCardCodec::parseTree(text, &card, &error, &skipped)) |
| 77 |
2/2✓ Branch 9 → 10 taken 4 times.
✓ Branch 10 → 11 taken 4 times.
|
4 | uids.insert(card.value(QStringLiteral("UID"))); |
| 78 | 4 | return uids; | |
| 79 | 4 | } | |
| 80 |
5/5✓ Branch 21 → 22 taken 4 times.
✓ Branch 24 → 25 taken 4 times.
✓ Branch 25 → 26 taken 4 times.
✓ Branch 48 → 27 taken 7 times.
✓ Branch 48 → 49 taken 4 times.
|
11 | for (const ICal::Component &component : ICal::parseFirst(text).components) |
| 81 |
5/6✓ Branch 30 → 31 taken 3 times.
✓ Branch 30 → 34 taken 4 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 3 times.
✓ Branch 36 → 37 taken 4 times.
✓ Branch 36 → 46 taken 3 times.
|
7 | if (component.name == QLatin1String("VEVENT") || component.name == QLatin1String("VTODO")) |
| 82 |
2/2✓ Branch 40 → 41 taken 4 times.
✓ Branch 41 → 42 taken 4 times.
|
8 | uids.insert(component.value(QStringLiteral("UID"))); |
| 83 | 4 | return uids; | |
| 84 | ✗ | } | |
| 85 | |||
| 86 | 56 | void checkComponent(Problems *problems, const Merge::Plan &plan, const ICal::Component &component, | |
| 87 | const ICalTime::ZoneResolver &zones) { | ||
| 88 |
1/1✓ Branch 2 → 3 taken 56 times.
|
56 | const QString key = keyOf(component); |
| 89 | 56 | const bool todo = component.name == QLatin1String("VTODO"); | |
| 90 | 112 | const auto time = [&](const QString &name) { | |
| 91 | 112 | const ICal::Property *property = component.property(name); | |
| 92 |
3/7✓ Branch 3 → 4 taken 96 times.
✓ Branch 3 → 5 taken 16 times.
✓ Branch 4 → 7 taken 96 times.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 12 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
|
224 | return property ? ICalTime::parseProperty(*property, zones) : ICalTime::Value{}; |
| 93 | 56 | }; | |
| 94 |
1/1✓ Branch 8 → 9 taken 56 times.
|
56 | const ICalTime::Value start = time(QStringLiteral("DTSTART")); |
| 95 |
6/6✓ Branch 11 → 12 taken 8 times.
✓ Branch 11 → 15 taken 48 times.
✓ Branch 18 → 19 taken 48 times.
✓ Branch 18 → 20 taken 8 times.
✓ Branch 20 → 21 taken 8 times.
✓ Branch 20 → 22 taken 48 times.
|
112 | const QString endName = todo ? QStringLiteral("DUE") : QStringLiteral("DTEND"); |
| 96 |
1/1✓ Branch 22 → 23 taken 56 times.
|
56 | const ICalTime::Value end = time(endName); |
| 97 |
11/11✓ Branch 23 → 24 taken 56 times.
✓ Branch 24 → 25 taken 48 times.
✓ Branch 24 → 31 taken 8 times.
✓ Branch 25 → 26 taken 48 times.
✓ Branch 26 → 27 taken 46 times.
✓ Branch 26 → 31 taken 2 times.
✓ Branch 27 → 28 taken 46 times.
✓ Branch 29 → 30 taken 6 times.
✓ Branch 29 → 31 taken 40 times.
✓ Branch 32 → 33 taken 6 times.
✓ Branch 32 → 71 taken 50 times.
|
56 | if (start.valid() && end.valid() && end.dateTime < start.dateTime) |
| 98 |
4/11✗ Branch 46 → 47 not taken.
✓ Branch 46 → 50 taken 6 times.
✓ Branch 53 → 54 taken 6 times.
✓ Branch 55 → 56 taken 6 times.
✗ Branch 55 → 57 not taken.
✗ Branch 57 → 58 not taken.
✓ Branch 57 → 59 taken 6 times.
✗ Branch 203 → 204 not taken.
✗ Branch 203 → 205 not taken.
✗ Branch 207 → 208 not taken.
✗ Branch 207 → 209 not taken.
|
12 | add(problems, plan, todo ? QStringLiteral("due-before-start") : QStringLiteral("end-before-start"), |
| 99 |
3/5✓ Branch 45 → 46 taken 6 times.
✓ Branch 62 → 63 taken 12 times.
✓ Branch 62 → 64 taken 6 times.
✗ Branch 217 → 218 not taken.
✗ Branch 217 → 219 not taken.
|
24 | itemsOf(plan, key, {QStringLiteral("DTSTART"), endName}), |
| 100 |
3/10✗ Branch 33 → 34 not taken.
✓ Branch 33 → 37 taken 6 times.
✓ Branch 66 → 67 taken 6 times.
✗ Branch 66 → 68 not taken.
✗ Branch 68 → 69 not taken.
✓ Branch 68 → 70 taken 6 times.
✗ Branch 233 → 234 not taken.
✗ Branch 233 → 235 not taken.
✗ Branch 237 → 238 not taken.
✗ Branch 237 → 239 not taken.
|
18 | todo ? QStringLiteral("The task is due before it starts") : QStringLiteral("The end is before the start")); |
| 101 |
12/16✓ Branch 71 → 72 taken 56 times.
✓ Branch 72 → 73 taken 48 times.
✓ Branch 72 → 79 taken 8 times.
✓ Branch 76 → 77 taken 48 times.
✓ Branch 77 → 78 taken 1 time.
✓ Branch 77 → 79 taken 47 times.
✓ Branch 80 → 81 taken 48 times.
✓ Branch 80 → 82 taken 8 times.
✓ Branch 82 → 83 taken 48 times.
✓ Branch 82 → 84 taken 8 times.
✓ Branch 84 → 85 taken 1 time.
✓ Branch 84 → 109 taken 55 times.
✗ Branch 242 → 243 not taken.
✗ Branch 242 → 244 not taken.
✗ Branch 246 → 247 not taken.
✗ Branch 246 → 248 not taken.
|
104 | if (component.hasProperty(endName) && component.hasProperty(QStringLiteral("DURATION"))) |
| 102 |
4/6✓ Branch 93 → 94 taken 1 time.
✓ Branch 97 → 98 taken 1 time.
✓ Branch 103 → 104 taken 2 times.
✓ Branch 103 → 105 taken 1 time.
✗ Branch 261 → 262 not taken.
✗ Branch 261 → 263 not taken.
|
4 | add(problems, plan, QStringLiteral("end-and-duration"), itemsOf(plan, key, {endName, QStringLiteral("DURATION")}), |
| 103 | 2 | QStringLiteral("An end and a duration were combined")); | |
| 104 |
2/2✓ Branch 109 → 110 taken 8 times.
✓ Branch 109 → 190 taken 48 times.
|
56 | if (todo) { |
| 105 |
3/3✓ Branch 113 → 114 taken 8 times.
✓ Branch 114 → 115 taken 8 times.
✓ Branch 115 → 116 taken 8 times.
|
8 | const QString status = component.value(QStringLiteral("STATUS")).trimmed().toUpper(); |
| 106 |
1/1✓ Branch 123 → 124 taken 8 times.
|
8 | const bool completedStamp = component.hasProperty(QStringLiteral("COMPLETED")); |
| 107 |
1/1✓ Branch 129 → 130 taken 8 times.
|
8 | const bool hasPercent = component.hasProperty(QStringLiteral("PERCENT-COMPLETE")); |
| 108 |
3/3✓ Branch 135 → 136 taken 8 times.
✓ Branch 136 → 137 taken 8 times.
✓ Branch 137 → 138 taken 8 times.
|
8 | const int percent = component.value(QStringLiteral("PERCENT-COMPLETE")).trimmed().toInt(); |
| 109 | 8 | const bool done = status == QLatin1String("COMPLETED"); | |
| 110 |
12/14✓ Branch 144 → 145 taken 3 times.
✓ Branch 144 → 146 taken 5 times.
✓ Branch 145 → 146 taken 2 times.
✓ Branch 145 → 154 taken 1 time.
✓ Branch 146 → 147 taken 2 times.
✓ Branch 146 → 149 taken 5 times.
✓ Branch 147 → 148 taken 2 times.
✗ Branch 147 → 149 not taken.
✓ Branch 148 → 149 taken 2 times.
✗ Branch 148 → 154 not taken.
✓ Branch 149 → 150 taken 2 times.
✓ Branch 149 → 155 taken 5 times.
✓ Branch 156 → 157 taken 1 time.
✓ Branch 156 → 188 taken 7 times.
|
10 | if ((completedStamp && !done) || (done && hasPercent && percent != 100) || |
| 111 |
3/6✓ Branch 150 → 151 taken 2 times.
✗ Branch 150 → 155 not taken.
✓ Branch 152 → 153 taken 2 times.
✗ Branch 152 → 155 not taken.
✗ Branch 153 → 154 not taken.
✓ Branch 153 → 155 taken 2 times.
|
2 | (hasPercent && percent == 100 && !status.isEmpty() && !done)) |
| 112 |
1/1✓ Branch 174 → 175 taken 1 time.
|
1 | add(problems, plan, QStringLiteral("task-completion"), |
| 113 |
3/5✓ Branch 170 → 171 taken 1 time.
✓ Branch 180 → 181 taken 3 times.
✓ Branch 180 → 182 taken 1 time.
✗ Branch 328 → 329 not taken.
✗ Branch 328 → 330 not taken.
|
5 | itemsOf(plan, key, {QStringLiteral("STATUS"), QStringLiteral("PERCENT-COMPLETE"), QStringLiteral("COMPLETED")}), |
| 114 | 2 | QStringLiteral("Done, progress and completion date do not agree")); | |
| 115 | 8 | } | |
| 116 | 74 | } | |
| 117 | |||
| 118 | 55 | Problems validateIcal(const Merge::Plan &plan) { | |
| 119 | 55 | Problems problems; | |
| 120 |
1/1✓ Branch 2 → 3 taken 55 times.
|
55 | const ICalMergePlan::Applied applied = ICalMergePlan::apply(plan); |
| 121 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 55 times.
|
55 | if (!applied.ok) |
| 122 | ✗ | return problems; // open conflicts: nothing to validate yet | |
| 123 | 55 | QList<ICal::Component> parsed; | |
| 124 | 55 | int skipped = 0; | |
| 125 |
7/9✓ Branch 5 → 6 taken 55 times.
✓ Branch 6 → 7 taken 55 times.
✗ Branch 6 → 10 not taken.
✓ Branch 7 → 8 taken 54 times.
✓ Branch 7 → 10 taken 1 time.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 54 times.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 31 taken 54 times.
|
55 | if (!ICal::parse(applied.text, &parsed, nullptr, &skipped) || skipped > 0 || parsed.isEmpty()) { |
| 126 |
3/5✓ Branch 21 → 22 taken 1 time.
✓ Branch 26 → 27 taken 1 time.
✓ Branch 26 → 28 taken 1 time.
✗ Branch 250 → 251 not taken.
✗ Branch 250 → 252 not taken.
|
2 | add(&problems, plan, QStringLiteral("unreadable-result"), {ICalMergePlan::kRawItem}, |
| 127 | 2 | QStringLiteral("The result cannot be read")); | |
| 128 | 1 | return problems; | |
| 129 | } | ||
| 130 |
12/16✓ Branch 31 → 32 taken 2 times.
✓ Branch 31 → 37 taken 52 times.
✓ Branch 32 → 33 taken 2 times.
✓ Branch 33 → 34 taken 2 times.
✓ Branch 35 → 36 taken 1 time.
✓ Branch 35 → 37 taken 1 time.
✓ Branch 38 → 39 taken 2 times.
✓ Branch 38 → 40 taken 52 times.
✓ Branch 40 → 41 taken 2 times.
✓ Branch 40 → 42 taken 52 times.
✓ Branch 42 → 43 taken 1 time.
✓ Branch 42 → 61 taken 53 times.
✗ Branch 266 → 267 not taken.
✗ Branch 266 → 268 not taken.
✗ Branch 270 → 271 not taken.
✗ Branch 270 → 272 not taken.
|
54 | if (!plan.comparable && uidsOf(applied.text, false) != uidsOf(plan.localText, false)) |
| 131 |
3/5✓ Branch 51 → 52 taken 1 time.
✓ Branch 56 → 57 taken 1 time.
✓ Branch 56 → 58 taken 1 time.
✗ Branch 283 → 284 not taken.
✗ Branch 283 → 285 not taken.
|
2 | add(&problems, plan, QStringLiteral("uid-changed"), {ICalMergePlan::kRawItem}, |
| 132 | 2 | QStringLiteral("The result must keep the UID")); | |
| 133 |
1/1✓ Branch 61 → 62 taken 54 times.
|
54 | const ICal::Component calendar = parsed.first(); |
| 134 |
1/1✓ Branch 63 → 64 taken 54 times.
|
54 | const ICalTime::ZoneResolver zones(calendar); |
| 135 | 54 | QHash<QString, QList<QDateTime>> excluded; // UID -> EXDATE instants of the master | |
| 136 | 54 | QHash<QString, QString> masterKey; | |
| 137 |
2/2✓ Branch 178 → 66 taken 97 times.
✓ Branch 178 → 179 taken 54 times.
|
151 | for (const ICal::Component &component : calendar.components) { |
| 138 |
6/6✓ Branch 69 → 70 taken 49 times.
✓ Branch 69 → 74 taken 48 times.
✓ Branch 72 → 73 taken 41 times.
✓ Branch 72 → 74 taken 8 times.
✓ Branch 75 → 76 taken 41 times.
✓ Branch 75 → 77 taken 56 times.
|
97 | if (component.name != QLatin1String("VEVENT") && component.name != QLatin1String("VTODO")) |
| 139 | 43 | continue; | |
| 140 |
1/1✓ Branch 77 → 78 taken 56 times.
|
56 | checkComponent(&problems, plan, component, zones); |
| 141 |
3/3✓ Branch 81 → 82 taken 56 times.
✓ Branch 84 → 85 taken 2 times.
✓ Branch 84 → 86 taken 54 times.
|
56 | if (component.hasProperty(QStringLiteral("RECURRENCE-ID"))) |
| 142 | 2 | continue; | |
| 143 |
1/1✓ Branch 86 → 87 taken 54 times.
|
54 | const QString key = keyOf(component); |
| 144 |
1/1✓ Branch 90 → 91 taken 54 times.
|
54 | const QString uid = component.value(QStringLiteral("UID")); |
| 145 |
1/1✓ Branch 93 → 94 taken 54 times.
|
54 | masterKey.insert(uid, key); |
| 146 |
1/1✓ Branch 97 → 98 taken 54 times.
|
54 | const QList<ICal::Property> exdates = component.propertiesNamed(QStringLiteral("EXDATE")); |
| 147 |
9/13✓ Branch 101 → 102 taken 2 times.
✓ Branch 101 → 113 taken 52 times.
✓ Branch 105 → 106 taken 2 times.
✓ Branch 106 → 107 taken 1 time.
✓ Branch 106 → 113 taken 1 time.
✓ Branch 120 → 121 taken 2 times.
✓ Branch 120 → 122 taken 52 times.
✓ Branch 122 → 123 taken 1 time.
✓ Branch 122 → 154 taken 53 times.
✗ Branch 325 → 326 not taken.
✗ Branch 325 → 327 not taken.
✗ Branch 329 → 330 not taken.
✗ Branch 329 → 331 not taken.
|
111 | if (!exdates.isEmpty() && !component.hasProperty(QStringLiteral("RRULE")) && |
| 148 |
8/13✓ Branch 110 → 111 taken 1 time.
✓ Branch 111 → 112 taken 1 time.
✗ Branch 111 → 113 not taken.
✓ Branch 114 → 115 taken 1 time.
✓ Branch 114 → 116 taken 53 times.
✓ Branch 116 → 117 taken 1 time.
✓ Branch 116 → 118 taken 53 times.
✓ Branch 118 → 119 taken 2 times.
✓ Branch 118 → 120 taken 52 times.
✗ Branch 317 → 318 not taken.
✗ Branch 317 → 319 not taken.
✗ Branch 321 → 322 not taken.
✗ Branch 321 → 323 not taken.
|
55 | !component.hasProperty(QStringLiteral("RDATE"))) |
| 149 |
1/1✓ Branch 140 → 141 taken 1 time.
|
1 | add(&problems, plan, QStringLiteral("exdate-without-recurrence"), |
| 150 |
3/5✓ Branch 136 → 137 taken 1 time.
✓ Branch 146 → 147 taken 3 times.
✓ Branch 146 → 148 taken 1 time.
✗ Branch 344 → 345 not taken.
✗ Branch 344 → 346 not taken.
|
5 | itemsOf(plan, key, {QStringLiteral("EXDATE"), QStringLiteral("RRULE"), QStringLiteral("RDATE")}), |
| 151 | 2 | QStringLiteral("Excluded dates without a repetition")); | |
| 152 |
2/2✓ Branch 170 → 156 taken 2 times.
✓ Branch 170 → 171 taken 54 times.
|
56 | for (const ICal::Property &exdate : exdates) |
| 153 |
5/5✓ Branch 157 → 158 taken 2 times.
✓ Branch 158 → 159 taken 2 times.
✓ Branch 159 → 160 taken 2 times.
✓ Branch 166 → 161 taken 2 times.
✓ Branch 166 → 167 taken 2 times.
|
4 | for (const ICalTime::Value &value : ICalTime::parseList(exdate, zones)) |
| 154 |
2/2✓ Branch 162 → 163 taken 2 times.
✓ Branch 163 → 164 taken 2 times.
|
4 | excluded[uid].append(value.dateTime); |
| 155 | 54 | } | |
| 156 |
2/2✓ Branch 232 → 181 taken 97 times.
✓ Branch 232 → 233 taken 54 times.
|
151 | for (const ICal::Component &component : calendar.components) { |
| 157 |
1/1✓ Branch 185 → 186 taken 97 times.
|
97 | const ICal::Property *recurrence = component.property(QStringLiteral("RECURRENCE-ID")); |
| 158 |
2/2✓ Branch 188 → 189 taken 95 times.
✓ Branch 188 → 190 taken 2 times.
|
97 | if (!recurrence) |
| 159 | 95 | continue; | |
| 160 |
1/1✓ Branch 193 → 194 taken 2 times.
|
2 | const QString uid = component.value(QStringLiteral("UID")); |
| 161 |
1/1✓ Branch 196 → 197 taken 2 times.
|
2 | const QDateTime instant = ICalTime::parseProperty(*recurrence, zones).dateTime; |
| 162 |
2/2✓ Branch 202 → 203 taken 1 time.
✓ Branch 202 → 227 taken 1 time.
|
2 | if (excluded.value(uid).contains(instant)) |
| 163 |
1/1✓ Branch 214 → 215 taken 1 time.
|
1 | add(&problems, plan, QStringLiteral("occurrence-moved-and-cancelled"), |
| 164 |
4/6✓ Branch 207 → 208 taken 1 time.
✓ Branch 210 → 211 taken 1 time.
✓ Branch 220 → 221 taken 1 time.
✓ Branch 220 → 222 taken 1 time.
✗ Branch 406 → 407 not taken.
✗ Branch 406 → 408 not taken.
|
4 | QStringList{keyOf(component)} + exdateItems(plan, masterKey.value(uid), instant, zones), |
| 165 | 2 | QStringLiteral("An occurrence is both changed and cancelled")); | |
| 166 | 2 | } | |
| 167 | 54 | return problems; | |
| 168 | 62 | } | |
| 169 | |||
| 170 | 7 | Problems validateCard(const Merge::Plan &plan) { | |
| 171 | 7 | Problems problems; | |
| 172 |
1/1✓ Branch 5 → 6 taken 7 times.
|
7 | const VCardMergePlan::Applied applied = VCardMergePlan::apply(plan, QStringLiteral("20000101T000000Z")); |
| 173 |
1/2✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 7 times.
|
7 | if (!applied.ok) |
| 174 | ✗ | return problems; | |
| 175 | 7 | ICal::Component card; | |
| 176 | 7 | QString error; | |
| 177 | 7 | int skipped = 0; | |
| 178 |
6/7✓ Branch 10 → 11 taken 7 times.
✓ Branch 11 → 12 taken 6 times.
✓ Branch 11 → 13 taken 1 time.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 6 times.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 34 taken 6 times.
|
7 | if (!VCardCodec::parseTree(applied.text, &card, &error, &skipped) || skipped > 0) { |
| 179 |
3/5✓ Branch 24 → 25 taken 1 time.
✓ Branch 29 → 30 taken 1 time.
✓ Branch 29 → 31 taken 1 time.
✗ Branch 123 → 124 not taken.
✗ Branch 123 → 125 not taken.
|
2 | add(&problems, plan, QStringLiteral("unreadable-result"), {VCardMergePlan::kRawItem}, |
| 180 | 2 | QStringLiteral("The result cannot be read")); | |
| 181 | 1 | return problems; | |
| 182 | } | ||
| 183 |
12/16✓ Branch 34 → 35 taken 2 times.
✓ Branch 34 → 40 taken 4 times.
✓ Branch 35 → 36 taken 2 times.
✓ Branch 36 → 37 taken 2 times.
✓ Branch 38 → 39 taken 1 time.
✓ Branch 38 → 40 taken 1 time.
✓ Branch 41 → 42 taken 2 times.
✓ Branch 41 → 43 taken 4 times.
✓ Branch 43 → 44 taken 2 times.
✓ Branch 43 → 45 taken 4 times.
✓ Branch 45 → 46 taken 1 time.
✓ Branch 45 → 64 taken 5 times.
✗ Branch 139 → 140 not taken.
✗ Branch 139 → 141 not taken.
✗ Branch 143 → 144 not taken.
✗ Branch 143 → 145 not taken.
|
6 | if (!plan.comparable && uidsOf(applied.text, true) != uidsOf(plan.localText, true)) |
| 184 |
3/5✓ Branch 54 → 55 taken 1 time.
✓ Branch 59 → 60 taken 1 time.
✓ Branch 59 → 61 taken 1 time.
✗ Branch 156 → 157 not taken.
✗ Branch 156 → 158 not taken.
|
2 | add(&problems, plan, QStringLiteral("uid-changed"), {VCardMergePlan::kRawItem}, |
| 185 | 2 | QStringLiteral("The result must keep the UID")); | |
| 186 |
5/5✓ Branch 67 → 68 taken 6 times.
✓ Branch 68 → 69 taken 6 times.
✓ Branch 69 → 70 taken 6 times.
✓ Branch 76 → 77 taken 1 time.
✓ Branch 76 → 102 taken 5 times.
|
6 | if (ICal::unescapeText(card.value(QStringLiteral("FN"))).trimmed().isEmpty()) |
| 187 |
3/5✓ Branch 90 → 91 taken 1 time.
✓ Branch 95 → 96 taken 2 times.
✓ Branch 95 → 97 taken 1 time.
✗ Branch 194 → 195 not taken.
✗ Branch 194 → 196 not taken.
|
3 | add(&problems, plan, QStringLiteral("contact-without-name"), {QStringLiteral("FN"), QStringLiteral("N")}, |
| 188 | 2 | QStringLiteral("A contact needs a name")); | |
| 189 | 6 | return problems; | |
| 190 | 12 | } | |
| 191 | |||
| 192 | 6 | Problems validateSieve(const Merge::Plan &plan) { | |
| 193 | 6 | Problems problems; | |
| 194 |
3/3✓ Branch 2 → 3 taken 6 times.
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 14 taken 4 times.
|
6 | if (Merge::uniformSide(plan) == Merge::Choice::None) { |
| 195 |
2/2✓ Branch 12 → 6 taken 8 times.
✓ Branch 12 → 13 taken 2 times.
|
10 | for (const Merge::Item &item : plan.items) |
| 196 |
2/3✓ Branch 7 → 8 taken 8 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 8 times.
|
8 | if (Merge::itemOpen(plan, item)) |
| 197 | ✗ | return problems; | |
| 198 | } | ||
| 199 |
1/1✓ Branch 14 → 15 taken 6 times.
|
6 | const SieveMergePlan::Applied applied = SieveMergePlan::apply(plan); |
| 200 |
7/11✓ Branch 15 → 16 taken 6 times.
✗ Branch 15 → 19 not taken.
✓ Branch 16 → 17 taken 6 times.
✓ Branch 17 → 18 taken 5 times.
✓ Branch 17 → 19 taken 1 time.
✓ Branch 20 → 21 taken 6 times.
✗ Branch 20 → 22 not taken.
✓ Branch 22 → 23 taken 5 times.
✓ Branch 22 → 24 taken 1 time.
✗ Branch 49 → 50 not taken.
✗ Branch 49 → 51 not taken.
|
6 | if (applied.ok && !Sieve::decode(applied.script).readOnly) |
| 201 | 5 | return problems; | |
| 202 | 1 | QStringList chosen; | |
| 203 |
2/2✓ Branch 32 → 26 taken 1 time.
✓ Branch 32 → 33 taken 1 time.
|
2 | for (const Merge::Item &item : plan.items) |
| 204 |
1/4✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 1 time.
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 30 not taken.
|
1 | if (item.state == Merge::State::Conflict || item.touched) |
| 205 |
1/1✓ Branch 29 → 30 taken 1 time.
|
1 | chosen.append(item.id); |
| 206 |
1/1✓ Branch 39 → 40 taken 1 time.
|
2 | add(&problems, plan, QStringLiteral("script-does-not-parse"), chosen, QStringLiteral("The combined script does not parse")); |
| 207 | 1 | return problems; | |
| 208 | 6 | } | |
| 209 | |||
| 210 | 6 | Problems validateSettings(const Merge::Plan &plan) { | |
| 211 | 6 | Problems problems; | |
| 212 |
1/1✓ Branch 2 → 3 taken 6 times.
|
6 | const SyncPayload result = SettingsMergePlan::apply(plan); |
| 213 | 6 | QSet<QString> accounts; | |
| 214 |
2/2✓ Branch 10 → 6 taken 3 times.
✓ Branch 10 → 11 taken 6 times.
|
9 | for (const SyncPayload::CardDavAccount &account : result.carddavAccounts) |
| 215 |
1/1✓ Branch 7 → 8 taken 3 times.
|
3 | accounts.insert(account.id); |
| 216 |
2/2✓ Branch 44 → 13 taken 5 times.
✓ Branch 44 → 45 taken 6 times.
|
11 | for (const SyncPayload::CalDavSyncConfig &config : result.caldavConfigs) |
| 217 |
2/2✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 42 taken 4 times.
|
5 | if (!accounts.contains(config.carddavAccountId)) |
| 218 |
3/5✓ Branch 29 → 30 taken 1 time.
✓ Branch 34 → 35 taken 2 times.
✓ Branch 34 → 36 taken 1 time.
✗ Branch 60 → 61 not taken.
✗ Branch 60 → 62 not taken.
|
3 | add(&problems, plan, QStringLiteral("calendars-without-account"), |
| 219 | 2 | {SettingsMergePlan::accountItemId(config.carddavAccountId, QStringLiteral("calendars")), | |
| 220 | 1 | SettingsMergePlan::accountItemId(config.carddavAccountId)}, | |
| 221 | 2 | QStringLiteral("Calendars of an account that is not there")); | |
| 222 | 6 | return problems; | |
| 223 | 8 | } | |
| 224 | |||
| 225 | } // namespace | ||
| 226 | |||
| 227 | 75 | QList<Merge::ValidationProblem> validate(const Merge::Plan &plan) { | |
| 228 |
2/2✓ Branch 4 → 5 taken 55 times.
✓ Branch 4 → 6 taken 20 times.
|
75 | if (plan.domain == QLatin1String("ical")) |
| 229 | 55 | return validateIcal(plan); | |
| 230 |
2/2✓ Branch 8 → 9 taken 7 times.
✓ Branch 8 → 10 taken 13 times.
|
20 | if (plan.domain == QLatin1String("vcard")) |
| 231 | 7 | return validateCard(plan); | |
| 232 |
2/2✓ Branch 12 → 13 taken 6 times.
✓ Branch 12 → 14 taken 7 times.
|
13 | if (plan.domain == QLatin1String("sieve")) |
| 233 | 6 | return validateSieve(plan); | |
| 234 |
2/2✓ Branch 16 → 17 taken 6 times.
✓ Branch 16 → 18 taken 1 time.
|
7 | if (plan.domain == QLatin1String("settings")) |
| 235 | 6 | return validateSettings(plan); | |
| 236 | 1 | return {}; | |
| 237 | } | ||
| 238 | |||
| 239 | 7 | bool fixWithSameSide(Merge::Plan *plan, const Merge::ValidationProblem &problem) { | |
| 240 |
2/2✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 6 times.
|
7 | if (problem.itemIds.isEmpty()) |
| 241 | 1 | return false; | |
| 242 | 6 | Merge::Choice side = Merge::Choice::Local; | |
| 243 |
1/2✓ Branch 15 → 7 taken 6 times.
✗ Branch 15 → 16 not taken.
|
6 | for (const QString &id : problem.itemIds) { |
| 244 |
1/1✓ Branch 8 → 9 taken 6 times.
|
6 | const Merge::Item *item = plan->item(id); |
| 245 |
4/6✓ Branch 9 → 10 taken 6 times.
✗ Branch 9 → 13 not taken.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 12 taken 5 times.
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 13 not taken.
|
6 | if (item && (item->choice == Merge::Choice::Local || item->choice == Merge::Choice::Server)) { |
| 246 | 6 | side = item->choice; | |
| 247 | 6 | break; | |
| 248 | } | ||
| 249 | } | ||
| 250 | 6 | bool changed = false; | |
| 251 |
2/2✓ Branch 26 → 18 taken 12 times.
✓ Branch 26 → 27 taken 6 times.
|
18 | for (const QString &id : problem.itemIds) |
| 252 |
2/5✓ Branch 19 → 20 taken 12 times.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 12 times.
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
|
12 | changed = Merge::choose(plan, id, side) || changed; |
| 253 | 6 | return changed; | |
| 254 | } | ||
| 255 | |||
| 256 | } // namespace MergeValidation | ||
| 257 |