data/ICalMergePlan.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "ICalMergePlan.h" | ||
| 2 | |||
| 3 | #include "ICalendar.h" | ||
| 4 | |||
| 5 | #include <QHash> | ||
| 6 | #include <QMap> | ||
| 7 | #include <QSet> | ||
| 8 | #include <algorithm> | ||
| 9 | |||
| 10 | namespace ICalMergePlan { | ||
| 11 | |||
| 12 | namespace { | ||
| 13 | |||
| 14 | const QSet<QString> kBookkeeping{QStringLiteral("DTSTAMP"), QStringLiteral("LAST-MODIFIED"), | ||
| 15 | QStringLiteral("SEQUENCE")}; | ||
| 16 | |||
| 17 | // Group key -> sorted content lines (properties) or serialized components. | ||
| 18 | using Groups = QMap<QString, QStringList>; | ||
| 19 | |||
| 20 | struct Calendar { | ||
| 21 | ICal::Component root; | ||
| 22 | QMap<QString, ICal::Component> events; // component key -> component | ||
| 23 | }; | ||
| 24 | |||
| 25 | struct Inputs { | ||
| 26 | Calendar base; | ||
| 27 | Calendar local; | ||
| 28 | Calendar server; | ||
| 29 | QString error; | ||
| 30 | }; | ||
| 31 | |||
| 32 | 32511 | Groups groupsOf(const ICal::Component &event) { | |
| 33 | 32511 | Groups groups; | |
| 34 |
2/2✓ Branch 15 → 4 taken 197311 times.
✓ Branch 15 → 16 taken 32511 times.
|
229822 | for (const ICal::Property &property : event.properties) { |
| 35 |
2/2✓ Branch 6 → 7 taken 35094 times.
✓ Branch 6 → 8 taken 162217 times.
|
197311 | if (kBookkeeping.contains(property.name)) |
| 36 | 35094 | continue; | |
| 37 |
3/3✓ Branch 8 → 9 taken 162217 times.
✓ Branch 9 → 10 taken 162217 times.
✓ Branch 10 → 11 taken 162217 times.
|
162217 | groups[property.name].append(property.contentLine()); |
| 38 | } | ||
| 39 |
2/2✓ Branch 32 → 18 taken 110 times.
✓ Branch 32 → 33 taken 32511 times.
|
32621 | for (const ICal::Component &child : event.components) |
| 40 |
4/4✓ Branch 22 → 23 taken 110 times.
✓ Branch 23 → 24 taken 110 times.
✓ Branch 24 → 25 taken 110 times.
✓ Branch 25 → 26 taken 110 times.
|
220 | groups[QStringLiteral("BEGIN:") + child.name].append(ICal::serialize(child)); |
| 41 |
4/4✓ Branch 33 → 34 taken 32511 times.
✓ Branch 38 → 39 taken 194741 times.
✓ Branch 40 → 35 taken 162230 times.
✓ Branch 40 → 41 taken 32511 times.
|
194741 | for (auto it = groups.begin(); it != groups.end(); ++it) |
| 42 |
1/1✓ Branch 36 → 37 taken 162230 times.
|
162230 | it.value().sort(); |
| 43 | 32511 | return groups; | |
| 44 | ✗ | } | |
| 45 | |||
| 46 | 32590 | QString eventKey(const ICal::Component &event) { | |
| 47 |
1/1✓ Branch 5 → 6 taken 32590 times.
|
32590 | const ICal::Property *recurrence = event.property(QStringLiteral("RECURRENCE-ID")); |
| 48 |
4/4✓ Branch 16 → 17 taken 32590 times.
✓ Branch 19 → 20 taken 32590 times.
✓ Branch 20 → 21 taken 32590 times.
✓ Branch 21 → 22 taken 32590 times.
|
97770 | return event.name + QLatin1Char(':') + event.value(QStringLiteral("UID")) + QLatin1Char(':') + |
| 49 |
4/4✓ Branch 8 → 9 taken 30145 times.
✓ Branch 8 → 10 taken 2445 times.
✓ Branch 9 → 11 taken 30145 times.
✓ Branch 22 → 23 taken 32590 times.
|
97770 | (recurrence ? recurrence->value.trimmed() : QString()); |
| 50 | } | ||
| 51 | |||
| 52 | // S106-137: two components with the same key cannot be matched; | ||
| 53 | // `*duplicate` names the key. | ||
| 54 | 2430 | QMap<QString, ICal::Component> eventsByKey(const ICal::Component &calendar, QString *duplicate) { | |
| 55 | 2430 | QMap<QString, ICal::Component> events; | |
| 56 |
2/2✓ Branch 29 → 4 taken 34372 times.
✓ Branch 29 → 30 taken 2430 times.
|
36802 | for (const ICal::Component &component : calendar.components) { |
| 57 |
6/6✓ Branch 7 → 8 taken 2325 times.
✓ Branch 7 → 12 taken 32047 times.
✓ Branch 10 → 11 taken 1782 times.
✓ Branch 10 → 12 taken 543 times.
✓ Branch 13 → 14 taken 1782 times.
✓ Branch 13 → 15 taken 32590 times.
|
34372 | if (component.name != QLatin1String("VEVENT") && component.name != QLatin1String("VTODO")) |
| 58 | 1782 | continue; | |
| 59 |
1/1✓ Branch 15 → 16 taken 32590 times.
|
32590 | const QString key = eventKey(component); |
| 60 |
6/7✓ Branch 16 → 17 taken 32590 times.
✓ Branch 17 → 18 taken 9 times.
✓ Branch 17 → 21 taken 32581 times.
✓ Branch 19 → 20 taken 9 times.
✗ Branch 19 → 21 not taken.
✓ Branch 22 → 23 taken 9 times.
✓ Branch 22 → 24 taken 32581 times.
|
32590 | if (events.contains(key) && duplicate->isEmpty()) |
| 61 | 9 | *duplicate = key; | |
| 62 |
1/1✓ Branch 24 → 25 taken 32590 times.
|
32590 | events.insert(key, component); |
| 63 | 32590 | } | |
| 64 | 2430 | return events; | |
| 65 | ✗ | } | |
| 66 | |||
| 67 | // The VCALENDAR of `text`; `*lossy` is set when the parse dropped lines. | ||
| 68 | 2469 | ICal::Component parseCalendar(const QString &text, QString *error, bool *lossy) { | |
| 69 | 2469 | QList<ICal::Component> components; | |
| 70 | 2469 | int skipped = 0; | |
| 71 |
2/3✓ Branch 2 → 3 taken 2469 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2469 times.
|
2469 | if (!ICal::parse(text, &components, error, &skipped)) |
| 72 | ✗ | return {}; | |
| 73 |
2/2✓ Branch 5 → 6 taken 12 times.
✓ Branch 5 → 7 taken 2457 times.
|
2469 | if (skipped > 0) |
| 74 | 12 | *lossy = true; | |
| 75 |
4/4✓ Branch 7 → 8 taken 2469 times.
✓ Branch 8 → 9 taken 2469 times.
✓ Branch 18 → 10 taken 2467 times.
✓ Branch 18 → 19 taken 2 times.
|
2469 | for (const ICal::Component &component : components) |
| 76 |
1/2✓ Branch 13 → 14 taken 2467 times.
✗ Branch 13 → 16 not taken.
|
2467 | if (component.name == QLatin1String("VCALENDAR")) |
| 77 | 2467 | return component; | |
| 78 | 2 | return {}; | |
| 79 | 2469 | } | |
| 80 | |||
| 81 | 823 | Inputs parseInputs(const QString &baseText, const QString &localText, const QString &serverText) { | |
| 82 | 823 | Inputs inputs; | |
| 83 | 823 | QString error; | |
| 84 | 823 | bool lossy = false; | |
| 85 |
1/1✓ Branch 2 → 3 taken 823 times.
|
823 | inputs.base.root = parseCalendar(baseText, &error, &lossy); |
| 86 |
1/1✓ Branch 5 → 6 taken 823 times.
|
823 | inputs.local.root = parseCalendar(localText, &error, &lossy); |
| 87 |
1/1✓ Branch 8 → 9 taken 823 times.
|
823 | inputs.server.root = parseCalendar(serverText, &error, &lossy); |
| 88 |
6/8✓ Branch 12 → 13 taken 823 times.
✗ Branch 12 → 17 not taken.
✓ Branch 14 → 15 taken 823 times.
✗ Branch 14 → 17 not taken.
✓ Branch 16 → 17 taken 2 times.
✓ Branch 16 → 18 taken 821 times.
✓ Branch 19 → 20 taken 2 times.
✓ Branch 19 → 31 taken 821 times.
|
823 | if (inputs.base.root.name.isEmpty() || inputs.local.root.name.isEmpty() || inputs.server.root.name.isEmpty()) { |
| 89 |
2/4✓ Branch 21 → 22 taken 2 times.
✗ Branch 21 → 25 not taken.
✓ Branch 28 → 29 taken 2 times.
✗ Branch 28 → 30 not taken.
|
4 | inputs.error = error.isEmpty() ? QStringLiteral("Unparseable resource") : error; |
| 90 | 2 | return inputs; | |
| 91 | } | ||
| 92 | // S106-129: lines the parser skipped would look deleted in every group. | ||
| 93 |
2/2✓ Branch 31 → 32 taken 11 times.
✓ Branch 31 → 39 taken 810 times.
|
821 | if (lossy) { |
| 94 | 11 | inputs.error = QStringLiteral("A version has lines MailJD cannot read; it is not merged"); | |
| 95 | 11 | return inputs; | |
| 96 | } | ||
| 97 | 810 | QString duplicate; | |
| 98 |
1/1✓ Branch 39 → 40 taken 810 times.
|
810 | inputs.base.events = eventsByKey(inputs.base.root, &duplicate); |
| 99 |
1/1✓ Branch 42 → 43 taken 810 times.
|
810 | inputs.local.events = eventsByKey(inputs.local.root, &duplicate); |
| 100 |
1/1✓ Branch 45 → 46 taken 810 times.
|
810 | inputs.server.events = eventsByKey(inputs.server.root, &duplicate); |
| 101 |
2/2✓ Branch 49 → 50 taken 9 times.
✓ Branch 49 → 60 taken 801 times.
|
810 | if (!duplicate.isEmpty()) |
| 102 |
1/1✓ Branch 54 → 55 taken 9 times.
|
18 | inputs.error = QStringLiteral("A version holds the component %1 twice; it is not merged").arg(duplicate); |
| 103 | 810 | return inputs; | |
| 104 | 823 | } | |
| 105 | |||
| 106 | 27495 | QString groupOfName(const QString &name, bool master) { | |
| 107 | 13 | static const QSet<QString> time{QStringLiteral("DTSTART"), QStringLiteral("DTEND"), QStringLiteral("DUE"), | |
| 108 |
5/10✓ Branch 2 → 3 taken 13 times.
✓ Branch 2 → 28 taken 27482 times.
✓ Branch 4 → 5 taken 13 times.
✗ Branch 4 → 28 not taken.
✓ Branch 21 → 22 taken 52 times.
✓ Branch 21 → 23 taken 13 times.
✗ Branch 100 → 101 not taken.
✗ Branch 100 → 102 not taken.
✗ Branch 121 → 122 not taken.
✗ Branch 121 → 123 not taken.
|
27573 | QStringLiteral("DURATION")}; |
| 109 | 13 | static const QSet<QString> completion{QStringLiteral("STATUS"), QStringLiteral("PERCENT-COMPLETE"), | |
| 110 |
5/10✓ Branch 28 → 29 taken 13 times.
✓ Branch 28 → 50 taken 27482 times.
✓ Branch 30 → 31 taken 13 times.
✗ Branch 30 → 50 not taken.
✓ Branch 44 → 45 taken 39 times.
✓ Branch 44 → 46 taken 13 times.
✗ Branch 125 → 126 not taken.
✗ Branch 125 → 127 not taken.
✗ Branch 143 → 144 not taken.
✗ Branch 143 → 145 not taken.
|
27560 | QStringLiteral("COMPLETED")}; |
| 111 |
5/10✓ Branch 50 → 51 taken 13 times.
✓ Branch 50 → 72 taken 27482 times.
✓ Branch 52 → 53 taken 13 times.
✗ Branch 52 → 72 not taken.
✓ Branch 66 → 67 taken 39 times.
✓ Branch 66 → 68 taken 13 times.
✗ Branch 147 → 148 not taken.
✗ Branch 147 → 149 not taken.
✗ Branch 165 → 166 not taken.
✗ Branch 165 → 167 not taken.
|
27547 | static const QSet<QString> recurrence{QStringLiteral("RRULE"), QStringLiteral("RDATE"), QStringLiteral("EXDATE")}; |
| 112 |
2/2✓ Branch 73 → 74 taken 10736 times.
✓ Branch 73 → 79 taken 16759 times.
|
27495 | if (time.contains(name)) |
| 113 | 10736 | return QStringLiteral("time"); | |
| 114 |
2/2✓ Branch 80 → 81 taken 113 times.
✓ Branch 80 → 86 taken 16646 times.
|
16759 | if (completion.contains(name)) |
| 115 | 113 | return QStringLiteral("completion"); | |
| 116 |
6/6✓ Branch 86 → 87 taken 1619 times.
✓ Branch 86 → 90 taken 15027 times.
✓ Branch 88 → 89 taken 117 times.
✓ Branch 88 → 90 taken 1502 times.
✓ Branch 91 → 92 taken 117 times.
✓ Branch 91 → 97 taken 16529 times.
|
16646 | if (master && recurrence.contains(name)) |
| 117 | 117 | return QStringLiteral("recurrence"); | |
| 118 | 16529 | return {}; | |
| 119 | 169 | } | |
| 120 | |||
| 121 | 27239 | bool isTextName(const QString &name) { | |
| 122 |
4/4✓ Branch 4 → 5 taken 27135 times.
✓ Branch 4 → 8 taken 104 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 27134 times.
|
27239 | return name == QLatin1String("DESCRIPTION") || name == QLatin1String("COMMENT"); |
| 123 | } | ||
| 124 | |||
| 125 | // D-8 (Sprint 107 S107.2.4): list properties merge as sets like vCard's — | ||
| 126 | // one item per attendee (by calendar address), tag, excluded/added date, | ||
| 127 | // parent link (by RELTYPE + UID), contact, attachment and reminder (by its | ||
| 128 | // UID, else ACTION + TRIGGER). Two people adding different values is no | ||
| 129 | // conflict; the same value changed differently on both sides still is. | ||
| 130 | 27386 | bool isLineSetName(const QString &name) { | |
| 131 |
4/4✓ Branch 7 → 8 taken 27336 times.
✓ Branch 7 → 14 taken 13 times.
✓ Branch 10 → 11 taken 27327 times.
✓ Branch 10 → 14 taken 9 times.
|
82071 | return name == QLatin1String("ATTENDEE") || name == QLatin1String("RELATED-TO") || |
| 132 |
4/4✓ Branch 4 → 5 taken 27349 times.
✓ Branch 4 → 14 taken 37 times.
✓ Branch 13 → 14 taken 9 times.
✓ Branch 13 → 15 taken 27318 times.
|
82071 | name == QLatin1String("CONTACT") || name == QLatin1String("ATTACH"); |
| 133 | } | ||
| 134 | |||
| 135 | 27812 | bool isValueSetName(const QString &name) { | |
| 136 |
6/6✓ Branch 4 → 5 taken 27644 times.
✓ Branch 4 → 11 taken 168 times.
✓ Branch 7 → 8 taken 27565 times.
✓ Branch 7 → 11 taken 79 times.
✓ Branch 10 → 11 taken 23 times.
✓ Branch 10 → 12 taken 27542 times.
|
27812 | return name == QLatin1String("CATEGORIES") || name == QLatin1String("EXDATE") || name == QLatin1String("RDATE"); |
| 137 | } | ||
| 138 | |||
| 139 | 27386 | bool isSetName(const QString &name) { | |
| 140 |
6/6✓ Branch 3 → 4 taken 27318 times.
✓ Branch 3 → 9 taken 68 times.
✓ Branch 5 → 6 taken 27263 times.
✓ Branch 5 → 9 taken 55 times.
✓ Branch 8 → 9 taken 24 times.
✓ Branch 8 → 10 taken 27239 times.
|
27386 | return isLineSetName(name) || isValueSetName(name) || name == QLatin1String("BEGIN:VALARM"); |
| 141 | } | ||
| 142 | |||
| 143 | struct SetUnit { | ||
| 144 | QString key; | ||
| 145 | QString text; // the content line (one value) or the serialized VALARM | ||
| 146 | }; | ||
| 147 | |||
| 148 | 614 | QList<SetUnit> setUnits(const ICal::Component *component, const QString &name) { | |
| 149 | 614 | QList<SetUnit> units; | |
| 150 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 614 times.
|
614 | if (!component) |
| 151 | ✗ | return units; | |
| 152 |
2/2✓ Branch 6 → 7 taken 97 times.
✓ Branch 6 → 86 taken 517 times.
|
614 | if (name == QLatin1String("BEGIN:VALARM")) { |
| 153 |
2/2✓ Branch 84 → 9 taken 87 times.
✓ Branch 84 → 85 taken 97 times.
|
184 | for (const ICal::Component &alarm : component->components) { |
| 154 |
1/2✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 87 times.
|
87 | if (alarm.name != QLatin1String("VALARM")) |
| 155 | ✗ | continue; | |
| 156 |
1/1✓ Branch 17 → 18 taken 87 times.
|
87 | const ICal::Property *trigger = alarm.property(QStringLiteral("TRIGGER")); |
| 157 |
2/2✓ Branch 23 → 24 taken 87 times.
✓ Branch 24 → 25 taken 87 times.
|
87 | const QString uid = alarm.value(QStringLiteral("UID")).trimmed(); |
| 158 |
2/6✓ Branch 73 → 74 taken 36 times.
✓ Branch 73 → 75 taken 51 times.
✗ Branch 235 → 236 not taken.
✗ Branch 235 → 237 not taken.
✗ Branch 239 → 240 not taken.
✗ Branch 239 → 241 not taken.
|
210 | const QString key = !uid.isEmpty() ? QStringLiteral("uid:") + uid |
| 159 |
22/40✓ Branch 42 → 43 taken 51 times.
✓ Branch 43 → 44 taken 51 times.
✓ Branch 44 → 45 taken 51 times.
✓ Branch 48 → 49 taken 51 times.
✓ Branch 51 → 52 taken 51 times.
✓ Branch 51 → 53 taken 36 times.
✓ Branch 53 → 54 taken 51 times.
✓ Branch 53 → 55 taken 36 times.
✓ Branch 55 → 56 taken 51 times.
✓ Branch 55 → 57 taken 36 times.
✓ Branch 57 → 58 taken 51 times.
✓ Branch 57 → 59 taken 36 times.
✓ Branch 59 → 60 taken 51 times.
✓ Branch 59 → 61 taken 36 times.
✓ Branch 61 → 62 taken 51 times.
✓ Branch 61 → 63 taken 36 times.
✓ Branch 63 → 64 taken 51 times.
✓ Branch 63 → 65 taken 36 times.
✓ Branch 65 → 66 taken 51 times.
✓ Branch 65 → 67 taken 36 times.
✓ Branch 67 → 68 taken 51 times.
✓ Branch 67 → 69 taken 36 times.
✗ Branch 193 → 194 not taken.
✗ Branch 193 → 195 not taken.
✗ Branch 197 → 198 not taken.
✗ Branch 197 → 199 not taken.
✗ Branch 201 → 202 not taken.
✗ Branch 201 → 203 not taken.
✗ Branch 205 → 206 not taken.
✗ Branch 205 → 207 not taken.
✗ 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.
✗ Branch 225 → 226 not taken.
✗ Branch 225 → 227 not taken.
|
189 | : QStringLiteral("a:") + alarm.value(QStringLiteral("ACTION")).trimmed().toUpper() + |
| 160 |
11/14✓ Branch 29 → 30 taken 36 times.
✓ Branch 29 → 34 taken 51 times.
✓ Branch 33 → 51 taken 36 times.
✓ Branch 34 → 35 taken 51 times.
✗ Branch 34 → 36 not taken.
✓ Branch 35 → 37 taken 51 times.
✓ Branch 49 → 50 taken 51 times.
✓ Branch 50 → 51 taken 51 times.
✓ Branch 69 → 70 taken 51 times.
✓ Branch 69 → 71 taken 36 times.
✓ Branch 71 → 72 taken 36 times.
✓ Branch 71 → 73 taken 51 times.
✗ Branch 231 → 232 not taken.
✗ Branch 231 → 233 not taken.
|
261 | QLatin1Char('|') + (trigger ? trigger->contentLine() : QString()); |
| 161 | 87 | units.append({key, ICal::serialize(alarm)}); | |
| 162 | 87 | } | |
| 163 | 97 | return units; | |
| 164 | } | ||
| 165 |
5/5✓ Branch 86 → 87 taken 517 times.
✓ Branch 87 → 88 taken 517 times.
✓ Branch 88 → 89 taken 517 times.
✓ Branch 174 → 90 taken 469 times.
✓ Branch 174 → 175 taken 517 times.
|
986 | for (const ICal::Property &property : component->propertiesNamed(name)) { |
| 166 |
2/2✓ Branch 92 → 93 taken 204 times.
✓ Branch 92 → 122 taken 265 times.
|
469 | if (isValueSetName(name)) { |
| 167 |
5/5✓ Branch 93 → 94 taken 204 times.
✓ Branch 94 → 95 taken 204 times.
✓ Branch 95 → 96 taken 204 times.
✓ Branch 119 → 97 taken 261 times.
✓ Branch 119 → 120 taken 204 times.
|
465 | for (const QString &value : ICal::splitValues(property.value)) { |
| 168 | 261 | ICal::Property single = property; | |
| 169 |
1/1✓ Branch 99 → 100 taken 261 times.
|
261 | single.setValue(value); |
| 170 |
1/1✓ Branch 100 → 101 taken 261 times.
|
261 | const QString text = single.contentLine(); |
| 171 |
6/10✓ Branch 104 → 105 taken 191 times.
✓ Branch 105 → 106 taken 191 times.
✓ Branch 111 → 112 taken 191 times.
✓ Branch 111 → 113 taken 70 times.
✓ Branch 113 → 114 taken 191 times.
✓ Branch 113 → 115 taken 70 times.
✗ Branch 260 → 261 not taken.
✗ Branch 260 → 262 not taken.
✗ Branch 264 → 265 not taken.
✗ Branch 264 → 266 not taken.
|
713 | units.append({name == QLatin1String("CATEGORIES") ? ICal::unescapeText(value).trimmed().toLower() : text, text}); |
| 172 | 465 | } | |
| 173 | 204 | continue; | |
| 174 | 204 | } | |
| 175 |
1/1✓ Branch 122 → 123 taken 265 times.
|
265 | QString key = property.value.trimmed(); |
| 176 |
2/2✓ Branch 125 → 126 taken 190 times.
✓ Branch 125 → 130 taken 75 times.
|
265 | if (name == QLatin1String("ATTENDEE")) |
| 177 |
1/1✓ Branch 126 → 127 taken 190 times.
|
190 | key = key.toLower(); |
| 178 |
2/2✓ Branch 132 → 133 taken 42 times.
✓ Branch 132 → 165 taken 33 times.
|
75 | else if (name == QLatin1String("RELATED-TO")) |
| 179 |
9/15✓ Branch 138 → 139 taken 42 times.
✓ Branch 139 → 140 taken 39 times.
✓ Branch 139 → 145 taken 3 times.
✓ Branch 143 → 144 taken 39 times.
✓ Branch 144 → 148 taken 39 times.
✓ Branch 158 → 159 taken 39 times.
✓ Branch 158 → 160 taken 3 times.
✓ Branch 160 → 161 taken 39 times.
✓ Branch 160 → 162 taken 3 times.
✗ Branch 287 → 288 not taken.
✗ Branch 287 → 289 not taken.
✗ Branch 291 → 292 not taken.
✗ Branch 291 → 293 not taken.
✗ Branch 295 → 296 not taken.
✗ Branch 295 → 297 not taken.
|
168 | key = (property.hasParameter(QStringLiteral("RELTYPE")) ? property.parameter(QStringLiteral("RELTYPE")).toUpper() |
| 180 |
4/6✓ Branch 154 → 155 taken 3 times.
✓ Branch 154 → 156 taken 39 times.
✓ Branch 156 → 157 taken 39 times.
✓ Branch 156 → 158 taken 3 times.
✗ Branch 283 → 284 not taken.
✗ Branch 283 → 285 not taken.
|
84 | : QStringLiteral("PARENT")) + |
| 181 |
2/2✓ Branch 148 → 149 taken 42 times.
✓ Branch 149 → 150 taken 42 times.
|
126 | QLatin1Char('|') + key; |
| 182 | 265 | units.append({key, property.contentLine()}); | |
| 183 | 782 | } | |
| 184 | 517 | return units; | |
| 185 | 804 | } | |
| 186 | |||
| 187 | 768 | const SetUnit *unitWithKey(const QList<SetUnit> &units, const QString &key) { | |
| 188 | 768 | const SetUnit *found = nullptr; | |
| 189 |
2/2✓ Branch 10 → 4 taken 858 times.
✓ Branch 10 → 11 taken 768 times.
|
1626 | for (const SetUnit &unit : units) |
| 190 |
2/2✓ Branch 6 → 7 taken 406 times.
✓ Branch 6 → 8 taken 452 times.
|
858 | if (unit.key == key) |
| 191 | 406 | found = &unit; | |
| 192 | 768 | return found; | |
| 193 | } | ||
| 194 | |||
| 195 | 256 | QString setItemId(const QString &key, const QString &name, const QString &unitKey) { | |
| 196 |
4/4✓ Branch 8 → 9 taken 256 times.
✓ Branch 9 → 10 taken 256 times.
✓ Branch 10 → 11 taken 256 times.
✓ Branch 11 → 12 taken 256 times.
|
512 | return key + QStringLiteral("::") + name + QStringLiteral("::") + unitKey; |
| 197 | } | ||
| 198 | |||
| 199 | 147 | void addSetItems(Merge::Plan *plan, const QString &key, const QString &name, const QString &recurrence, | |
| 200 | const ICal::Component *base, const ICal::Component *local, const ICal::Component *server) { | ||
| 201 |
3/3✓ Branch 2 → 3 taken 147 times.
✓ Branch 3 → 4 taken 147 times.
✓ Branch 4 → 5 taken 147 times.
|
147 | const QList<SetUnit> b = setUnits(base, name), l = setUnits(local, name), s = setUnits(server, name); |
| 202 | 147 | QStringList keys; | |
| 203 |
2/2✓ Branch 17 → 7 taken 441 times.
✓ Branch 17 → 18 taken 147 times.
|
588 | for (const QList<SetUnit> *units : {&s, &l, &b}) |
| 204 |
2/2✓ Branch 15 → 9 taken 406 times.
✓ Branch 15 → 16 taken 441 times.
|
847 | for (const SetUnit &unit : *units) |
| 205 |
2/2✓ Branch 11 → 12 taken 256 times.
✓ Branch 11 → 13 taken 150 times.
|
406 | if (!keys.contains(unit.key)) |
| 206 |
1/1✓ Branch 12 → 13 taken 256 times.
|
256 | keys.append(unit.key); |
| 207 |
2/2✓ Branch 2 → 3 taken 406 times.
✓ Branch 2 → 4 taken 362 times.
|
768 | const auto value = [](const SetUnit *unit) { return unit ? Merge::Value{true, unit->text} : Merge::Value{}; }; |
| 208 |
4/4✓ Branch 18 → 19 taken 147 times.
✓ Branch 19 → 20 taken 147 times.
✓ Branch 49 → 21 taken 256 times.
✓ Branch 49 → 50 taken 147 times.
|
403 | for (const QString &unitKey : keys) { |
| 209 | 256 | Merge::Item item; | |
| 210 |
1/1✓ Branch 22 → 23 taken 256 times.
|
256 | item.id = setItemId(key, name, unitKey); |
| 211 | 256 | item.name = name; | |
| 212 | 256 | item.parent = key; | |
| 213 | 256 | item.context = recurrence; | |
| 214 | 256 | item.kind = Merge::Kind::SetValue; | |
| 215 |
1/1✓ Branch 29 → 30 taken 256 times.
|
256 | item.group = groupOfName(name, recurrence.isEmpty()); |
| 216 |
1/1✓ Branch 32 → 33 taken 256 times.
|
256 | item.base = value(unitWithKey(b, unitKey)); |
| 217 |
1/1✓ Branch 36 → 37 taken 256 times.
|
256 | item.local = value(unitWithKey(l, unitKey)); |
| 218 |
1/1✓ Branch 40 → 41 taken 256 times.
|
256 | item.server = value(unitWithKey(s, unitKey)); |
| 219 |
1/1✓ Branch 44 → 45 taken 256 times.
|
256 | item.state = Merge::stateOf(item.base, item.local, item.server); |
| 220 |
1/1✓ Branch 45 → 46 taken 256 times.
|
256 | plan->items.append(item); |
| 221 | 256 | } | |
| 222 | 147 | } | |
| 223 | |||
| 224 | // The lines of a set name for the chosen values. Unchanged sets keep the | ||
| 225 | // exact lines of the side they equal; mixed value lists are written as one | ||
| 226 | // line per parameter set (values comma-separated). | ||
| 227 | 126 | QStringList setLines(const QList<const Merge::Item *> &siblings, const QString &name, const Groups &localGroups, | |
| 228 | const Groups &serverGroups, const ICal::Component *local, const ICal::Component *server) { | ||
| 229 | 126 | QStringList texts; | |
| 230 |
2/2✓ Branch 19 → 4 taken 812 times.
✓ Branch 19 → 20 taken 126 times.
|
938 | for (const Merge::Item *item : siblings) { |
| 231 |
5/6✓ Branch 6 → 7 taken 219 times.
✓ Branch 6 → 8 taken 593 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 219 times.
✓ Branch 10 → 11 taken 593 times.
✓ Branch 10 → 12 taken 219 times.
|
812 | if (item->name != name || item->kind != Merge::Kind::SetValue) |
| 232 | 593 | continue; | |
| 233 | 219 | bool present = false; | |
| 234 |
1/1✓ Branch 12 → 13 taken 219 times.
|
219 | const QString text = Merge::resultText(*item, &present); |
| 235 |
2/2✓ Branch 13 → 14 taken 164 times.
✓ Branch 13 → 15 taken 55 times.
|
219 | if (present) |
| 236 |
1/1✓ Branch 14 → 15 taken 164 times.
|
164 | texts.append(text); |
| 237 | 219 | } | |
| 238 | 173 | const auto sameSet = [&texts](const QList<SetUnit> &units) { | |
| 239 | 173 | QStringList side; | |
| 240 |
2/2✓ Branch 8 → 4 taken 207 times.
✓ Branch 8 → 9 taken 173 times.
|
380 | for (const SetUnit &unit : units) |
| 241 |
1/1✓ Branch 5 → 6 taken 207 times.
|
207 | side.append(unit.text); |
| 242 | 173 | QStringList mine = texts; | |
| 243 |
1/1✓ Branch 10 → 11 taken 173 times.
|
173 | side.sort(); |
| 244 |
1/1✓ Branch 11 → 12 taken 173 times.
|
173 | mine.sort(); |
| 245 |
1/1✓ Branch 12 → 13 taken 173 times.
|
346 | return side == mine; |
| 246 | 173 | }; | |
| 247 |
4/4✓ Branch 20 → 21 taken 126 times.
✓ Branch 21 → 22 taken 126 times.
✓ Branch 23 → 24 taken 79 times.
✓ Branch 23 → 29 taken 47 times.
|
126 | if (sameSet(setUnits(server, name))) |
| 248 |
1/1✓ Branch 25 → 26 taken 79 times.
|
79 | return serverGroups.value(name); |
| 249 |
4/4✓ Branch 29 → 30 taken 47 times.
✓ Branch 30 → 31 taken 47 times.
✓ Branch 32 → 33 taken 22 times.
✓ Branch 32 → 38 taken 25 times.
|
47 | if (sameSet(setUnits(local, name))) |
| 250 |
1/1✓ Branch 34 → 35 taken 22 times.
|
22 | return localGroups.value(name); |
| 251 |
2/2✓ Branch 39 → 40 taken 14 times.
✓ Branch 39 → 42 taken 11 times.
|
25 | if (!isValueSetName(name)) { |
| 252 |
1/1✓ Branch 40 → 41 taken 14 times.
|
14 | texts.sort(); |
| 253 | 14 | return texts; | |
| 254 | } | ||
| 255 | // One line per parameter set, values in the chosen order. | ||
| 256 | 11 | QStringList heads; | |
| 257 | 11 | QHash<QString, QStringList> values; | |
| 258 |
4/4✓ Branch 42 → 43 taken 11 times.
✓ Branch 43 → 44 taken 11 times.
✓ Branch 92 → 45 taken 24 times.
✓ Branch 92 → 93 taken 11 times.
|
35 | for (const QString &text : texts) { |
| 259 | const ICal::Component parsed = | ||
| 260 |
3/3✓ Branch 55 → 56 taken 24 times.
✓ Branch 56 → 57 taken 24 times.
✓ Branch 57 → 58 taken 24 times.
|
72 | ICal::parseFirst(QStringLiteral("BEGIN:X\r\n") + text + QStringLiteral("\r\nEND:X\r\n"), QStringLiteral("X")); |
| 261 |
1/2✗ Branch 67 → 68 not taken.
✓ Branch 67 → 69 taken 24 times.
|
24 | if (parsed.properties.isEmpty()) |
| 262 | ✗ | continue; | |
| 263 | 24 | ICal::Property head = parsed.properties.first(); | |
| 264 | 24 | const QString value = head.value; | |
| 265 |
1/1✓ Branch 73 → 74 taken 24 times.
|
24 | head.setValue(QString()); |
| 266 |
1/1✓ Branch 75 → 76 taken 24 times.
|
24 | const QString headLine = head.contentLine(); |
| 267 |
2/2✓ Branch 77 → 78 taken 11 times.
✓ Branch 77 → 79 taken 13 times.
|
24 | if (!heads.contains(headLine)) |
| 268 |
1/1✓ Branch 78 → 79 taken 11 times.
|
11 | heads.append(headLine); |
| 269 |
2/2✓ Branch 79 → 80 taken 24 times.
✓ Branch 80 → 81 taken 24 times.
|
24 | values[headLine].append(value); |
| 270 | 24 | } | |
| 271 | 11 | QStringList lines; | |
| 272 |
4/4✓ Branch 93 → 94 taken 11 times.
✓ Branch 94 → 95 taken 11 times.
✓ Branch 108 → 96 taken 11 times.
✓ Branch 108 → 109 taken 11 times.
|
22 | for (const QString &head : heads) |
| 273 |
3/3✓ Branch 100 → 101 taken 11 times.
✓ Branch 101 → 102 taken 11 times.
✓ Branch 102 → 103 taken 11 times.
|
11 | lines.append(head + values.value(head).join(QLatin1Char(','))); |
| 274 |
1/1✓ Branch 109 → 110 taken 11 times.
|
11 | lines.sort(); |
| 275 | 11 | return lines; | |
| 276 | 126 | } | |
| 277 | |||
| 278 | 81717 | Merge::Value valueOf(const QStringList &lines) { | |
| 279 | 326868 | return {!lines.isEmpty(), lines.join(QLatin1Char('\n'))}; | |
| 280 | 245151 | } | |
| 281 | |||
| 282 | 315 | QString plainOf(const QStringList &lines) { | |
| 283 |
2/2✓ Branch 3 → 4 taken 6 times.
✓ Branch 3 → 5 taken 309 times.
|
315 | if (lines.isEmpty()) |
| 284 | 6 | return {}; | |
| 285 |
1/1✓ Branch 15 → 16 taken 309 times.
|
927 | const ICal::Component parsed = ICal::parseFirst(QStringLiteral("BEGIN:X\r\n") + lines.first() + |
| 286 |
1/1✓ Branch 16 → 17 taken 309 times.
|
927 | QStringLiteral("\r\nEND:X\r\n"), |
| 287 |
1/1✓ Branch 17 → 18 taken 309 times.
|
927 | QStringLiteral("X")); |
| 288 |
2/3✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 309 times.
✓ Branch 30 → 31 taken 309 times.
|
309 | return parsed.properties.isEmpty() ? QString() : ICal::unescapeText(parsed.properties.first().value); |
| 289 | 309 | } | |
| 290 | |||
| 291 | 22 | Merge::Plan rawPlan(const QString &base, const QString &local, const QString &server, const QString &error) { | |
| 292 | 22 | Merge::Plan plan; | |
| 293 | 22 | plan.domain = QStringLiteral("ical"); | |
| 294 | 22 | plan.comparable = false; | |
| 295 | 22 | plan.error = error; | |
| 296 | 22 | plan.baseText = base; | |
| 297 | 22 | plan.localText = local; | |
| 298 | 22 | plan.serverText = server; | |
| 299 | 22 | Merge::Item raw; | |
| 300 | 22 | raw.id = kRawItem; | |
| 301 | 22 | raw.name = QStringLiteral("resource"); | |
| 302 | 22 | raw.kind = Merge::Kind::Text; | |
| 303 | 22 | raw.base = {true, base}; | |
| 304 | 22 | raw.local = {true, local}; | |
| 305 | 22 | raw.server = {true, server}; | |
| 306 |
1/1✓ Branch 28 → 29 taken 22 times.
|
22 | raw.state = Merge::stateOf(raw.base, raw.local, raw.server); |
| 307 |
1/2✓ Branch 29 → 30 taken 22 times.
✗ Branch 29 → 31 not taken.
|
22 | if (raw.state != Merge::State::Same) |
| 308 | 22 | raw.state = Merge::State::Conflict; // a person decides an unreadable resource | |
| 309 | 22 | raw.basePlain = base; | |
| 310 | 22 | raw.localPlain = local; | |
| 311 | 22 | raw.serverPlain = server; | |
| 312 |
1/1✓ Branch 34 → 35 taken 22 times.
|
22 | raw.hunks = TextMerge::diff3(base, local, server); |
| 313 |
1/1✓ Branch 37 → 38 taken 22 times.
|
22 | plan.items.append(raw); |
| 314 |
1/1✓ Branch 38 → 39 taken 22 times.
|
22 | Merge::applyDefaults(&plan); |
| 315 | 22 | return plan; | |
| 316 | 88 | } | |
| 317 | |||
| 318 | // Rebuilds a component from merged groups, keeping the server's property | ||
| 319 | // order where possible (server first, then local-only names). | ||
| 320 | 5346 | ICal::Component rebuild(const ICal::Component &theirs, const ICal::Component &ours, const Groups &merged, | |
| 321 | int sequence) { | ||
| 322 | 5346 | ICal::Component event; | |
| 323 | 5346 | event.name = theirs.name; | |
| 324 | 5346 | QStringList order; | |
| 325 |
2/2✓ Branch 11 → 5 taken 32417 times.
✓ Branch 11 → 12 taken 5346 times.
|
37763 | for (const ICal::Property &property : theirs.properties) |
| 326 |
3/3✓ Branch 7 → 8 taken 32387 times.
✓ Branch 7 → 9 taken 30 times.
✓ Branch 8 → 9 taken 32387 times.
|
32417 | if (!order.contains(property.name)) order.append(property.name); |
| 327 |
2/2✓ Branch 20 → 14 taken 32405 times.
✓ Branch 20 → 21 taken 5346 times.
|
37751 | for (const ICal::Property &property : ours.properties) |
| 328 |
3/3✓ Branch 16 → 17 taken 45 times.
✓ Branch 16 → 18 taken 32360 times.
✓ Branch 17 → 18 taken 45 times.
|
32405 | if (!order.contains(property.name)) order.append(property.name); |
| 329 |
4/4✓ Branch 21 → 22 taken 5346 times.
✓ Branch 22 → 23 taken 5346 times.
✓ Branch 88 → 24 taken 32432 times.
✓ Branch 88 → 89 taken 5346 times.
|
37778 | for (const QString &name : order) { |
| 330 |
2/2✓ Branch 26 → 27 taken 5684 times.
✓ Branch 26 → 47 taken 26748 times.
|
32432 | if (kBookkeeping.contains(name)) { |
| 331 |
3/5✓ Branch 27 → 28 taken 5684 times.
✓ Branch 28 → 29 taken 5684 times.
✗ Branch 28 → 31 not taken.
✓ Branch 29 → 30 taken 5684 times.
✗ Branch 31 → 32 not taken.
|
5684 | const ICal::Property *source = theirs.property(name) ? theirs.property(name) : ours.property(name); |
| 332 |
1/2✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 5684 times.
|
5684 | if (!source) |
| 333 | ✗ | continue; | |
| 334 | 5684 | ICal::Property property = *source; | |
| 335 |
2/2✓ Branch 38 → 39 taken 279 times.
✓ Branch 38 → 43 taken 5405 times.
|
5684 | if (name == QLatin1String("SEQUENCE")) |
| 336 |
2/2✓ Branch 39 → 40 taken 279 times.
✓ Branch 40 → 41 taken 279 times.
|
279 | property.setValue(QString::number(sequence)); |
| 337 |
1/1✓ Branch 43 → 44 taken 5684 times.
|
5684 | event.appendProperty(property); |
| 338 | 5684 | continue; | |
| 339 | 5684 | } | |
| 340 |
5/5✓ Branch 48 → 49 taken 26748 times.
✓ Branch 50 → 51 taken 26748 times.
✓ Branch 51 → 52 taken 26748 times.
✓ Branch 83 → 53 taken 26751 times.
✓ Branch 83 → 84 taken 26748 times.
|
53499 | for (const QString &line : merged.value(name)) { |
| 341 | 26751 | QList<ICal::Component> parsed; | |
| 342 |
3/3✓ Branch 60 → 61 taken 26751 times.
✓ Branch 61 → 62 taken 26751 times.
✓ Branch 62 → 63 taken 26751 times.
|
53502 | ICal::parse(QStringLiteral("BEGIN:X\r\n") + line + QStringLiteral("\r\nEND:X\r\n"), &parsed); |
| 343 |
4/7✓ Branch 70 → 71 taken 26751 times.
✗ Branch 70 → 75 not taken.
✓ Branch 71 → 72 taken 26751 times.
✓ Branch 73 → 74 taken 26751 times.
✗ Branch 73 → 75 not taken.
✓ Branch 76 → 77 taken 26751 times.
✗ Branch 76 → 80 not taken.
|
26751 | if (!parsed.isEmpty() && !parsed.first().properties.isEmpty()) |
| 344 |
3/3✓ Branch 77 → 78 taken 26751 times.
✓ Branch 78 → 79 taken 26751 times.
✓ Branch 79 → 80 taken 26751 times.
|
26751 | event.appendProperty(parsed.first().properties.first()); |
| 345 | 53499 | } | |
| 346 | } | ||
| 347 |
4/4✓ Branch 89 → 90 taken 5346 times.
✓ Branch 115 → 116 taken 32113 times.
✓ Branch 117 → 91 taken 26767 times.
✓ Branch 117 → 118 taken 5346 times.
|
32113 | for (auto it = merged.constBegin(); it != merged.constEnd(); ++it) { |
| 348 |
3/3✓ Branch 93 → 94 taken 26767 times.
✓ Branch 94 → 95 taken 26748 times.
✓ Branch 94 → 96 taken 19 times.
|
26767 | if (!it.key().startsWith(QLatin1String("BEGIN:"))) |
| 349 | 26748 | continue; | |
| 350 |
2/2✓ Branch 112 → 99 taken 22 times.
✓ Branch 112 → 113 taken 19 times.
|
41 | for (const QString &text : it.value()) { |
| 351 | 22 | QList<ICal::Component> parsed; | |
| 352 |
4/7✓ Branch 100 → 101 taken 22 times.
✓ Branch 101 → 102 taken 22 times.
✗ Branch 101 → 105 not taken.
✓ Branch 103 → 104 taken 22 times.
✗ Branch 103 → 105 not taken.
✓ Branch 106 → 107 taken 22 times.
✗ Branch 106 → 109 not taken.
|
22 | if (ICal::parse(text, &parsed) && !parsed.isEmpty()) |
| 353 |
2/2✓ Branch 107 → 108 taken 22 times.
✓ Branch 108 → 109 taken 22 times.
|
22 | event.components.append(parsed.first()); |
| 354 | 22 | } | |
| 355 | } | ||
| 356 | 5346 | return event; | |
| 357 | 5346 | } | |
| 358 | |||
| 359 | // The lines of a text item the user edited: the property of the local side | ||
| 360 | // (else the server's) with the new value; empty text removes it. | ||
| 361 | 13 | QStringList editedLines(const QString &text, const QStringList &local, const QStringList &server) { | |
| 362 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 13 times.
|
13 | if (text.isEmpty()) |
| 363 | ✗ | return {}; | |
| 364 |
1/4✓ Branch 6 → 7 taken 13 times.
✗ Branch 6 → 9 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 13 not taken.
|
13 | const QString source = !local.isEmpty() ? local.first() : !server.isEmpty() ? server.first() : QString(); |
| 365 |
2/2✓ Branch 23 → 24 taken 13 times.
✓ Branch 24 → 25 taken 13 times.
|
39 | ICal::Component parsed = ICal::parseFirst(QStringLiteral("BEGIN:X\r\n") + source + QStringLiteral("\r\nEND:X\r\n"), |
| 366 |
1/1✓ Branch 25 → 26 taken 13 times.
|
39 | QStringLiteral("X")); |
| 367 |
1/2✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 13 times.
|
13 | if (parsed.properties.isEmpty()) |
| 368 | ✗ | return {}; | |
| 369 |
1/1✓ Branch 37 → 38 taken 13 times.
|
13 | ICal::Property property = parsed.properties.first(); |
| 370 |
2/2✓ Branch 39 → 40 taken 13 times.
✓ Branch 40 → 41 taken 13 times.
|
13 | property.setValue(ICal::escapeText(text)); |
| 371 |
2/4✓ Branch 45 → 46 taken 13 times.
✓ Branch 45 → 47 taken 13 times.
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 82 not taken.
|
26 | return {property.contentLine()}; |
| 372 | 26 | } | |
| 373 | |||
| 374 | // Sprint 107 J3: an occurrence added or moved on one side while the other | ||
| 375 | // side cancelled it (a new EXDATE with its RECURRENCE-ID) would combine | ||
| 376 | // into an exception the EXDATE hides — the move was lost without a word. | ||
| 377 | // Both items become one question (group "occurrence:<id>"): this side's | ||
| 378 | // component and the other side's EXDATE value are chosen together. | ||
| 379 | 465 | void coupleMovedAndCancelled(Merge::Plan *plan) { | |
| 380 | 465 | QList<Merge::Item *> added; // EXDATE values one side added | |
| 381 |
4/4✓ Branch 2 → 3 taken 465 times.
✓ Branch 3 → 4 taken 465 times.
✓ Branch 17 → 5 taken 27523 times.
✓ Branch 17 → 18 taken 465 times.
|
27988 | for (Merge::Item &exdate : plan->items) |
| 382 |
7/8✓ Branch 6 → 7 taken 256 times.
✓ Branch 6 → 12 taken 27267 times.
✓ Branch 9 → 10 taken 30 times.
✓ Branch 9 → 12 taken 226 times.
✓ Branch 10 → 11 taken 30 times.
✗ Branch 10 → 12 not taken.
✓ Branch 13 → 14 taken 30 times.
✓ Branch 13 → 15 taken 27493 times.
|
27523 | if (exdate.kind == Merge::Kind::SetValue && exdate.name == QLatin1String("EXDATE") && !exdate.base.present) |
| 383 |
1/1✓ Branch 14 → 15 taken 30 times.
|
30 | added.append(&exdate); |
| 384 |
2/2✓ Branch 19 → 20 taken 444 times.
✓ Branch 19 → 21 taken 21 times.
|
465 | if (added.isEmpty()) |
| 385 | 444 | return; | |
| 386 |
4/4✓ Branch 21 → 22 taken 21 times.
✓ Branch 22 → 23 taken 21 times.
✓ Branch 79 → 24 taken 144 times.
✓ Branch 79 → 80 taken 21 times.
|
165 | for (Merge::Item &occurrence : plan->items) { |
| 387 |
6/8✓ Branch 25 → 26 taken 11 times.
✓ Branch 25 → 31 taken 133 times.
✓ Branch 27 → 28 taken 11 times.
✗ Branch 27 → 31 not taken.
✓ Branch 28 → 29 taken 11 times.
✗ Branch 28 → 31 not taken.
✓ Branch 33 → 34 taken 133 times.
✓ Branch 33 → 35 taken 11 times.
|
155 | if (occurrence.kind != Merge::Kind::Component || occurrence.context.isEmpty() || occurrence.base.present || |
| 388 |
1/4✗ Branch 29 → 30 not taken.
✓ Branch 29 → 32 taken 11 times.
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 32 not taken.
|
11 | (occurrence.state != Merge::State::LocalOnly && occurrence.state != Merge::State::ServerOnly)) |
| 389 | 133 | continue; | |
| 390 | 11 | const Merge::State cancelledBy = | |
| 391 |
1/2✓ Branch 35 → 36 taken 11 times.
✗ Branch 35 → 37 not taken.
|
11 | occurrence.state == Merge::State::LocalOnly ? Merge::State::ServerOnly : Merge::State::LocalOnly; |
| 392 |
4/4✓ Branch 38 → 39 taken 11 times.
✓ Branch 39 → 40 taken 11 times.
✓ Branch 75 → 41 taken 11 times.
✓ Branch 75 → 76 taken 11 times.
|
22 | for (Merge::Item *pointer : added) { |
| 393 | 11 | Merge::Item &exdate = *pointer; | |
| 394 |
1/2✗ Branch 42 → 43 not taken.
✓ Branch 42 → 44 taken 11 times.
|
11 | if (exdate.state != cancelledBy) |
| 395 | ✗ | continue; | |
| 396 |
1/2✓ Branch 44 → 45 taken 11 times.
✗ Branch 44 → 46 not taken.
|
11 | const QString line = cancelledBy == Merge::State::ServerOnly ? exdate.server.text : exdate.local.text; |
| 397 |
3/4✓ Branch 51 → 52 taken 11 times.
✓ Branch 52 → 53 taken 11 times.
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 58 taken 11 times.
|
11 | if (line.section(QLatin1Char(':'), -1).trimmed() != occurrence.context) |
| 398 | ✗ | continue; | |
| 399 | 11 | occurrence.state = Merge::State::Conflict; | |
| 400 | 11 | exdate.state = Merge::State::Conflict; | |
| 401 |
1/1✓ Branch 61 → 62 taken 11 times.
|
22 | occurrence.group = exdate.group = QStringLiteral("occurrence:") + occurrence.context; |
| 402 | 11 | } | |
| 403 | } | ||
| 404 | 465 | } | |
| 405 | |||
| 406 | } // namespace | ||
| 407 | |||
| 408 | 487 | Merge::Plan analyze(const QString &baseText, const QString &localText, const QString &serverText) { | |
| 409 |
1/1✓ Branch 2 → 3 taken 487 times.
|
487 | const Inputs inputs = parseInputs(baseText, localText, serverText); |
| 410 |
2/2✓ Branch 4 → 5 taken 22 times.
✓ Branch 4 → 7 taken 465 times.
|
487 | if (!inputs.error.isEmpty()) |
| 411 |
1/1✓ Branch 5 → 6 taken 22 times.
|
22 | return rawPlan(baseText, localText, serverText, inputs.error); |
| 412 | 465 | Merge::Plan plan; | |
| 413 | 465 | plan.domain = QStringLiteral("ical"); | |
| 414 | 465 | plan.baseText = baseText; | |
| 415 | 465 | plan.localText = localText; | |
| 416 | 465 | plan.serverText = serverText; | |
| 417 |
5/5✓ Branch 16 → 17 taken 465 times.
✓ Branch 17 → 18 taken 465 times.
✓ Branch 18 → 19 taken 465 times.
✓ Branch 19 → 20 taken 465 times.
✓ Branch 20 → 21 taken 465 times.
|
465 | QStringList keys = inputs.base.events.keys() + inputs.local.events.keys() + inputs.server.events.keys(); |
| 418 |
1/1✓ Branch 25 → 26 taken 465 times.
|
465 | keys.removeDuplicates(); |
| 419 |
3/3✓ Branch 26 → 27 taken 465 times.
✓ Branch 27 → 28 taken 465 times.
✓ Branch 28 → 29 taken 465 times.
|
465 | std::sort(keys.begin(), keys.end()); |
| 420 |
4/4✓ Branch 29 → 30 taken 465 times.
✓ Branch 30 → 31 taken 465 times.
✓ Branch 266 → 32 taken 5504 times.
✓ Branch 266 → 267 taken 465 times.
|
5969 | for (const QString &key : keys) { |
| 421 |
1/1✓ Branch 33 → 34 taken 5504 times.
|
5504 | const bool inBase = inputs.base.events.contains(key); |
| 422 |
1/1✓ Branch 34 → 35 taken 5504 times.
|
5504 | const bool inLocal = inputs.local.events.contains(key); |
| 423 |
1/1✓ Branch 35 → 36 taken 5504 times.
|
5504 | const bool inServer = inputs.server.events.contains(key); |
| 424 |
3/4✓ Branch 36 → 37 taken 9 times.
✓ Branch 36 → 39 taken 5495 times.
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 9 times.
|
5504 | if (!inLocal && !inServer) |
| 425 | 28 | continue; // removed on both sides | |
| 426 |
4/4✓ Branch 39 → 40 taken 5495 times.
✓ Branch 39 → 41 taken 9 times.
✓ Branch 40 → 42 taken 5495 times.
✓ Branch 41 → 42 taken 9 times.
|
5504 | const ICal::Component &any = inLocal ? inputs.local.events[key] : inputs.server.events[key]; |
| 427 |
1/1✓ Branch 45 → 46 taken 5504 times.
|
5504 | const QString recurrence = any.value(QStringLiteral("RECURRENCE-ID")); |
| 428 |
6/8✓ Branch 48 → 49 taken 5493 times.
✓ Branch 48 → 51 taken 11 times.
✓ Branch 49 → 50 taken 5493 times.
✓ Branch 50 → 52 taken 5493 times.
✓ Branch 52 → 53 taken 5493 times.
✓ Branch 52 → 54 taken 11 times.
✗ Branch 293 → 294 not taken.
✗ Branch 293 → 295 not taken.
|
5504 | const Groups baseGroups = inBase ? groupsOf(inputs.base.events[key]) : Groups{}; |
| 429 |
6/8✓ Branch 54 → 55 taken 5495 times.
✓ Branch 54 → 57 taken 9 times.
✓ Branch 55 → 56 taken 5495 times.
✓ Branch 56 → 58 taken 5495 times.
✓ Branch 58 → 59 taken 5495 times.
✓ Branch 58 → 60 taken 9 times.
✗ Branch 297 → 298 not taken.
✗ Branch 297 → 299 not taken.
|
5504 | const Groups localGroups = inLocal ? groupsOf(inputs.local.events[key]) : Groups{}; |
| 430 |
6/8✓ Branch 60 → 61 taken 5485 times.
✓ Branch 60 → 63 taken 19 times.
✓ Branch 61 → 62 taken 5485 times.
✓ Branch 62 → 64 taken 5485 times.
✓ Branch 64 → 65 taken 5485 times.
✓ Branch 64 → 66 taken 19 times.
✗ Branch 301 → 302 not taken.
✗ Branch 301 → 303 not taken.
|
5504 | const Groups serverGroups = inServer ? groupsOf(inputs.server.events[key]) : Groups{}; |
| 431 |
4/4✓ Branch 66 → 67 taken 5495 times.
✓ Branch 66 → 68 taken 9 times.
✓ Branch 67 → 68 taken 19 times.
✓ Branch 67 → 121 taken 5476 times.
|
5504 | if (!inLocal || !inServer) { |
| 432 | 28 | Merge::Item component; | |
| 433 | 28 | component.id = key; | |
| 434 | 28 | component.name = any.name; | |
| 435 | 28 | component.context = recurrence; | |
| 436 | 28 | component.kind = Merge::Kind::Component; | |
| 437 |
2/2✓ Branch 71 → 72 taken 17 times.
✓ Branch 71 → 78 taken 11 times.
|
28 | if (inBase) |
| 438 | 17 | component.base = {true, ICal::serialize(inputs.base.events[key])}; | |
| 439 |
2/2✓ Branch 78 → 79 taken 19 times.
✓ Branch 78 → 85 taken 9 times.
|
28 | if (inLocal) |
| 440 | 19 | component.local = {true, ICal::serialize(inputs.local.events[key])}; | |
| 441 |
2/2✓ Branch 85 → 86 taken 9 times.
✓ Branch 85 → 92 taken 19 times.
|
28 | if (inServer) |
| 442 | 9 | component.server = {true, ICal::serialize(inputs.server.events[key])}; | |
| 443 |
4/4✓ Branch 92 → 93 taken 17 times.
✓ Branch 92 → 95 taken 11 times.
✓ Branch 93 → 94 taken 9 times.
✓ Branch 93 → 95 taken 8 times.
|
28 | const bool removedLocally = inBase && !inLocal; |
| 444 |
4/4✓ Branch 96 → 97 taken 17 times.
✓ Branch 96 → 99 taken 11 times.
✓ Branch 97 → 98 taken 8 times.
✓ Branch 97 → 99 taken 9 times.
|
28 | const bool removedOnServer = inBase && !inServer; |
| 445 |
10/12✓ Branch 100 → 101 taken 9 times.
✓ Branch 100 → 103 taken 19 times.
✓ Branch 101 → 102 taken 9 times.
✗ Branch 102 → 103 not taken.
✓ Branch 102 → 106 taken 9 times.
✓ Branch 103 → 104 taken 8 times.
✓ Branch 103 → 107 taken 11 times.
✓ Branch 104 → 105 taken 8 times.
✗ Branch 105 → 106 not taken.
✓ Branch 105 → 107 taken 8 times.
✓ Branch 108 → 109 taken 9 times.
✓ Branch 108 → 110 taken 19 times.
|
28 | if ((removedLocally && serverGroups != baseGroups) || (removedOnServer && localGroups != baseGroups)) { |
| 446 | 9 | component.kind = Merge::Kind::Deletion; | |
| 447 | 9 | component.state = Merge::State::Conflict; | |
| 448 | } else { | ||
| 449 |
1/2✓ Branch 110 → 111 taken 19 times.
✗ Branch 110 → 112 not taken.
|
19 | component.state = inLocal ? Merge::State::LocalOnly : Merge::State::ServerOnly; |
| 450 |
1/2✗ Branch 113 → 114 not taken.
✓ Branch 113 → 115 taken 19 times.
|
19 | if (removedLocally) |
| 451 | ✗ | component.state = Merge::State::LocalOnly; | |
| 452 |
2/2✓ Branch 115 → 116 taken 8 times.
✓ Branch 115 → 117 taken 11 times.
|
19 | else if (removedOnServer) |
| 453 | 8 | component.state = Merge::State::ServerOnly; | |
| 454 | } | ||
| 455 |
1/1✓ Branch 117 → 118 taken 28 times.
|
28 | plan.items.append(component); |
| 456 | 28 | continue; | |
| 457 | 28 | } | |
| 458 |
5/5✓ Branch 121 → 122 taken 5476 times.
✓ Branch 122 → 123 taken 5476 times.
✓ Branch 123 → 124 taken 5476 times.
✓ Branch 124 → 125 taken 5476 times.
✓ Branch 125 → 126 taken 5476 times.
|
5476 | QStringList names = baseGroups.keys() + localGroups.keys() + serverGroups.keys(); |
| 459 |
1/1✓ Branch 130 → 131 taken 5476 times.
|
5476 | names.removeDuplicates(); |
| 460 |
4/4✓ Branch 131 → 132 taken 5476 times.
✓ Branch 132 → 133 taken 5476 times.
✓ Branch 240 → 134 taken 27386 times.
✓ Branch 240 → 241 taken 5476 times.
|
32862 | for (const QString &name : names) { |
| 461 |
2/2✓ Branch 136 → 137 taken 147 times.
✓ Branch 136 → 155 taken 27239 times.
|
27386 | if (isSetName(name)) { |
| 462 |
1/1✓ Branch 138 → 139 taken 147 times.
|
147 | const ICal::Component baseComponent = inputs.base.events.value(key); |
| 463 |
1/1✓ Branch 141 → 142 taken 147 times.
|
147 | const ICal::Component localComponent = inputs.local.events.value(key); |
| 464 |
1/1✓ Branch 144 → 145 taken 147 times.
|
147 | const ICal::Component serverComponent = inputs.server.events.value(key); |
| 465 |
2/3✓ Branch 146 → 147 taken 147 times.
✗ Branch 146 → 148 not taken.
✓ Branch 149 → 150 taken 147 times.
|
147 | addSetItems(&plan, key, name, recurrence, inBase ? &baseComponent : nullptr, &localComponent, |
| 466 | &serverComponent); | ||
| 467 | 147 | continue; | |
| 468 | 147 | } | |
| 469 |
3/3✓ Branch 156 → 157 taken 27239 times.
✓ Branch 159 → 160 taken 27239 times.
✓ Branch 162 → 163 taken 27239 times.
|
27239 | const QStringList b = baseGroups.value(name), l = localGroups.value(name), s = serverGroups.value(name); |
| 470 | 27239 | Merge::Item item; | |
| 471 |
2/2✓ Branch 167 → 168 taken 27239 times.
✓ Branch 168 → 169 taken 27239 times.
|
27239 | item.id = key + QStringLiteral("::") + name; |
| 472 | 27239 | item.name = name; | |
| 473 | 27239 | item.parent = key; | |
| 474 | 27239 | item.context = recurrence; | |
| 475 |
1/1✓ Branch 178 → 179 taken 27239 times.
|
27239 | item.group = groupOfName(name, recurrence.isEmpty()); |
| 476 |
1/1✓ Branch 181 → 182 taken 27239 times.
|
27239 | item.base = valueOf(b); |
| 477 |
1/1✓ Branch 184 → 185 taken 27239 times.
|
27239 | item.local = valueOf(l); |
| 478 |
1/1✓ Branch 187 → 188 taken 27239 times.
|
27239 | item.server = valueOf(s); |
| 479 | // The pre-Sprint-107 decision: local == base → server; server == | ||
| 480 | // base or both alike → local; otherwise a conflict. | ||
| 481 |
8/8✓ Branch 190 → 191 taken 27239 times.
✓ Branch 191 → 192 taken 26728 times.
✓ Branch 191 → 195 taken 511 times.
✓ Branch 192 → 193 taken 26728 times.
✓ Branch 193 → 194 taken 26557 times.
✓ Branch 193 → 195 taken 171 times.
✓ Branch 196 → 197 taken 26557 times.
✓ Branch 196 → 198 taken 682 times.
|
27239 | if (l == b && s == b) |
| 482 | 26557 | item.state = Merge::State::Same; | |
| 483 |
3/3✓ Branch 198 → 199 taken 682 times.
✓ Branch 199 → 200 taken 171 times.
✓ Branch 199 → 201 taken 511 times.
|
682 | else if (l == b) |
| 484 | 171 | item.state = Merge::State::ServerOnly; | |
| 485 |
3/3✓ Branch 201 → 202 taken 511 times.
✓ Branch 202 → 203 taken 179 times.
✓ Branch 202 → 204 taken 332 times.
|
511 | else if (s == b) |
| 486 | 179 | item.state = Merge::State::LocalOnly; | |
| 487 |
3/3✓ Branch 204 → 205 taken 332 times.
✓ Branch 205 → 206 taken 17 times.
✓ Branch 205 → 207 taken 315 times.
|
332 | else if (l == s) |
| 488 | 17 | item.state = Merge::State::BothSame; | |
| 489 | else | ||
| 490 | 315 | item.state = Merge::State::Conflict; | |
| 491 |
7/10✓ Branch 209 → 210 taken 105 times.
✓ Branch 209 → 217 taken 27134 times.
✓ Branch 211 → 212 taken 105 times.
✗ Branch 211 → 217 not taken.
✓ Branch 213 → 214 taken 105 times.
✗ Branch 213 → 217 not taken.
✓ Branch 215 → 216 taken 105 times.
✗ Branch 215 → 217 not taken.
✓ Branch 218 → 219 taken 105 times.
✓ Branch 218 → 232 taken 27134 times.
|
27239 | if (isTextName(name) && b.size() <= 1 && l.size() <= 1 && s.size() <= 1) { |
| 492 | 105 | item.kind = Merge::Kind::Text; | |
| 493 |
1/1✓ Branch 219 → 220 taken 105 times.
|
105 | item.basePlain = plainOf(b); |
| 494 |
1/1✓ Branch 222 → 223 taken 105 times.
|
105 | item.localPlain = plainOf(l); |
| 495 |
1/1✓ Branch 225 → 226 taken 105 times.
|
105 | item.serverPlain = plainOf(s); |
| 496 |
1/1✓ Branch 228 → 229 taken 105 times.
|
105 | item.hunks = TextMerge::diff3(item.basePlain, item.localPlain, item.serverPlain); |
| 497 | } | ||
| 498 |
1/1✓ Branch 232 → 233 taken 27239 times.
|
27239 | plan.items.append(item); |
| 499 | 27239 | } | |
| 500 | 5616 | } | |
| 501 |
1/1✓ Branch 267 → 268 taken 465 times.
|
465 | coupleMovedAndCancelled(&plan); |
| 502 |
1/1✓ Branch 268 → 269 taken 465 times.
|
465 | Merge::applyDefaults(&plan); |
| 503 | 465 | return plan; | |
| 504 | 532 | } | |
| 505 | |||
| 506 | 356 | Applied apply(const Merge::Plan &plan) { | |
| 507 | 356 | Applied applied; | |
| 508 |
2/2✓ Branch 16 → 4 taken 26929 times.
✓ Branch 16 → 17 taken 342 times.
|
27271 | for (const Merge::Item &item : plan.items) |
| 509 |
3/3✓ Branch 5 → 6 taken 26929 times.
✓ Branch 6 → 7 taken 14 times.
✓ Branch 6 → 14 taken 26915 times.
|
26929 | if (Merge::itemOpen(plan, item)) { |
| 510 | 14 | applied.error = QStringLiteral("Open conflicts remain"); | |
| 511 | 14 | return applied; | |
| 512 | } | ||
| 513 |
2/2✓ Branch 17 → 18 taken 6 times.
✓ Branch 17 → 26 taken 336 times.
|
342 | if (!plan.comparable) { |
| 514 |
1/1✓ Branch 18 → 19 taken 6 times.
|
6 | const Merge::Item *raw = plan.item(kRawItem); |
| 515 |
1/2✗ Branch 19 → 20 not taken.
✓ Branch 19 → 22 taken 6 times.
|
6 | if (!raw) { |
| 516 | ✗ | applied.error = plan.error; | |
| 517 | ✗ | return applied; | |
| 518 | } | ||
| 519 | 6 | applied.ok = true; | |
| 520 |
1/1✓ Branch 22 → 23 taken 6 times.
|
6 | applied.text = Merge::resultText(*raw); |
| 521 | 6 | return applied; | |
| 522 | } | ||
| 523 |
1/1✓ Branch 26 → 27 taken 336 times.
|
336 | const Inputs inputs = parseInputs(plan.baseText, plan.localText, plan.serverText); |
| 524 |
1/2✗ Branch 28 → 29 not taken.
✓ Branch 28 → 31 taken 336 times.
|
336 | if (!inputs.error.isEmpty()) { |
| 525 | ✗ | applied.error = inputs.error; | |
| 526 | ✗ | return applied; | |
| 527 | } | ||
| 528 | 336 | ICal::Component merged = inputs.server.root; | |
| 529 |
1/1✓ Branch 35 → 36 taken 336 times.
|
336 | merged.removeComponents(QStringLiteral("VEVENT")); |
| 530 |
1/1✓ Branch 41 → 42 taken 336 times.
|
336 | merged.removeComponents(QStringLiteral("VTODO")); |
| 531 |
5/5✓ Branch 44 → 45 taken 336 times.
✓ Branch 45 → 46 taken 336 times.
✓ Branch 46 → 47 taken 336 times.
✓ Branch 47 → 48 taken 336 times.
✓ Branch 48 → 49 taken 336 times.
|
336 | QStringList keys = inputs.base.events.keys() + inputs.local.events.keys() + inputs.server.events.keys(); |
| 532 |
1/1✓ Branch 53 → 54 taken 336 times.
|
336 | keys.removeDuplicates(); |
| 533 |
3/3✓ Branch 54 → 55 taken 336 times.
✓ Branch 55 → 56 taken 336 times.
✓ Branch 56 → 57 taken 336 times.
|
336 | std::sort(keys.begin(), keys.end()); |
| 534 | // The items of each component and the component items, indexed once (G11: | ||
| 535 | // a series with 500 overrides has thousands of items). | ||
| 536 | 336 | QHash<QString, QList<const Merge::Item *>> children; | |
| 537 | 336 | QHash<QString, const Merge::Item *> byId; | |
| 538 |
2/2✓ Branch 65 → 59 taken 26887 times.
✓ Branch 65 → 66 taken 336 times.
|
27223 | for (const Merge::Item &item : plan.items) { |
| 539 |
2/2✓ Branch 60 → 61 taken 26887 times.
✓ Branch 61 → 62 taken 26887 times.
|
26887 | children[item.parent].append(&item); |
| 540 |
1/1✓ Branch 62 → 63 taken 26887 times.
|
26887 | byId.insert(item.id, &item); |
| 541 | } | ||
| 542 |
4/4✓ Branch 66 → 67 taken 336 times.
✓ Branch 67 → 68 taken 336 times.
✓ Branch 185 → 69 taken 5373 times.
✓ Branch 185 → 186 taken 336 times.
|
5709 | for (const QString &key : keys) { |
| 543 |
2/2✓ Branch 71 → 72 taken 27 times.
✓ Branch 71 → 87 taken 5346 times.
|
5373 | if (const Merge::Item *component = byId.value(key)) { |
| 544 |
2/2✓ Branch 72 → 73 taken 19 times.
✓ Branch 72 → 74 taken 8 times.
|
35 | const QMap<QString, ICal::Component> *side = component->choice == Merge::Choice::Server ? &inputs.server.events |
| 545 |
1/2✗ Branch 74 → 75 not taken.
✓ Branch 74 → 76 taken 8 times.
|
8 | : component->choice == Merge::Choice::Base ? &inputs.base.events |
| 546 | : &inputs.local.events; | ||
| 547 |
3/3✓ Branch 78 → 79 taken 27 times.
✓ Branch 79 → 80 taken 12 times.
✓ Branch 79 → 86 taken 15 times.
|
27 | if (side->contains(key)) |
| 548 |
2/2✓ Branch 81 → 82 taken 12 times.
✓ Branch 82 → 83 taken 12 times.
|
12 | merged.components.append(side->value(key)); |
| 549 | 27 | continue; | |
| 550 | 27 | } | |
| 551 |
5/8✓ Branch 87 → 88 taken 5346 times.
✓ Branch 88 → 89 taken 5346 times.
✗ Branch 88 → 91 not taken.
✓ Branch 89 → 90 taken 5346 times.
✗ Branch 90 → 91 not taken.
✓ Branch 90 → 92 taken 5346 times.
✗ Branch 93 → 94 not taken.
✓ Branch 93 → 95 taken 5346 times.
|
5346 | if (!inputs.local.events.contains(key) || !inputs.server.events.contains(key)) |
| 552 | ✗ | continue; // removed on both sides | |
| 553 |
1/1✓ Branch 95 → 96 taken 5346 times.
|
5346 | const ICal::Component &ours = inputs.local.events[key]; |
| 554 |
1/1✓ Branch 96 → 97 taken 5346 times.
|
5346 | const ICal::Component &theirs = inputs.server.events[key]; |
| 555 |
5/9✓ Branch 97 → 98 taken 5346 times.
✓ Branch 98 → 99 taken 5346 times.
✗ Branch 98 → 101 not taken.
✓ Branch 99 → 100 taken 5346 times.
✓ Branch 100 → 102 taken 5346 times.
✓ Branch 102 → 103 taken 5346 times.
✗ Branch 102 → 104 not taken.
✗ Branch 289 → 290 not taken.
✗ Branch 289 → 291 not taken.
|
5346 | const Groups baseGroups = inputs.base.events.contains(key) ? groupsOf(inputs.base.events[key]) : Groups{}; |
| 556 |
1/1✓ Branch 104 → 105 taken 5346 times.
|
5346 | const Groups localGroups = groupsOf(ours); |
| 557 |
1/1✓ Branch 105 → 106 taken 5346 times.
|
5346 | const Groups serverGroups = groupsOf(theirs); |
| 558 | 5346 | Groups mergedGroups; | |
| 559 | 5346 | const QList<const Merge::Item *> siblings = children.value(key); | |
| 560 |
2/2✓ Branch 153 → 109 taken 26860 times.
✓ Branch 153 → 154 taken 5346 times.
|
32206 | for (const Merge::Item *entry : siblings) { |
| 561 | 26860 | const Merge::Item &item = *entry; | |
| 562 |
2/2✓ Branch 110 → 111 taken 219 times.
✓ Branch 110 → 118 taken 26641 times.
|
26860 | if (item.kind == Merge::Kind::SetValue) { |
| 563 |
3/3✓ Branch 111 → 112 taken 219 times.
✓ Branch 112 → 113 taken 126 times.
✓ Branch 112 → 117 taken 93 times.
|
219 | if (!mergedGroups.contains(item.name)) |
| 564 |
2/2✓ Branch 113 → 114 taken 126 times.
✓ Branch 114 → 115 taken 126 times.
|
126 | mergedGroups.insert(item.name, setLines(siblings, item.name, localGroups, serverGroups, &ours, &theirs)); |
| 565 | 219 | continue; | |
| 566 | } | ||
| 567 |
4/4✓ Branch 118 → 119 taken 799 times.
✓ Branch 118 → 125 taken 1 time.
✓ Branch 118 → 131 taken 13 times.
✓ Branch 118 → 145 taken 25828 times.
|
26641 | switch (item.choice) { |
| 568 | 799 | case Merge::Choice::Server: | |
| 569 |
2/2✓ Branch 120 → 121 taken 799 times.
✓ Branch 121 → 122 taken 799 times.
|
799 | mergedGroups.insert(item.name, serverGroups.value(item.name)); |
| 570 | 799 | break; | |
| 571 | 1 | case Merge::Choice::Base: | |
| 572 |
2/2✓ Branch 126 → 127 taken 1 time.
✓ Branch 127 → 128 taken 1 time.
|
1 | mergedGroups.insert(item.name, baseGroups.value(item.name)); |
| 573 | 1 | break; | |
| 574 | 13 | case Merge::Choice::Edited: | |
| 575 |
4/4✓ Branch 134 → 135 taken 13 times.
✓ Branch 135 → 136 taken 13 times.
✓ Branch 136 → 137 taken 13 times.
✓ Branch 137 → 138 taken 13 times.
|
13 | mergedGroups.insert(item.name, editedLines(Merge::resultText(item), localGroups.value(item.name), |
| 576 |
1/1✓ Branch 132 → 133 taken 13 times.
|
26 | serverGroups.value(item.name))); |
| 577 | 13 | break; | |
| 578 | 25828 | default: | |
| 579 |
2/2✓ Branch 146 → 147 taken 25828 times.
✓ Branch 147 → 148 taken 25828 times.
|
25828 | mergedGroups.insert(item.name, localGroups.value(item.name)); |
| 580 | 25828 | break; | |
| 581 | } | ||
| 582 | } | ||
| 583 |
2/2✓ Branch 162 → 163 taken 5346 times.
✓ Branch 163 → 164 taken 5346 times.
|
10692 | const int sequence = qMax(ours.value(QStringLiteral("SEQUENCE")).toInt(), |
| 584 |
2/2✓ Branch 157 → 158 taken 5346 times.
✓ Branch 158 → 159 taken 5346 times.
|
16038 | theirs.value(QStringLiteral("SEQUENCE")).toInt()); |
| 585 |
2/2✓ Branch 171 → 172 taken 5346 times.
✓ Branch 172 → 173 taken 5346 times.
|
5346 | merged.components.append(rebuild(theirs, ours, mergedGroups, sequence)); |
| 586 | 5346 | } | |
| 587 | // A zone the local edit introduced needs its definition next to theirs. | ||
| 588 | 336 | QSet<QString> zones; | |
| 589 |
5/5✓ Branch 190 → 191 taken 336 times.
✓ Branch 193 → 194 taken 336 times.
✓ Branch 194 → 195 taken 336 times.
✓ Branch 207 → 196 taken 256 times.
✓ Branch 207 → 208 taken 336 times.
|
592 | for (const ICal::Component &component : merged.componentsNamed(QStringLiteral("VTIMEZONE"))) |
| 590 |
2/2✓ Branch 200 → 201 taken 256 times.
✓ Branch 201 → 202 taken 256 times.
|
592 | zones.insert(component.value(QStringLiteral("TZID"))); |
| 591 | 336 | int insertAt = 0; | |
| 592 |
6/6✓ Branch 212 → 213 taken 592 times.
✓ Branch 212 → 218 taken 60 times.
✓ Branch 216 → 217 taken 316 times.
✓ Branch 216 → 218 taken 276 times.
✓ Branch 219 → 210 taken 316 times.
✓ Branch 219 → 220 taken 336 times.
|
652 | while (insertAt < merged.components.size() && merged.components.at(insertAt).name != QLatin1String("VEVENT")) |
| 593 | 316 | ++insertAt; | |
| 594 |
5/5✓ Branch 223 → 224 taken 336 times.
✓ Branch 226 → 227 taken 336 times.
✓ Branch 227 → 228 taken 336 times.
✓ Branch 242 → 229 taken 264 times.
✓ Branch 242 → 243 taken 336 times.
|
600 | for (const ICal::Component &component : inputs.local.root.componentsNamed(QStringLiteral("VTIMEZONE"))) |
| 595 |
3/3✓ Branch 233 → 234 taken 264 times.
✓ Branch 238 → 239 taken 8 times.
✓ Branch 238 → 240 taken 256 times.
|
264 | if (!zones.contains(component.value(QStringLiteral("TZID")))) |
| 596 |
1/1✓ Branch 239 → 240 taken 8 times.
|
344 | merged.components.insert(insertAt++, component); |
| 597 | 336 | applied.ok = true; | |
| 598 |
1/1✓ Branch 244 → 245 taken 336 times.
|
336 | applied.text = ICal::serialize(merged); |
| 599 | 336 | return applied; | |
| 600 | 336 | } | |
| 601 | |||
| 602 | 153 | QString conflictName(const Merge::Item &item) { | |
| 603 |
7/11✓ Branch 3 → 4 taken 146 times.
✓ Branch 3 → 5 taken 7 times.
✓ Branch 8 → 9 taken 7 times.
✓ Branch 9 → 10 taken 7 times.
✓ Branch 9 → 11 taken 146 times.
✓ Branch 11 → 12 taken 7 times.
✓ Branch 11 → 13 taken 146 times.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 37 not taken.
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 41 not taken.
|
160 | const QString label = item.context.isEmpty() ? QString() : QStringLiteral("@") + item.context; |
| 604 |
2/2✓ Branch 14 → 15 taken 5 times.
✓ Branch 14 → 23 taken 148 times.
|
153 | if (item.parent.isEmpty()) |
| 605 |
1/1✓ Branch 18 → 19 taken 5 times.
|
5 | return QStringLiteral("VEVENT") + label; |
| 606 |
3/5✓ Branch 24 → 25 taken 148 times.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 148 times.
✗ Branch 26 → 28 not taken.
✓ Branch 28 → 29 taken 148 times.
|
148 | return (item.name.startsWith(QLatin1String("BEGIN:")) ? item.name.mid(6) : item.name) + label; |
| 607 | 153 | } | |
| 608 | |||
| 609 | } // namespace ICalMergePlan | ||
| 610 |