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: 97.8% 265 / 0 / 271
Functions: 100.0% 20 / 0 / 20
Branches: 91.9% 387 / 0 / 421

presentation/ConflictRows.cpp
Line Branch Exec Source
1 #include "ConflictRows.h"
2
3 #include <QHash>
4
5 #include "data/TextMerge3.h"
6
7 #include <QCoreApplication>
8 #include <QSet>
9 #include <QVariantMap>
10
11 namespace ConflictRows {
12
13 namespace {
14
15 using Side = ConflictValueText::Side;
16
17 370 QString pickName(Merge::Choice choice) {
18
3/6
✓ Branch 2 → 3 taken 248 times.
✓ Branch 2 → 8 taken 91 times.
✗ Branch 2 → 13 not taken.
✗ Branch 2 → 18 not taken.
✓ Branch 2 → 23 taken 31 times.
✗ Branch 2 → 24 not taken.
370 switch (choice) {
19 248 case Merge::Choice::Local:
20 248 return QStringLiteral("local");
21 91 case Merge::Choice::Server:
22 91 return QStringLiteral("server");
23 ✗ case Merge::Choice::Both:
24 ✗ return QStringLiteral("both");
25 ✗ case Merge::Choice::Base:
26 ✗ return QStringLiteral("base");
27 31 case Merge::Choice::Edited:
28 case Merge::Choice::None:
29 31 break;
30 }
31 31 return QStringLiteral("open");
32 }
33
34 370 QString hunkKindName(TextMerge::HunkKind kind) {
35
4/6
✓ Branch 2 → 3 taken 171 times.
✓ Branch 2 → 8 taken 77 times.
✓ Branch 2 → 13 taken 91 times.
✗ Branch 2 → 18 not taken.
✓ Branch 2 → 23 taken 31 times.
✗ Branch 2 → 24 not taken.
370 switch (kind) {
36 171 case TextMerge::HunkKind::Same:
37 171 return QStringLiteral("same");
38 77 case TextMerge::HunkKind::LocalOnly:
39 77 return QStringLiteral("local");
40 91 case TextMerge::HunkKind::ServerOnly:
41 91 return QStringLiteral("server");
42 ✗ case TextMerge::HunkKind::BothSame:
43 ✗ return QStringLiteral("both-same");
44 31 case TextMerge::HunkKind::Conflict:
45 31 break;
46 }
47 31 return QStringLiteral("conflict");
48 }
49
50 1103 QString stateOfMembers(const Merge::Plan &plan, const QList<const Merge::Item *> &members, bool conflict) {
51 1103 bool open = false, edited = false;
52
2/2
✓ Branch 16 → 4 taken 1386 times.
✓ Branch 16 → 17 taken 1103 times.
2489 for (const Merge::Item *item : members) {
53
5/5
✓ Branch 5 → 6 taken 1295 times.
✓ Branch 5 → 8 taken 91 times.
✓ Branch 6 → 7 taken 1295 times.
✓ Branch 7 → 8 taken 337 times.
✓ Branch 7 → 9 taken 958 times.
1386 open = open || Merge::itemOpen(plan, *item);
54
3/4
✓ Branch 10 → 11 taken 1386 times.
✗ Branch 10 → 12 not taken.
✓ Branch 11 → 12 taken 6 times.
✓ Branch 11 → 13 taken 1380 times.
1386 edited = edited || item->choice == Merge::Choice::Edited;
55 }
56
2/2
✓ Branch 17 → 18 taken 337 times.
✓ Branch 17 → 23 taken 766 times.
1103 if (open)
57 337 return QStringLiteral("open");
58
2/2
✓ Branch 23 → 24 taken 6 times.
✓ Branch 23 → 29 taken 760 times.
766 if (edited)
59 6 return QStringLiteral("edited");
60
2/2
✓ Branch 29 → 30 taken 78 times.
✓ Branch 29 → 35 taken 682 times.
760 if (conflict)
61 78 return QStringLiteral("decided");
62 682 bool local = false, server = false;
63
2/2
✓ Branch 48 → 37 taken 856 times.
✓ Branch 48 → 49 taken 682 times.
1538 for (const Merge::Item *item : members) {
64
4/4
✓ Branch 38 → 39 taken 835 times.
✓ Branch 38 → 40 taken 21 times.
✓ Branch 39 → 40 taken 330 times.
✓ Branch 39 → 41 taken 505 times.
856 local = local || item->state == Merge::State::LocalOnly;
65
4/4
✓ Branch 42 → 43 taken 758 times.
✓ Branch 42 → 44 taken 98 times.
✓ Branch 43 → 44 taken 409 times.
✓ Branch 43 → 45 taken 349 times.
856 server = server || item->state == Merge::State::ServerOnly;
66 }
67
8/8
✓ Branch 50 → 51 taken 249 times.
✓ Branch 50 → 54 taken 81 times.
✓ Branch 54 → 55 taken 409 times.
✓ Branch 54 → 59 taken 24 times.
✓ Branch 55 → 56 taken 328 times.
✓ Branch 55 → 59 taken 81 times.
✓ Branch 67 → 68 taken 249 times.
✓ Branch 67 → 69 taken 433 times.
1364 return local && !server ? QStringLiteral("local") : server && !local ? QStringLiteral("server")
68
6/6
✓ Branch 49 → 50 taken 330 times.
✓ Branch 49 → 54 taken 352 times.
✓ Branch 63 → 64 taken 105 times.
✓ Branch 63 → 65 taken 577 times.
✓ Branch 65 → 66 taken 328 times.
✓ Branch 65 → 67 taken 354 times.
2046 : QStringLiteral("both-same");
69 }
70
71 1698 QString choiceOfMembers(const QList<const Merge::Item *> &members, bool conflictOnly) {
72 1698 QString choice;
73
2/2
✓ Branch 31 → 4 taken 2063 times.
✓ Branch 31 → 32 taken 1512 times.
3575 for (const Merge::Item *item : members) {
74
4/4
✓ Branch 5 → 6 taken 445 times.
✓ Branch 5 → 8 taken 1618 times.
✓ Branch 6 → 7 taken 13 times.
✓ Branch 6 → 8 taken 432 times.
2063 if (conflictOnly && item->state != Merge::State::Conflict)
75 13 continue;
76
4/4
✓ Branch 8 → 9 taken 336 times.
✓ Branch 8 → 10 taken 1714 times.
✓ Branch 10 → 11 taken 1714 times.
✓ Branch 12 → 13 taken 1714 times.
2050 const QString name = item->choice == Merge::Choice::None ? QString() : QString::fromLatin1(Merge::choiceName(item->choice));
77
2/2
✓ Branch 14 → 15 taken 1776 times.
✓ Branch 14 → 16 taken 274 times.
2050 if (choice.isNull())
78 1776 choice = name;
79
2/2
✓ Branch 17 → 18 taken 186 times.
✓ Branch 17 → 23 taken 88 times.
274 else if (choice != name)
80 186 return QStringLiteral("mixed");
81 2050 }
82
2/2
✓ Branch 33 → 34 taken 258 times.
✓ Branch 33 → 35 taken 1254 times.
1512 return choice.isNull() ? QString() : choice;
83 1698 }
84
85 846 Side sideOf(Merge::Choice choice) {
86
2/2
✓ Branch 2 → 3 taken 439 times.
✓ Branch 2 → 4 taken 407 times.
846 return choice == Merge::Choice::Server ? Side::Server : choice == Merge::Choice::Base ? Side::Base : Side::Local;
87 }
88
89 978 void fillTexts(Row *row, const Merge::Plan &plan, const QList<const Merge::Item *> &members,
90 const ConflictValueText::Context &context) {
91 3561 const auto present = [&members](Side side) {
92
2/2
✓ Branch 15 → 4 taken 3676 times.
✓ Branch 15 → 16 taken 449 times.
4125 for (const Merge::Item *item : members) {
93
4/4
✓ Branch 5 → 6 taken 1339 times.
✓ Branch 5 → 7 taken 2337 times.
✓ Branch 7 → 8 taken 1293 times.
✓ Branch 7 → 9 taken 1044 times.
3676 const Merge::Value &value = side == Side::Local ? item->local : side == Side::Server ? item->server : item->base;
94
2/2
✓ Branch 11 → 12 taken 3112 times.
✓ Branch 11 → 13 taken 564 times.
3676 if (value.present)
95 3112 return true;
96 }
97 449 return false;
98 978 };
99 3112 const auto text = [&](Side side) {
100
2/2
✓ Branch 3 → 4 taken 2469 times.
✓ Branch 3 → 6 taken 643 times.
3112 if (members.size() == 1)
101 2469 return ConflictValueText::value(plan, *members.first(), side, context);
102 643 return ConflictValueText::groupValue(plan, members, side, context);
103 978 };
104 2934 const auto source = [&](Side side) {
105 2934 QStringList lines;
106
2/2
✓ Branch 12 → 4 taken 3783 times.
✓ Branch 12 → 13 taken 2934 times.
6717 for (const Merge::Item *item : members) {
107
1/1
✓ Branch 5 → 6 taken 3783 times.
3783 const QString line = ConflictValueText::source(*item, side);
108
2/2
✓ Branch 7 → 8 taken 2923 times.
✓ Branch 7 → 9 taken 860 times.
3783 if (!line.isEmpty())
109
1/1
✓ Branch 8 → 9 taken 2923 times.
2923 lines.append(line);
110 3783 }
111
1/1
✓ Branch 15 → 16 taken 2934 times.
5868 return lines.join(QLatin1Char('\n'));
112 2934 };
113
1/1
✓ Branch 2 → 3 taken 978 times.
978 row->localPresent = present(Side::Local);
114
1/1
✓ Branch 3 → 4 taken 978 times.
978 row->serverPresent = present(Side::Server);
115
1/1
✓ Branch 4 → 5 taken 978 times.
978 row->basePresent = present(Side::Base);
116
4/4
✓ Branch 5 → 6 taken 843 times.
✓ Branch 5 → 7 taken 135 times.
✓ Branch 6 → 9 taken 843 times.
✓ Branch 8 → 9 taken 135 times.
978 row->localText = row->localPresent ? text(Side::Local) : ConflictValueText::absent(*members.first());
117
4/4
✓ Branch 11 → 12 taken 896 times.
✓ Branch 11 → 13 taken 82 times.
✓ Branch 12 → 15 taken 896 times.
✓ Branch 14 → 15 taken 82 times.
978 row->serverText = row->serverPresent ? text(Side::Server) : ConflictValueText::absent(*members.first());
118
4/4
✓ Branch 17 → 18 taken 765 times.
✓ Branch 17 → 19 taken 213 times.
✓ Branch 18 → 21 taken 765 times.
✓ Branch 20 → 21 taken 213 times.
978 row->baseText = row->basePresent ? text(Side::Base) : ConflictValueText::absent(*members.first());
119
1/1
✓ Branch 23 → 24 taken 978 times.
978 row->localSource = source(Side::Local);
120
1/1
✓ Branch 26 → 27 taken 978 times.
978 row->serverSource = source(Side::Server);
121
1/1
✓ Branch 29 → 30 taken 978 times.
978 row->baseSource = source(Side::Base);
122
2/2
✓ Branch 34 → 35 taken 258 times.
✓ Branch 34 → 37 taken 720 times.
978 if (row->state == QLatin1String("open")) {
123 258 row->resultText.clear();
124 258 row->resultPresent = false;
125 885 return;
126 }
127 // The result: a uniform choice shows that side's text; a mix (separated
128 // group) lists each member's result.
129
1/1
✓ Branch 37 → 38 taken 720 times.
720 const QString choice = choiceOfMembers(members, false);
130
5/6
✓ Branch 40 → 41 taken 627 times.
✓ Branch 40 → 45 taken 93 times.
✓ Branch 43 → 44 taken 627 times.
✗ Branch 43 → 45 not taken.
✓ Branch 46 → 47 taken 627 times.
✓ Branch 46 → 57 taken 93 times.
720 if (choice != QLatin1String("mixed") && choice != QLatin1String("edited")) {
131
1/1
✓ Branch 47 → 48 taken 627 times.
627 const Side side = sideOf(Merge::choiceFromName(choice));
132
1/1
✓ Branch 49 → 50 taken 627 times.
627 row->resultPresent = present(side);
133
4/4
✓ Branch 50 → 51 taken 608 times.
✓ Branch 50 → 52 taken 19 times.
✓ Branch 51 → 54 taken 608 times.
✓ Branch 53 → 54 taken 19 times.
627 row->resultText = row->resultPresent ? text(side) : ConflictValueText::absent(*members.first());
134 627 return;
135 }
136 93 QStringList parts;
137
2/2
✓ Branch 74 → 59 taken 249 times.
✓ Branch 74 → 75 taken 93 times.
342 for (const Merge::Item *item : members) {
138 249 bool itemPresent = false;
139
1/1
✓ Branch 60 → 61 taken 249 times.
249 Merge::resultText(*item, &itemPresent);
140
2/2
✓ Branch 62 → 63 taken 219 times.
✓ Branch 62 → 68 taken 30 times.
249 if (itemPresent)
141
2/2
✓ Branch 64 → 65 taken 219 times.
✓ Branch 65 → 66 taken 219 times.
219 parts.append(ConflictValueText::value(plan, *item, sideOf(item->choice), context));
142
3/4
✓ Branch 68 → 69 taken 93 times.
✓ Branch 68 → 70 taken 156 times.
✓ Branch 69 → 70 taken 93 times.
✗ Branch 69 → 71 not taken.
249 row->resultPresent = row->resultPresent || itemPresent;
143 }
144
1/1
✓ Branch 78 → 79 taken 93 times.
93 row->resultText = parts.join(QStringLiteral(" · "));
145 720 }
146
147 125 Row textRow(const Merge::Plan &plan, const Merge::Item &item, const ConflictValueText::Context &context) {
148 125 Row row;
149 125 row.id = item.id;
150 125 row.kind = QStringLiteral("text");
151
2/4
✓ Branch 12 → 13 taken 125 times.
✓ Branch 12 → 14 taken 125 times.
✗ Branch 245 → 246 not taken.
✗ Branch 245 → 247 not taken.
250 row.itemIds = {item.id};
152 125 row.conflict = item.state == Merge::State::Conflict;
153
2/2
✓ Branch 14 → 15 taken 125 times.
✓ Branch 15 → 16 taken 125 times.
125 row.state = stateOfMembers(plan, {&item}, row.conflict);
154
4/4
✓ Branch 19 → 20 taken 79 times.
✓ Branch 19 → 21 taken 46 times.
✓ Branch 21 → 22 taken 46 times.
✓ Branch 23 → 24 taken 46 times.
125 row.choice = item.choice == Merge::Choice::None ? QString() : QString::fromLatin1(Merge::choiceName(item.choice));
155 125 int here = 0, there = 0;
156
2/2
✓ Branch 188 → 27 taken 370 times.
✓ Branch 188 → 189 taken 125 times.
495 for (int index = 0; index < item.hunks.hunks.size(); ++index) {
157 370 const TextMerge::Hunk &hunk = item.hunks.hunks.at(index);
158
2/2
✓ Branch 28 → 29 taken 31 times.
✓ Branch 28 → 30 taken 339 times.
370 if (hunk.kind == TextMerge::HunkKind::Conflict)
159 31 row.overlapping = true;
160
4/4
✓ Branch 30 → 31 taken 293 times.
✓ Branch 30 → 32 taken 77 times.
✓ Branch 31 → 32 taken 31 times.
✓ Branch 31 → 33 taken 262 times.
370 if (hunk.kind == TextMerge::HunkKind::LocalOnly || hunk.kind == TextMerge::HunkKind::Conflict)
161 108 ++here;
162
4/4
✓ Branch 33 → 34 taken 279 times.
✓ Branch 33 → 35 taken 91 times.
✓ Branch 34 → 35 taken 31 times.
✓ Branch 34 → 36 taken 248 times.
370 if (hunk.kind == TextMerge::HunkKind::ServerOnly || hunk.kind == TextMerge::HunkKind::Conflict)
163 122 ++there;
164
1/2
✓ Branch 37 → 38 taken 370 times.
✗ Branch 37 → 40 not taken.
370 const Merge::Choice pick = index < item.hunkChoices.size() ? item.hunkChoices.at(index) : Merge::Choice::None;
165 370 QVariantList localWords, serverWords;
166
8/8
✓ Branch 41 → 42 taken 31 times.
✓ Branch 41 → 47 taken 339 times.
✓ Branch 43 → 44 taken 19 times.
✓ Branch 43 → 47 taken 12 times.
✓ Branch 45 → 46 taken 18 times.
✓ Branch 45 → 47 taken 1 time.
✓ Branch 48 → 49 taken 18 times.
✓ Branch 48 → 112 taken 352 times.
370 if (hunk.kind == TextMerge::HunkKind::Conflict && hunk.local.size() == 1 && hunk.server.size() == 1) {
167 // Word highlights inside a changed line (display only, D-19: plain segments).
168
5/5
✓ Branch 51 → 52 taken 18 times.
✓ Branch 52 → 53 taken 18 times.
✓ Branch 53 → 54 taken 18 times.
✓ Branch 78 → 55 taken 47 times.
✓ Branch 78 → 79 taken 18 times.
65 for (const TextMerge::Segment &segment : TextMerge::wordSegments(hunk.server.first(), hunk.local.first()))
169
3/5
✓ Branch 66 → 67 taken 47 times.
✓ Branch 70 → 71 taken 94 times.
✓ Branch 70 → 72 taken 47 times.
✗ Branch 267 → 268 not taken.
✗ Branch 267 → 269 not taken.
253 localWords.append(QVariantMap{{QStringLiteral("text"), segment.text}, {QStringLiteral("changed"), segment.changed}});
170
5/5
✓ Branch 82 → 83 taken 18 times.
✓ Branch 83 → 84 taken 18 times.
✓ Branch 84 → 85 taken 18 times.
✓ Branch 109 → 86 taken 47 times.
✓ Branch 109 → 110 taken 18 times.
65 for (const TextMerge::Segment &segment : TextMerge::wordSegments(hunk.local.first(), hunk.server.first()))
171
3/5
✓ Branch 97 → 98 taken 47 times.
✓ Branch 101 → 102 taken 94 times.
✓ Branch 101 → 103 taken 47 times.
✗ Branch 298 → 299 not taken.
✗ Branch 298 → 300 not taken.
253 serverWords.append(QVariantMap{{QStringLiteral("text"), segment.text}, {QStringLiteral("changed"), segment.changed}});
172 }
173
1/1
✓ Branch 157 → 158 taken 370 times.
1110 row.hunks.append(QVariantMap{{QStringLiteral("index"), index},
174
1/1
✓ Branch 119 → 120 taken 370 times.
740 {QStringLiteral("kind"), hunkKindName(hunk.kind)},
175
1/1
✓ Branch 126 → 127 taken 370 times.
740 {QStringLiteral("local"), hunk.local.join(QLatin1Char('\n'))},
176
1/1
✓ Branch 133 → 134 taken 370 times.
740 {QStringLiteral("server"), hunk.server.join(QLatin1Char('\n'))},
177
1/1
✓ Branch 140 → 141 taken 370 times.
740 {QStringLiteral("base"), hunk.base.join(QLatin1Char('\n'))},
178 740 {QStringLiteral("localWords"), localWords},
179 740 {QStringLiteral("serverWords"), serverWords},
180
3/5
✓ Branch 153 → 154 taken 370 times.
✓ Branch 161 → 162 taken 2960 times.
✓ Branch 161 → 163 taken 370 times.
✗ Branch 329 → 330 not taken.
✗ Branch 329 → 331 not taken.
3700 {QStringLiteral("pick"), pickName(pick)}});
181 370 }
182
4/4
✓ Branch 196 → 197 taken 88 times.
✓ Branch 196 → 198 taken 37 times.
✓ Branch 197 → 199 taken 88 times.
✓ Branch 198 → 199 taken 37 times.
250 row.summary = (here == 1 ? QCoreApplication::translate("ConflictRows", "1 change here")
183 125 : QCoreApplication::translate("ConflictRows", "%n changes here", nullptr, here)) +
184
1/1
✓ Branch 199 → 200 taken 125 times.
500 QStringLiteral(", ") +
185
2/2
✓ Branch 192 → 193 taken 125 times.
✓ Branch 200 → 201 taken 125 times.
500 QCoreApplication::translate("ConflictRows", "%n on the server", nullptr, there) +
186
4/4
✓ Branch 189 → 190 taken 31 times.
✓ Branch 189 → 191 taken 94 times.
✓ Branch 190 → 192 taken 31 times.
✓ Branch 191 → 192 taken 94 times.
250 (row.overlapping ? QCoreApplication::translate("ConflictRows", " — a line changed on both")
187
1/1
✓ Branch 201 → 202 taken 125 times.
125 : QCoreApplication::translate("ConflictRows", " — no line changed on both"));
188 125 row.localPresent = item.local.present;
189 125 row.serverPresent = item.server.present;
190 125 row.basePresent = item.base.present;
191 375 const auto plain = [&item](const Merge::Value &value, const QString &text) {
192
3/4
✓ Branch 2 → 3 taken 40 times.
✓ Branch 2 → 4 taken 335 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 335 times.
375 return !value.present ? ConflictValueText::absent(item) : text.isNull() ? value.text : text;
193 125 };
194
1/1
✓ Branch 211 → 212 taken 125 times.
125 row.localText = plain(item.local, item.localPlain);
195
1/1
✓ Branch 214 → 215 taken 125 times.
125 row.serverText = plain(item.server, item.serverPlain);
196
1/1
✓ Branch 217 → 218 taken 125 times.
125 row.baseText = plain(item.base, item.basePlain);
197 125 row.localSource = item.local.text;
198 125 row.serverSource = item.server.text;
199 125 row.baseSource = item.base.text;
200 125 bool present = false;
201
3/3
✓ Branch 225 → 226 taken 79 times.
✓ Branch 225 → 227 taken 46 times.
✓ Branch 227 → 228 taken 46 times.
125 row.resultText = row.state == QLatin1String("open") ? QString() : Merge::resultText(item, &present);
202
5/6
✓ Branch 230 → 231 taken 112 times.
✓ Branch 230 → 233 taken 13 times.
✓ Branch 231 → 232 taken 85 times.
✓ Branch 231 → 233 taken 27 times.
✗ Branch 232 → 233 not taken.
✓ Branch 232 → 240 taken 85 times.
125 if (item.choice == Merge::Choice::Local || item.choice == Merge::Choice::Server || item.choice == Merge::Choice::Base)
203 40 row.resultText = item.choice == Merge::Choice::Local ? row.localText
204 27 : item.choice == Merge::Choice::Server ? row.serverText
205
3/4
✓ Branch 233 → 234 taken 13 times.
✓ Branch 233 → 235 taken 27 times.
✓ Branch 235 → 236 taken 27 times.
✗ Branch 235 → 237 not taken.
40 : row.baseText;
206 125 row.resultPresent = row.state != QLatin1String("open");
207 Q_UNUSED(context);
208 125 return row;
209 3737 }
210
211 978 void finishRow(Row *row, const Merge::Plan &plan, const QList<const Merge::Item *> &members,
212 const ConflictValueText::Context &context) {
213
2/2
✓ Branch 12 → 4 taken 1261 times.
✓ Branch 12 → 13 taken 978 times.
2239 for (const Merge::Item *item : members) {
214
1/1
✓ Branch 5 → 6 taken 1261 times.
1261 row->itemIds.append(item->id);
215
4/4
✓ Branch 6 → 7 taken 1152 times.
✓ Branch 6 → 8 taken 109 times.
✓ Branch 7 → 8 taken 336 times.
✓ Branch 7 → 9 taken 816 times.
1261 row->conflict = row->conflict || item->state == Merge::State::Conflict;
216 }
217
1/1
✓ Branch 13 → 14 taken 978 times.
978 row->state = stateOfMembers(plan, members, row->conflict);
218
1/1
✓ Branch 16 → 17 taken 978 times.
978 row->choice = choiceOfMembers(members, row->conflict);
219 978 fillTexts(row, plan, members, context);
220 978 }
221
222 } // namespace
223
224 674 QList<Row> build(const Merge::Plan &plan, const ConflictValueText::Context &context) {
225 674 QList<Row> rows;
226 674 QSet<QString> handled;
227 // Indexes instead of a scan per item (G11: a series with 500 overrides has
228 // thousands of items): the items of each component, the members of each
229 // cross-component group and the groups that hold a conflict.
230 674 QHash<QString, QList<int>> byParent;
231 674 QHash<QString, QList<int>> byCrossGroup;
232 674 QSet<QString> conflictGroups;
233 21162 const auto scopeKey = [](const Merge::Item &item) {
234
5/5
✓ Branch 4 → 5 taken 21162 times.
✓ Branch 5 → 6 taken 24 times.
✓ Branch 5 → 7 taken 21138 times.
✓ Branch 8 → 9 taken 21162 times.
✓ Branch 9 → 10 taken 21162 times.
21162 return (Merge::Plan::crossParentGroup(item.group) ? QString() : item.parent) + QLatin1Char('\n') + item.group;
235 };
236
2/2
✓ Branch 24 → 5 taken 62948 times.
✓ Branch 24 → 25 taken 674 times.
63622 for (int index = 0; index < plan.items.size(); ++index) {
237 62948 const Merge::Item &item = plan.items.at(index);
238
2/2
✓ Branch 6 → 7 taken 62948 times.
✓ Branch 7 → 8 taken 62948 times.
62948 byParent[item.parent].append(index);
239
3/3
✓ Branch 8 → 9 taken 62948 times.
✓ Branch 9 → 10 taken 16 times.
✓ Branch 9 → 12 taken 62932 times.
62948 if (Merge::Plan::crossParentGroup(item.group))
240
2/2
✓ Branch 10 → 11 taken 16 times.
✓ Branch 11 → 12 taken 16 times.
16 byCrossGroup[item.group].append(index);
241
6/6
✓ Branch 13 → 14 taken 21071 times.
✓ Branch 13 → 16 taken 41877 times.
✓ Branch 14 → 15 taken 266 times.
✓ Branch 14 → 16 taken 20805 times.
✓ Branch 17 → 18 taken 266 times.
✓ Branch 17 → 22 taken 62682 times.
62948 if (!item.group.isEmpty() && item.state == Merge::State::Conflict)
242
2/2
✓ Branch 18 → 19 taken 266 times.
✓ Branch 19 → 20 taken 266 times.
266 conflictGroups.insert(scopeKey(item));
243 }
244
2/2
✓ Branch 246 → 26 taken 62948 times.
✓ Branch 246 → 247 taken 674 times.
63622 for (int index = 0; index < plan.items.size(); ++index) {
245 62948 const Merge::Item &item = plan.items.at(index);
246
2/2
✓ Branch 28 → 29 taken 283 times.
✓ Branch 28 → 30 taken 62665 times.
62948 if (handled.contains(item.id))
247 61845 continue;
248 // Members of the same row: the coupled group (with a conflict, not
249 // separated) or the values of one list property.
250 62665 QList<const Merge::Item *> members;
251 // J3: "occurrence:<id>" couples an occurrence with the master's EXDATE value.
252
1/1
✓ Branch 30 → 31 taken 62665 times.
62665 const bool crossParent = Merge::Plan::crossParentGroup(item.group);
253 299 const auto collect = [&](const QList<int> &scope, const std::function<bool(const Merge::Item &)> &belongs) {
254
2/2
✓ Branch 15 → 4 taken 1942 times.
✓ Branch 15 → 16 taken 299 times.
2241 for (const int other : scope)
255
3/3
✓ Branch 6 → 7 taken 1942 times.
✓ Branch 7 → 8 taken 582 times.
✓ Branch 7 → 13 taken 1360 times.
1942 if (belongs(plan.items.at(other))) {
256
1/1
✓ Branch 9 → 10 taken 582 times.
582 members.append(&plan.items.at(other));
257
1/1
✓ Branch 11 → 12 taken 582 times.
582 handled.insert(plan.items.at(other).id);
258 }
259 299 };
260 939 const auto prefix = [&plan, &item, &context] {
261
3/4
✓ Branch 5 → 6 taken 27 times.
✓ Branch 5 → 9 taken 608 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 27 times.
635 return item.parent.isEmpty() || item.context.isEmpty() || plan.domain != QLatin1String("ical")
262
2/2
✓ Branch 3 → 4 taken 635 times.
✓ Branch 3 → 9 taken 304 times.
939 ? QString()
263
8/14
✓ Branch 13 → 14 taken 27 times.
✓ Branch 14 → 15 taken 27 times.
✓ Branch 16 → 17 taken 27 times.
✓ Branch 16 → 18 taken 912 times.
✓ Branch 18 → 19 taken 27 times.
✓ Branch 18 → 20 taken 912 times.
✓ Branch 20 → 21 taken 27 times.
✓ Branch 20 → 22 taken 912 times.
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 26 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 30 not taken.
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 34 not taken.
2817 : ConflictValueText::componentLabel(plan, item, context) + QStringLiteral(" — ");
264 62665 };
265 const bool groupConflict =
266
9/11
✓ Branch 32 → 33 taken 20956 times.
✓ Branch 32 → 39 taken 41709 times.
✓ Branch 34 → 35 taken 20896 times.
✓ Branch 34 → 39 taken 60 times.
✓ Branch 35 → 36 taken 20896 times.
✓ Branch 37 → 38 taken 110 times.
✓ Branch 37 → 39 taken 20786 times.
✓ Branch 40 → 41 taken 20896 times.
✓ Branch 40 → 42 taken 41769 times.
✗ Branch 260 → 261 not taken.
✗ Branch 260 → 262 not taken.
62665 !item.group.isEmpty() && !plan.groupSeparated(item.group) && conflictGroups.contains(scopeKey(item));
267 62665 Row row;
268
2/2
✓ Branch 42 → 43 taken 110 times.
✓ Branch 42 → 87 taken 62555 times.
62665 if (groupConflict) {
269
3/3
✓ Branch 44 → 45 taken 8 times.
✓ Branch 44 → 46 taken 102 times.
✓ Branch 47 → 48 taken 110 times.
110 collect(crossParent ? byCrossGroup.value(item.group) : byParent.value(item.parent),
270 829 [&item](const Merge::Item &other) { return other.group == item.group; });
271
1/1
✓ Branch 53 → 54 taken 110 times.
110 row.id = QStringLiteral("group:%1:%2").arg(item.parent, item.group);
272 110 row.kind = QStringLiteral("field");
273 110 row.group = item.group;
274 110 row.separable = members.size() > 1;
275
3/3
✓ Branch 66 → 67 taken 110 times.
✓ Branch 67 → 68 taken 110 times.
✓ Branch 68 → 69 taken 110 times.
110 row.label = prefix() + ConflictValueText::groupLabel(item.group);
276
4/4
✓ Branch 73 → 74 taken 110 times.
✓ Branch 74 → 75 taken 110 times.
✓ Branch 85 → 76 taken 219 times.
✓ Branch 85 → 86 taken 110 times.
329 for (const Merge::Item *member : members)
277
4/4
✓ Branch 77 → 78 taken 16 times.
✓ Branch 77 → 83 taken 203 times.
✓ Branch 78 → 79 taken 8 times.
✓ Branch 78 → 83 taken 8 times.
219 if (crossParent && member->kind == Merge::Kind::Component)
278
1/1
✓ Branch 79 → 80 taken 8 times.
8 row.label = ConflictValueText::componentLabel(plan, *member, context);
279
1/1
✓ Branch 86 → 220 taken 110 times.
110 finishRow(&row, plan, members, context);
280
2/2
✓ Branch 87 → 88 taken 189 times.
✓ Branch 87 → 156 taken 62366 times.
62555 } else if (item.kind == Merge::Kind::SetValue) {
281
1/1
✓ Branch 90 → 91 taken 189 times.
189 collect(byParent.value(item.parent), [&item](const Merge::Item &other) {
282
6/6
✓ Branch 2 → 3 taken 589 times.
✓ Branch 2 → 10 taken 744 times.
✓ Branch 4 → 5 taken 363 times.
✓ Branch 4 → 10 taken 226 times.
✓ Branch 6 → 7 taken 18 times.
✓ Branch 6 → 9 taken 345 times.
1714 return other.kind == Merge::Kind::SetValue && other.name == item.name &&
283
1/2
✓ Branch 8 → 9 taken 18 times.
✗ Branch 8 → 10 not taken.
1714 (other.group.isEmpty() || other.group == item.group);
284 });
285 189 bool changed = false;
286
4/4
✓ Branch 93 → 94 taken 189 times.
✓ Branch 94 → 95 taken 189 times.
✓ Branch 103 → 96 taken 363 times.
✓ Branch 103 → 104 taken 189 times.
552 for (const Merge::Item *member : members)
287
4/4
✓ Branch 97 → 98 taken 258 times.
✓ Branch 97 → 99 taken 105 times.
✓ Branch 98 → 99 taken 175 times.
✓ Branch 98 → 100 taken 83 times.
363 changed = changed || member->state != Merge::State::Same;
288
2/2
✓ Branch 104 → 105 taken 14 times.
✓ Branch 104 → 106 taken 175 times.
189 if (!changed)
289 14 continue;
290
1/1
✓ Branch 109 → 110 taken 175 times.
175 row.id = QStringLiteral("list:%1:%2").arg(item.parent, item.name);
291 175 row.kind = QStringLiteral("list");
292
3/3
✓ Branch 120 → 121 taken 175 times.
✓ Branch 121 → 122 taken 175 times.
✓ Branch 122 → 123 taken 175 times.
175 row.label = prefix() + ConflictValueText::label(plan, item);
293
1/1
✓ Branch 127 → 128 taken 175 times.
175 finishRow(&row, plan, members, context);
294
4/4
✓ Branch 128 → 129 taken 175 times.
✓ Branch 129 → 130 taken 175 times.
✓ Branch 154 → 131 taken 349 times.
✓ Branch 154 → 155 taken 175 times.
524 for (const Merge::Item *member : members) {
295 349 bool included = false;
296
1/1
✓ Branch 132 → 133 taken 349 times.
349 Merge::resultText(*member, &included);
297
2/2
✓ Branch 134 → 135 taken 200 times.
✓ Branch 134 → 136 taken 149 times.
498 const ConflictValueText::Side side = member->local.present ? ConflictValueText::Side::Local
298
2/2
✓ Branch 136 → 137 taken 129 times.
✓ Branch 136 → 138 taken 20 times.
149 : member->server.present ? ConflictValueText::Side::Server
299 : ConflictValueText::Side::Base;
300 349 row.values.append({member->id, ConflictValueText::value(plan, *member, side, context), member->local.present,
301 349 member->server.present, member->base.present,
302
3/3
✓ Branch 143 → 144 taken 301 times.
✓ Branch 144 → 145 taken 294 times.
✓ Branch 144 → 146 taken 7 times.
698 included && !Merge::itemOpen(plan, *member), QString::fromLatin1(Merge::stateName(member->state))});
303 }
304 } else {
305
1/1
✓ Branch 156 → 157 taken 62366 times.
62366 handled.insert(item.id);
306
2/2
✓ Branch 157 → 158 taken 61548 times.
✓ Branch 157 → 159 taken 818 times.
62366 if (item.state == Merge::State::Same)
307 61548 continue;
308
1/1
✓ Branch 159 → 160 taken 818 times.
818 members = {&item};
309
2/2
✓ Branch 160 → 161 taken 125 times.
✓ Branch 160 → 172 taken 693 times.
818 if (item.kind == Merge::Kind::Text) {
310
1/1
✓ Branch 161 → 162 taken 125 times.
125 row = textRow(plan, item, context);
311
3/3
✓ Branch 164 → 165 taken 125 times.
✓ Branch 165 → 166 taken 125 times.
✓ Branch 166 → 167 taken 125 times.
125 row.label = prefix() + ConflictValueText::label(plan, item);
312 } else {
313 693 row.id = item.id;
314
2/2
✓ Branch 173 → 174 taken 140 times.
✓ Branch 173 → 177 taken 553 times.
2219 row.kind = item.kind == Merge::Kind::Component ? QStringLiteral("component")
315
4/4
✓ Branch 177 → 178 taken 24 times.
✓ Branch 177 → 181 taken 529 times.
✓ Branch 204 → 205 taken 140 times.
✓ Branch 204 → 206 taken 553 times.
1246 : item.kind == Merge::Kind::Deletion ? QStringLiteral("deletion")
316
4/4
✓ Branch 181 → 182 taken 12 times.
✓ Branch 181 → 185 taken 517 times.
✓ Branch 202 → 203 taken 24 times.
✓ Branch 202 → 204 taken 669 times.
1222 : item.kind == Merge::Kind::Order ? QStringLiteral("order")
317
4/4
✓ Branch 187 → 188 taken 20 times.
✓ Branch 187 → 191 taken 497 times.
✓ Branch 200 → 201 taken 12 times.
✓ Branch 200 → 202 taken 681 times.
1210 : item.name == QLatin1String("PHOTO") ? QStringLiteral("photo")
318
4/4
✓ Branch 196 → 197 taken 497 times.
✓ Branch 196 → 198 taken 196 times.
✓ Branch 198 → 199 taken 20 times.
✓ Branch 198 → 200 taken 673 times.
1386 : QStringLiteral("field");
319
2/2
✓ Branch 207 → 208 taken 24 times.
✓ Branch 207 → 210 taken 529 times.
553 row.label = item.kind == Merge::Kind::Component || item.kind == Merge::Kind::Deletion
320
4/4
✓ Branch 206 → 207 taken 553 times.
✓ Branch 206 → 208 taken 140 times.
✓ Branch 208 → 209 taken 164 times.
✓ Branch 212 → 213 taken 529 times.
1939 ? ConflictValueText::componentLabel(plan, item, context)
321
6/10
✓ Branch 210 → 211 taken 529 times.
✓ Branch 211 → 212 taken 529 times.
✓ Branch 215 → 216 taken 529 times.
✓ Branch 215 → 217 taken 164 times.
✓ Branch 217 → 218 taken 529 times.
✓ Branch 217 → 219 taken 164 times.
✗ Branch 333 → 334 not taken.
✗ Branch 333 → 335 not taken.
✗ Branch 337 → 338 not taken.
✗ Branch 337 → 339 not taken.
1915 : prefix() + ConflictValueText::label(plan, item);
322
1/1
✓ Branch 219 → 220 taken 693 times.
693 finishRow(&row, plan, members, context);
323 }
324 }
325
6/6
✓ Branch 220 → 221 taken 421 times.
✓ Branch 220 → 224 taken 682 times.
✓ Branch 229 → 230 taken 682 times.
✓ Branch 229 → 231 taken 421 times.
✓ Branch 231 → 232 taken 421 times.
✓ Branch 231 → 233 taken 682 times.
2206 row.section = row.conflict ? QStringLiteral("question") : QStringLiteral("combined");
326
1/1
✓ Branch 233 → 234 taken 1103 times.
1103 rows.append(row);
327 124227 }
328
7/7
✓ Branch 2 → 3 taken 217 times.
✓ Branch 2 → 5 taken 432 times.
✓ Branch 3 → 4 taken 70 times.
✓ Branch 3 → 5 taken 147 times.
✓ Branch 247 → 248 taken 674 times.
✓ Branch 248 → 249 taken 674 times.
✓ Branch 249 → 250 taken 674 times.
1323 std::stable_sort(rows.begin(), rows.end(), [](const Row &a, const Row &b) { return a.conflict && !b.conflict; });
329 674 return rows;
330 2070 }
331
332 83 const Row *find(const QList<Row> &rows, const QString &id) {
333
2/2
✓ Branch 10 → 4 taken 99 times.
✓ Branch 10 → 11 taken 9 times.
108 for (const Row &row : rows)
334
2/2
✓ Branch 6 → 7 taken 74 times.
✓ Branch 6 → 8 taken 25 times.
99 if (row.id == id)
335 74 return &row;
336 9 return nullptr;
337 }
338
339 } // namespace ConflictRows
340