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: 95.2% 220 / 0 / 231
Functions: 100.0% 15 / 0 / 15
Branches: 83.0% 328 / 0 / 395

presentation/ContactEditorFields.cpp
Line Branch Exec Source
1 #include "ContactEditorFields.h"
2
3 #include "ContactEditorPeople.h"
4
5 #include <QCoreApplication>
6 #include <QRegularExpression>
7
8 namespace ContactEditorFields {
9
10 namespace {
11
12 5 QString tr(const char *text) { return QCoreApplication::translate("ContactEditorFields", text); }
13
14 2250 QVariantList valuesToList(const QList<ContactValue> &values) {
15 2250 QVariantList list;
16
2/2
✓ Branch 53 → 4 taken 852 times.
✓ Branch 53 → 54 taken 2250 times.
3102 for (const ContactValue &value : values)
17
1/1
✓ Branch 32 → 33 taken 852 times.
2556 list.append(QVariantMap{{QStringLiteral("value"), value.value},
18
1/1
✓ Branch 12 → 13 taken 852 times.
1704 {QStringLiteral("type"), value.types.value(0)},
19 1704 {QStringLiteral("types"), value.types},
20 1704 {QStringLiteral("preferred"), value.preferred},
21 1704 {QStringLiteral("label"), value.label},
22
2/4
✓ Branch 36 → 37 taken 5112 times.
✓ Branch 36 → 38 taken 852 times.
✗ Branch 61 → 62 not taken.
✗ Branch 61 → 63 not taken.
7668 {QStringLiteral("sourceIndex"), value.sourceIndex}});
23 2250 return list;
24 5964 }
25
26 66 QList<ContactValue> valuesFromList(const QVariantList &list) {
27 66 QList<ContactValue> values;
28
2/2
✓ Branch 111 → 4 taken 41 times.
✓ Branch 111 → 112 taken 66 times.
107 for (const QVariant &item : list) {
29
1/1
✓ Branch 5 → 6 taken 41 times.
41 const QVariantMap map = item.toMap();
30 41 ContactValue value;
31
3/3
✓ Branch 10 → 11 taken 41 times.
✓ Branch 11 → 12 taken 41 times.
✓ Branch 12 → 13 taken 41 times.
82 value.value = map.value(QStringLiteral("value")).toString().trimmed();
32
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 41 times.
41 if (value.value.isEmpty())
33 ✗ continue;
34 // The editor offers one type; further types the card had are kept
35 // while the chosen first type is unchanged.
36
2/2
✓ Branch 27 → 28 taken 41 times.
✓ Branch 28 → 29 taken 41 times.
82 const QStringList types = map.value(QStringLiteral("types")).toStringList();
37
3/3
✓ Branch 37 → 38 taken 41 times.
✓ Branch 38 → 39 taken 41 times.
✓ Branch 39 → 40 taken 41 times.
82 const QString type = map.value(QStringLiteral("type")).toString().toLower();
38
8/11
✓ Branch 46 → 47 taken 16 times.
✓ Branch 46 → 51 taken 25 times.
✓ Branch 47 → 48 taken 16 times.
✓ Branch 49 → 50 taken 16 times.
✗ Branch 49 → 51 not taken.
✓ Branch 52 → 53 taken 16 times.
✓ Branch 52 → 54 taken 25 times.
✓ Branch 54 → 55 taken 16 times.
✓ Branch 54 → 56 taken 25 times.
✗ Branch 157 → 158 not taken.
✗ Branch 157 → 159 not taken.
41 if (!types.isEmpty() && types.value(0) == type)
39 16 value.types = types;
40
2/2
✓ Branch 57 → 58 taken 3 times.
✓ Branch 57 → 64 taken 22 times.
25 else if (!type.isEmpty())
41
2/4
✓ Branch 61 → 62 taken 3 times.
✓ Branch 61 → 63 taken 3 times.
✗ Branch 162 → 163 not taken.
✗ Branch 162 → 164 not taken.
6 value.types = {type};
42
2/2
✓ Branch 68 → 69 taken 41 times.
✓ Branch 69 → 70 taken 41 times.
82 value.preferred = map.value(QStringLiteral("preferred")).toBool();
43
2/2
✓ Branch 78 → 79 taken 41 times.
✓ Branch 79 → 80 taken 41 times.
82 value.label = map.value(QStringLiteral("label")).toString();
44
2/2
✓ Branch 90 → 91 taken 41 times.
✓ Branch 91 → 92 taken 41 times.
82 value.sourceIndex = map.value(QStringLiteral("sourceIndex"), -1).toInt();
45
1/1
✓ Branch 96 → 97 taken 41 times.
41 values.append(value);
46 41 }
47 66 return values;
48 3 }
49
50 } // namespace
51
52 750 QVariantMap toMap(const ContactCard &card) {
53 750 QVariantList addresses;
54
2/2
✓ Branch 97 → 4 taken 375 times.
✓ Branch 97 → 98 taken 750 times.
1125 for (const ContactAddress &a : card.addresses)
55
1/1
✓ Branch 61 → 62 taken 375 times.
1125 addresses.append(QVariantMap{{QStringLiteral("street"), a.street},
56 750 {QStringLiteral("extended"), a.extended},
57 750 {QStringLiteral("poBox"), a.poBox},
58 750 {QStringLiteral("locality"), a.locality},
59 750 {QStringLiteral("region"), a.region},
60 750 {QStringLiteral("postalCode"), a.postalCode},
61 750 {QStringLiteral("country"), a.country},
62
1/1
✓ Branch 36 → 37 taken 375 times.
750 {QStringLiteral("type"), a.types.value(0)},
63 750 {QStringLiteral("types"), a.types},
64 750 {QStringLiteral("preferred"), a.preferred},
65 750 {QStringLiteral("label"), a.label},
66
1/1
✓ Branch 53 → 54 taken 375 times.
750 {QStringLiteral("oneLine"), a.oneLine()},
67
2/4
✓ Branch 65 → 66 taken 4875 times.
✓ Branch 65 → 67 taken 375 times.
✗ Branch 335 → 336 not taken.
✗ Branch 335 → 337 not taken.
6000 {QStringLiteral("sourceIndex"), a.sourceIndex}});
68 750 QVariantList extra;
69
1/2
✗ Branch 129 → 100 not taken.
✓ Branch 129 → 130 taken 750 times.
750 for (const ContactExtraField &field : card.extraFields)
70 ✗ extra.append(QVariantMap{{QStringLiteral("name"), field.name},
71 ✗ {QStringLiteral("label"), field.label},
72 ✗ {QStringLiteral("value"), field.value}});
73 // Sprint 103 IMP-6: the card's own GEO has no row until the map shows it
74 // (S103.4); it stays listed read-only under "More fields".
75
1/2
✗ Branch 130 → 131 not taken.
✓ Branch 130 → 167 taken 750 times.
750 if (card.geo.valid)
76 ✗ extra.append(QVariantMap{{QStringLiteral("name"), QStringLiteral("GEO")},
77 ✗ {QStringLiteral("label"), QString()},
78 ✗ {QStringLiteral("value"), card.geo.toUri()}});
79 1500 QVariantMap map{{QStringLiteral("uid"), card.uid},
80 1500 {QStringLiteral("kind"), card.kind},
81 1500 {QStringLiteral("version"), card.version},
82 1500 {QStringLiteral("formattedName"), card.formattedName},
83 1500 {QStringLiteral("given"), card.name.given},
84 1500 {QStringLiteral("family"), card.name.family},
85 1500 {QStringLiteral("additional"), card.name.additional},
86 1500 {QStringLiteral("prefix"), card.name.prefix},
87 1500 {QStringLiteral("suffix"), card.name.suffix},
88 1500 {QStringLiteral("nickname"), card.nickname},
89 1500 {QStringLiteral("organization"), card.organization},
90 1500 {QStringLiteral("department"), card.department},
91 1500 {QStringLiteral("title"), card.title},
92
1/1
✓ Branch 222 → 223 taken 750 times.
1500 {QStringLiteral("birthday"), card.birthday.toIso()},
93
1/1
✓ Branch 227 → 228 taken 750 times.
1500 {QStringLiteral("anniversary"), card.anniversary.toIso()},
94 1500 {QStringLiteral("note"), card.note},
95 1500 {QStringLiteral("categories"), card.categories},
96 1500 {QStringLiteral("members"), card.members},
97
1/1
✓ Branch 244 → 245 taken 750 times.
1500 {QStringLiteral("emails"), valuesToList(card.emails)},
98
1/1
✓ Branch 249 → 250 taken 750 times.
1500 {QStringLiteral("phones"), valuesToList(card.phones)},
99
1/1
✓ Branch 254 → 255 taken 750 times.
1500 {QStringLiteral("urls"), valuesToList(card.urls)},
100 1500 {QStringLiteral("addresses"), addresses},
101 1500 {QStringLiteral("hasPhoto"), card.photo.kind != ContactPhoto::Kind::None},
102
2/4
✓ Branch 270 → 271 taken 18000 times.
✓ Branch 270 → 272 taken 750 times.
✗ Branch 513 → 514 not taken.
✗ Branch 513 → 515 not taken.
19500 {QStringLiteral("extraFields"), extra}};
103
1/1
✓ Branch 325 → 326 taken 750 times.
750 ContactEditorPeople::insert(&map, card); // Sprint 103 S103.3.2
104 750 return map;
105 24750 }
106
107 70 ContactCard applyMap(ContactCard card, const QVariantMap &map) {
108 840 const auto text = [&map](const char *key, QString *target) {
109
4/4
✓ Branch 3 → 4 taken 840 times.
✓ Branch 4 → 5 taken 840 times.
✓ Branch 6 → 7 taken 151 times.
✓ Branch 6 → 20 taken 689 times.
840 if (map.contains(QLatin1String(key)))
110
4/4
✓ Branch 9 → 10 taken 151 times.
✓ Branch 10 → 11 taken 151 times.
✓ Branch 11 → 12 taken 151 times.
✓ Branch 12 → 13 taken 151 times.
151 *target = map.value(QLatin1String(key)).toString().trimmed();
111 840 };
112 140 const auto date = [&map](const char *key, PartialDate *target) {
113
4/4
✓ Branch 3 → 4 taken 140 times.
✓ Branch 4 → 5 taken 140 times.
✓ Branch 6 → 7 taken 15 times.
✓ Branch 6 → 18 taken 125 times.
140 if (map.contains(QLatin1String(key)))
114
4/4
✓ Branch 9 → 10 taken 15 times.
✓ Branch 10 → 11 taken 15 times.
✓ Branch 11 → 12 taken 15 times.
✓ Branch 12 → 13 taken 15 times.
15 *target = PartialDate::fromIso(map.value(QLatin1String(key)).toString());
115 140 };
116
1/1
✓ Branch 2 → 3 taken 70 times.
70 text("uid", &card.uid);
117
1/1
✓ Branch 3 → 4 taken 70 times.
70 text("kind", &card.kind);
118
2/2
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 13 taken 69 times.
70 if (card.kind.isEmpty())
119 1 card.kind = QStringLiteral("individual");
120
1/1
✓ Branch 13 → 14 taken 70 times.
70 text("formattedName", &card.formattedName);
121
1/1
✓ Branch 14 → 15 taken 70 times.
70 text("given", &card.name.given);
122
1/1
✓ Branch 15 → 16 taken 70 times.
70 text("family", &card.name.family);
123
1/1
✓ Branch 16 → 17 taken 70 times.
70 text("additional", &card.name.additional);
124
1/1
✓ Branch 17 → 18 taken 70 times.
70 text("prefix", &card.name.prefix);
125
1/1
✓ Branch 18 → 19 taken 70 times.
70 text("suffix", &card.name.suffix);
126
1/1
✓ Branch 19 → 20 taken 70 times.
70 text("nickname", &card.nickname);
127
1/1
✓ Branch 20 → 21 taken 70 times.
70 text("organization", &card.organization);
128
1/1
✓ Branch 21 → 22 taken 70 times.
70 text("department", &card.department);
129
1/1
✓ Branch 22 → 23 taken 70 times.
70 text("title", &card.title);
130
1/1
✓ Branch 23 → 24 taken 70 times.
70 date("birthday", &card.birthday);
131
1/1
✓ Branch 24 → 25 taken 70 times.
70 date("anniversary", &card.anniversary);
132
3/3
✓ Branch 28 → 29 taken 70 times.
✓ Branch 31 → 32 taken 15 times.
✓ Branch 31 → 45 taken 55 times.
70 if (map.contains(QStringLiteral("note")))
133
2/2
✓ Branch 36 → 37 taken 15 times.
✓ Branch 37 → 38 taken 15 times.
30 card.note = map.value(QStringLiteral("note")).toString();
134
3/3
✓ Branch 48 → 49 taken 70 times.
✓ Branch 51 → 52 taken 28 times.
✓ Branch 51 → 89 taken 42 times.
70 if (map.contains(QStringLiteral("categories"))) {
135
1/1
✓ Branch 52 → 53 taken 28 times.
28 card.categories.clear();
136
6/6
✓ Branch 57 → 58 taken 28 times.
✓ Branch 58 → 59 taken 28 times.
✓ Branch 63 → 64 taken 28 times.
✓ Branch 64 → 65 taken 28 times.
✓ Branch 86 → 66 taken 15 times.
✓ Branch 86 → 87 taken 28 times.
71 for (const QString &category : map.value(QStringLiteral("categories")).toStringList())
137
11/16
✓ Branch 67 → 68 taken 15 times.
✓ Branch 69 → 70 taken 14 times.
✓ Branch 69 → 74 taken 1 time.
✓ Branch 70 → 71 taken 14 times.
✓ Branch 72 → 73 taken 13 times.
✓ Branch 72 → 74 taken 1 time.
✓ Branch 75 → 76 taken 14 times.
✓ Branch 75 → 77 taken 1 time.
✓ Branch 77 → 78 taken 15 times.
✗ Branch 77 → 79 not taken.
✓ Branch 79 → 80 taken 13 times.
✓ Branch 79 → 84 taken 2 times.
✗ Branch 476 → 477 not taken.
✗ Branch 476 → 478 not taken.
✗ Branch 480 → 481 not taken.
✗ Branch 480 → 482 not taken.
15 if (!category.trimmed().isEmpty() && !card.categories.contains(category.trimmed()))
138
2/2
✓ Branch 80 → 81 taken 13 times.
✓ Branch 81 → 82 taken 13 times.
41 card.categories.append(category.trimmed());
139 }
140
3/3
✓ Branch 92 → 93 taken 70 times.
✓ Branch 95 → 96 taken 1 time.
✓ Branch 95 → 109 taken 69 times.
70 if (map.contains(QStringLiteral("members")))
141
2/2
✓ Branch 100 → 101 taken 1 time.
✓ Branch 101 → 102 taken 1 time.
2 card.members = map.value(QStringLiteral("members")).toStringList();
142
3/3
✓ Branch 112 → 113 taken 70 times.
✓ Branch 115 → 116 taken 25 times.
✓ Branch 115 → 131 taken 45 times.
70 if (map.contains(QStringLiteral("emails")))
143
3/3
✓ Branch 120 → 121 taken 25 times.
✓ Branch 121 → 122 taken 25 times.
✓ Branch 122 → 123 taken 25 times.
50 card.emails = valuesFromList(map.value(QStringLiteral("emails")).toList());
144
3/3
✓ Branch 134 → 135 taken 70 times.
✓ Branch 137 → 138 taken 21 times.
✓ Branch 137 → 153 taken 49 times.
70 if (map.contains(QStringLiteral("phones")))
145
3/3
✓ Branch 142 → 143 taken 21 times.
✓ Branch 143 → 144 taken 21 times.
✓ Branch 144 → 145 taken 21 times.
42 card.phones = valuesFromList(map.value(QStringLiteral("phones")).toList());
146
3/3
✓ Branch 156 → 157 taken 70 times.
✓ Branch 159 → 160 taken 20 times.
✓ Branch 159 → 175 taken 50 times.
70 if (map.contains(QStringLiteral("urls")))
147
3/3
✓ Branch 164 → 165 taken 20 times.
✓ Branch 165 → 166 taken 20 times.
✓ Branch 166 → 167 taken 20 times.
40 card.urls = valuesFromList(map.value(QStringLiteral("urls")).toList());
148
3/3
✓ Branch 178 → 179 taken 70 times.
✓ Branch 181 → 182 taken 20 times.
✓ Branch 181 → 381 taken 50 times.
70 if (map.contains(QStringLiteral("addresses"))) {
149
1/1
✓ Branch 182 → 183 taken 20 times.
20 card.addresses.clear();
150
6/6
✓ Branch 187 → 188 taken 20 times.
✓ Branch 188 → 189 taken 20 times.
✓ Branch 193 → 194 taken 20 times.
✓ Branch 194 → 195 taken 20 times.
✓ Branch 378 → 196 taken 4 times.
✓ Branch 378 → 379 taken 20 times.
44 for (const QVariant &item : map.value(QStringLiteral("addresses")).toList()) {
151
1/1
✓ Branch 197 → 198 taken 4 times.
4 const QVariantMap a = item.toMap();
152 4 ContactAddress address;
153
3/3
✓ Branch 202 → 203 taken 4 times.
✓ Branch 203 → 204 taken 4 times.
✓ Branch 204 → 205 taken 4 times.
8 address.street = a.value(QStringLiteral("street")).toString().trimmed();
154
3/3
✓ Branch 216 → 217 taken 4 times.
✓ Branch 217 → 218 taken 4 times.
✓ Branch 218 → 219 taken 4 times.
8 address.extended = a.value(QStringLiteral("extended")).toString().trimmed();
155
3/3
✓ Branch 230 → 231 taken 4 times.
✓ Branch 231 → 232 taken 4 times.
✓ Branch 232 → 233 taken 4 times.
8 address.poBox = a.value(QStringLiteral("poBox")).toString().trimmed();
156
3/3
✓ Branch 244 → 245 taken 4 times.
✓ Branch 245 → 246 taken 4 times.
✓ Branch 246 → 247 taken 4 times.
8 address.locality = a.value(QStringLiteral("locality")).toString().trimmed();
157
3/3
✓ Branch 258 → 259 taken 4 times.
✓ Branch 259 → 260 taken 4 times.
✓ Branch 260 → 261 taken 4 times.
8 address.region = a.value(QStringLiteral("region")).toString().trimmed();
158
3/3
✓ Branch 272 → 273 taken 4 times.
✓ Branch 273 → 274 taken 4 times.
✓ Branch 274 → 275 taken 4 times.
8 address.postalCode = a.value(QStringLiteral("postalCode")).toString().trimmed();
159
3/3
✓ Branch 286 → 287 taken 4 times.
✓ Branch 287 → 288 taken 4 times.
✓ Branch 288 → 289 taken 4 times.
8 address.country = a.value(QStringLiteral("country")).toString().trimmed();
160
2/2
✓ Branch 300 → 301 taken 4 times.
✓ Branch 301 → 302 taken 4 times.
8 const QStringList types = a.value(QStringLiteral("types")).toStringList();
161
3/3
✓ Branch 310 → 311 taken 4 times.
✓ Branch 311 → 312 taken 4 times.
✓ Branch 312 → 313 taken 4 times.
8 const QString type = a.value(QStringLiteral("type")).toString().toLower();
162
8/11
✓ Branch 319 → 320 taken 2 times.
✓ Branch 319 → 324 taken 2 times.
✓ Branch 320 → 321 taken 2 times.
✓ Branch 322 → 323 taken 2 times.
✗ Branch 322 → 324 not taken.
✓ Branch 325 → 326 taken 2 times.
✓ Branch 325 → 327 taken 2 times.
✓ Branch 327 → 328 taken 2 times.
✓ Branch 327 → 329 taken 2 times.
✗ Branch 732 → 733 not taken.
✗ Branch 732 → 734 not taken.
4 if (!types.isEmpty() && types.value(0) == type)
163 2 address.types = types;
164
1/2
✓ Branch 330 → 331 taken 2 times.
✗ Branch 330 → 337 not taken.
2 else if (!type.isEmpty())
165
2/4
✓ Branch 334 → 335 taken 2 times.
✓ Branch 334 → 336 taken 2 times.
✗ Branch 737 → 738 not taken.
✗ Branch 737 → 739 not taken.
4 address.types = {type};
166
2/2
✓ Branch 341 → 342 taken 4 times.
✓ Branch 342 → 343 taken 4 times.
8 address.preferred = a.value(QStringLiteral("preferred")).toBool();
167
2/2
✓ Branch 351 → 352 taken 4 times.
✓ Branch 352 → 353 taken 4 times.
8 address.label = a.value(QStringLiteral("label")).toString();
168
2/2
✓ Branch 363 → 364 taken 4 times.
✓ Branch 364 → 365 taken 4 times.
8 address.sourceIndex = a.value(QStringLiteral("sourceIndex"), -1).toInt();
169
3/3
✓ Branch 369 → 370 taken 4 times.
✓ Branch 370 → 371 taken 3 times.
✓ Branch 370 → 372 taken 1 time.
4 if (!address.isEmpty())
170
1/1
✓ Branch 371 → 372 taken 3 times.
3 card.addresses.append(address);
171 24 }
172 }
173
19/33
✓ Branch 384 → 385 taken 70 times.
✓ Branch 385 → 386 taken 15 times.
✓ Branch 385 → 394 taken 55 times.
✓ Branch 390 → 391 taken 15 times.
✓ Branch 391 → 392 taken 15 times.
✓ Branch 392 → 393 taken 2 times.
✓ Branch 392 → 394 taken 13 times.
✓ Branch 395 → 396 taken 15 times.
✓ Branch 395 → 397 taken 55 times.
✓ Branch 397 → 398 taken 15 times.
✓ Branch 397 → 399 taken 55 times.
✓ Branch 399 → 400 taken 15 times.
✓ Branch 399 → 401 taken 55 times.
✓ Branch 401 → 402 taken 15 times.
✓ Branch 401 → 403 taken 55 times.
✓ Branch 403 → 404 taken 70 times.
✗ Branch 403 → 405 not taken.
✓ Branch 405 → 406 taken 70 times.
✗ Branch 405 → 407 not taken.
✓ Branch 407 → 408 taken 2 times.
✓ Branch 407 → 411 taken 68 times.
✗ Branch 795 → 796 not taken.
✗ Branch 795 → 797 not taken.
✗ Branch 799 → 800 not taken.
✗ Branch 799 → 801 not taken.
✗ Branch 803 → 804 not taken.
✗ Branch 803 → 805 not taken.
✗ Branch 807 → 808 not taken.
✗ Branch 807 → 809 not taken.
✗ Branch 811 → 812 not taken.
✗ Branch 811 → 813 not taken.
✗ Branch 815 → 816 not taken.
✗ Branch 815 → 817 not taken.
155 if (map.contains(QStringLiteral("removePhoto")) && map.value(QStringLiteral("removePhoto")).toBool())
174 2 card.photo = {};
175 // S97.5.7: a new photo (base64 JPEG from ContactPhotoProvider::prepareForCard).
176
3/3
✓ Branch 416 → 417 taken 70 times.
✓ Branch 417 → 418 taken 70 times.
✓ Branch 418 → 419 taken 70 times.
140 if (const QByteArray photo = QByteArray::fromBase64(map.value(QStringLiteral("photoData")).toByteArray());
177
2/2
✓ Branch 425 → 426 taken 2 times.
✓ Branch 425 → 434 taken 68 times.
70 !photo.isEmpty()) {
178 2 card.photo.kind = ContactPhoto::Kind::Inline;
179 2 card.photo.data = photo;
180 2 card.photo.mimeType = QStringLiteral("image/jpeg");
181 2 card.photo.uri.clear();
182 70 }
183
1/1
✓ Branch 435 → 436 taken 70 times.
70 ContactEditorPeople::apply(&card, map);
184 140 return card;
185 2 }
186
187 63 bool isValidAddress(const QString &input) {
188 static const QRegularExpression pattern(
189
4/7
✓ Branch 2 → 3 taken 5 times.
✓ Branch 2 → 15 taken 58 times.
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 15 not taken.
✓ Branch 9 → 10 taken 5 times.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 33 not taken.
68 QStringLiteral(R"(^[^\s@<>,;:"()\[\]\\]+@(?:[^\s@<>,;:"()\[\]\\.]+(?:\.[^\s@<>,;:"()\[\]\\.]+)+|\[[^\s\]]+\])$)"));
190
3/3
✓ Branch 16 → 17 taken 63 times.
✓ Branch 17 → 18 taken 63 times.
✓ Branch 18 → 19 taken 63 times.
63 return pattern.match(input.trimmed()).hasMatch();
191 }
192
193 4 bool isValidPhone(const QString &phone) {
194
2/2
✓ Branch 8 → 4 taken 13 times.
✓ Branch 8 → 9 taken 1 time.
14 for (const QChar c : phone)
195
2/2
✓ Branch 5 → 6 taken 3 times.
✓ Branch 5 → 7 taken 10 times.
13 if (c.isDigit())
196 3 return true;
197 1 return false;
198 }
199
200 70 QVariantMap validate(const ContactCard &card) {
201 70 QVariantMap errors;
202
2/2
✓ Branch 22 → 3 taken 63 times.
✓ Branch 22 → 23 taken 70 times.
133 for (int i = 0; i < card.emails.size(); ++i)
203
3/3
✓ Branch 4 → 5 taken 63 times.
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 20 taken 61 times.
63 if (!isValidAddress(card.emails.at(i).value))
204
3/3
✓ Branch 6 → 7 taken 2 times.
✓ Branch 12 → 13 taken 2 times.
✓ Branch 13 → 14 taken 2 times.
6 errors.insert(QStringLiteral("emails.%1").arg(i), tr("Enter a complete email address, like name@example.org."));
205
2/2
✓ Branch 43 → 24 taken 4 times.
✓ Branch 43 → 44 taken 70 times.
74 for (int i = 0; i < card.phones.size(); ++i)
206
2/2
✓ Branch 26 → 27 taken 1 time.
✓ Branch 26 → 41 taken 3 times.
4 if (!isValidPhone(card.phones.at(i).value))
207
3/3
✓ Branch 27 → 28 taken 1 time.
✓ Branch 33 → 34 taken 1 time.
✓ Branch 34 → 35 taken 1 time.
3 errors.insert(QStringLiteral("phones.%1").arg(i), tr("A phone number needs digits."));
208
5/7
✓ Branch 45 → 46 taken 2 times.
✓ Branch 45 → 50 taken 68 times.
✓ Branch 46 → 47 taken 2 times.
✓ Branch 47 → 48 taken 2 times.
✗ Branch 47 → 50 not taken.
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 51 taken 2 times.
70 const bool named = !card.formattedName.isEmpty() || !card.name.isEmpty() || !card.organization.isEmpty();
209
6/8
✓ Branch 52 → 53 taken 2 times.
✓ Branch 52 → 58 taken 68 times.
✓ Branch 54 → 55 taken 2 times.
✗ Branch 54 → 58 not taken.
✓ Branch 56 → 57 taken 2 times.
✗ Branch 56 → 58 not taken.
✓ Branch 59 → 60 taken 2 times.
✓ Branch 59 → 71 taken 68 times.
70 if (!named && card.emails.isEmpty() && card.phones.isEmpty())
210
2/2
✓ Branch 60 → 61 taken 2 times.
✓ Branch 65 → 66 taken 2 times.
4 errors.insert(QStringLiteral("name"), tr("Enter a name, an organization or an address."));
211 70 return errors;
212 ✗ }
213
214 1567 QString formatPartialDate(const PartialDate &date, const QLocale &locale) {
215
2/2
✓ Branch 3 → 4 taken 1324 times.
✓ Branch 3 → 5 taken 243 times.
1567 if (!date.isValid())
216 1324 return {};
217
1/1
✓ Branch 5 → 6 taken 243 times.
243 QString format = locale.dateFormat(QLocale::LongFormat);
218
2/2
✓ Branch 10 → 11 taken 243 times.
✓ Branch 11 → 12 taken 243 times.
243 format.remove(QRegularExpression(QStringLiteral(R"(d{4}[,.]?\s*)")));
219
2/2
✓ Branch 16 → 17 taken 39 times.
✓ Branch 16 → 36 taken 204 times.
243 if (!date.hasYear()) {
220
2/2
✓ Branch 21 → 22 taken 39 times.
✓ Branch 22 → 23 taken 39 times.
39 format.remove(QRegularExpression(QStringLiteral(R"([,.]?\s*y+)")));
221
2/2
✓ Branch 30 → 31 taken 39 times.
✓ Branch 31 → 32 taken 39 times.
39 format.remove(QRegularExpression(QStringLiteral(R"(y+[,.]?\s*)")));
222 }
223
3/3
✓ Branch 37 → 38 taken 204 times.
✓ Branch 37 → 39 taken 39 times.
✓ Branch 40 → 41 taken 243 times.
243 const QDate value(date.hasYear() ? date.year : 2000, date.month, date.day);
224
5/9
✓ Branch 41 → 42 taken 243 times.
✓ Branch 42 → 43 taken 243 times.
✗ Branch 42 → 45 not taken.
✓ Branch 43 → 44 taken 243 times.
✓ Branch 44 → 46 taken 243 times.
✓ Branch 47 → 48 taken 243 times.
✗ Branch 47 → 49 not taken.
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 84 not taken.
243 return value.isValid() ? locale.toString(value, format.trimmed()) : QString();
225 243 }
226
227 namespace {
228
229 // The locale's short date format with a four-digit year, e.g. "dd.MM.yyyy".
230 403 QString shortFormat(const QLocale &locale) {
231 403 QString format = locale.dateFormat(QLocale::ShortFormat);
232
3/3
✓ Branch 4 → 5 taken 403 times.
✓ Branch 5 → 6 taken 14 times.
✓ Branch 5 → 10 taken 389 times.
403 if (!format.contains(QLatin1String("yyyy")))
233
1/1
✓ Branch 8 → 9 taken 14 times.
14 format.replace(QLatin1String("yy"), QLatin1String("yyyy"));
234 403 return format;
235 ✗ }
236
237 // The same format without the year and its separator ("dd.MM", "M/d").
238 80 QString dayMonthFormat(const QLocale &locale) {
239 80 QString format = shortFormat(locale);
240
2/2
✓ Branch 7 → 8 taken 80 times.
✓ Branch 8 → 9 taken 80 times.
80 format.remove(QRegularExpression(QStringLiteral(R"([^dMy]*y+[^dMy]*$)")));
241
2/2
✓ Branch 16 → 17 taken 80 times.
✓ Branch 17 → 18 taken 80 times.
80 format.remove(QRegularExpression(QStringLiteral(R"(^y+[^dMy]*)")));
242 80 return format;
243 ✗ }
244
245 } // namespace
246
247 258 QString formatShortDate(const PartialDate &date, const QLocale &locale) {
248
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 257 times.
258 if (!date.isValid())
249 1 return {};
250
2/2
✓ Branch 6 → 7 taken 211 times.
✓ Branch 6 → 12 taken 46 times.
257 if (date.hasYear())
251
3/3
✓ Branch 7 → 8 taken 211 times.
✓ Branch 8 → 9 taken 211 times.
✓ Branch 9 → 10 taken 211 times.
211 return locale.toString(QDate(date.year, date.month, date.day), shortFormat(locale));
252
3/3
✓ Branch 12 → 13 taken 46 times.
✓ Branch 13 → 14 taken 46 times.
✓ Branch 14 → 15 taken 46 times.
46 return locale.toString(QDate(2000, date.month, date.day), dayMonthFormat(locale));
253 }
254
255 113 PartialDate parseDateText(const QString &text, const QLocale &locale) {
256
1/1
✓ Branch 2 → 3 taken 113 times.
113 const QString trimmed = text.trimmed();
257
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 113 times.
113 if (trimmed.isEmpty())
258 ✗ return {};
259
1/1
✓ Branch 6 → 7 taken 113 times.
113 const PartialDate iso = PartialDate::fromIso(trimmed);
260
2/2
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 112 times.
113 if (iso.isValid())
261 1 return iso;
262
4/8
✓ Branch 10 → 11 taken 112 times.
✓ Branch 11 → 12 taken 112 times.
✓ Branch 23 → 14 taken 146 times.
✓ Branch 23 → 24 taken 34 times.
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 73 not taken.
✗ Branch 71 → 72 not taken.
✗ Branch 71 → 73 not taken.
516 for (const QString &format : {shortFormat(locale), locale.dateFormat(QLocale::ShortFormat)}) {
263
1/1
✓ Branch 14 → 15 taken 146 times.
146 const QDate date = locale.toDate(trimmed, format);
264
3/3
✓ Branch 15 → 16 taken 146 times.
✓ Branch 16 → 17 taken 78 times.
✓ Branch 16 → 21 taken 68 times.
146 if (date.isValid())
265
3/3
✓ Branch 17 → 18 taken 78 times.
✓ Branch 18 → 19 taken 78 times.
✓ Branch 19 → 20 taken 78 times.
78 return {date.year(), date.month(), date.day()};
266 336 }
267 // Day and month only; a trailing separator ("12.04.") is accepted.
268 34 QString dayMonth = trimmed;
269 // Only separators: a month name ("12 Apr" in the C locale) stays.
270
6/7
✓ Branch 35 → 36 taken 35 times.
✗ Branch 35 → 40 not taken.
✓ Branch 36 → 37 taken 35 times.
✓ Branch 38 → 39 taken 1 time.
✓ Branch 38 → 40 taken 34 times.
✓ Branch 41 → 33 taken 1 time.
✓ Branch 41 → 42 taken 34 times.
35 while (!dayMonth.isEmpty() && !dayMonth.back().isLetterOrNumber())
271
1/1
✓ Branch 33 → 34 taken 1 time.
1 dayMonth.chop(1);
272
4/4
✓ Branch 45 → 46 taken 34 times.
✓ Branch 46 → 47 taken 34 times.
✓ Branch 50 → 51 taken 34 times.
✓ Branch 51 → 52 taken 34 times.
68 const QDate date = locale.toDate(dayMonth + QStringLiteral("/2000"), dayMonthFormat(locale) + QStringLiteral("/yyyy"));
273
3/3
✓ Branch 59 → 60 taken 34 times.
✓ Branch 60 → 61 taken 15 times.
✓ Branch 60 → 64 taken 19 times.
34 if (date.isValid())
274
2/2
✓ Branch 61 → 62 taken 15 times.
✓ Branch 62 → 63 taken 15 times.
15 return {0, date.month(), date.day()};
275 19 return {};
276 113 }
277
278 } // namespace ContactEditorFields
279