MailJDTourDownloadDocsQualityTestsCoverage

Which source lines and branches the tests execute. Lines 91.5 %, branches 75.0 % (minimum 85 % and 72 %). main @ 399ffe3d · 21 October 2026 · pipeline 7238.

GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 96.5% 218 / 0 / 226
Functions: 100.0% 12 / 0 / 12
Branches: 82.2% 369 / 0 / 449

presentation/ContactEditorPeople.cpp
Line Branch Exec Source
1 #include "ContactEditorPeople.h"
2
3 #include "ContactEditorFields.h"
4 #include "data/RelationVocabulary.h"
5
6 #include <QCoreApplication>
7 #include <QDate>
8 #include <QRegularExpression>
9 #include <QVariantList>
10
11 namespace ContactEditorPeople {
12
13 namespace {
14
15 4 QString tr(const char *text) { return QCoreApplication::translate("ContactEditorPeople", text); }
16
17 367 QString textOf(const QVariantMap &map, const char *key) {
18
4/4
✓ Branch 4 → 5 taken 367 times.
✓ Branch 5 → 6 taken 367 times.
✓ Branch 6 → 7 taken 367 times.
✓ Branch 7 → 8 taken 367 times.
367 return map.value(QLatin1String(key)).toString().trimmed();
19 }
20
21
2/2
✓ Branch 6 → 7 taken 24 times.
✓ Branch 7 → 8 taken 24 times.
48 int indexOf(const QVariantMap &map) { return map.value(QStringLiteral("sourceIndex"), -1).toInt(); }
22
23 750 QVariantList relationsToList(const QList<ContactRelation> &relations) {
24 750 QVariantList list;
25
2/2
✓ Branch 64 → 4 taken 380 times.
✓ Branch 64 → 65 taken 750 times.
1130 for (const ContactRelation &relation : relations)
26
1/1
✓ Branch 40 → 41 taken 380 times.
1140 list.append(QVariantMap{{QStringLiteral("type"), relation.type},
27 760 {QStringLiteral("label"), relation.label},
28 760 {QStringLiteral("targetUid"), relation.targetUid},
29 760 {QStringLiteral("targetUri"), relation.targetUri},
30 760 {QStringLiteral("targetName"), relation.targetName},
31 760 {QStringLiteral("model"), relation.model},
32 760 {QStringLiteral("readOnly"), relation.readOnly()},
33
2/4
✓ Branch 44 → 45 taken 3040 times.
✓ Branch 44 → 46 taken 380 times.
✗ Branch 72 → 73 not taken.
✗ Branch 72 → 74 not taken.
4180 {QStringLiteral("sourceIndex"), relation.sourceIndex}});
34 750 return list;
35 3420 }
36
37 750 QVariantMap metToMap(const ContactMet &met) {
38
3/3
✓ Branch 2 → 3 taken 750 times.
✓ Branch 3 → 4 taken 660 times.
✓ Branch 3 → 5 taken 90 times.
750 if (met.isEmpty())
39 660 return {};
40 90 QVariantList via;
41
2/2
✓ Branch 42 → 7 taken 72 times.
✓ Branch 42 → 43 taken 90 times.
162 for (const ContactPersonRef &ref : met.via)
42
1/1
✓ Branch 26 → 27 taken 72 times.
216 via.append(QVariantMap{{QStringLiteral("uid"), ref.uid},
43 144 {QStringLiteral("uri"), ref.uri},
44 144 {QStringLiteral("name"), ref.name},
45
2/4
✓ Branch 30 → 31 taken 288 times.
✓ Branch 30 → 32 taken 72 times.
✗ Branch 101 → 102 not taken.
✗ Branch 101 → 103 not taken.
504 {QStringLiteral("sourceIndex"), ref.sourceIndex}});
46
1/1
✓ Branch 46 → 47 taken 90 times.
180 return {{QStringLiteral("date"), met.date.toIso()},
47 180 {QStringLiteral("place"), met.place},
48
1/1
✓ Branch 55 → 56 taken 90 times.
180 {QStringLiteral("placeGeo"), met.placeGeo.toUri()},
49 180 {QStringLiteral("eventUid"), met.eventUid},
50 180 {QStringLiteral("note"), met.note},
51 180 {QStringLiteral("channel"), met.channel},
52
2/4
✓ Branch 75 → 76 taken 630 times.
✓ Branch 75 → 77 taken 90 times.
✗ Branch 138 → 139 not taken.
✗ Branch 138 → 140 not taken.
810 {QStringLiteral("via"), via}};
53 1170 }
54
55 // A relation from the editor: the stored one it was loaded from (same
56 // sourceIndex) keeps its model and URI; type, label and target follow the
57 // editor.
58 9 ContactRelation relationFrom(const QVariantMap &map, const QList<ContactRelation> &before) {
59 9 ContactRelation relation;
60
1/1
✓ Branch 2 → 3 taken 9 times.
9 const int source = indexOf(map);
61
2/2
✓ Branch 11 → 5 taken 3 times.
✓ Branch 11 → 12 taken 9 times.
12 for (const ContactRelation &old : before)
62
3/4
✓ Branch 6 → 7 taken 2 times.
✓ Branch 6 → 9 taken 1 time.
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 9 not taken.
3 if (source >= 0 && old.sourceIndex == source)
63 2 relation = old;
64
2/2
✓ Branch 12 → 13 taken 9 times.
✓ Branch 13 → 14 taken 9 times.
9 relation.type = RelationVocabulary::canonical(textOf(map, "type"));
65
1/3
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 9 times.
✗ Branch 20 → 22 not taken.
9 relation.label = relation.type == QLatin1String("custom") ? textOf(map, "label") : QString();
66
1/1
✓ Branch 24 → 25 taken 9 times.
9 const QString uid = textOf(map, "targetUid");
67
1/1
✓ Branch 25 → 26 taken 9 times.
9 const QString name = textOf(map, "targetName");
68
7/8
✓ Branch 27 → 28 taken 4 times.
✓ Branch 27 → 32 taken 5 times.
✓ Branch 29 → 30 taken 2 times.
✓ Branch 29 → 33 taken 2 times.
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 33 taken 2 times.
✓ Branch 34 → 35 taken 5 times.
✓ Branch 34 → 42 taken 4 times.
9 if (uid != relation.targetUid || (uid.isEmpty() && name != relation.targetName)) {
69
1/3
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 38 taken 5 times.
✗ Branch 37 → 39 not taken.
5 relation.targetUri = uid.isEmpty() ? textOf(map, "targetUri") : QString();
70 5 relation.targetUid = uid;
71 }
72 9 relation.targetName = name;
73 9 relation.sourceIndex = source;
74 9 return relation;
75 9 }
76
77 24 ContactMet metFrom(const QVariantMap &map, const ContactMet &before) {
78 24 ContactMet met;
79
2/2
✓ Branch 2 → 3 taken 24 times.
✓ Branch 3 → 4 taken 24 times.
24 met.date = LooseDate::fromIso(textOf(map, "date"));
80
1/1
✓ Branch 5 → 6 taken 24 times.
24 met.place = textOf(map, "place");
81 // A position belongs to the place it was set for (D-10).
82
6/8
✓ Branch 9 → 10 taken 20 times.
✓ Branch 9 → 11 taken 4 times.
✓ Branch 11 → 12 taken 4 times.
✓ Branch 12 → 13 taken 4 times.
✓ Branch 13 → 14 taken 4 times.
✓ Branch 13 → 15 taken 20 times.
✗ Branch 73 → 74 not taken.
✗ Branch 73 → 75 not taken.
24 met.placeGeo = met.place == before.place ? before.placeGeo : GeoPoint::fromText(textOf(map, "placeGeo"));
83
1/1
✓ Branch 15 → 16 taken 24 times.
24 met.eventUid = textOf(map, "eventUid");
84
2/2
✓ Branch 18 → 19 taken 24 times.
✓ Branch 19 → 20 taken 24 times.
24 met.note = textOf(map, "note").left(200);
85
1/1
✓ Branch 23 → 24 taken 24 times.
24 met.channel = textOf(map, "channel");
86
6/6
✓ Branch 30 → 31 taken 24 times.
✓ Branch 31 → 32 taken 24 times.
✓ Branch 36 → 37 taken 24 times.
✓ Branch 37 → 38 taken 24 times.
✓ Branch 65 → 39 taken 6 times.
✓ Branch 65 → 66 taken 24 times.
54 for (const QVariant &item : map.value(QStringLiteral("via")).toList()) {
87
1/1
✓ Branch 40 → 41 taken 6 times.
6 const QVariantMap entry = item.toMap();
88 6 ContactPersonRef ref;
89
1/1
✓ Branch 41 → 42 taken 6 times.
6 ref.uid = textOf(entry, "uid");
90
1/1
✓ Branch 44 → 45 taken 6 times.
6 ref.uri = textOf(entry, "uri");
91
1/1
✓ Branch 47 → 48 taken 6 times.
6 ref.name = textOf(entry, "name");
92
1/1
✓ Branch 50 → 51 taken 6 times.
6 ref.sourceIndex = indexOf(entry);
93
2/8
✗ Branch 52 → 53 not taken.
✓ Branch 52 → 57 taken 6 times.
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 57 not taken.
✗ Branch 56 → 57 not taken.
✗ Branch 56 → 58 not taken.
✓ Branch 59 → 60 taken 6 times.
✗ Branch 59 → 61 not taken.
6 if (!ref.uid.isEmpty() || !ref.uri.isEmpty() || !ref.name.isEmpty())
94
1/1
✓ Branch 60 → 61 taken 6 times.
6 met.via.append(ref);
95 30 }
96 24 return met;
97 ✗ }
98
99 32 QStringList cleanList(const QVariant &value) {
100 32 QStringList out;
101
5/5
✓ Branch 2 → 3 taken 32 times.
✓ Branch 3 → 4 taken 32 times.
✓ Branch 4 → 5 taken 32 times.
✓ Branch 19 → 6 taken 10 times.
✓ Branch 19 → 20 taken 32 times.
42 for (const QString &item : value.toStringList())
102
4/7
✓ Branch 7 → 8 taken 10 times.
✓ Branch 9 → 10 taken 10 times.
✗ Branch 9 → 13 not taken.
✓ Branch 11 → 12 taken 10 times.
✗ Branch 11 → 13 not taken.
✓ Branch 14 → 15 taken 10 times.
✗ Branch 14 → 16 not taken.
10 if (const QString trimmed = item.trimmed(); !trimmed.isEmpty() && !out.contains(trimmed, Qt::CaseInsensitive))
103
1/1
✓ Branch 15 → 16 taken 10 times.
42 out.append(trimmed);
104 32 return out;
105 ✗ }
106
107 } // namespace
108
109 750 void insert(QVariantMap *map, const ContactCard &card) {
110
2/2
✓ Branch 2 → 3 taken 750 times.
✓ Branch 7 → 8 taken 750 times.
1500 map->insert(QStringLiteral("relations"), relationsToList(card.relations));
111
2/2
✓ Branch 12 → 13 taken 750 times.
✓ Branch 17 → 18 taken 750 times.
1500 map->insert(QStringLiteral("met"), metToMap(card.met));
112 750 QVariantList social;
113
2/2
✓ Branch 71 → 24 taken 126 times.
✓ Branch 71 → 72 taken 750 times.
876 for (const ContactSocial &value : card.social)
114
1/1
✓ Branch 51 → 52 taken 126 times.
378 social.append(QVariantMap{{QStringLiteral("kind"), value.kind},
115 252 {QStringLiteral("service"), value.service},
116 252 {QStringLiteral("value"), value.value},
117 252 {QStringLiteral("user"), value.user},
118 252 {QStringLiteral("property"), value.property},
119
2/4
✓ Branch 55 → 56 taken 756 times.
✓ Branch 55 → 57 taken 126 times.
✗ Branch 186 → 187 not taken.
✗ Branch 186 → 188 not taken.
1134 {QStringLiteral("sourceIndex"), value.sourceIndex}});
120
1/1
✓ Branch 76 → 77 taken 750 times.
1500 map->insert(QStringLiteral("social"), social);
121
1/1
✓ Branch 84 → 85 taken 750 times.
1500 map->insert(QStringLiteral("languages"), card.languages);
122
1/1
✓ Branch 92 → 93 taken 750 times.
1500 map->insert(QStringLiteral("interests"), card.interests);
123 750 QVariantList dates;
124
2/2
✓ Branch 129 → 98 taken 26 times.
✓ Branch 129 → 130 taken 750 times.
776 for (const ContactDate &date : card.otherDates)
125
1/1
✓ Branch 114 → 115 taken 26 times.
78 dates.append(QVariantMap{{QStringLiteral("label"), date.label},
126
1/1
✓ Branch 106 → 107 taken 26 times.
52 {QStringLiteral("date"), date.date.toIso()},
127
2/4
✓ Branch 118 → 119 taken 78 times.
✓ Branch 118 → 120 taken 26 times.
✗ Branch 266 → 267 not taken.
✗ Branch 266 → 268 not taken.
156 {QStringLiteral("sourceIndex"), date.sourceIndex}});
128
1/1
✓ Branch 134 → 135 taken 750 times.
1500 map->insert(QStringLiteral("otherDates"), dates);
129
1/1
✓ Branch 142 → 143 taken 750 times.
1500 map->insert(QStringLiteral("birthplace"), card.birthplace);
130
1/1
✓ Branch 150 → 151 taken 750 times.
1500 map->insert(QStringLiteral("gender"), card.gender);
131 1736 }
132
133 70 void apply(ContactCard *card, const QVariantMap &map) {
134
3/3
✓ Branch 5 → 6 taken 70 times.
✓ Branch 8 → 9 taken 31 times.
✓ Branch 8 → 73 taken 39 times.
70 if (map.contains(QStringLiteral("relations"))) {
135 31 QList<ContactRelation> relations;
136
4/4
✓ Branch 9 → 10 taken 31 times.
✓ Branch 10 → 11 taken 31 times.
✓ Branch 18 → 12 taken 3 times.
✓ Branch 18 → 19 taken 31 times.
34 for (const ContactRelation &relation : card->relations)
137
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 3 times.
3 if (relation.readOnly())
138 ✗ relations.append(relation);
139
6/6
✓ Branch 23 → 24 taken 31 times.
✓ Branch 24 → 25 taken 31 times.
✓ Branch 29 → 30 taken 31 times.
✓ Branch 30 → 31 taken 31 times.
✓ Branch 68 → 32 taken 9 times.
✓ Branch 68 → 69 taken 31 times.
71 for (const QVariant &item : map.value(QStringLiteral("relations")).toList()) {
140
1/1
✓ Branch 33 → 34 taken 9 times.
9 const QVariantMap entry = item.toMap();
141
3/4
✓ Branch 38 → 39 taken 9 times.
✓ Branch 39 → 40 taken 9 times.
✗ Branch 44 → 45 not taken.
✓ Branch 44 → 46 taken 9 times.
18 if (entry.value(QStringLiteral("readOnly")).toBool())
142 ✗ continue; // kept above
143
1/1
✓ Branch 46 → 47 taken 9 times.
9 const ContactRelation relation = relationFrom(entry, card->relations);
144
7/8
✓ Branch 48 → 49 taken 7 times.
✓ Branch 48 → 56 taken 2 times.
✓ Branch 50 → 51 taken 1 time.
✓ Branch 50 → 55 taken 6 times.
✓ Branch 52 → 53 taken 1 time.
✗ Branch 52 → 55 not taken.
✓ Branch 57 → 58 taken 6 times.
✓ Branch 57 → 59 taken 3 times.
10 if (!relation.type.isEmpty() && (!relation.targetUid.isEmpty() || !relation.targetUri.isEmpty() ||
145
1/2
✗ Branch 54 → 55 not taken.
✓ Branch 54 → 56 taken 1 time.
1 !relation.targetName.isEmpty()))
146
1/1
✓ Branch 58 → 59 taken 6 times.
6 relations.append(relation);
147 40 }
148 31 card->relations = relations;
149 31 }
150
3/3
✓ Branch 76 → 77 taken 70 times.
✓ Branch 79 → 80 taken 24 times.
✓ Branch 79 → 95 taken 46 times.
70 if (map.contains(QStringLiteral("met")))
151
3/3
✓ Branch 84 → 85 taken 24 times.
✓ Branch 85 → 86 taken 24 times.
✓ Branch 86 → 87 taken 24 times.
48 card->met = metFrom(map.value(QStringLiteral("met")).toMap(), card->met);
152
3/3
✓ Branch 98 → 99 taken 70 times.
✓ Branch 101 → 102 taken 16 times.
✓ Branch 101 → 162 taken 54 times.
70 if (map.contains(QStringLiteral("social"))) {
153 16 QList<ContactSocial> social;
154
6/6
✓ Branch 106 → 107 taken 16 times.
✓ Branch 107 → 108 taken 16 times.
✓ Branch 112 → 113 taken 16 times.
✓ Branch 113 → 114 taken 16 times.
✓ Branch 157 → 115 taken 6 times.
✓ Branch 157 → 158 taken 16 times.
38 for (const QVariant &item : map.value(QStringLiteral("social")).toList()) {
155
1/1
✓ Branch 116 → 117 taken 6 times.
6 const QVariantMap entry = item.toMap();
156
1/1
✓ Branch 117 → 118 taken 6 times.
6 ContactSocial value;
157
7/7
✓ Branch 119 → 120 taken 6 times.
✓ Branch 121 → 122 taken 3 times.
✓ Branch 121 → 125 taken 3 times.
✓ Branch 130 → 131 taken 3 times.
✓ Branch 130 → 132 taken 3 times.
✓ Branch 132 → 133 taken 3 times.
✓ Branch 132 → 134 taken 3 times.
12 value.kind = textOf(entry, "kind") == QLatin1String("chat") ? QStringLiteral("chat") : QStringLiteral("profile");
158
2/2
✓ Branch 135 → 136 taken 6 times.
✓ Branch 136 → 137 taken 6 times.
6 value.service = textOf(entry, "service").toLower();
159
1/1
✓ Branch 140 → 141 taken 6 times.
6 value.value = textOf(entry, "value");
160
1/1
✓ Branch 143 → 144 taken 6 times.
6 value.user = textOf(entry, "user");
161
1/1
✓ Branch 146 → 147 taken 6 times.
6 value.property = textOf(entry, "property");
162
1/1
✓ Branch 149 → 150 taken 6 times.
6 value.sourceIndex = indexOf(entry);
163
1/2
✓ Branch 151 → 152 taken 6 times.
✗ Branch 151 → 153 not taken.
6 if (!value.value.isEmpty())
164
1/1
✓ Branch 152 → 153 taken 6 times.
6 social.append(value);
165 22 }
166 16 card->social = social;
167 16 }
168
3/3
✓ Branch 165 → 166 taken 70 times.
✓ Branch 168 → 169 taken 16 times.
✓ Branch 168 → 182 taken 54 times.
70 if (map.contains(QStringLiteral("languages")))
169
2/2
✓ Branch 173 → 174 taken 16 times.
✓ Branch 174 → 175 taken 16 times.
32 card->languages = cleanList(map.value(QStringLiteral("languages")));
170
3/3
✓ Branch 185 → 186 taken 70 times.
✓ Branch 188 → 189 taken 16 times.
✓ Branch 188 → 202 taken 54 times.
70 if (map.contains(QStringLiteral("interests")))
171
2/2
✓ Branch 193 → 194 taken 16 times.
✓ Branch 194 → 195 taken 16 times.
32 card->interests = cleanList(map.value(QStringLiteral("interests")));
172
3/3
✓ Branch 205 → 206 taken 70 times.
✓ Branch 208 → 209 taken 17 times.
✓ Branch 208 → 243 taken 53 times.
70 if (map.contains(QStringLiteral("otherDates"))) {
173 17 QList<ContactDate> dates;
174
6/6
✓ Branch 213 → 214 taken 17 times.
✓ Branch 214 → 215 taken 17 times.
✓ Branch 219 → 220 taken 17 times.
✓ Branch 220 → 221 taken 17 times.
✓ Branch 238 → 222 taken 3 times.
✓ Branch 238 → 239 taken 17 times.
37 for (const QVariant &item : map.value(QStringLiteral("otherDates")).toList()) {
175
1/1
✓ Branch 223 → 224 taken 3 times.
3 const QVariantMap entry = item.toMap();
176 3 ContactDate date;
177
1/1
✓ Branch 224 → 225 taken 3 times.
3 date.label = textOf(entry, "label");
178
2/2
✓ Branch 227 → 228 taken 3 times.
✓ Branch 228 → 229 taken 3 times.
3 date.date = PartialDate::fromIso(textOf(entry, "date"));
179
1/1
✓ Branch 230 → 231 taken 3 times.
3 date.sourceIndex = indexOf(entry);
180
2/2
✓ Branch 232 → 233 taken 2 times.
✓ Branch 232 → 234 taken 1 time.
3 if (date.date.isValid())
181
1/1
✓ Branch 233 → 234 taken 2 times.
2 dates.append(date);
182 20 }
183 17 card->otherDates = dates;
184 17 }
185
3/3
✓ Branch 246 → 247 taken 70 times.
✓ Branch 249 → 250 taken 16 times.
✓ Branch 249 → 254 taken 54 times.
70 if (map.contains(QStringLiteral("birthplace")))
186
1/1
✓ Branch 250 → 251 taken 16 times.
16 card->birthplace = textOf(map, "birthplace");
187
3/3
✓ Branch 257 → 258 taken 70 times.
✓ Branch 260 → 261 taken 17 times.
✓ Branch 260 → 265 taken 53 times.
70 if (map.contains(QStringLiteral("gender")))
188
1/1
✓ Branch 261 → 262 taken 17 times.
17 card->gender = textOf(map, "gender");
189 70 }
190
191 70 QVariantMap validate(const QVariantMap &fields, const QString &holderName) {
192 70 QVariantMap errors;
193
2/2
✓ Branch 6 → 7 taken 70 times.
✓ Branch 7 → 8 taken 70 times.
140 const QVariantList relations = fields.value(QStringLiteral("relations")).toList();
194
2/2
✓ Branch 101 → 13 taken 23 times.
✓ Branch 101 → 102 taken 70 times.
93 for (int i = 0; i < relations.size(); ++i) {
195
1/1
✓ Branch 14 → 15 taken 23 times.
23 const QVariantMap entry = relations.at(i).toMap();
196
1/1
✓ Branch 15 → 16 taken 23 times.
23 const QString name = textOf(entry, "targetName");
197
2/2
✓ Branch 16 → 17 taken 23 times.
✓ Branch 17 → 18 taken 23 times.
23 const QString type = RelationVocabulary::canonical(textOf(entry, "type"));
198
7/9
✓ Branch 20 → 21 taken 10 times.
✓ Branch 20 → 24 taken 13 times.
✓ Branch 21 → 22 taken 10 times.
✓ Branch 23 → 24 taken 8 times.
✓ Branch 23 → 25 taken 2 times.
✓ Branch 26 → 27 taken 10 times.
✓ Branch 26 → 28 taken 13 times.
✗ Branch 189 → 190 not taken.
✗ Branch 189 → 191 not taken.
23 const bool hasPerson = !name.isEmpty() || !textOf(entry, "targetUid").isEmpty();
199
6/6
✓ Branch 28 → 29 taken 21 times.
✓ Branch 28 → 32 taken 2 times.
✓ Branch 30 → 31 taken 1 time.
✓ Branch 30 → 32 taken 20 times.
✓ Branch 33 → 34 taken 1 time.
✓ Branch 33 → 50 taken 22 times.
23 if (hasPerson && type.isEmpty())
200 //: The relationship editor: a person was chosen, the type was not ("Choose what Marta is to Ana.").
201
4/4
✓ Branch 34 → 35 taken 1 time.
✓ Branch 35 → 36 taken 1 time.
✓ Branch 41 → 42 taken 1 time.
✓ Branch 42 → 43 taken 1 time.
3 errors.insert(QStringLiteral("relations.%1").arg(i), tr("Choose what %1 is to %2.").arg(name, holderName));
202
5/13
✓ Branch 50 → 51 taken 20 times.
✓ Branch 50 → 58 taken 2 times.
✗ Branch 53 → 54 not taken.
✓ Branch 53 → 58 taken 20 times.
✗ Branch 54 → 55 not taken.
✗ Branch 56 → 57 not taken.
✗ Branch 56 → 58 not taken.
✗ Branch 59 → 60 not taken.
✓ Branch 59 → 61 taken 22 times.
✗ Branch 61 → 62 not taken.
✓ Branch 61 → 76 taken 22 times.
✗ Branch 212 → 213 not taken.
✗ Branch 212 → 214 not taken.
22 else if (hasPerson && type == QLatin1String("custom") && textOf(entry, "label").isEmpty())
203 ✗ errors.insert(QStringLiteral("relations.%1").arg(i), tr("Enter a name for the relationship."));
204
6/6
✓ Branch 76 → 77 taken 2 times.
✓ Branch 76 → 80 taken 20 times.
✓ Branch 78 → 79 taken 1 time.
✓ Branch 78 → 80 taken 1 time.
✓ Branch 81 → 82 taken 1 time.
✓ Branch 81 → 96 taken 21 times.
22 else if (!hasPerson && !type.isEmpty())
205 //: F103-03: a relationship type was chosen, the person was not.
206
3/3
✓ Branch 82 → 83 taken 1 time.
✓ Branch 88 → 89 taken 1 time.
✓ Branch 89 → 90 taken 1 time.
3 errors.insert(QStringLiteral("relations.%1").arg(i), tr("Choose the person for this relationship."));
207 23 }
208
2/2
✓ Branch 106 → 107 taken 70 times.
✓ Branch 107 → 108 taken 70 times.
140 const QVariantMap met = fields.value(QStringLiteral("met")).toMap();
209
9/9
✓ Branch 112 → 113 taken 70 times.
✓ Branch 114 → 115 taken 11 times.
✓ Branch 114 → 119 taken 59 times.
✓ Branch 115 → 116 taken 11 times.
✓ Branch 116 → 117 taken 11 times.
✓ Branch 117 → 118 taken 1 time.
✓ Branch 117 → 119 taken 10 times.
✓ Branch 120 → 121 taken 1 time.
✓ Branch 120 → 132 taken 69 times.
70 if (const QString date = textOf(met, "date"); !date.isEmpty() && !LooseDate::fromIso(date).isValid())
210
2/2
✓ Branch 121 → 122 taken 1 time.
✓ Branch 126 → 127 taken 1 time.
71 errors.insert(QStringLiteral("met.date"), tr("e.g. 2019, June 2019 or 14.06.2019"));
211
2/2
✓ Branch 137 → 138 taken 70 times.
✓ Branch 138 → 139 taken 70 times.
140 const QVariantList dates = fields.value(QStringLiteral("otherDates")).toList();
212
2/2
✓ Branch 168 → 144 taken 3 times.
✓ Branch 168 → 169 taken 70 times.
73 for (int i = 0; i < dates.size(); ++i)
213
5/5
✓ Branch 145 → 146 taken 3 times.
✓ Branch 146 → 147 taken 3 times.
✓ Branch 147 → 148 taken 3 times.
✓ Branch 151 → 152 taken 1 time.
✓ Branch 151 → 166 taken 2 times.
3 if (!PartialDate::fromIso(textOf(dates.at(i).toMap(), "date")).isValid())
214
3/3
✓ Branch 152 → 153 taken 1 time.
✓ Branch 158 → 159 taken 1 time.
✓ Branch 159 → 160 taken 1 time.
3 errors.insert(QStringLiteral("otherDates.%1").arg(i), tr("Enter a day, e.g. 26.07."));
215 70 return errors;
216 70 }
217
218 53 LooseDate parseLooseDate(const QString &input, const QLocale &locale) {
219
1/1
✓ Branch 2 → 3 taken 53 times.
53 const QString text = input.trimmed();
220
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 53 times.
53 if (text.isEmpty())
221 ✗ return {};
222
4/7
✓ Branch 6 → 7 taken 2 times.
✓ Branch 6 → 19 taken 51 times.
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 19 not taken.
✓ Branch 13 → 14 taken 2 times.
✗ Branch 244 → 245 not taken.
✗ Branch 244 → 246 not taken.
55 static const QRegularExpression year(QStringLiteral(R"(^(\d{4})$)"));
223
4/7
✓ Branch 19 → 20 taken 2 times.
✓ Branch 19 → 32 taken 51 times.
✓ Branch 21 → 22 taken 2 times.
✗ Branch 21 → 32 not taken.
✓ Branch 26 → 27 taken 2 times.
✗ Branch 254 → 255 not taken.
✗ Branch 254 → 256 not taken.
55 static const QRegularExpression isoMonth(QStringLiteral(R"(^(\d{4})-(\d{1,2})$)"));
224
4/7
✓ Branch 32 → 33 taken 2 times.
✓ Branch 32 → 45 taken 51 times.
✓ Branch 34 → 35 taken 2 times.
✗ Branch 34 → 45 not taken.
✓ Branch 39 → 40 taken 2 times.
✗ Branch 264 → 265 not taken.
✗ Branch 264 → 266 not taken.
55 static const QRegularExpression numericMonth(QStringLiteral(R"(^(\d{1,2})\s*[./]\s*(\d{4})$)"));
225
4/7
✓ Branch 45 → 46 taken 2 times.
✓ Branch 45 → 58 taken 51 times.
✓ Branch 47 → 48 taken 2 times.
✗ Branch 47 → 58 not taken.
✓ Branch 52 → 53 taken 2 times.
✗ Branch 274 → 275 not taken.
✗ Branch 274 → 276 not taken.
55 static const QRegularExpression namedMonth(QStringLiteral(R"(^(\p{L}+)\.?\s+(\d{4})$)"));
226
4/4
✓ Branch 59 → 60 taken 53 times.
✓ Branch 60 → 61 taken 53 times.
✓ Branch 61 → 62 taken 19 times.
✓ Branch 61 → 67 taken 34 times.
53 if (const auto m = year.match(text); m.hasMatch())
227
4/4
✓ Branch 62 → 63 taken 19 times.
✓ Branch 63 → 64 taken 19 times.
✓ Branch 69 → 70 taken 34 times.
✓ Branch 69 → 73 taken 19 times.
53 return {m.captured(1).toInt(), 0, 0};
228 34 LooseDate month;
229
4/4
✓ Branch 72 → 74 taken 34 times.
✓ Branch 74 → 75 taken 34 times.
✓ Branch 75 → 76 taken 1 time.
✓ Branch 75 → 83 taken 33 times.
34 if (const auto m = isoMonth.match(text); m.hasMatch())
230
4/4
✓ Branch 76 → 77 taken 1 time.
✓ Branch 77 → 78 taken 1 time.
✓ Branch 78 → 79 taken 1 time.
✓ Branch 79 → 80 taken 1 time.
1 month = {m.captured(1).toInt(), m.captured(2).toInt(), 0};
231
4/4
✓ Branch 84 → 85 taken 33 times.
✓ Branch 85 → 86 taken 33 times.
✓ Branch 86 → 87 taken 3 times.
✓ Branch 86 → 94 taken 30 times.
33 else if (const auto n = numericMonth.match(text); n.hasMatch())
232
4/4
✓ Branch 87 → 88 taken 3 times.
✓ Branch 88 → 89 taken 3 times.
✓ Branch 89 → 90 taken 3 times.
✓ Branch 90 → 91 taken 3 times.
3 month = {n.captured(2).toInt(), n.captured(1).toInt(), 0};
233
4/4
✓ Branch 95 → 96 taken 30 times.
✓ Branch 96 → 97 taken 30 times.
✓ Branch 97 → 98 taken 13 times.
✓ Branch 97 → 136 taken 17 times.
30 else if (const auto w = namedMonth.match(text); w.hasMatch()) {
234
2/2
✓ Branch 98 → 99 taken 13 times.
✓ Branch 99 → 100 taken 13 times.
13 const QString name = w.captured(1).toLower();
235 // The UI language first, English as a fallback ("June 2019" in German).
236
3/7
✓ Branch 102 → 103 taken 13 times.
✓ Branch 127 → 105 taken 26 times.
✓ Branch 127 → 128 taken 13 times.
✗ Branch 302 → 303 not taken.
✗ Branch 302 → 306 not taken.
✗ Branch 304 → 305 not taken.
✗ Branch 304 → 306 not taken.
65 for (const QLocale &candidate : {locale, QLocale(QLocale::English)})
237
4/4
✓ Branch 124 → 125 taken 106 times.
✓ Branch 124 → 126 taken 1 time.
✓ Branch 125 → 106 taken 81 times.
✓ Branch 125 → 126 taken 25 times.
107 for (int i = 1; i <= 12 && month.month == 0; ++i)
238
2/2
✓ Branch 122 → 108 taken 162 times.
✓ Branch 122 → 123 taken 81 times.
243 for (const QLocale::FormatType format : {QLocale::LongFormat, QLocale::ShortFormat})
239
5/5
✓ Branch 108 → 109 taken 162 times.
✓ Branch 109 → 110 taken 162 times.
✓ Branch 113 → 114 taken 162 times.
✓ Branch 115 → 116 taken 23 times.
✓ Branch 115 → 120 taken 139 times.
162 if (QString monthName = candidate.monthName(i, format).toLower(); monthName.remove(QLatin1Char('.')) == name)
240
4/6
✓ Branch 116 → 117 taken 23 times.
✓ Branch 117 → 118 taken 23 times.
✓ Branch 129 → 130 taken 26 times.
✓ Branch 129 → 133 taken 13 times.
✗ Branch 320 → 321 not taken.
✗ Branch 320 → 324 not taken.
201 month = {w.captured(2).toInt(), i, 0};
241 110 }
242
2/2
✓ Branch 141 → 142 taken 17 times.
✓ Branch 141 → 147 taken 17 times.
34 if (month.month > 0)
243
3/3
✓ Branch 142 → 143 taken 17 times.
✓ Branch 143 → 144 taken 16 times.
✓ Branch 143 → 145 taken 1 time.
17 return month.isValid() ? month : LooseDate{};
244 // Day, month and year without leading zeros ("14.6.2019", "6/14/2019")
245 // in the order of the locale's short format.
246
4/7
✓ Branch 147 → 148 taken 2 times.
✓ Branch 147 → 160 taken 15 times.
✓ Branch 149 → 150 taken 2 times.
✗ Branch 149 → 160 not taken.
✓ Branch 154 → 155 taken 2 times.
✗ Branch 346 → 347 not taken.
✗ Branch 346 → 348 not taken.
19 static const QRegularExpression numeric(QStringLiteral(R"(^(\d{1,2})\s*[./-]\s*(\d{1,2})\s*[./-]\s*(\d{4})$)"));
247
4/7
✓ Branch 160 → 161 taken 2 times.
✓ Branch 160 → 173 taken 15 times.
✓ Branch 162 → 163 taken 2 times.
✗ Branch 162 → 173 not taken.
✓ Branch 167 → 168 taken 2 times.
✗ Branch 356 → 357 not taken.
✗ Branch 356 → 358 not taken.
19 static const QRegularExpression dayMonth(QStringLiteral(R"(^(\d{1,2})\s*[./]\s*(\d{1,2})\.?$)"));
248
1/1
✓ Branch 173 → 174 taken 17 times.
17 const QString format = locale.dateFormat(QLocale::ShortFormat);
249 17 const bool monthFirst = format.indexOf(QLatin1Char('M')) < format.indexOf(QLatin1Char('d'));
250
1/1
✓ Branch 181 → 182 taken 17 times.
17 auto numericMatch = numeric.match(text);
251
3/3
✓ Branch 182 → 183 taken 17 times.
✓ Branch 183 → 184 taken 16 times.
✓ Branch 183 → 189 taken 1 time.
17 if (!numericMatch.hasMatch())
252
1/1
✓ Branch 185 → 186 taken 16 times.
16 numericMatch = dayMonth.match(text);
253
3/3
✓ Branch 189 → 190 taken 17 times.
✓ Branch 190 → 191 taken 2 times.
✓ Branch 190 → 223 taken 15 times.
17 if (numericMatch.hasMatch()) {
254
2/2
✓ Branch 191 → 192 taken 2 times.
✓ Branch 192 → 193 taken 2 times.
2 const int first = numericMatch.captured(1).toInt();
255
2/2
✓ Branch 194 → 195 taken 2 times.
✓ Branch 195 → 196 taken 2 times.
2 const int second = numericMatch.captured(2).toInt();
256
7/9
✓ Branch 197 → 198 taken 2 times.
✓ Branch 198 → 199 taken 1 time.
✓ Branch 198 → 202 taken 1 time.
✓ Branch 199 → 200 taken 1 time.
✓ Branch 200 → 201 taken 1 time.
✓ Branch 203 → 204 taken 1 time.
✓ Branch 203 → 205 taken 1 time.
✗ Branch 368 → 369 not taken.
✗ Branch 368 → 370 not taken.
2 const int yearValue = numericMatch.lastCapturedIndex() >= 3 ? numericMatch.captured(3).toInt() : 0;
257 // A day without a year is checked against a leap year (29 February).
258
5/7
✗ Branch 205 → 206 not taken.
✓ Branch 205 → 207 taken 2 times.
✗ Branch 208 → 209 not taken.
✓ Branch 208 → 210 taken 2 times.
✓ Branch 211 → 212 taken 1 time.
✓ Branch 211 → 213 taken 1 time.
✓ Branch 214 → 215 taken 2 times.
2 const QDate date(yearValue > 0 ? yearValue : 2000, monthFirst ? first : second, monthFirst ? second : first);
259
4/5
✓ Branch 215 → 216 taken 2 times.
✓ Branch 216 → 217 taken 2 times.
✗ Branch 216 → 220 not taken.
✓ Branch 217 → 218 taken 2 times.
✓ Branch 218 → 219 taken 2 times.
2 return date.isValid() ? LooseDate{yearValue, date.month(), date.day()} : LooseDate{};
260 }
261
1/1
✓ Branch 223 → 224 taken 15 times.
15 const PartialDate full = ContactEditorFields::parseDateText(text, locale);
262
1/2
✓ Branch 225 → 226 taken 15 times.
✗ Branch 225 → 227 not taken.
15 if (!full.isValid())
263 15 return {};
264 ✗ const LooseDate date{full.year, full.month, full.day};
265 ✗ return date.isValid() ? date : LooseDate{};
266 53 }
267
268 } // namespace ContactEditorPeople
269