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: 94.2% 275 / 0 / 292
Functions: 100.0% 29 / 0 / 29
Branches: 85.0% 475 / 0 / 559

presentation/SearchMenuModel.cpp
Line Branch Exec Source
1 #include "SearchMenuModel.h"
2
3 #include <QCoreApplication>
4
5 namespace SearchMenuModel {
6
7 namespace {
8
9 using SearchTermModel::Kind;
10 using SearchTermModel::Term;
11
12 239 QString tr(const char *text) { return QCoreApplication::translate("SearchMenuModel", text); }
13
14 2219 QVariantMap entry(const QString &id, const QString &label, qint64 count = -1, const QString &icon = {}) {
15 8876 return {{QStringLiteral("id"), id}, {QStringLiteral("label"), label}, {QStringLiteral("count"), count},
16
2/4
✓ Branch 24 → 25 taken 11095 times.
✓ Branch 24 → 26 taken 2219 times.
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 41 not taken.
22190 {QStringLiteral("icon"), icon}, {QStringLiteral("enabled"), true}};
17 15533 }
18
19 2031 QVariantMap checkEntry(const QString &id, const QString &label, bool checked, qint64 count = -1) {
20
1/1
✓ Branch 3 → 4 taken 2031 times.
2031 QVariantMap item = entry(id, label, count);
21
1/1
✓ Branch 9 → 10 taken 2031 times.
4062 item.insert(QStringLiteral("checkable"), true);
22
1/1
✓ Branch 17 → 18 taken 2031 times.
4062 item.insert(QStringLiteral("checked"), checked);
23 2031 return item;
24 ✗ }
25
26
3/9
✓ Branch 6 → 7 taken 39 times.
✓ Branch 8 → 9 taken 39 times.
✓ Branch 8 → 10 taken 39 times.
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 17 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 29 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
117 QVariantMap separator() { return {{QStringLiteral("separator"), true}}; }
27
28 // Sub-menu ids ("menu:from") name the native QMenu; apply() ignores them.
29 88 QVariantMap submenu(const QString &id, const QString &label, const QString &icon, const QVariantList &children) {
30
2/2
✓ Branch 5 → 6 taken 88 times.
✓ Branch 6 → 7 taken 88 times.
88 QVariantMap item = entry(QStringLiteral("menu:") + id, label, -1, icon);
31
1/1
✓ Branch 14 → 15 taken 88 times.
176 item.insert(QStringLiteral("children"), children);
32 88 return item;
33 ✗ }
34
35 1126 const QList<MailSearchFacetValue> *facetValues(const MailSearchSummary *summary, Kind kind) {
36
2/2
✓ Branch 2 → 3 taken 241 times.
✓ Branch 2 → 4 taken 885 times.
1126 if (!summary) return nullptr;
37
5/6
✓ Branch 4 → 5 taken 431 times.
✓ Branch 4 → 6 taken 8 times.
✓ Branch 4 → 7 taken 9 times.
✓ Branch 4 → 8 taken 429 times.
✓ Branch 4 → 9 taken 8 times.
✗ Branch 4 → 10 not taken.
885 switch (kind) {
38 431 case Kind::From: return &summary->topSenders;
39 8 case Kind::To: return &summary->topRecipients;
40 9 case Kind::Folder: return &summary->topFolders;
41 429 case Kind::Label: return &summary->topLabels;
42 8 case Kind::List: return &summary->topLists;
43 ✗ default: return nullptr;
44 }
45 }
46
47 // The positive values of `kind` in the query (a single kind has at most one).
48 1683 QStringList currentValues(const QList<Term> &terms, Kind kind, bool negated = false) {
49 1683 QStringList values;
50
2/2
✓ Branch 10 → 4 taken 2147 times.
✓ Branch 10 → 11 taken 1683 times.
3830 for (const Term &term : terms)
51
5/5
✓ Branch 5 → 6 taken 368 times.
✓ Branch 5 → 8 taken 1779 times.
✓ Branch 6 → 7 taken 354 times.
✓ Branch 6 → 8 taken 14 times.
✓ Branch 7 → 8 taken 354 times.
2147 if (term.kind == kind && term.negated == negated) values.append(term.value);
52 1683 return values;
53 ✗ }
54
55 902 QString shownValue(Kind kind, const MailSearchFacetValue &value, const SearchTermModel::Lookups &lookups) {
56
5/6
✓ Branch 2 → 3 taken 359 times.
✓ Branch 2 → 6 taken 543 times.
✓ Branch 4 → 5 taken 359 times.
✗ Branch 4 → 6 not taken.
✓ Branch 7 → 8 taken 359 times.
✓ Branch 7 → 16 taken 543 times.
902 if (kind == Kind::Label && lookups.label) {
57 359 const QString name = lookups.label(value.value);
58
1/2
✓ Branch 10 → 11 taken 359 times.
✗ Branch 10 → 12 not taken.
359 if (!name.isEmpty()) return name;
59 ✗ }
60
8/8
✓ Branch 16 → 17 taken 38 times.
✓ Branch 16 → 18 taken 505 times.
✓ Branch 17 → 18 taken 17 times.
✓ Branch 17 → 21 taken 21 times.
✓ Branch 19 → 20 taken 16 times.
✓ Branch 19 → 21 taken 506 times.
✓ Branch 22 → 23 taken 16 times.
✓ Branch 22 → 34 taken 527 times.
543 if ((kind == Kind::From || kind == Kind::To) && lookups.name) {
61
1/1
✓ Branch 23 → 24 taken 16 times.
16 const QString name = lookups.name(value.value);
62
2/2
✓ Branch 25 → 26 taken 7 times.
✓ Branch 25 → 28 taken 9 times.
16 if (!name.isEmpty()) return name;
63 16 }
64
1/2
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 536 times.
536 return value.label.isEmpty() ? value.value : value.label;
65 }
66
67 // The checked current values first (also when the summary does not list
68 // them), then the other top values of the hits with their counts.
69 1078 QVariantList valueEntries(const Context &context, const QList<Term> &terms, Kind kind) {
70
1/1
✓ Branch 2 → 3 taken 1078 times.
1078 const QString kindName = SearchTermModel::kindName(kind);
71
1/1
✓ Branch 3 → 4 taken 1078 times.
1078 const QStringList current = currentValues(terms, kind);
72 1078 QVariantList entries;
73 1078 const auto *values = facetValues(context.summary, kind);
74
2/2
✓ Branch 44 → 7 taken 1347 times.
✓ Branch 44 → 45 taken 1078 times.
2425 for (const Term &term : terms) {
75
4/4
✓ Branch 8 → 9 taken 326 times.
✓ Branch 8 → 10 taken 1021 times.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 325 times.
1347 if (term.kind != kind || term.negated) continue;
76 // A constraint every hit satisfies counts all hits; a folder (OR) its own.
77
3/4
✓ Branch 11 → 12 taken 325 times.
✗ Branch 11 → 14 not taken.
✓ Branch 12 → 13 taken 303 times.
✓ Branch 12 → 14 taken 22 times.
325 qint64 count = kind == Kind::Folder || !context.summary ? -1 : context.summary->total;
78
2/2
✓ Branch 15 → 16 taken 303 times.
✓ Branch 15 → 26 taken 22 times.
325 if (values)
79
2/2
✓ Branch 24 → 18 taken 291 times.
✓ Branch 24 → 25 taken 303 times.
594 for (const MailSearchFacetValue &value : *values)
80
2/2
✓ Branch 20 → 21 taken 10 times.
✓ Branch 20 → 22 taken 281 times.
291 if (value.value == term.value) count = value.count;
81
3/3
✓ Branch 32 → 33 taken 325 times.
✓ Branch 33 → 34 taken 325 times.
✓ Branch 35 → 36 taken 325 times.
650 entries.append(checkEntry(QStringLiteral("pick:%1:%2").arg(kindName, term.value), term.shortLabel, true,
82
2/2
✓ Branch 26 → 27 taken 303 times.
✓ Branch 26 → 28 taken 22 times.
325 context.countsShown ? count : -1));
83 }
84
2/2
✓ Branch 45 → 46 taken 863 times.
✓ Branch 45 → 74 taken 215 times.
1078 if (values) {
85
2/2
✓ Branch 72 → 48 taken 851 times.
✓ Branch 72 → 73 taken 863 times.
1714 for (const MailSearchFacetValue &value : *values) {
86
2/2
✓ Branch 50 → 51 taken 10 times.
✓ Branch 50 → 52 taken 841 times.
851 if (current.contains(value.value)) continue;
87
3/3
✓ Branch 59 → 60 taken 841 times.
✓ Branch 60 → 61 taken 841 times.
✓ Branch 62 → 63 taken 841 times.
1682 entries.append(checkEntry(QStringLiteral("pick:%1:%2").arg(kindName, value.value),
88
1/1
✓ Branch 55 → 56 taken 841 times.
1682 shownValue(kind, value, context.lookups), false,
89
2/2
✓ Branch 52 → 53 taken 836 times.
✓ Branch 52 → 54 taken 5 times.
841 context.countsShown ? value.count : -1));
90 }
91 }
92 1078 return entries;
93 1078 }
94
95 45 QVariantList excludeEntries(const Context &context, const QList<Term> &terms, Kind kind) {
96
1/1
✓ Branch 2 → 3 taken 45 times.
45 const QString kindName = SearchTermModel::kindName(kind);
97
1/1
✓ Branch 3 → 4 taken 45 times.
45 const QStringList excluded = currentValues(terms, kind, true);
98 45 QVariantList entries;
99
2/2
✓ Branch 5 → 6 taken 20 times.
✓ Branch 5 → 35 taken 25 times.
45 if (const auto *values = facetValues(context.summary, kind))
100
2/2
✓ Branch 33 → 8 taken 24 times.
✓ Branch 33 → 34 taken 20 times.
44 for (const MailSearchFacetValue &value : *values)
101
1/2
✓ Branch 10 → 11 taken 24 times.
✗ Branch 10 → 31 not taken.
24 if (!excluded.contains(value.value))
102
3/3
✓ Branch 19 → 20 taken 24 times.
✓ Branch 20 → 21 taken 24 times.
✓ Branch 22 → 23 taken 24 times.
96 entries.append(entry(QStringLiteral("exclude:%1:%2").arg(kindName, value.value),
103
3/3
✓ Branch 12 → 13 taken 19 times.
✓ Branch 12 → 14 taken 5 times.
✓ Branch 15 → 16 taken 24 times.
72 shownValue(kind, value, context.lookups), context.countsShown ? value.count : -1));
104 45 return entries;
105 45 }
106
107 45 QVariantMap facetMenu(const Context &context, const QList<Term> &terms, Kind kind, const QString &icon) {
108
1/1
✓ Branch 2 → 3 taken 45 times.
45 QVariantList children = valueEntries(context, terms, kind);
109
4/4
✓ Branch 4 → 5 taken 16 times.
✓ Branch 4 → 11 taken 29 times.
✓ Branch 5 → 6 taken 16 times.
✓ Branch 7 → 8 taken 16 times.
45 if (!children.isEmpty()) children.append(separator());
110
5/5
✓ Branch 12 → 13 taken 45 times.
✓ Branch 13 → 14 taken 45 times.
✓ Branch 17 → 18 taken 45 times.
✓ Branch 18 → 19 taken 45 times.
✓ Branch 20 → 21 taken 45 times.
90 children.append(entry(QStringLiteral("editor:") + SearchTermModel::kindName(kind), tr("Other…")));
111
1/1
✓ Branch 29 → 30 taken 45 times.
45 const QVariantList excluded = excludeEntries(context, terms, kind);
112
1/1
✓ Branch 30 → 31 taken 45 times.
45 const QString name = SearchTermModel::kindName(kind);
113
6/6
✓ Branch 32 → 33 taken 16 times.
✓ Branch 32 → 53 taken 29 times.
✓ Branch 36 → 37 taken 16 times.
✓ Branch 40 → 41 taken 16 times.
✓ Branch 41 → 42 taken 16 times.
✓ Branch 43 → 44 taken 16 times.
77 if (!excluded.isEmpty()) children.append(submenu(name + QStringLiteral(":exclude"), tr("Exclude"), QStringLiteral("list-remove"), excluded));
114
2/2
✓ Branch 53 → 54 taken 45 times.
✓ Branch 54 → 55 taken 45 times.
90 return submenu(name, SearchTermModel::kindLabel(kind), icon, children);
115 45 }
116
117 struct Preset {
118 const char *word;
119 const char *label;
120 };
121 constexpr Preset kPresets[] = {
122 {"today", QT_TRANSLATE_NOOP("SearchMenuModel", "Today")},
123 {"yesterday", QT_TRANSLATE_NOOP("SearchMenuModel", "Yesterday")},
124 {"week", QT_TRANSLATE_NOOP("SearchMenuModel", "Last 7 days")},
125 {"month", QT_TRANSLATE_NOOP("SearchMenuModel", "Last 30 days")},
126 {"year", QT_TRANSLATE_NOOP("SearchMenuModel", "Last 12 months")},
127 };
128
129 9 QVariantList dateEntries(const QString &query) {
130
1/1
✓ Branch 2 → 3 taken 9 times.
9 const QString preset = SearchTermModel::datePreset(query);
131
7/8
✓ Branch 3 → 4 taken 9 times.
✓ Branch 4 → 5 taken 9 times.
✓ Branch 5 → 6 taken 7 times.
✓ Branch 5 → 9 taken 2 times.
✓ Branch 6 → 7 taken 7 times.
✓ Branch 7 → 8 taken 7 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 7 times.
9 const bool dated = SearchTermModel::dateFrom(query).isValid() || SearchTermModel::dateTo(query).isValid();
132 9 QVariantList entries;
133
3/3
✓ Branch 11 → 12 taken 9 times.
✓ Branch 15 → 16 taken 9 times.
✓ Branch 17 → 18 taken 9 times.
18 entries.append(checkEntry(QStringLiteral("date:"), tr("All time"), !dated));
134
2/2
✓ Branch 44 → 24 taken 45 times.
✓ Branch 44 → 45 taken 9 times.
54 for (const Preset &item : kPresets)
135
5/5
✓ Branch 26 → 27 taken 45 times.
✓ Branch 28 → 29 taken 45 times.
✓ Branch 32 → 33 taken 45 times.
✓ Branch 33 → 34 taken 45 times.
✓ Branch 35 → 36 taken 45 times.
90 entries.append(checkEntry(QStringLiteral("date:") + QLatin1String(item.word), tr(item.label),
136 90 preset == QLatin1String(item.word)));
137
2/2
✓ Branch 45 → 46 taken 9 times.
✓ Branch 47 → 48 taken 9 times.
9 entries.append(separator());
138
7/7
✓ Branch 50 → 51 taken 2 times.
✓ Branch 50 → 54 taken 7 times.
✓ Branch 52 → 53 taken 1 time.
✓ Branch 52 → 54 taken 1 time.
✓ Branch 55 → 56 taken 9 times.
✓ Branch 59 → 60 taken 9 times.
✓ Branch 61 → 62 taken 9 times.
18 entries.append(checkEntry(QStringLiteral("editor:range"), tr("Custom range…"), dated && preset.isEmpty()));
139 9 return entries;
140 9 }
141
142 // Yes / No / Any of a state, with the counts of the hits when known.
143 19 QVariantList stateEntries(const Context &context, Kind kind, const char *yes, const char *no, qint64 yesCount) {
144
1/1
✓ Branch 2 → 3 taken 19 times.
19 const int current = SearchTermModel::state(context.query, kind);
145
1/1
✓ Branch 3 → 4 taken 19 times.
19 const QString name = SearchTermModel::kindName(kind);
146
5/6
✓ Branch 4 → 5 taken 15 times.
✓ Branch 4 → 8 taken 4 times.
✓ Branch 5 → 6 taken 7 times.
✓ Branch 5 → 8 taken 8 times.
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 8 not taken.
19 const bool counted = context.countsShown && context.summary && yesCount >= 0;
147
2/2
✓ Branch 9 → 10 taken 9 times.
✓ Branch 9 → 11 taken 10 times.
19 const qint64 total = context.summary ? context.summary->total : -1;
148
3/3
✓ Branch 15 → 16 taken 19 times.
✓ Branch 20 → 21 taken 19 times.
✓ Branch 21 → 22 taken 19 times.
76 return {checkEntry(QStringLiteral("state:%1:1").arg(name), tr(yes), current == 1, counted ? yesCount : -1),
149
3/3
✓ Branch 26 → 27 taken 19 times.
✓ Branch 31 → 32 taken 19 times.
✓ Branch 32 → 33 taken 19 times.
76 checkEntry(QStringLiteral("state:%1:0").arg(name), tr(no), current == 0, counted ? total - yesCount : -1),
150
4/6
✓ Branch 39 → 40 taken 19 times.
✓ Branch 40 → 41 taken 19 times.
✓ Branch 44 → 45 taken 57 times.
✓ Branch 44 → 46 taken 19 times.
✗ Branch 65 → 66 not taken.
✗ Branch 65 → 67 not taken.
133 checkEntry(QStringLiteral("state:%1:-1").arg(name), tr("Any"), current == -1)};
151 95 }
152
153 19 qint64 stateCount(const MailSearchSummary *summary, Kind kind) {
154
2/2
✓ Branch 2 → 3 taken 10 times.
✓ Branch 2 → 4 taken 9 times.
19 if (!summary) return -1;
155
2/5
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 6 not taken.
✓ Branch 4 → 7 taken 4 times.
✗ Branch 4 → 8 not taken.
✗ Branch 4 → 9 not taken.
9 switch (kind) {
156 5 case Kind::Unread: return summary->unread;
157 ✗ case Kind::Flagged: return summary->flagged;
158 4 case Kind::Answered: return summary->answered;
159 ✗ case Kind::Attachment: return summary->withAttachment;
160 ✗ default: return -1;
161 }
162 }
163
164 19 QVariantList stateMenu(const Context &context, Kind kind) {
165 19 const qint64 count = stateCount(context.summary, kind);
166
2/5
✓ Branch 3 → 4 taken 10 times.
✗ Branch 3 → 5 not taken.
✓ Branch 3 → 6 taken 9 times.
✗ Branch 3 → 7 not taken.
✗ Branch 3 → 8 not taken.
19 switch (kind) {
167 10 case Kind::Unread:
168 return stateEntries(context, kind, QT_TRANSLATE_NOOP("SearchMenuModel", "Unread"),
169 10 QT_TRANSLATE_NOOP("SearchMenuModel", "Read"), count);
170 ✗ case Kind::Flagged:
171 return stateEntries(context, kind, QT_TRANSLATE_NOOP("SearchMenuModel", "Important"),
172 ✗ QT_TRANSLATE_NOOP("SearchMenuModel", "Not important"), count);
173 9 case Kind::Answered:
174 return stateEntries(context, kind, QT_TRANSLATE_NOOP("SearchMenuModel", "Answered"),
175 9 QT_TRANSLATE_NOOP("SearchMenuModel", "Not answered"), count);
176 ✗ case Kind::Attachment:
177 return stateEntries(context, kind, QT_TRANSLATE_NOOP("SearchMenuModel", "With attachment"),
178 ✗ QT_TRANSLATE_NOOP("SearchMenuModel", "Without attachment"), count);
179 ✗ default: return {};
180 }
181 }
182
183 16 bool isFacet(Kind kind) {
184
4/10
✓ Branch 2 → 3 taken 9 times.
✓ Branch 2 → 7 taken 7 times.
✓ Branch 3 → 4 taken 9 times.
✗ Branch 3 → 7 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 9 times.
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
16 return kind == Kind::From || kind == Kind::To || kind == Kind::Folder || kind == Kind::Label || kind == Kind::List;
185 }
186
187 8 bool isState(Kind kind) {
188
5/8
✓ Branch 2 → 3 taken 5 times.
✓ Branch 2 → 6 taken 3 times.
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 6 not taken.
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 6 not taken.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 5 times.
8 return kind == Kind::Unread || kind == Kind::Flagged || kind == Kind::Answered || kind == Kind::Attachment;
189 }
190
191 // "kind:value" after the verb; the value may contain ':' (folder paths).
192 23 bool splitKindValue(const QString &rest, Kind &kind, QString &value) {
193 23 const int colon = rest.indexOf(QLatin1Char(':'));
194
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 23 times.
23 if (colon <= 0) return false;
195
1/1
✓ Branch 7 → 8 taken 23 times.
23 const QString name = rest.left(colon);
196
1/1
✓ Branch 8 → 9 taken 23 times.
23 kind = SearchTermModel::kindFromName(name);
197
3/3
✓ Branch 9 → 10 taken 23 times.
✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 14 taken 22 times.
23 if (SearchTermModel::kindName(kind) != name) return false;
198
1/1
✓ Branch 14 → 15 taken 22 times.
22 value = rest.mid(colon + 1);
199 22 return true;
200 23 }
201
202 8 QString pick(const QString &query, Kind kind, const QString &value) {
203
5/5
✓ Branch 2 → 3 taken 8 times.
✓ Branch 8 → 9 taken 8 times.
✓ Branch 9 → 10 taken 8 times.
✓ Branch 23 → 11 taken 14 times.
✓ Branch 23 → 24 taken 7 times.
29 for (const Term &term : SearchTermModel::terms(query))
204
11/11
✓ Branch 12 → 13 taken 3 times.
✓ Branch 12 → 17 taken 11 times.
✓ Branch 13 → 14 taken 2 times.
✓ Branch 13 → 17 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 17 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 21 taken 13 times.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 26 → 27 taken 7 times.
✓ Branch 26 → 29 taken 1 time.
21 if (term.kind == kind && !term.negated && term.value == value) return SearchTermModel::remove(query, term.index);
205 7 return SearchTermModel::add(query, kind, value);
206 8 }
207
208 } // namespace
209
210 9 QVariantList filterEntries(const Context &context) {
211
1/1
✓ Branch 2 → 3 taken 9 times.
9 const QList<Term> terms = SearchTermModel::terms(context.query, context.lookups, context.locale);
212 9 QVariantList entries;
213
2/2
✓ Branch 6 → 7 taken 9 times.
✓ Branch 8 → 9 taken 9 times.
9 entries.append(facetMenu(context, terms, Kind::From, QStringLiteral("im-user")));
214
2/2
✓ Branch 16 → 17 taken 9 times.
✓ Branch 18 → 19 taken 9 times.
9 entries.append(facetMenu(context, terms, Kind::To, QStringLiteral("mail-reply-sender")));
215
2/2
✓ Branch 26 → 27 taken 9 times.
✓ Branch 28 → 29 taken 9 times.
9 entries.append(facetMenu(context, terms, Kind::Folder, QStringLiteral("folder")));
216
2/2
✓ Branch 36 → 37 taken 9 times.
✓ Branch 38 → 39 taken 9 times.
9 entries.append(facetMenu(context, terms, Kind::Label, QStringLiteral("tag")));
217
2/2
✓ Branch 46 → 47 taken 9 times.
✓ Branch 48 → 49 taken 9 times.
9 entries.append(facetMenu(context, terms, Kind::List, QStringLiteral("mail-mark-task")));
218
3/3
✓ Branch 56 → 57 taken 9 times.
✓ Branch 60 → 61 taken 9 times.
✓ Branch 62 → 63 taken 9 times.
18 entries.append(entry(QStringLiteral("editor:subject"), tr("Subject…"), -1, QStringLiteral("format-text-bold")));
219
2/2
✓ Branch 70 → 71 taken 9 times.
✓ Branch 72 → 73 taken 9 times.
9 entries.append(separator());
220
4/4
✓ Branch 75 → 76 taken 9 times.
✓ Branch 79 → 80 taken 9 times.
✓ Branch 83 → 84 taken 9 times.
✓ Branch 85 → 86 taken 9 times.
27 entries.append(submenu(QStringLiteral("date"), tr("Date"), QStringLiteral("view-calendar"), dateEntries(context.query)));
221
4/4
✓ Branch 94 → 95 taken 9 times.
✓ Branch 98 → 99 taken 9 times.
✓ Branch 102 → 103 taken 9 times.
✓ Branch 104 → 105 taken 9 times.
27 entries.append(submenu(QStringLiteral("unread"), tr("Read state"), QStringLiteral("mail-read"), stateMenu(context, Kind::Unread)));
222
4/4
✓ Branch 113 → 114 taken 9 times.
✓ Branch 117 → 118 taken 9 times.
✓ Branch 121 → 122 taken 9 times.
✓ Branch 123 → 124 taken 9 times.
27 entries.append(submenu(QStringLiteral("answered"), tr("Answered"), QStringLiteral("mail-replied"), stateMenu(context, Kind::Answered)));
223 9 return entries;
224 9 }
225
226 7 QVariantList chipEntries(const Context &context, int termIndex) {
227
1/1
✓ Branch 2 → 3 taken 7 times.
7 const QList<Term> terms = SearchTermModel::terms(context.query, context.lookups, context.locale);
228
5/6
✓ Branch 3 → 4 taken 7 times.
✗ Branch 3 → 6 not taken.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 6 times.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 6 times.
7 if (termIndex < 0 || termIndex >= terms.size()) return {};
229 6 const Term &term = terms.at(termIndex);
230
1/1
✓ Branch 11 → 12 taken 6 times.
6 const QString index = QString::number(termIndex);
231 6 QVariantList entries;
232
3/4
✓ Branch 12 → 13 taken 5 times.
✓ Branch 12 → 14 taken 1 time.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 33 taken 5 times.
6 if (term.kind == Kind::Text || term.kind == Kind::ExcludedText) {
233 // S106-327: negate() turns excluded text back into text but keeps free
234 // text as it is (typing "-word" excludes it) — no entry that does nothing.
235
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 32 taken 1 time.
1 if (term.kind == Kind::ExcludedText)
236 ✗ entries.append(entry(QStringLiteral("negate:") + index, tr("Include again")));
237
1/2
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 43 taken 5 times.
5 } else if (term.kind == Kind::Date) {
238 ✗ entries = dateEntries(context.query);
239 ✗ entries.append(separator());
240
2/2
✓ Branch 44 → 45 taken 1 time.
✓ Branch 44 → 54 taken 4 times.
5 } else if (isState(term.kind)) {
241
1/1
✓ Branch 45 → 46 taken 1 time.
1 entries = stateMenu(context, term.kind);
242
2/2
✓ Branch 48 → 49 taken 1 time.
✓ Branch 50 → 51 taken 1 time.
1 entries.append(separator());
243 } else {
244
3/3
✓ Branch 57 → 58 taken 4 times.
✓ Branch 58 → 59 taken 4 times.
✓ Branch 60 → 61 taken 4 times.
8 entries.append(checkEntry(QStringLiteral("edit:") + index, term.shortLabel, true));
245
5/6
✓ Branch 66 → 67 taken 3 times.
✓ Branch 66 → 70 taken 1 time.
✓ Branch 68 → 69 taken 3 times.
✗ Branch 68 → 70 not taken.
✓ Branch 71 → 72 taken 3 times.
✓ Branch 71 → 103 taken 1 time.
4 if (!term.negated && isFacet(term.kind)) {
246
2/2
✓ Branch 73 → 74 taken 2 times.
✓ Branch 73 → 103 taken 1 time.
3 if (const auto *values = facetValues(context.summary, term.kind)) {
247
1/1
✓ Branch 74 → 75 taken 2 times.
2 const QStringList current = currentValues(terms, term.kind);
248
2/2
✓ Branch 100 → 77 taken 4 times.
✓ Branch 100 → 101 taken 2 times.
6 for (const MailSearchFacetValue &value : *values)
249
2/2
✓ Branch 79 → 80 taken 2 times.
✓ Branch 79 → 98 taken 2 times.
4 if (!current.contains(value.value))
250
3/3
✓ Branch 87 → 88 taken 2 times.
✓ Branch 88 → 89 taken 2 times.
✓ Branch 90 → 91 taken 2 times.
4 entries.append(checkEntry(QStringLiteral("replace:%1:%2").arg(index, value.value),
251
1/1
✓ Branch 83 → 84 taken 2 times.
4 shownValue(term.kind, value, context.lookups), false,
252
1/2
✓ Branch 80 → 81 taken 2 times.
✗ Branch 80 → 82 not taken.
2 context.countsShown ? value.count : -1));
253 2 }
254 }
255
2/2
✓ Branch 103 → 104 taken 4 times.
✓ Branch 105 → 106 taken 4 times.
4 entries.append(separator());
256
4/4
✓ Branch 111 → 112 taken 4 times.
✓ Branch 115 → 116 taken 4 times.
✓ Branch 116 → 117 taken 4 times.
✓ Branch 118 → 119 taken 4 times.
8 entries.append(entry(QStringLiteral("edit:") + index, tr("Edit…"), -1, QStringLiteral("document-edit")));
257
1/2
✓ Branch 127 → 128 taken 4 times.
✗ Branch 127 → 150 not taken.
4 if (term.kind != Kind::About) // about: has no negated form
258
7/7
✓ Branch 131 → 132 taken 1 time.
✓ Branch 131 → 133 taken 3 times.
✓ Branch 132 → 134 taken 1 time.
✓ Branch 133 → 134 taken 3 times.
✓ Branch 137 → 138 taken 4 times.
✓ Branch 138 → 139 taken 4 times.
✓ Branch 140 → 141 taken 4 times.
8 entries.append(entry(QStringLiteral("negate:") + index, term.negated ? tr("Include again") : tr("Exclude"), -1,
259 8 QStringLiteral("list-remove")));
260 }
261
4/4
✓ Branch 153 → 154 taken 6 times.
✓ Branch 157 → 158 taken 6 times.
✓ Branch 158 → 159 taken 6 times.
✓ Branch 160 → 161 taken 6 times.
12 entries.append(entry(QStringLiteral("remove:") + index, tr("Remove"), -1, QStringLiteral("edit-delete")));
262 6 return entries;
263 7 }
264
265 namespace {
266 38 QString lastWord(const QString &fieldText) {
267
3/3
✓ Branch 4 → 5 taken 38 times.
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 37 times.
38 if (fieldText.endsWith(QLatin1Char(' '))) return {};
268
2/2
✓ Branch 10 → 11 taken 37 times.
✓ Branch 11 → 12 taken 37 times.
37 return fieldText.section(QLatin1Char(' '), -1).trimmed();
269 }
270 } // namespace
271
272 33 QVariantList personCompletions(const Context &context, const QString &fieldText, int limit) {
273
1/1
✓ Branch 2 → 3 taken 33 times.
33 const QString word = lastWord(fieldText);
274
11/12
✓ Branch 3 → 4 taken 24 times.
✓ Branch 3 → 14 taken 9 times.
✓ Branch 5 → 6 taken 22 times.
✓ Branch 5 → 14 taken 2 times.
✓ Branch 8 → 9 taken 22 times.
✓ Branch 9 → 10 taken 20 times.
✓ Branch 9 → 14 taken 2 times.
✓ Branch 12 → 13 taken 20 times.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 20 times.
✓ Branch 16 → 17 taken 13 times.
✓ Branch 16 → 18 taken 20 times.
33 if (!context.summary || word.size() < 2 || word.contains(QLatin1Char(':')) || word.startsWith(QLatin1Char('-')))
275 13 return {};
276
1/1
✓ Branch 18 → 19 taken 20 times.
20 const QList<Term> terms = SearchTermModel::terms(context.query, context.lookups, context.locale);
277 20 QVariantList rows;
278 20 QStringList seen;
279 40 const auto addFrom = [&](Kind kind, const QList<MailSearchFacetValue> &values, const char *pattern) {
280
1/1
✓ Branch 2 → 3 taken 40 times.
40 const QStringList current = currentValues(terms, kind);
281
2/2
✓ Branch 78 → 5 taken 35 times.
✓ Branch 78 → 79 taken 40 times.
75 for (const MailSearchFacetValue &value : values) {
282
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 35 times.
35 if (rows.size() >= limit) return;
283
1/1
✓ Branch 9 → 10 taken 35 times.
35 const QString name = shownValue(kind, value, context.lookups);
284
11/16
✓ Branch 11 → 12 taken 33 times.
✓ Branch 11 → 16 taken 2 times.
✓ Branch 12 → 13 taken 33 times.
✓ Branch 13 → 14 taken 33 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 33 times.
✓ Branch 18 → 19 taken 33 times.
✓ Branch 18 → 20 taken 2 times.
✓ Branch 20 → 21 taken 33 times.
✓ Branch 20 → 22 taken 2 times.
✓ Branch 22 → 23 taken 2 times.
✓ Branch 22 → 24 taken 33 times.
✗ Branch 86 → 87 not taken.
✗ Branch 86 → 88 not taken.
✗ Branch 90 → 91 not taken.
✗ Branch 90 → 92 not taken.
35 if (current.contains(value.value) || seen.contains(SearchTermModel::kindName(kind) + value.value)) continue;
285
7/8
✓ Branch 24 → 25 taken 33 times.
✓ Branch 25 → 26 taken 25 times.
✓ Branch 25 → 29 taken 8 times.
✓ Branch 26 → 27 taken 25 times.
✓ Branch 27 → 28 taken 25 times.
✗ Branch 27 → 29 not taken.
✓ Branch 30 → 31 taken 25 times.
✓ Branch 30 → 32 taken 8 times.
33 if (!name.contains(word, Qt::CaseInsensitive) && !value.value.contains(word, Qt::CaseInsensitive)) continue;
286
3/3
✓ Branch 32 → 33 taken 8 times.
✓ Branch 33 → 34 taken 8 times.
✓ Branch 34 → 35 taken 8 times.
8 seen.append(SearchTermModel::kindName(kind) + value.value);
287
2/2
✓ Branch 47 → 48 taken 8 times.
✓ Branch 48 → 49 taken 8 times.
24 QVariantMap row = entry(QStringLiteral("person:%1:%2").arg(SearchTermModel::kindName(kind), value.value),
288
4/5
✓ Branch 38 → 39 taken 8 times.
✗ Branch 38 → 40 not taken.
✓ Branch 41 → 42 taken 8 times.
✓ Branch 43 → 44 taken 8 times.
✓ Branch 49 → 50 taken 8 times.
32 tr(pattern).arg(name), context.countsShown ? value.count : -1);
289
1/1
✓ Branch 61 → 62 taken 8 times.
16 row.insert(QStringLiteral("detail"), value.value);
290
1/1
✓ Branch 66 → 67 taken 8 times.
8 rows.append(row);
291 35 }
292
1/2
✓ Branch 81 → 82 taken 40 times.
✗ Branch 81 → 84 not taken.
40 };
293
1/1
✓ Branch 19 → 20 taken 20 times.
20 addFrom(Kind::From, context.summary->topSenders, QT_TRANSLATE_NOOP("SearchMenuModel", "From %1"));
294
1/1
✓ Branch 20 → 21 taken 20 times.
20 addFrom(Kind::To, context.summary->topRecipients, QT_TRANSLATE_NOOP("SearchMenuModel", "To %1"));
295 20 return rows;
296 33 }
297
298 6 QString applyPerson(const QString &query, const QString &fieldText, const QString &id) {
299
2/3
✓ Branch 3 → 4 taken 6 times.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 6 times.
6 if (!id.startsWith(QLatin1String("person:"))) return {};
300 6 Kind kind = Kind::Text;
301 6 QString value;
302
11/16
✓ Branch 6 → 7 taken 6 times.
✓ Branch 7 → 8 taken 6 times.
✓ Branch 8 → 9 taken 6 times.
✗ Branch 8 → 13 not taken.
✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 11 taken 4 times.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 13 taken 1 time.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 5 times.
✓ Branch 15 → 16 taken 6 times.
✗ Branch 15 → 17 not taken.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 17 → 19 taken 5 times.
✗ Branch 52 → 53 not taken.
✗ Branch 52 → 54 not taken.
6 if (!splitKindValue(id.mid(7), kind, value) || (kind != Kind::From && kind != Kind::To) || value.isEmpty()) return {};
303 // S106-326: lastWord() is trimmed — trailing white space (a pasted tab,
304 // no-break space or line break) goes before the word is cut off.
305 5 QString text = fieldText;
306
7/8
✓ Branch 21 → 22 taken 3 times.
✓ Branch 23 → 24 taken 8 times.
✗ Branch 23 → 28 not taken.
✓ Branch 24 → 25 taken 8 times.
✓ Branch 26 → 27 taken 3 times.
✓ Branch 26 → 28 taken 5 times.
✓ Branch 29 → 21 taken 3 times.
✓ Branch 29 → 30 taken 5 times.
8 while (!text.isEmpty() && text.back().isSpace()) text.chop(1);
307
1/1
✓ Branch 30 → 31 taken 5 times.
5 const QString word = lastWord(fieldText);
308
5/8
✓ Branch 32 → 33 taken 5 times.
✗ Branch 32 → 36 not taken.
✓ Branch 33 → 34 taken 5 times.
✓ Branch 34 → 35 taken 5 times.
✗ Branch 34 → 36 not taken.
✓ Branch 37 → 38 taken 5 times.
✗ Branch 37 → 40 not taken.
✓ Branch 39 → 40 taken 5 times.
5 if (!word.isEmpty() && text.endsWith(word)) text.chop(word.size());
309
3/3
✓ Branch 40 → 41 taken 5 times.
✓ Branch 41 → 42 taken 5 times.
✓ Branch 42 → 43 taken 5 times.
10 return SearchTermModel::add(SearchTermModel::withFieldText(query, text.trimmed()), kind, value);
310 6 }
311
312 518 QVariantList folderFacets(const Context &context, const QList<FolderRow> &tree) {
313 518 QHash<QString, qint64> counts;
314
2/2
✓ Branch 2 → 3 taken 422 times.
✓ Branch 2 → 11 taken 96 times.
518 if (context.summary)
315
3/3
✓ Branch 6 → 7 taken 726 times.
✓ Branch 9 → 5 taken 726 times.
✓ Branch 9 → 10 taken 422 times.
1148 for (const MailSearchFacetValue &value : context.summary->folders) counts.insert(value.value, value.count);
316
2/2
✓ Branch 11 → 12 taken 518 times.
✓ Branch 15 → 16 taken 518 times.
1036 const QStringList picked = currentValues(SearchTermModel::terms(context.query), Kind::Folder);
317
1/1
✓ Branch 20 → 21 taken 518 times.
518 QVector<bool> keep(tree.size(), false);
318 518 QList<int> ancestors; // indexes of the open path above the current row
319
2/2
✓ Branch 55 → 22 taken 1570 times.
✓ Branch 55 → 56 taken 518 times.
2088 for (int i = 0; i < tree.size(); ++i) {
320
7/7
✓ Branch 25 → 26 taken 1076 times.
✓ Branch 25 → 31 taken 1542 times.
✓ Branch 26 → 27 taken 1076 times.
✓ Branch 29 → 30 taken 1048 times.
✓ Branch 29 → 31 taken 28 times.
✓ Branch 32 → 23 taken 1048 times.
✓ Branch 32 → 33 taken 1570 times.
2618 while (!ancestors.isEmpty() && tree.at(ancestors.last()).depth >= tree.at(i).depth) ancestors.removeLast();
321
6/6
✓ Branch 35 → 36 taken 844 times.
✓ Branch 35 → 39 taken 726 times.
✓ Branch 38 → 39 taken 10 times.
✓ Branch 38 → 40 taken 834 times.
✓ Branch 41 → 42 taken 736 times.
✓ Branch 41 → 52 taken 834 times.
1570 if (counts.value(tree.at(i).path) > 0 || picked.contains(tree.at(i).path)) {
322
1/1
✓ Branch 42 → 43 taken 736 times.
736 keep[i] = true;
323
3/3
✓ Branch 47 → 48 taken 3 times.
✓ Branch 50 → 46 taken 3 times.
✓ Branch 50 → 51 taken 736 times.
739 for (const int ancestor : std::as_const(ancestors)) keep[ancestor] = true;
324 }
325
1/1
✓ Branch 52 → 53 taken 1570 times.
1570 ancestors.append(i);
326 }
327 518 QVariantList rows;
328
2/2
✓ Branch 107 → 57 taken 1570 times.
✓ Branch 107 → 108 taken 518 times.
2088 for (int i = 0; i < tree.size(); ++i) {
329
2/2
✓ Branch 58 → 59 taken 831 times.
✓ Branch 58 → 60 taken 739 times.
1570 if (!keep.at(i)) continue;
330 739 const FolderRow &row = tree.at(i);
331 739 const qint64 count = counts.value(row.path, 0);
332
1/1
✓ Branch 70 → 71 taken 739 times.
2217 QVariantMap item = checkEntry(QStringLiteral("pick:folder:") + row.path, row.name, picked.contains(row.path),
333
4/5
✓ Branch 62 → 63 taken 726 times.
✓ Branch 62 → 65 taken 13 times.
✓ Branch 63 → 64 taken 726 times.
✗ Branch 63 → 65 not taken.
✓ Branch 71 → 72 taken 739 times.
2217 count > 0 && context.countsShown ? count : -1);
334
1/1
✓ Branch 79 → 80 taken 739 times.
1478 item.insert(QStringLiteral("path"), row.path);
335
1/1
✓ Branch 87 → 88 taken 739 times.
1478 item.insert(QStringLiteral("depth"), row.depth);
336
1/1
✓ Branch 95 → 96 taken 739 times.
1478 item.insert(QStringLiteral("hits"), count > 0);
337
1/1
✓ Branch 100 → 101 taken 739 times.
739 rows.append(item);
338 739 }
339 518 return rows;
340 1036 }
341
342 1033 QVariantList sidebarValues(const Context &context, Kind kind, int limit) {
343
1/1
✓ Branch 2 → 3 taken 1033 times.
1033 const QList<Term> terms = SearchTermModel::terms(context.query, context.lookups, context.locale);
344
1/1
✓ Branch 3 → 4 taken 1033 times.
1033 QVariantList rows = valueEntries(context, terms, kind);
345
1/1
✓ Branch 4 → 5 taken 1033 times.
2066 return rows.mid(0, limit);
346 1033 }
347
348 33 bool isViewAction(const QString &id) {
349
6/6
✓ Branch 3 → 4 taken 33 times.
✓ Branch 4 → 5 taken 31 times.
✓ Branch 4 → 11 taken 2 times.
✓ Branch 6 → 7 taken 31 times.
✓ Branch 7 → 8 taken 30 times.
✓ Branch 7 → 11 taken 1 time.
63 return id.startsWith(QLatin1String("editor:")) || id.startsWith(QLatin1String("edit:")) ||
350
3/3
✓ Branch 9 → 10 taken 30 times.
✓ Branch 10 → 11 taken 2 times.
✓ Branch 10 → 12 taken 28 times.
63 id.startsWith(QLatin1String("view:"));
351 }
352
353 32 QString apply(const QString &query, const QString &id) {
354 32 const int colon = id.indexOf(QLatin1Char(':'));
355
7/7
✓ Branch 5 → 6 taken 30 times.
✓ Branch 5 → 8 taken 2 times.
✓ Branch 6 → 7 taken 30 times.
✓ Branch 7 → 8 taken 3 times.
✓ Branch 7 → 9 taken 27 times.
✓ Branch 10 → 11 taken 5 times.
✓ Branch 10 → 12 taken 27 times.
32 if (colon <= 0 || isViewAction(id)) return {};
356
1/1
✓ Branch 12 → 13 taken 27 times.
27 const QString verb = id.left(colon);
357
1/1
✓ Branch 13 → 14 taken 27 times.
27 const QString rest = id.mid(colon + 1);
358 27 Kind kind = Kind::Text;
359 27 QString value;
360
10/11
✓ Branch 16 → 17 taken 10 times.
✓ Branch 16 → 24 taken 17 times.
✓ Branch 17 → 18 taken 10 times.
✓ Branch 18 → 19 taken 9 times.
✓ Branch 18 → 24 taken 1 time.
✓ Branch 20 → 21 taken 9 times.
✗ Branch 20 → 24 not taken.
✓ Branch 22 → 23 taken 8 times.
✓ Branch 22 → 24 taken 1 time.
✓ Branch 25 → 26 taken 8 times.
✓ Branch 25 → 28 taken 19 times.
27 if (verb == QLatin1String("pick") && splitKindValue(rest, kind, value) && isFacet(kind) && !value.isEmpty())
361
1/1
✓ Branch 26 → 27 taken 8 times.
8 return pick(query, kind, value);
362
8/11
✓ Branch 30 → 31 taken 4 times.
✓ Branch 30 → 38 taken 15 times.
✓ Branch 31 → 32 taken 4 times.
✓ Branch 32 → 33 taken 4 times.
✗ Branch 32 → 38 not taken.
✓ Branch 34 → 35 taken 4 times.
✗ Branch 34 → 38 not taken.
✓ Branch 36 → 37 taken 4 times.
✗ Branch 36 → 38 not taken.
✓ Branch 39 → 40 taken 4 times.
✓ Branch 39 → 42 taken 15 times.
19 if (verb == QLatin1String("exclude") && splitKindValue(rest, kind, value) && isFacet(kind) && !value.isEmpty())
363
1/1
✓ Branch 40 → 41 taken 4 times.
4 return SearchTermModel::add(query, kind, value, true);
364
8/9
✓ Branch 44 → 45 taken 3 times.
✓ Branch 44 → 50 taken 12 times.
✓ Branch 45 → 46 taken 3 times.
✓ Branch 46 → 47 taken 3 times.
✗ Branch 46 → 50 not taken.
✓ Branch 48 → 49 taken 2 times.
✓ Branch 48 → 50 taken 1 time.
✓ Branch 51 → 52 taken 2 times.
✓ Branch 51 → 58 taken 13 times.
15 if (verb == QLatin1String("state") && splitKindValue(rest, kind, value) && isState(kind)) {
365 2 bool ok = false;
366
1/1
✓ Branch 52 → 53 taken 2 times.
2 const int state = value.toInt(&ok);
367
2/3
✓ Branch 53 → 54 taken 2 times.
✗ Branch 53 → 55 not taken.
✓ Branch 54 → 56 taken 2 times.
2 return ok ? SearchTermModel::setState(query, kind, state) : QString();
368 }
369
3/3
✓ Branch 60 → 61 taken 2 times.
✓ Branch 60 → 63 taken 11 times.
✓ Branch 61 → 62 taken 2 times.
13 if (verb == QLatin1String("date")) return SearchTermModel::setDatePreset(query, rest);
370
2/2
✓ Branch 65 → 66 taken 1 time.
✓ Branch 65 → 84 taken 10 times.
11 if (verb == QLatin1String("replace")) {
371 1 const int split = rest.indexOf(QLatin1Char(':'));
372 1 bool ok = false;
373
4/8
✓ Branch 69 → 70 taken 1 time.
✗ Branch 69 → 73 not taken.
✓ Branch 70 → 71 taken 1 time.
✓ Branch 71 → 72 taken 1 time.
✓ Branch 74 → 75 taken 1 time.
✗ Branch 74 → 76 not taken.
✗ Branch 107 → 108 not taken.
✗ Branch 107 → 109 not taken.
1 const int index = split > 0 ? rest.left(split).toInt(&ok) : -1;
374
4/8
✓ Branch 76 → 77 taken 1 time.
✗ Branch 76 → 79 not taken.
✓ Branch 77 → 78 taken 1 time.
✓ Branch 78 → 80 taken 1 time.
✓ Branch 81 → 82 taken 1 time.
✗ Branch 81 → 83 not taken.
✗ Branch 111 → 112 not taken.
✗ Branch 111 → 113 not taken.
2 return ok ? SearchTermModel::replace(query, index, rest.mid(split + 1)) : QString();
375 }
376 10 bool ok = false;
377
1/1
✓ Branch 84 → 85 taken 10 times.
10 const int index = rest.toInt(&ok);
378
2/2
✓ Branch 85 → 86 taken 6 times.
✓ Branch 85 → 87 taken 4 times.
10 if (!ok) return {};
379
3/3
✓ Branch 89 → 90 taken 2 times.
✓ Branch 89 → 92 taken 2 times.
✓ Branch 90 → 91 taken 2 times.
4 if (verb == QLatin1String("negate")) return SearchTermModel::negate(query, index);
380
2/3
✓ Branch 94 → 95 taken 2 times.
✗ Branch 94 → 97 not taken.
✓ Branch 95 → 96 taken 2 times.
2 if (verb == QLatin1String("remove")) return SearchTermModel::remove(query, index);
381 ✗ return {};
382 27 }
383
384 } // namespace SearchMenuModel
385